mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-02-17 19:19:16 +01:00
CRLF to LF + cleanup
This commit is contained in:
parent
32400b311b
commit
588c24b767
@ -1,206 +1,205 @@
|
||||
#include "coding.h"
|
||||
|
||||
#include "ea_mt_decoder_utk.h"
|
||||
|
||||
/* Decodes EA MicroTalk (speech codec) using utkencode lib (slightly modified for vgmstream).
|
||||
* EA separates MT10:1 and MT5:1 (bigger frames), but apparently are the same
|
||||
* with different encoding parameters. Later revisions may have PCM blocks (rare).
|
||||
*
|
||||
* Decoder by Andrew D'Addesio: https://github.com/daddesio/utkencode
|
||||
* Info: http://wiki.niotso.org/UTK
|
||||
*/
|
||||
|
||||
|
||||
//#define UTK_MAKE_U32(a,b,c,d) ((a)|((b)<<8)|((c)<<16)|((d)<<24))
|
||||
#define UTK_ROUND(x) ((x) >= 0.0f ? ((x)+0.5f) : ((x)-0.5f))
|
||||
#define UTK_MIN(x,y) ((x)<(y)?(x):(y))
|
||||
#define UTK_MAX(x,y) ((x)>(y)?(x):(y))
|
||||
#define UTK_CLAMP(x,min,max) UTK_MIN(UTK_MAX(x,min),max)
|
||||
|
||||
#define UTK_BUFFER_SIZE 0x1000
|
||||
|
||||
struct ea_mt_codec_data {
|
||||
STREAMFILE *streamfile;
|
||||
uint8_t buffer[UTK_BUFFER_SIZE];
|
||||
off_t offset;
|
||||
off_t loop_offset;
|
||||
int loop_sample;
|
||||
|
||||
int pcm_blocks;
|
||||
int samples_filled;
|
||||
int samples_used;
|
||||
int samples_done;
|
||||
int samples_discard;
|
||||
void* utk_context;
|
||||
};
|
||||
|
||||
static size_t ea_mt_read_callback(void *dest, int size, void *arg);
|
||||
|
||||
ea_mt_codec_data *init_ea_mt(int channels, int pcm_blocks) {
|
||||
return init_ea_mt_loops(channels, pcm_blocks, 0, NULL);
|
||||
}
|
||||
|
||||
ea_mt_codec_data *init_ea_mt_loops(int channels, int pcm_blocks, int loop_sample, off_t *loop_offsets) {
|
||||
ea_mt_codec_data *data = NULL;
|
||||
int i;
|
||||
|
||||
data = calloc(channels, sizeof(ea_mt_codec_data)); /* one decoder per channel */
|
||||
if (!data) goto fail;
|
||||
|
||||
for (i = 0; i < channels; i++) {
|
||||
data[i].utk_context = calloc(1, sizeof(UTKContext));
|
||||
if (!data[i].utk_context) goto fail;
|
||||
utk_init(data[i].utk_context);
|
||||
|
||||
data[i].pcm_blocks = pcm_blocks;
|
||||
data[i].loop_sample = loop_sample;
|
||||
if (loop_offsets)
|
||||
data[i].loop_offset = loop_offsets[i];
|
||||
|
||||
utk_set_callback(data[i].utk_context, data[i].buffer, UTK_BUFFER_SIZE, &data[i], &ea_mt_read_callback);
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
fail:
|
||||
free_ea_mt(data, channels);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void decode_ea_mt(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) {
|
||||
int i;
|
||||
ea_mt_codec_data *data = vgmstream->codec_data;
|
||||
ea_mt_codec_data *ch_data = &data[channel];
|
||||
UTKContext* ctx = ch_data->utk_context;
|
||||
int samples_done = 0;
|
||||
|
||||
|
||||
while (samples_done < samples_to_do) {
|
||||
|
||||
if (ch_data->samples_filled) {
|
||||
/* consume current frame */
|
||||
int samples_to_get = ch_data->samples_filled;
|
||||
|
||||
/* don't go past loop, to reset decoder */
|
||||
if (ch_data->loop_sample > 0 && ch_data->samples_done < ch_data->loop_sample &&
|
||||
ch_data->samples_done + samples_to_get > ch_data->loop_sample)
|
||||
samples_to_get = ch_data->loop_sample - ch_data->samples_done;
|
||||
|
||||
if (ch_data->samples_discard) {
|
||||
/* discard samples for looping */
|
||||
if (samples_to_get > ch_data->samples_discard)
|
||||
samples_to_get = ch_data->samples_discard;
|
||||
ch_data->samples_discard -= samples_to_get;
|
||||
}
|
||||
else {
|
||||
/* get max samples and copy */
|
||||
if (samples_to_get > samples_to_do - samples_done)
|
||||
samples_to_get = samples_to_do - samples_done;
|
||||
|
||||
for (i = ch_data->samples_used; i < ch_data->samples_used + samples_to_get; i++) {
|
||||
int pcm = UTK_ROUND(ctx->decompressed_frame[i]);
|
||||
outbuf[0] = (int16_t)UTK_CLAMP(pcm, -32768, 32767);
|
||||
outbuf += channelspacing;
|
||||
}
|
||||
|
||||
samples_done += samples_to_get;
|
||||
}
|
||||
|
||||
/* mark consumed samples */
|
||||
ch_data->samples_used += samples_to_get;
|
||||
ch_data->samples_filled -= samples_to_get;
|
||||
ch_data->samples_done += samples_to_get;
|
||||
|
||||
/* Loops in EA-MT are done with fully separate intro/loop substreams. We must
|
||||
* notify the decoder when a new substream begins (even with looping disabled). */
|
||||
if (ch_data->loop_sample > 0 && ch_data->samples_done == ch_data->loop_sample) {
|
||||
ch_data->samples_filled = 0;
|
||||
ch_data->samples_discard = 0;
|
||||
|
||||
/* offset is usually at loop_offset here, but not always (ex. loop_sample < 432) */
|
||||
ch_data->offset = ch_data->loop_offset;
|
||||
utk_set_ptr(ctx, 0, 0); /* reset the buffer reader */
|
||||
utk_reset(ctx); /* decoder init (all fields must be reset, for some edge cases) */
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* new frame */
|
||||
if (ch_data->pcm_blocks)
|
||||
utk_rev3_decode_frame(ctx);
|
||||
else
|
||||
utk_decode_frame(ctx);
|
||||
|
||||
ch_data->samples_used = 0;
|
||||
ch_data->samples_filled = 432;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void flush_ea_mt_offsets(VGMSTREAM *vgmstream, int is_start, int samples_discard) {
|
||||
ea_mt_codec_data *data = vgmstream->codec_data;
|
||||
int i;
|
||||
|
||||
if (!data) return;
|
||||
|
||||
|
||||
/* EA-MT frames are VBR (not byte-aligned?), so utk_decoder reads new buffer data automatically.
|
||||
* When decoding starts or a SCHl block changes, flush_ea_mt must be called to reset the state.
|
||||
* A bit hacky but would need some restructuring otherwise. */
|
||||
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
UTKContext* ctx = data[i].utk_context;
|
||||
|
||||
data[i].streamfile = vgmstream->ch[i].streamfile; /* maybe should keep its own STREAMFILE? */
|
||||
if (is_start)
|
||||
data[i].offset = vgmstream->ch[i].channel_start_offset;
|
||||
else
|
||||
data[i].offset = vgmstream->ch[i].offset;
|
||||
utk_set_ptr(ctx, 0, 0); /* reset the buffer reader */
|
||||
|
||||
if (is_start) {
|
||||
utk_reset(ctx);
|
||||
ctx->parsed_header = 0;
|
||||
data[i].samples_done = 0;
|
||||
}
|
||||
|
||||
data[i].samples_filled = 0;
|
||||
data[i].samples_discard = samples_discard;
|
||||
}
|
||||
}
|
||||
|
||||
void flush_ea_mt(VGMSTREAM *vgmstream) {
|
||||
flush_ea_mt_offsets(vgmstream, 0, 0);
|
||||
}
|
||||
|
||||
void reset_ea_mt(VGMSTREAM *vgmstream) {
|
||||
flush_ea_mt_offsets(vgmstream, 1, 0);
|
||||
}
|
||||
|
||||
void seek_ea_mt(VGMSTREAM * vgmstream, int32_t num_sample) {
|
||||
flush_ea_mt_offsets(vgmstream, 1, num_sample);
|
||||
}
|
||||
|
||||
void free_ea_mt(ea_mt_codec_data *data, int channels) {
|
||||
int i;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
for (i = 0; i < channels; i++) {
|
||||
free(data[i].utk_context);
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
|
||||
/* ********************** */
|
||||
|
||||
static size_t ea_mt_read_callback(void *dest, int size, void *arg) {
|
||||
ea_mt_codec_data *ch_data = arg;
|
||||
int bytes_read;
|
||||
|
||||
bytes_read = read_streamfile(dest,ch_data->offset,size,ch_data->streamfile);
|
||||
ch_data->offset += bytes_read;
|
||||
|
||||
return bytes_read;
|
||||
|
||||
}
|
||||
#include "coding.h"
|
||||
|
||||
#include "ea_mt_decoder_utk.h"
|
||||
|
||||
/* Decodes EA MicroTalk (speech codec) using utkencode lib (slightly modified for vgmstream).
|
||||
* EA separates MT10:1 and MT5:1 (bigger frames), but apparently are the same
|
||||
* with different encoding parameters. Later revisions may have PCM blocks (rare).
|
||||
*
|
||||
* Decoder by Andrew D'Addesio: https://github.com/daddesio/utkencode
|
||||
* Info: http://wiki.niotso.org/UTK
|
||||
*/
|
||||
|
||||
|
||||
//#define UTK_MAKE_U32(a,b,c,d) ((a)|((b)<<8)|((c)<<16)|((d)<<24))
|
||||
#define UTK_ROUND(x) ((x) >= 0.0f ? ((x)+0.5f) : ((x)-0.5f))
|
||||
#define UTK_MIN(x,y) ((x)<(y)?(x):(y))
|
||||
#define UTK_MAX(x,y) ((x)>(y)?(x):(y))
|
||||
#define UTK_CLAMP(x,min,max) UTK_MIN(UTK_MAX(x,min),max)
|
||||
|
||||
#define UTK_BUFFER_SIZE 0x1000
|
||||
|
||||
struct ea_mt_codec_data {
|
||||
STREAMFILE *streamfile;
|
||||
uint8_t buffer[UTK_BUFFER_SIZE];
|
||||
off_t offset;
|
||||
off_t loop_offset;
|
||||
int loop_sample;
|
||||
|
||||
int pcm_blocks;
|
||||
int samples_filled;
|
||||
int samples_used;
|
||||
int samples_done;
|
||||
int samples_discard;
|
||||
void* utk_context;
|
||||
};
|
||||
|
||||
static size_t ea_mt_read_callback(void *dest, int size, void *arg);
|
||||
|
||||
ea_mt_codec_data* init_ea_mt(int channels, int pcm_blocks) {
|
||||
return init_ea_mt_loops(channels, pcm_blocks, 0, NULL);
|
||||
}
|
||||
|
||||
ea_mt_codec_data* init_ea_mt_loops(int channels, int pcm_blocks, int loop_sample, off_t *loop_offsets) {
|
||||
ea_mt_codec_data* data = NULL;
|
||||
int i;
|
||||
|
||||
data = calloc(channels, sizeof(ea_mt_codec_data)); /* one decoder per channel */
|
||||
if (!data) goto fail;
|
||||
|
||||
for (i = 0; i < channels; i++) {
|
||||
data[i].utk_context = calloc(1, sizeof(UTKContext));
|
||||
if (!data[i].utk_context) goto fail;
|
||||
utk_init(data[i].utk_context);
|
||||
|
||||
data[i].pcm_blocks = pcm_blocks;
|
||||
data[i].loop_sample = loop_sample;
|
||||
if (loop_offsets)
|
||||
data[i].loop_offset = loop_offsets[i];
|
||||
|
||||
utk_set_callback(data[i].utk_context, data[i].buffer, UTK_BUFFER_SIZE, &data[i], &ea_mt_read_callback);
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
fail:
|
||||
free_ea_mt(data, channels);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void decode_ea_mt(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t samples_to_do, int channel) {
|
||||
int i;
|
||||
ea_mt_codec_data* data = vgmstream->codec_data;
|
||||
ea_mt_codec_data* ch_data = &data[channel];
|
||||
UTKContext* ctx = ch_data->utk_context;
|
||||
int samples_done = 0;
|
||||
|
||||
|
||||
while (samples_done < samples_to_do) {
|
||||
|
||||
if (ch_data->samples_filled) {
|
||||
/* consume current frame */
|
||||
int samples_to_get = ch_data->samples_filled;
|
||||
|
||||
/* don't go past loop, to reset decoder */
|
||||
if (ch_data->loop_sample > 0 && ch_data->samples_done < ch_data->loop_sample &&
|
||||
ch_data->samples_done + samples_to_get > ch_data->loop_sample)
|
||||
samples_to_get = ch_data->loop_sample - ch_data->samples_done;
|
||||
|
||||
if (ch_data->samples_discard) {
|
||||
/* discard samples for looping */
|
||||
if (samples_to_get > ch_data->samples_discard)
|
||||
samples_to_get = ch_data->samples_discard;
|
||||
ch_data->samples_discard -= samples_to_get;
|
||||
}
|
||||
else {
|
||||
/* get max samples and copy */
|
||||
if (samples_to_get > samples_to_do - samples_done)
|
||||
samples_to_get = samples_to_do - samples_done;
|
||||
|
||||
for (i = ch_data->samples_used; i < ch_data->samples_used + samples_to_get; i++) {
|
||||
int pcm = UTK_ROUND(ctx->decompressed_frame[i]);
|
||||
outbuf[0] = (int16_t)UTK_CLAMP(pcm, -32768, 32767);
|
||||
outbuf += channelspacing;
|
||||
}
|
||||
|
||||
samples_done += samples_to_get;
|
||||
}
|
||||
|
||||
/* mark consumed samples */
|
||||
ch_data->samples_used += samples_to_get;
|
||||
ch_data->samples_filled -= samples_to_get;
|
||||
ch_data->samples_done += samples_to_get;
|
||||
|
||||
/* Loops in EA-MT are done with fully separate intro/loop substreams. We must
|
||||
* notify the decoder when a new substream begins (even with looping disabled). */
|
||||
if (ch_data->loop_sample > 0 && ch_data->samples_done == ch_data->loop_sample) {
|
||||
ch_data->samples_filled = 0;
|
||||
ch_data->samples_discard = 0;
|
||||
|
||||
/* offset is usually at loop_offset here, but not always (ex. loop_sample < 432) */
|
||||
ch_data->offset = ch_data->loop_offset;
|
||||
utk_set_ptr(ctx, 0, 0); /* reset the buffer reader */
|
||||
utk_reset(ctx); /* decoder init (all fields must be reset, for some edge cases) */
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* new frame */
|
||||
if (ch_data->pcm_blocks)
|
||||
utk_rev3_decode_frame(ctx);
|
||||
else
|
||||
utk_decode_frame(ctx);
|
||||
|
||||
ch_data->samples_used = 0;
|
||||
ch_data->samples_filled = 432;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void flush_ea_mt_offsets(VGMSTREAM* vgmstream, int is_start, int samples_discard) {
|
||||
ea_mt_codec_data* data = vgmstream->codec_data;
|
||||
int i;
|
||||
|
||||
if (!data) return;
|
||||
|
||||
|
||||
/* EA-MT frames are VBR (not byte-aligned?), so utk_decoder reads new buffer data automatically.
|
||||
* When decoding starts or a SCHl block changes, flush_ea_mt must be called to reset the state.
|
||||
* A bit hacky but would need some restructuring otherwise. */
|
||||
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
UTKContext* ctx = data[i].utk_context;
|
||||
|
||||
data[i].streamfile = vgmstream->ch[i].streamfile; /* maybe should keep its own STREAMFILE? */
|
||||
if (is_start)
|
||||
data[i].offset = vgmstream->ch[i].channel_start_offset;
|
||||
else
|
||||
data[i].offset = vgmstream->ch[i].offset;
|
||||
utk_set_ptr(ctx, 0, 0); /* reset the buffer reader */
|
||||
|
||||
if (is_start) {
|
||||
utk_reset(ctx);
|
||||
ctx->parsed_header = 0;
|
||||
data[i].samples_done = 0;
|
||||
}
|
||||
|
||||
data[i].samples_filled = 0;
|
||||
data[i].samples_discard = samples_discard;
|
||||
}
|
||||
}
|
||||
|
||||
void flush_ea_mt(VGMSTREAM* vgmstream) {
|
||||
flush_ea_mt_offsets(vgmstream, 0, 0);
|
||||
}
|
||||
|
||||
void reset_ea_mt(VGMSTREAM* vgmstream) {
|
||||
flush_ea_mt_offsets(vgmstream, 1, 0);
|
||||
}
|
||||
|
||||
void seek_ea_mt(VGMSTREAM* vgmstream, int32_t num_sample) {
|
||||
flush_ea_mt_offsets(vgmstream, 1, num_sample);
|
||||
}
|
||||
|
||||
void free_ea_mt(ea_mt_codec_data* data, int channels) {
|
||||
int i;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
for (i = 0; i < channels; i++) {
|
||||
free(data[i].utk_context);
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
|
||||
/* ********************** */
|
||||
|
||||
static size_t ea_mt_read_callback(void *dest, int size, void *arg) {
|
||||
ea_mt_codec_data *ch_data = arg;
|
||||
int bytes_read;
|
||||
|
||||
bytes_read = read_streamfile(dest,ch_data->offset,size,ch_data->streamfile);
|
||||
ch_data->offset += bytes_read;
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
@ -1,279 +1,279 @@
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* AKA "EA ADPCM", evolved from CDXA. Inconsistently called EA XA/EA-XA/EAXA.
|
||||
* Some variations contain ADPCM hist header per block, but it's handled in ea_block.c */
|
||||
|
||||
/*
|
||||
* Another way to get coefs in EAXA v2, with no diffs (no idea which table is actually used in games):
|
||||
* coef1 = EA_XA_TABLE2[(((frame_info >> 4) & 0x0F) << 1) + 0];
|
||||
* coef2 = EA_XA_TABLE2[(((frame_info >> 4) & 0x0F) << 1) + 1];
|
||||
*/
|
||||
/*
|
||||
static const int32_t EA_XA_TABLE2[28] = {
|
||||
0, 0, 240, 0,
|
||||
460, -208, 392, -220,
|
||||
0, 0, 240, 0,
|
||||
460, 0, 392, 0,
|
||||
0, 0, 0, 0,
|
||||
-208, -1, -220, -1,
|
||||
0, 0, 0, 0x3F70
|
||||
};
|
||||
*/
|
||||
|
||||
static const int EA_XA_TABLE[20] = {
|
||||
0, 240, 460, 392,
|
||||
0, 0, -208, -220,
|
||||
0, 1, 3, 4,
|
||||
7, 8, 10, 11,
|
||||
0, -1, -3, -4
|
||||
};
|
||||
|
||||
/* EA XA v2 (always mono); like v1 but with "PCM samples" flag and doesn't add 128 on expand or clamp (pre-adjusted by the encoder?) */
|
||||
void decode_ea_xa_v2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
uint8_t frame_info;
|
||||
int32_t coef1, coef2;
|
||||
int i, sample_count, shift;
|
||||
|
||||
int pcm_frame_size = 0x01 + 2*0x02 + 28*0x02;
|
||||
int xa_frame_size = 0x0f;
|
||||
int frame_samples = 28;
|
||||
first_sample = first_sample % frame_samples;
|
||||
|
||||
/* header */
|
||||
frame_info = read_8bit(stream->offset,stream->streamfile);
|
||||
|
||||
if (frame_info == 0xEE) { /* PCM frame (used in later revisions), samples always BE */
|
||||
stream->adpcm_history1_32 = read_16bitBE(stream->offset + 0x01 + 0x00,stream->streamfile);
|
||||
stream->adpcm_history2_32 = read_16bitBE(stream->offset + 0x01 + 0x02,stream->streamfile);
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
outbuf[sample_count] = read_16bitBE(stream->offset + 0x01 + 2*0x02 + i*0x02,stream->streamfile);
|
||||
}
|
||||
|
||||
/* only increment offset on complete frame */
|
||||
if (i == frame_samples)
|
||||
stream->offset += pcm_frame_size;
|
||||
}
|
||||
else { /* ADPCM frame */
|
||||
coef1 = EA_XA_TABLE[(frame_info >> 4) + 0];
|
||||
coef2 = EA_XA_TABLE[(frame_info >> 4) + 4];
|
||||
shift = (frame_info & 0x0F) + 8;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
uint8_t sample_byte, sample_nibble;
|
||||
int32_t new_sample;
|
||||
off_t byte_offset = (stream->offset + 0x01 + i/2);
|
||||
int nibble_shift = (!(i&1)) ? 4 : 0; /* high nibble first */
|
||||
|
||||
sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile);
|
||||
sample_nibble = (sample_byte >> nibble_shift) & 0x0F;
|
||||
new_sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */
|
||||
new_sample = (new_sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32) >> 8;
|
||||
new_sample = clamp16(new_sample);
|
||||
|
||||
outbuf[sample_count] = new_sample;
|
||||
stream->adpcm_history2_32 = stream->adpcm_history1_32;
|
||||
stream->adpcm_history1_32 = new_sample;
|
||||
}
|
||||
|
||||
/* only increment offset on complete frame */
|
||||
if (i == frame_samples)
|
||||
stream->offset += xa_frame_size;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* later PC games use float math, though in the end sounds basically the same (decompiled from various exes) */
|
||||
static const double XA_K0[16] = { 0.0, 0.9375, 1.796875, 1.53125 };
|
||||
static const double XA_K1[16] = { 0.0, 0.0, -0.8125, -0.859375 };
|
||||
/* code uses look-up table but it's be equivalent to:
|
||||
* (double)((nibble << 28) >> (shift + 8) >> 8) or (double)(signed_nibble << (12 - shift)) */
|
||||
static const uint32_t FLOAT_TABLE_INT[256] = {
|
||||
0x00000000,0x45800000,0x46000000,0x46400000,0x46800000,0x46A00000,0x46C00000,0x46E00000,
|
||||
0xC7000000,0xC6E00000,0xC6C00000,0xC6A00000,0xC6800000,0xC6400000,0xC6000000,0xC5800000,
|
||||
0x00000000,0x45000000,0x45800000,0x45C00000,0x46000000,0x46200000,0x46400000,0x46600000,
|
||||
0xC6800000,0xC6600000,0xC6400000,0xC6200000,0xC6000000,0xC5C00000,0xC5800000,0xC5000000,
|
||||
0x00000000,0x44800000,0x45000000,0x45400000,0x45800000,0x45A00000,0x45C00000,0x45E00000,
|
||||
0xC6000000,0xC5E00000,0xC5C00000,0xC5A00000,0xC5800000,0xC5400000,0xC5000000,0xC4800000,
|
||||
0x00000000,0x44000000,0x44800000,0x44C00000,0x45000000,0x45200000,0x45400000,0x45600000,
|
||||
0xC5800000,0xC5600000,0xC5400000,0xC5200000,0xC5000000,0xC4C00000,0xC4800000,0xC4000000,
|
||||
0x00000000,0x43800000,0x44000000,0x44400000,0x44800000,0x44A00000,0x44C00000,0x44E00000,
|
||||
0xC5000000,0xC4E00000,0xC4C00000,0xC4A00000,0xC4800000,0xC4400000,0xC4000000,0xC3800000,
|
||||
0x00000000,0x43000000,0x43800000,0x43C00000,0x44000000,0x44200000,0x44400000,0x44600000,
|
||||
0xC4800000,0xC4600000,0xC4400000,0xC4200000,0xC4000000,0xC3C00000,0xC3800000,0xC3000000,
|
||||
0x00000000,0x42800000,0x43000000,0x43400000,0x43800000,0x43A00000,0x43C00000,0x43E00000,
|
||||
0xC4000000,0xC3E00000,0xC3C00000,0xC3A00000,0xC3800000,0xC3400000,0xC3000000,0xC2800000,
|
||||
0x00000000,0x42000000,0x42800000,0x42C00000,0x43000000,0x43200000,0x43400000,0x43600000,
|
||||
0xC3800000,0xC3600000,0xC3400000,0xC3200000,0xC3000000,0xC2C00000,0xC2800000,0xC2000000,
|
||||
0x00000000,0x41800000,0x42000000,0x42400000,0x42800000,0x42A00000,0x42C00000,0x42E00000,
|
||||
0xC3000000,0xC2E00000,0xC2C00000,0xC2A00000,0xC2800000,0xC2400000,0xC2000000,0xC1800000,
|
||||
0x00000000,0x41000000,0x41800000,0x41C00000,0x42000000,0x42200000,0x42400000,0x42600000,
|
||||
0xC2800000,0xC2600000,0xC2400000,0xC2200000,0xC2000000,0xC1C00000,0xC1800000,0xC1000000,
|
||||
0x00000000,0x40800000,0x41000000,0x41400000,0x41800000,0x41A00000,0x41C00000,0x41E00000,
|
||||
0xC2000000,0xC1E00000,0xC1C00000,0xC1A00000,0xC1800000,0xC1400000,0xC1000000,0xC0800000,
|
||||
0x00000000,0x40000000,0x40800000,0x40C00000,0x41000000,0x41200000,0x41400000,0x41600000,
|
||||
0xC1800000,0xC1600000,0xC1400000,0xC1200000,0xC1000000,0xC0C00000,0xC0800000,0xC0000000,
|
||||
0x00000000,0x3F800000,0x40000000,0x40400000,0x40800000,0x40A00000,0x40C00000,0x40E00000,
|
||||
0xC1000000,0xC0E00000,0xC0C00000,0xC0A00000,0xC0800000,0xC0400000,0xC0000000,0xBF800000,
|
||||
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
|
||||
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
|
||||
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
|
||||
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
|
||||
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
|
||||
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
|
||||
};
|
||||
static const float *FLOAT_TABLE = (const float *)FLOAT_TABLE_INT;
|
||||
|
||||
void decode_ea_xa_v2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
uint8_t frame_info;
|
||||
int i, sample_count, shift;
|
||||
|
||||
int pcm_frame_size = 0x01 + 2*0x02 + 28*0x02;
|
||||
int xa_frame_size = 0x0f;
|
||||
int frame_samples = 28;
|
||||
first_sample = first_sample % frame_samples;
|
||||
|
||||
/* header */
|
||||
frame_info = read_8bit(stream->offset,stream->streamfile);
|
||||
|
||||
if (frame_info == 0xEE) { /* PCM frame (used in later revisions), samples always BE */
|
||||
stream->adpcm_history1_double = read_16bitBE(stream->offset + 0x01 + 0x00,stream->streamfile);
|
||||
stream->adpcm_history2_double = read_16bitBE(stream->offset + 0x01 + 0x02,stream->streamfile);
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
outbuf[sample_count] = read_16bitBE(stream->offset + 0x01 + 2*0x02 + i*0x02,stream->streamfile);
|
||||
}
|
||||
|
||||
/* only increment offset on complete frame */
|
||||
if (i == frame_samples)
|
||||
stream->offset += pcm_frame_size;
|
||||
}
|
||||
else { /* ADPCM frame */
|
||||
double coef1, coef2, hist1, hist2, new_sample;
|
||||
|
||||
coef1 = XA_K0[(frame_info >> 4)];
|
||||
coef2 = XA_K1[(frame_info >> 4)];
|
||||
shift = (frame_info & 0x0F) + 8;// << 4;
|
||||
hist1 = stream->adpcm_history1_double;
|
||||
hist2 = stream->adpcm_history2_double;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
uint8_t sample_byte, sample_nibble;
|
||||
off_t byte_offset = (stream->offset + 0x01 + i/2);
|
||||
int nibble_shift = (!(i&1)) ? 4 : 0; /* high nibble first */
|
||||
|
||||
sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile);
|
||||
sample_nibble = (sample_byte >> nibble_shift) & 0x0F;
|
||||
new_sample = (double)FLOAT_TABLE[sample_nibble + shift];
|
||||
new_sample = new_sample + coef1 * hist1 + coef2 * hist2;
|
||||
|
||||
outbuf[sample_count] = clamp16((int)new_sample);
|
||||
hist2 = hist1;
|
||||
hist1 = new_sample;
|
||||
}
|
||||
|
||||
stream->adpcm_history1_double = hist1;
|
||||
stream->adpcm_history2_double = hist2;
|
||||
|
||||
/* only increment offset on complete frame */
|
||||
if (i == frame_samples)
|
||||
stream->offset += xa_frame_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* EA XA v1 (mono/stereo) */
|
||||
void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo) {
|
||||
uint8_t frame_info;
|
||||
int32_t coef1, coef2;
|
||||
int i, sample_count, shift;
|
||||
int hn = (channel==0); /* high nibble marker for stereo subinterleave, ch0/L=high nibble, ch1/R=low nibble */
|
||||
|
||||
int frame_size = is_stereo ? 0x0f*2 : 0x0f;
|
||||
int frame_samples = 28;
|
||||
first_sample = first_sample % frame_samples;
|
||||
|
||||
/* header */
|
||||
if (is_stereo) {
|
||||
/* coefs ch0+ch1 + shift ch0+ch1 */
|
||||
frame_info = read_8bit(stream->offset + 0x00, stream->streamfile);
|
||||
coef1 = EA_XA_TABLE[(hn ? frame_info >> 4 : frame_info & 0x0F) + 0];
|
||||
coef2 = EA_XA_TABLE[(hn ? frame_info >> 4 : frame_info & 0x0F) + 4];
|
||||
|
||||
frame_info = read_8bit(stream->offset + 0x01, stream->streamfile);
|
||||
shift = (hn ? frame_info >> 4 : frame_info & 0x0F) + 8;
|
||||
} else {
|
||||
/* coefs + shift ch0 */
|
||||
frame_info = read_8bit(stream->offset + 0x00, stream->streamfile);
|
||||
coef1 = EA_XA_TABLE[(frame_info >> 4) + 0];
|
||||
coef2 = EA_XA_TABLE[(frame_info >> 4) + 4];
|
||||
shift = (frame_info & 0x0F) + 8;
|
||||
}
|
||||
|
||||
/* samples */
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
uint8_t sample_byte, sample_nibble;
|
||||
int32_t new_sample;
|
||||
off_t byte_offset = is_stereo ? (stream->offset + 0x02 + i) : (stream->offset + 0x01 + i/2);
|
||||
int nibble_shift = is_stereo ? (hn ? 4 : 0) : ((!(i & 1)) ? 4 : 0); /* high nibble first */
|
||||
|
||||
sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile);
|
||||
sample_nibble = (sample_byte >> nibble_shift) & 0x0F;
|
||||
new_sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */
|
||||
new_sample = (new_sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32 + 128) >> 8;
|
||||
new_sample = clamp16(new_sample);
|
||||
|
||||
outbuf[sample_count] = new_sample;
|
||||
stream->adpcm_history2_32 = stream->adpcm_history1_32;
|
||||
stream->adpcm_history1_32 = new_sample;
|
||||
}
|
||||
|
||||
/* only increment offset on complete frame */
|
||||
if (i == frame_samples)
|
||||
stream->offset += frame_size;
|
||||
}
|
||||
|
||||
/* Maxis EA-XA v1 (mono/stereo) with byte-interleave layout in stereo mode */
|
||||
void decode_maxis_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
uint8_t frame_info;
|
||||
int32_t coef1, coef2;
|
||||
int i, sample_count, shift;
|
||||
|
||||
int frame_size = 0x0f * channelspacing; /* varies in mono/stereo */
|
||||
int frame_samples = 28;
|
||||
first_sample = first_sample % frame_samples;
|
||||
|
||||
/* header (coefs+shift ch0 + coefs+shift ch1) */
|
||||
frame_info = read_8bit(stream->offset + channel,stream->streamfile);
|
||||
coef1 = EA_XA_TABLE[(frame_info >> 4) + 0];
|
||||
coef2 = EA_XA_TABLE[(frame_info >> 4) + 4];
|
||||
shift = (frame_info & 0x0F) + 8;
|
||||
|
||||
/* samples */
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
uint8_t sample_byte, sample_nibble;
|
||||
int32_t new_sample;
|
||||
off_t byte_offset = (stream->offset + 0x01*channelspacing + (channelspacing == 2 ? i/2 + channel + (i/2)*0x01 : i/2));
|
||||
int nibble_shift = (!(i&1)) ? 4 : 0; /* high nibble first */
|
||||
|
||||
sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile);
|
||||
sample_nibble = (sample_byte >> nibble_shift) & 0x0F;
|
||||
new_sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */
|
||||
new_sample = (new_sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32 + 128) >> 8;
|
||||
new_sample = clamp16(new_sample);
|
||||
|
||||
outbuf[sample_count] = new_sample;
|
||||
stream->adpcm_history2_32 = stream->adpcm_history1_32;
|
||||
stream->adpcm_history1_32 = new_sample;
|
||||
}
|
||||
|
||||
/* only increment offset on complete frame */
|
||||
if (i == frame_samples)
|
||||
stream->offset += frame_size;
|
||||
}
|
||||
|
||||
int32_t ea_xa_bytes_to_samples(size_t bytes, int channels) {
|
||||
if (channels <= 0) return 0;
|
||||
return bytes / channels / 0x0f * 28;
|
||||
}
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* AKA "EA ADPCM", evolved from CDXA. Inconsistently called EA XA/EA-XA/EAXA.
|
||||
* Some variations contain ADPCM hist header per block, but it's handled in ea_block.c */
|
||||
|
||||
/*
|
||||
* Another way to get coefs in EAXA v2, with no diffs (no idea which table is actually used in games):
|
||||
* coef1 = EA_XA_TABLE2[(((frame_info >> 4) & 0x0F) << 1) + 0];
|
||||
* coef2 = EA_XA_TABLE2[(((frame_info >> 4) & 0x0F) << 1) + 1];
|
||||
*/
|
||||
/*
|
||||
static const int32_t EA_XA_TABLE2[28] = {
|
||||
0, 0, 240, 0,
|
||||
460, -208, 392, -220,
|
||||
0, 0, 240, 0,
|
||||
460, 0, 392, 0,
|
||||
0, 0, 0, 0,
|
||||
-208, -1, -220, -1,
|
||||
0, 0, 0, 0x3F70
|
||||
};
|
||||
*/
|
||||
|
||||
static const int EA_XA_TABLE[20] = {
|
||||
0, 240, 460, 392,
|
||||
0, 0, -208, -220,
|
||||
0, 1, 3, 4,
|
||||
7, 8, 10, 11,
|
||||
0, -1, -3, -4
|
||||
};
|
||||
|
||||
/* EA XA v2 (always mono); like v1 but with "PCM samples" flag and doesn't add 128 on expand or clamp (pre-adjusted by the encoder?) */
|
||||
void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
uint8_t frame_info;
|
||||
int32_t coef1, coef2;
|
||||
int i, sample_count, shift;
|
||||
|
||||
int pcm_frame_size = 0x01 + 2*0x02 + 28*0x02;
|
||||
int xa_frame_size = 0x0f;
|
||||
int frame_samples = 28;
|
||||
first_sample = first_sample % frame_samples;
|
||||
|
||||
/* header */
|
||||
frame_info = read_8bit(stream->offset,stream->streamfile);
|
||||
|
||||
if (frame_info == 0xEE) { /* PCM frame (used in later revisions), samples always BE */
|
||||
stream->adpcm_history1_32 = read_16bitBE(stream->offset + 0x01 + 0x00,stream->streamfile);
|
||||
stream->adpcm_history2_32 = read_16bitBE(stream->offset + 0x01 + 0x02,stream->streamfile);
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
outbuf[sample_count] = read_16bitBE(stream->offset + 0x01 + 2*0x02 + i*0x02,stream->streamfile);
|
||||
}
|
||||
|
||||
/* only increment offset on complete frame */
|
||||
if (i == frame_samples)
|
||||
stream->offset += pcm_frame_size;
|
||||
}
|
||||
else { /* ADPCM frame */
|
||||
coef1 = EA_XA_TABLE[(frame_info >> 4) + 0];
|
||||
coef2 = EA_XA_TABLE[(frame_info >> 4) + 4];
|
||||
shift = (frame_info & 0x0F) + 8;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
uint8_t sample_byte, sample_nibble;
|
||||
int32_t new_sample;
|
||||
off_t byte_offset = (stream->offset + 0x01 + i/2);
|
||||
int nibble_shift = (!(i&1)) ? 4 : 0; /* high nibble first */
|
||||
|
||||
sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile);
|
||||
sample_nibble = (sample_byte >> nibble_shift) & 0x0F;
|
||||
new_sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */
|
||||
new_sample = (new_sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32) >> 8;
|
||||
new_sample = clamp16(new_sample);
|
||||
|
||||
outbuf[sample_count] = new_sample;
|
||||
stream->adpcm_history2_32 = stream->adpcm_history1_32;
|
||||
stream->adpcm_history1_32 = new_sample;
|
||||
}
|
||||
|
||||
/* only increment offset on complete frame */
|
||||
if (i == frame_samples)
|
||||
stream->offset += xa_frame_size;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* later PC games use float math, though in the end sounds basically the same (decompiled from various exes) */
|
||||
static const double XA_K0[16] = { 0.0, 0.9375, 1.796875, 1.53125 };
|
||||
static const double XA_K1[16] = { 0.0, 0.0, -0.8125, -0.859375 };
|
||||
/* code uses look-up table but it's equivalent to:
|
||||
* (double)((nibble << 28) >> (shift + 8) >> 8) or (double)(signed_nibble << (12 - shift)) */
|
||||
static const uint32_t FLOAT_TABLE_INT[256] = {
|
||||
0x00000000,0x45800000,0x46000000,0x46400000,0x46800000,0x46A00000,0x46C00000,0x46E00000,
|
||||
0xC7000000,0xC6E00000,0xC6C00000,0xC6A00000,0xC6800000,0xC6400000,0xC6000000,0xC5800000,
|
||||
0x00000000,0x45000000,0x45800000,0x45C00000,0x46000000,0x46200000,0x46400000,0x46600000,
|
||||
0xC6800000,0xC6600000,0xC6400000,0xC6200000,0xC6000000,0xC5C00000,0xC5800000,0xC5000000,
|
||||
0x00000000,0x44800000,0x45000000,0x45400000,0x45800000,0x45A00000,0x45C00000,0x45E00000,
|
||||
0xC6000000,0xC5E00000,0xC5C00000,0xC5A00000,0xC5800000,0xC5400000,0xC5000000,0xC4800000,
|
||||
0x00000000,0x44000000,0x44800000,0x44C00000,0x45000000,0x45200000,0x45400000,0x45600000,
|
||||
0xC5800000,0xC5600000,0xC5400000,0xC5200000,0xC5000000,0xC4C00000,0xC4800000,0xC4000000,
|
||||
0x00000000,0x43800000,0x44000000,0x44400000,0x44800000,0x44A00000,0x44C00000,0x44E00000,
|
||||
0xC5000000,0xC4E00000,0xC4C00000,0xC4A00000,0xC4800000,0xC4400000,0xC4000000,0xC3800000,
|
||||
0x00000000,0x43000000,0x43800000,0x43C00000,0x44000000,0x44200000,0x44400000,0x44600000,
|
||||
0xC4800000,0xC4600000,0xC4400000,0xC4200000,0xC4000000,0xC3C00000,0xC3800000,0xC3000000,
|
||||
0x00000000,0x42800000,0x43000000,0x43400000,0x43800000,0x43A00000,0x43C00000,0x43E00000,
|
||||
0xC4000000,0xC3E00000,0xC3C00000,0xC3A00000,0xC3800000,0xC3400000,0xC3000000,0xC2800000,
|
||||
0x00000000,0x42000000,0x42800000,0x42C00000,0x43000000,0x43200000,0x43400000,0x43600000,
|
||||
0xC3800000,0xC3600000,0xC3400000,0xC3200000,0xC3000000,0xC2C00000,0xC2800000,0xC2000000,
|
||||
0x00000000,0x41800000,0x42000000,0x42400000,0x42800000,0x42A00000,0x42C00000,0x42E00000,
|
||||
0xC3000000,0xC2E00000,0xC2C00000,0xC2A00000,0xC2800000,0xC2400000,0xC2000000,0xC1800000,
|
||||
0x00000000,0x41000000,0x41800000,0x41C00000,0x42000000,0x42200000,0x42400000,0x42600000,
|
||||
0xC2800000,0xC2600000,0xC2400000,0xC2200000,0xC2000000,0xC1C00000,0xC1800000,0xC1000000,
|
||||
0x00000000,0x40800000,0x41000000,0x41400000,0x41800000,0x41A00000,0x41C00000,0x41E00000,
|
||||
0xC2000000,0xC1E00000,0xC1C00000,0xC1A00000,0xC1800000,0xC1400000,0xC1000000,0xC0800000,
|
||||
0x00000000,0x40000000,0x40800000,0x40C00000,0x41000000,0x41200000,0x41400000,0x41600000,
|
||||
0xC1800000,0xC1600000,0xC1400000,0xC1200000,0xC1000000,0xC0C00000,0xC0800000,0xC0000000,
|
||||
0x00000000,0x3F800000,0x40000000,0x40400000,0x40800000,0x40A00000,0x40C00000,0x40E00000,
|
||||
0xC1000000,0xC0E00000,0xC0C00000,0xC0A00000,0xC0800000,0xC0400000,0xC0000000,0xBF800000,
|
||||
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
|
||||
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
|
||||
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
|
||||
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
|
||||
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
|
||||
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
|
||||
};
|
||||
static const float* FLOAT_TABLE = (const float *)FLOAT_TABLE_INT;
|
||||
|
||||
void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
uint8_t frame_info;
|
||||
int i, sample_count, shift;
|
||||
|
||||
int pcm_frame_size = 0x01 + 2*0x02 + 28*0x02;
|
||||
int xa_frame_size = 0x0f;
|
||||
int frame_samples = 28;
|
||||
first_sample = first_sample % frame_samples;
|
||||
|
||||
/* header */
|
||||
frame_info = read_8bit(stream->offset,stream->streamfile);
|
||||
|
||||
if (frame_info == 0xEE) { /* PCM frame (used in later revisions), samples always BE */
|
||||
stream->adpcm_history1_double = read_16bitBE(stream->offset + 0x01 + 0x00,stream->streamfile);
|
||||
stream->adpcm_history2_double = read_16bitBE(stream->offset + 0x01 + 0x02,stream->streamfile);
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
outbuf[sample_count] = read_16bitBE(stream->offset + 0x01 + 2*0x02 + i*0x02,stream->streamfile);
|
||||
}
|
||||
|
||||
/* only increment offset on complete frame */
|
||||
if (i == frame_samples)
|
||||
stream->offset += pcm_frame_size;
|
||||
}
|
||||
else { /* ADPCM frame */
|
||||
double coef1, coef2, hist1, hist2, new_sample;
|
||||
|
||||
coef1 = XA_K0[(frame_info >> 4)];
|
||||
coef2 = XA_K1[(frame_info >> 4)];
|
||||
shift = (frame_info & 0x0F) + 8;// << 4;
|
||||
hist1 = stream->adpcm_history1_double;
|
||||
hist2 = stream->adpcm_history2_double;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
uint8_t sample_byte, sample_nibble;
|
||||
off_t byte_offset = (stream->offset + 0x01 + i/2);
|
||||
int nibble_shift = (!(i&1)) ? 4 : 0; /* high nibble first */
|
||||
|
||||
sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile);
|
||||
sample_nibble = (sample_byte >> nibble_shift) & 0x0F;
|
||||
new_sample = (double)FLOAT_TABLE[sample_nibble + shift];
|
||||
new_sample = new_sample + coef1 * hist1 + coef2 * hist2;
|
||||
|
||||
outbuf[sample_count] = clamp16((int)new_sample);
|
||||
hist2 = hist1;
|
||||
hist1 = new_sample;
|
||||
}
|
||||
|
||||
stream->adpcm_history1_double = hist1;
|
||||
stream->adpcm_history2_double = hist2;
|
||||
|
||||
/* only increment offset on complete frame */
|
||||
if (i == frame_samples)
|
||||
stream->offset += xa_frame_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* EA XA v1 (mono/stereo) */
|
||||
void decode_ea_xa(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo) {
|
||||
uint8_t frame_info;
|
||||
int32_t coef1, coef2;
|
||||
int i, sample_count, shift;
|
||||
int hn = (channel==0); /* high nibble marker for stereo subinterleave, ch0/L=high nibble, ch1/R=low nibble */
|
||||
|
||||
int frame_size = is_stereo ? 0x0f*2 : 0x0f;
|
||||
int frame_samples = 28;
|
||||
first_sample = first_sample % frame_samples;
|
||||
|
||||
/* header */
|
||||
if (is_stereo) {
|
||||
/* coefs ch0+ch1 + shift ch0+ch1 */
|
||||
frame_info = read_8bit(stream->offset + 0x00, stream->streamfile);
|
||||
coef1 = EA_XA_TABLE[(hn ? frame_info >> 4 : frame_info & 0x0F) + 0];
|
||||
coef2 = EA_XA_TABLE[(hn ? frame_info >> 4 : frame_info & 0x0F) + 4];
|
||||
|
||||
frame_info = read_8bit(stream->offset + 0x01, stream->streamfile);
|
||||
shift = (hn ? frame_info >> 4 : frame_info & 0x0F) + 8;
|
||||
} else {
|
||||
/* coefs + shift ch0 */
|
||||
frame_info = read_8bit(stream->offset + 0x00, stream->streamfile);
|
||||
coef1 = EA_XA_TABLE[(frame_info >> 4) + 0];
|
||||
coef2 = EA_XA_TABLE[(frame_info >> 4) + 4];
|
||||
shift = (frame_info & 0x0F) + 8;
|
||||
}
|
||||
|
||||
/* samples */
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
uint8_t sample_byte, sample_nibble;
|
||||
int32_t new_sample;
|
||||
off_t byte_offset = is_stereo ? (stream->offset + 0x02 + i) : (stream->offset + 0x01 + i/2);
|
||||
int nibble_shift = is_stereo ? (hn ? 4 : 0) : ((!(i & 1)) ? 4 : 0); /* high nibble first */
|
||||
|
||||
sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile);
|
||||
sample_nibble = (sample_byte >> nibble_shift) & 0x0F;
|
||||
new_sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */
|
||||
new_sample = (new_sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32 + 128) >> 8;
|
||||
new_sample = clamp16(new_sample);
|
||||
|
||||
outbuf[sample_count] = new_sample;
|
||||
stream->adpcm_history2_32 = stream->adpcm_history1_32;
|
||||
stream->adpcm_history1_32 = new_sample;
|
||||
}
|
||||
|
||||
/* only increment offset on complete frame */
|
||||
if (i == frame_samples)
|
||||
stream->offset += frame_size;
|
||||
}
|
||||
|
||||
/* Maxis EA-XA v1 (mono/stereo) with byte-interleave layout in stereo mode */
|
||||
void decode_maxis_xa(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
uint8_t frame_info;
|
||||
int32_t coef1, coef2;
|
||||
int i, sample_count, shift;
|
||||
|
||||
int frame_size = 0x0f * channelspacing; /* varies in mono/stereo */
|
||||
int frame_samples = 28;
|
||||
first_sample = first_sample % frame_samples;
|
||||
|
||||
/* header (coefs+shift ch0 + coefs+shift ch1) */
|
||||
frame_info = read_8bit(stream->offset + channel,stream->streamfile);
|
||||
coef1 = EA_XA_TABLE[(frame_info >> 4) + 0];
|
||||
coef2 = EA_XA_TABLE[(frame_info >> 4) + 4];
|
||||
shift = (frame_info & 0x0F) + 8;
|
||||
|
||||
/* samples */
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
uint8_t sample_byte, sample_nibble;
|
||||
int32_t new_sample;
|
||||
off_t byte_offset = (stream->offset + 0x01*channelspacing + (channelspacing == 2 ? i/2 + channel + (i/2)*0x01 : i/2));
|
||||
int nibble_shift = (!(i&1)) ? 4 : 0; /* high nibble first */
|
||||
|
||||
sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile);
|
||||
sample_nibble = (sample_byte >> nibble_shift) & 0x0F;
|
||||
new_sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */
|
||||
new_sample = (new_sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32 + 128) >> 8;
|
||||
new_sample = clamp16(new_sample);
|
||||
|
||||
outbuf[sample_count] = new_sample;
|
||||
stream->adpcm_history2_32 = stream->adpcm_history1_32;
|
||||
stream->adpcm_history1_32 = new_sample;
|
||||
}
|
||||
|
||||
/* only increment offset on complete frame */
|
||||
if (i == frame_samples)
|
||||
stream->offset += frame_size;
|
||||
}
|
||||
|
||||
int32_t ea_xa_bytes_to_samples(size_t bytes, int channels) {
|
||||
if (channels <= 0) return 0;
|
||||
return bytes / channels / 0x0f * 28;
|
||||
}
|
||||
|
@ -1,183 +1,183 @@
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
|
||||
static const int step_table[4] = {
|
||||
5, 1, -1, -3
|
||||
};
|
||||
|
||||
static const int mc3_table[4][4][64] = {
|
||||
{
|
||||
{
|
||||
2, 2, 3, 7, 15, 27, 45, 70, 104, 148, 202, 268, 347, 441, 551, 677,
|
||||
821, 984, 1168, 1374, 1602, 1854, 2131, 2435, 2767, 3127, 3517, 3938, 4392, 4880, 5402, 5960,
|
||||
6555, 7189, 7862, 8577, 9333, 10132, 10976, 11865, 12802, 13786, 14819, 15903, 17038, 18226, 19469, 20766,
|
||||
22120, 23531, 25001, 26531, 28123, 29776, 31494, 33276, 35124, 37039, 39023, 41076, 43201, 45397, 47666, 50010
|
||||
},
|
||||
{
|
||||
1, 1, 2, 5, 10, 18, 31, 48, 72, 101, 139, 184, 239, 303, 378, 465,
|
||||
564, 677, 803, 944, 1101, 1274, 1465, 1674, 1902, 2150, 2418, 2707, 3019, 3355, 3714, 4097,
|
||||
4507, 4942, 5405, 5896, 6416, 6966, 7546, 8157, 8801, 9477, 10188, 10933, 11714, 12530, 13384, 14276,
|
||||
15207, 16177, 17188, 18240, 19334, 20471, 21652, 22877, 24148, 25464, 26828, 28240, 29700, 31210, 32770, 34382
|
||||
},
|
||||
{
|
||||
0, 0, 1, 2, 4, 8, 14, 22, 32, 46, 63, 83, 108, 138, 172, 211,
|
||||
256, 307, 365, 429, 500, 579, 666, 761, 864, 977, 1099, 1230, 1372, 1525, 1688, 1862,
|
||||
2048, 2246, 2457, 2680, 2916, 3166, 3430, 3708, 4000, 4308, 4631, 4969, 5324, 5695, 6084, 6489,
|
||||
6912, 7353, 7813, 8291, 8788, 9305, 9841, 10398, 10976, 11574, 12194, 12836, 13500, 14186, 14895, 15628
|
||||
},
|
||||
{
|
||||
0, 0, 0, 0, 1, 3, 5, 8, 13, 18, 25, 33, 43, 55, 68, 84,
|
||||
102, 123, 146, 171, 200, 231, 266, 304, 345, 390, 439, 492, 549, 610, 675, 745,
|
||||
819, 898, 982, 1072, 1166, 1266, 1372, 1483, 1600, 1723, 1852, 1987, 2129, 2278, 2433, 2595,
|
||||
2765, 2941, 3125, 3316, 3515, 3722, 3936, 4159, 4390, 4629, 4877, 5134, 5400, 5674, 5958, 6251
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
1, 1, 2, 4, 9, 17, 28, 44, 65, 92, 126, 167, 217, 276, 344, 423,
|
||||
513, 615, 730, 858, 1001, 1159, 1332, 1522, 1729, 1954, 2198, 2461, 2745, 3050, 3376, 3725,
|
||||
4097, 4493, 4914, 5360, 5833, 6332, 6860, 7416, 8001, 8616, 9262, 9939, 10649, 11391, 12168, 12978,
|
||||
13825, 14707, 15626, 16582, 17576, 18610, 19683, 20797, 21952, 23149, 24389, 25673, 27000, 28373, 29791, 31256
|
||||
},
|
||||
{
|
||||
0, 0, 1, 2, 5, 10, 17, 26, 39, 55, 75, 100, 130, 165, 206, 254,
|
||||
308, 369, 438, 515, 600, 695, 799, 913, 1037, 1172, 1319, 1477, 1647, 1830, 2025, 2235,
|
||||
2458, 2696, 2948, 3216, 3499, 3799, 4116, 4449, 4800, 5169, 5557, 5963, 6389, 6835, 7300, 7787,
|
||||
8295, 8824, 9375, 9949, 10546, 11166, 11810, 12478, 13171, 13889, 14633, 15403, 16200, 17023, 17874, 18753
|
||||
},
|
||||
{
|
||||
0, 0, 0, 1, 3, 6, 11, 17, 26, 37, 50, 67, 86, 110, 137, 169,
|
||||
205, 246, 292, 343, 400, 463, 532, 608, 691, 781, 879, 984, 1098, 1220, 1350, 1490,
|
||||
1638, 1797, 1965, 2144, 2333, 2533, 2744, 2966, 3200, 3446, 3704, 3975, 4259, 4556, 4867, 5191,
|
||||
5530, 5882, 6250, 6632, 7030, 7444, 7873, 8319, 8781, 9259, 9755, 10269, 10800, 11349, 11916, 12502
|
||||
},
|
||||
{
|
||||
0, 0, 0, 0, 0, 1, 2, 4, 6, 9, 12, 16, 21, 27, 34, 42,
|
||||
51, 61, 73, 85, 100, 115, 133, 152, 172, 195, 219, 246, 274, 305, 337, 372,
|
||||
409, 449, 491, 536, 583, 633, 686, 741, 800, 861, 926, 993, 1064, 1139, 1216, 1297,
|
||||
1382, 1470, 1562, 1658, 1757, 1861, 1968, 2079, 2195, 2314, 2438, 2567, 2700, 2837, 2979, 3125
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
1, 1, 2, 5, 10, 18, 31, 48, 72, 101, 139, 184, 239, 303, 378, 465,
|
||||
564, 677, 803, 944, 1101, 1274, 1465, 1674, 1902, 2150, 2418, 2707, 3019, 3355, 3714, 4097,
|
||||
4507, 4942, 5405, 5896, 6416, 6966, 7546, 8157, 8801, 9477, 10188, 10933, 11714, 12530, 13384, 14276,
|
||||
15207, 16177, 17188, 18240, 19334, 20471, 21652, 22877, 24148, 25464, 26828, 28240, 29700, 31210, 32770, 34382
|
||||
},
|
||||
{
|
||||
1, 1, 1, 3, 7, 13, 22, 35, 52, 74, 101, 134, 173, 220, 275, 338,
|
||||
410, 492, 584, 687, 801, 927, 1065, 1217, 1383, 1563, 1758, 1969, 2196, 2440, 2701, 2980,
|
||||
3277, 3594, 3931, 4288, 4666, 5066, 5488, 5932, 6401, 6893, 7409, 7951, 8519, 9113, 9734, 10383,
|
||||
11060, 11765, 12500, 13265, 14061, 14888, 15747, 16638, 17562, 18519, 19511, 20538, 21600, 22698, 23833, 25005
|
||||
},
|
||||
{
|
||||
0, 0, 1, 2, 4, 8, 14, 22, 32, 46, 63, 83, 108, 138, 172, 211,
|
||||
256, 307, 365, 429, 500, 579, 666, 761, 864, 977, 1099, 1230, 1372, 1525, 1688, 1862,
|
||||
2048, 2246, 2457, 2680, 2916, 3166, 3430, 3708, 4000, 4308, 4631, 4969, 5324, 5695, 6084, 6489,
|
||||
6912, 7353, 7813, 8291, 8788, 9305, 9841, 10398, 10976, 11574, 12194, 12836, 13500, 14186, 14895, 15628
|
||||
},
|
||||
{
|
||||
0, 0, 0, 1, 2, 5, 8, 13, 19, 27, 37, 50, 65, 82, 103, 127,
|
||||
154, 184, 219, 257, 300, 347, 399, 456, 518, 586, 659, 738, 823, 915, 1012, 1117,
|
||||
1229, 1348, 1474, 1608, 1749, 1899, 2058, 2224, 2400, 2584, 2778, 2981, 3194, 3417, 3650, 3893,
|
||||
4147, 4412, 4687, 4974, 5273, 5583, 5905, 6239, 6585, 6944, 7316, 7701, 8100, 8511, 8937, 9376
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
1, 1, 2, 5, 11, 20, 34, 53, 78, 111, 151, 201, 260, 331, 413, 508,
|
||||
616, 738, 876, 1030, 1201, 1390, 1598, 1826, 2075, 2345, 2638, 2954, 3294, 3660, 4051, 4470,
|
||||
4916, 5392, 5897, 6432, 6999, 7599, 8232, 8899, 9601, 10339, 11114, 11927, 12779, 13670, 14601, 15574,
|
||||
16590, 17648, 18751, 19898, 21092, 22332, 23620, 24957, 26343, 27779, 29267, 30807, 32400, 34047, 35749, 37507
|
||||
},
|
||||
{
|
||||
1, 1, 1, 3, 6, 11, 19, 31, 45, 64, 88, 117, 152, 193, 241, 296,
|
||||
359, 430, 511, 601, 701, 811, 932, 1065, 1210, 1368, 1538, 1723, 1921, 2135, 2363, 2607,
|
||||
2868, 3145, 3440, 3752, 4083, 4433, 4802, 5191, 5600, 6031, 6483, 6957, 7454, 7974, 8517, 9085,
|
||||
9677, 10295, 10938, 11607, 12303, 13027, 13778, 14558, 15366, 16204, 17072, 17971, 18900, 19861, 20854, 21879
|
||||
},
|
||||
{
|
||||
0, 0, 0, 1, 2, 5, 8, 13, 19, 27, 37, 50, 65, 82, 103, 127,
|
||||
154, 184, 219, 257, 300, 347, 399, 456, 518, 586, 659, 738, 823, 915, 1012, 1117,
|
||||
1229, 1348, 1474, 1608, 1749, 1899, 2058, 2224, 2400, 2584, 2778, 2981, 3194, 3417, 3650, 3893,
|
||||
4147, 4412, 4687, 4974, 5273, 5583, 5905, 6239, 6585, 6944, 7316, 7701, 8100, 8511, 8937, 9376
|
||||
},
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* MC3 3-bit ADPCM (Paradigm Entertainment games).
|
||||
*
|
||||
* Layout: blocks with 32b header + 32b ch1, 32b ch2, 32b ch1...
|
||||
* Each 32b is a sub-block with 10 samples (3b x10) sharing a 'mode' of sorts.
|
||||
* More than one block is rarely used though.
|
||||
*
|
||||
* Tables and original algorithm by daemon1
|
||||
*/
|
||||
void decode_mc3(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, sample_count = 0;
|
||||
|
||||
int32_t hist = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
|
||||
/* internal interleave */
|
||||
int block_samples = (vgmstream->interleave_block_size - 4) / 4 / vgmstream->channels * 10;
|
||||
first_sample = first_sample % block_samples;
|
||||
|
||||
|
||||
/* block header */
|
||||
if (first_sample == 0) {
|
||||
uint32_t header = (uint32_t)read_32bitLE(stream->offset, stream->streamfile);
|
||||
header = (header >> channel*16); /* lower 16=ch1, upper 16b=ch2 */
|
||||
step_index = header & 0x3f; /* 6b */
|
||||
hist = header & 0xffc0; /* 16b sans 6b */
|
||||
if (hist > 0x7fff) hist -= 0x10000; /* sign extend */
|
||||
}
|
||||
|
||||
|
||||
/* block samples */
|
||||
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||
uint32_t subblock, mode, samples, index, sign, diff;
|
||||
|
||||
/* header + ch shift + sub-block number (ex. ch0 i=10: sub-block 1, ch0 i=23: sub-block 2) */
|
||||
off_t subblock_offset = stream->offset + 4 + 4*channel + (i/10)*(4*vgmstream->channels);
|
||||
int sample_shift = (i%10)*3;
|
||||
|
||||
/* expand 3b */
|
||||
subblock = (uint32_t)read_32bitLE(subblock_offset, stream->streamfile);
|
||||
mode = (subblock >> 30) & 0x3; /* upper 2b */
|
||||
samples = (subblock) & 0x3FFFFFFF; /* lower 3b*10 */
|
||||
|
||||
index = (samples >> sample_shift) & 3; /* lower 2b */
|
||||
sign = (samples >> sample_shift) & 4; /* upper 1b */
|
||||
diff = mc3_table[mode][index][step_index];
|
||||
if (sign == 0)
|
||||
hist += (- 1 - diff);
|
||||
else
|
||||
hist += diff;
|
||||
|
||||
/* new step + clamp */
|
||||
step_index += step_table[index];
|
||||
if (step_index < 0) step_index = 0;
|
||||
else if (step_index > 63) step_index = 63;
|
||||
|
||||
/* output */
|
||||
outbuf[sample_count] = hist;
|
||||
sample_count += channelspacing;
|
||||
}
|
||||
|
||||
|
||||
/* internal interleave: increment offset on complete frame */
|
||||
if (i == block_samples) stream->offset += vgmstream->interleave_block_size;
|
||||
|
||||
stream->adpcm_history1_32 = hist;
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
|
||||
static const int step_table[4] = {
|
||||
5, 1, -1, -3
|
||||
};
|
||||
|
||||
static const int mc3_table[4][4][64] = {
|
||||
{
|
||||
{
|
||||
2, 2, 3, 7, 15, 27, 45, 70, 104, 148, 202, 268, 347, 441, 551, 677,
|
||||
821, 984, 1168, 1374, 1602, 1854, 2131, 2435, 2767, 3127, 3517, 3938, 4392, 4880, 5402, 5960,
|
||||
6555, 7189, 7862, 8577, 9333, 10132, 10976, 11865, 12802, 13786, 14819, 15903, 17038, 18226, 19469, 20766,
|
||||
22120, 23531, 25001, 26531, 28123, 29776, 31494, 33276, 35124, 37039, 39023, 41076, 43201, 45397, 47666, 50010
|
||||
},
|
||||
{
|
||||
1, 1, 2, 5, 10, 18, 31, 48, 72, 101, 139, 184, 239, 303, 378, 465,
|
||||
564, 677, 803, 944, 1101, 1274, 1465, 1674, 1902, 2150, 2418, 2707, 3019, 3355, 3714, 4097,
|
||||
4507, 4942, 5405, 5896, 6416, 6966, 7546, 8157, 8801, 9477, 10188, 10933, 11714, 12530, 13384, 14276,
|
||||
15207, 16177, 17188, 18240, 19334, 20471, 21652, 22877, 24148, 25464, 26828, 28240, 29700, 31210, 32770, 34382
|
||||
},
|
||||
{
|
||||
0, 0, 1, 2, 4, 8, 14, 22, 32, 46, 63, 83, 108, 138, 172, 211,
|
||||
256, 307, 365, 429, 500, 579, 666, 761, 864, 977, 1099, 1230, 1372, 1525, 1688, 1862,
|
||||
2048, 2246, 2457, 2680, 2916, 3166, 3430, 3708, 4000, 4308, 4631, 4969, 5324, 5695, 6084, 6489,
|
||||
6912, 7353, 7813, 8291, 8788, 9305, 9841, 10398, 10976, 11574, 12194, 12836, 13500, 14186, 14895, 15628
|
||||
},
|
||||
{
|
||||
0, 0, 0, 0, 1, 3, 5, 8, 13, 18, 25, 33, 43, 55, 68, 84,
|
||||
102, 123, 146, 171, 200, 231, 266, 304, 345, 390, 439, 492, 549, 610, 675, 745,
|
||||
819, 898, 982, 1072, 1166, 1266, 1372, 1483, 1600, 1723, 1852, 1987, 2129, 2278, 2433, 2595,
|
||||
2765, 2941, 3125, 3316, 3515, 3722, 3936, 4159, 4390, 4629, 4877, 5134, 5400, 5674, 5958, 6251
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
1, 1, 2, 4, 9, 17, 28, 44, 65, 92, 126, 167, 217, 276, 344, 423,
|
||||
513, 615, 730, 858, 1001, 1159, 1332, 1522, 1729, 1954, 2198, 2461, 2745, 3050, 3376, 3725,
|
||||
4097, 4493, 4914, 5360, 5833, 6332, 6860, 7416, 8001, 8616, 9262, 9939, 10649, 11391, 12168, 12978,
|
||||
13825, 14707, 15626, 16582, 17576, 18610, 19683, 20797, 21952, 23149, 24389, 25673, 27000, 28373, 29791, 31256
|
||||
},
|
||||
{
|
||||
0, 0, 1, 2, 5, 10, 17, 26, 39, 55, 75, 100, 130, 165, 206, 254,
|
||||
308, 369, 438, 515, 600, 695, 799, 913, 1037, 1172, 1319, 1477, 1647, 1830, 2025, 2235,
|
||||
2458, 2696, 2948, 3216, 3499, 3799, 4116, 4449, 4800, 5169, 5557, 5963, 6389, 6835, 7300, 7787,
|
||||
8295, 8824, 9375, 9949, 10546, 11166, 11810, 12478, 13171, 13889, 14633, 15403, 16200, 17023, 17874, 18753
|
||||
},
|
||||
{
|
||||
0, 0, 0, 1, 3, 6, 11, 17, 26, 37, 50, 67, 86, 110, 137, 169,
|
||||
205, 246, 292, 343, 400, 463, 532, 608, 691, 781, 879, 984, 1098, 1220, 1350, 1490,
|
||||
1638, 1797, 1965, 2144, 2333, 2533, 2744, 2966, 3200, 3446, 3704, 3975, 4259, 4556, 4867, 5191,
|
||||
5530, 5882, 6250, 6632, 7030, 7444, 7873, 8319, 8781, 9259, 9755, 10269, 10800, 11349, 11916, 12502
|
||||
},
|
||||
{
|
||||
0, 0, 0, 0, 0, 1, 2, 4, 6, 9, 12, 16, 21, 27, 34, 42,
|
||||
51, 61, 73, 85, 100, 115, 133, 152, 172, 195, 219, 246, 274, 305, 337, 372,
|
||||
409, 449, 491, 536, 583, 633, 686, 741, 800, 861, 926, 993, 1064, 1139, 1216, 1297,
|
||||
1382, 1470, 1562, 1658, 1757, 1861, 1968, 2079, 2195, 2314, 2438, 2567, 2700, 2837, 2979, 3125
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
1, 1, 2, 5, 10, 18, 31, 48, 72, 101, 139, 184, 239, 303, 378, 465,
|
||||
564, 677, 803, 944, 1101, 1274, 1465, 1674, 1902, 2150, 2418, 2707, 3019, 3355, 3714, 4097,
|
||||
4507, 4942, 5405, 5896, 6416, 6966, 7546, 8157, 8801, 9477, 10188, 10933, 11714, 12530, 13384, 14276,
|
||||
15207, 16177, 17188, 18240, 19334, 20471, 21652, 22877, 24148, 25464, 26828, 28240, 29700, 31210, 32770, 34382
|
||||
},
|
||||
{
|
||||
1, 1, 1, 3, 7, 13, 22, 35, 52, 74, 101, 134, 173, 220, 275, 338,
|
||||
410, 492, 584, 687, 801, 927, 1065, 1217, 1383, 1563, 1758, 1969, 2196, 2440, 2701, 2980,
|
||||
3277, 3594, 3931, 4288, 4666, 5066, 5488, 5932, 6401, 6893, 7409, 7951, 8519, 9113, 9734, 10383,
|
||||
11060, 11765, 12500, 13265, 14061, 14888, 15747, 16638, 17562, 18519, 19511, 20538, 21600, 22698, 23833, 25005
|
||||
},
|
||||
{
|
||||
0, 0, 1, 2, 4, 8, 14, 22, 32, 46, 63, 83, 108, 138, 172, 211,
|
||||
256, 307, 365, 429, 500, 579, 666, 761, 864, 977, 1099, 1230, 1372, 1525, 1688, 1862,
|
||||
2048, 2246, 2457, 2680, 2916, 3166, 3430, 3708, 4000, 4308, 4631, 4969, 5324, 5695, 6084, 6489,
|
||||
6912, 7353, 7813, 8291, 8788, 9305, 9841, 10398, 10976, 11574, 12194, 12836, 13500, 14186, 14895, 15628
|
||||
},
|
||||
{
|
||||
0, 0, 0, 1, 2, 5, 8, 13, 19, 27, 37, 50, 65, 82, 103, 127,
|
||||
154, 184, 219, 257, 300, 347, 399, 456, 518, 586, 659, 738, 823, 915, 1012, 1117,
|
||||
1229, 1348, 1474, 1608, 1749, 1899, 2058, 2224, 2400, 2584, 2778, 2981, 3194, 3417, 3650, 3893,
|
||||
4147, 4412, 4687, 4974, 5273, 5583, 5905, 6239, 6585, 6944, 7316, 7701, 8100, 8511, 8937, 9376
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
1, 1, 2, 5, 11, 20, 34, 53, 78, 111, 151, 201, 260, 331, 413, 508,
|
||||
616, 738, 876, 1030, 1201, 1390, 1598, 1826, 2075, 2345, 2638, 2954, 3294, 3660, 4051, 4470,
|
||||
4916, 5392, 5897, 6432, 6999, 7599, 8232, 8899, 9601, 10339, 11114, 11927, 12779, 13670, 14601, 15574,
|
||||
16590, 17648, 18751, 19898, 21092, 22332, 23620, 24957, 26343, 27779, 29267, 30807, 32400, 34047, 35749, 37507
|
||||
},
|
||||
{
|
||||
1, 1, 1, 3, 6, 11, 19, 31, 45, 64, 88, 117, 152, 193, 241, 296,
|
||||
359, 430, 511, 601, 701, 811, 932, 1065, 1210, 1368, 1538, 1723, 1921, 2135, 2363, 2607,
|
||||
2868, 3145, 3440, 3752, 4083, 4433, 4802, 5191, 5600, 6031, 6483, 6957, 7454, 7974, 8517, 9085,
|
||||
9677, 10295, 10938, 11607, 12303, 13027, 13778, 14558, 15366, 16204, 17072, 17971, 18900, 19861, 20854, 21879
|
||||
},
|
||||
{
|
||||
0, 0, 0, 1, 2, 5, 8, 13, 19, 27, 37, 50, 65, 82, 103, 127,
|
||||
154, 184, 219, 257, 300, 347, 399, 456, 518, 586, 659, 738, 823, 915, 1012, 1117,
|
||||
1229, 1348, 1474, 1608, 1749, 1899, 2058, 2224, 2400, 2584, 2778, 2981, 3194, 3417, 3650, 3893,
|
||||
4147, 4412, 4687, 4974, 5273, 5583, 5905, 6239, 6585, 6944, 7316, 7701, 8100, 8511, 8937, 9376
|
||||
},
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* MC3 3-bit ADPCM (Paradigm Entertainment games).
|
||||
*
|
||||
* Layout: blocks with 32b header + 32b ch1, 32b ch2, 32b ch1...
|
||||
* Each 32b is a sub-block with 10 samples (3b x10) sharing a 'mode' of sorts.
|
||||
* More than one block is rarely used though.
|
||||
*
|
||||
* Tables and original algorithm by daemon1
|
||||
*/
|
||||
void decode_mc3(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, sample_count = 0;
|
||||
|
||||
int32_t hist = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
|
||||
/* internal interleave */
|
||||
int block_samples = (vgmstream->interleave_block_size - 4) / 4 / vgmstream->channels * 10;
|
||||
first_sample = first_sample % block_samples;
|
||||
|
||||
|
||||
/* block header */
|
||||
if (first_sample == 0) {
|
||||
uint32_t header = (uint32_t)read_32bitLE(stream->offset, stream->streamfile);
|
||||
header = (header >> channel*16); /* lower 16=ch1, upper 16b=ch2 */
|
||||
step_index = header & 0x3f; /* 6b */
|
||||
hist = header & 0xffc0; /* 16b sans 6b */
|
||||
if (hist > 0x7fff) hist -= 0x10000; /* sign extend */
|
||||
}
|
||||
|
||||
|
||||
/* block samples */
|
||||
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||
uint32_t subblock, mode, samples, index, sign, diff;
|
||||
|
||||
/* header + ch shift + sub-block number (ex. ch0 i=10: sub-block 1, ch0 i=23: sub-block 2) */
|
||||
off_t subblock_offset = stream->offset + 4 + 4*channel + (i/10)*(4*vgmstream->channels);
|
||||
int sample_shift = (i%10)*3;
|
||||
|
||||
/* expand 3b */
|
||||
subblock = (uint32_t)read_32bitLE(subblock_offset, stream->streamfile);
|
||||
mode = (subblock >> 30) & 0x3; /* upper 2b */
|
||||
samples = (subblock) & 0x3FFFFFFF; /* lower 3b*10 */
|
||||
|
||||
index = (samples >> sample_shift) & 3; /* lower 2b */
|
||||
sign = (samples >> sample_shift) & 4; /* upper 1b */
|
||||
diff = mc3_table[mode][index][step_index];
|
||||
if (sign == 0)
|
||||
hist += (- 1 - diff);
|
||||
else
|
||||
hist += diff;
|
||||
|
||||
/* new step + clamp */
|
||||
step_index += step_table[index];
|
||||
if (step_index < 0) step_index = 0;
|
||||
else if (step_index > 63) step_index = 63;
|
||||
|
||||
/* output */
|
||||
outbuf[sample_count] = hist;
|
||||
sample_count += channelspacing;
|
||||
}
|
||||
|
||||
|
||||
/* internal interleave: increment offset on complete frame */
|
||||
if (i == block_samples) stream->offset += vgmstream->interleave_block_size;
|
||||
|
||||
stream->adpcm_history1_32 = hist;
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
@ -1,254 +1,254 @@
|
||||
#include "../util.h"
|
||||
#include "coding.h"
|
||||
|
||||
|
||||
static const int16_t msadpcm_steps[16] = {
|
||||
230, 230, 230, 230,
|
||||
307, 409, 512, 614,
|
||||
768, 614, 512, 409,
|
||||
307, 230, 230, 230
|
||||
};
|
||||
|
||||
static const int16_t msadpcm_coefs[7][2] = {
|
||||
{ 256, 0 },
|
||||
{ 512, -256 },
|
||||
{ 0, 0 },
|
||||
{ 192, 64 },
|
||||
{ 240, 0 },
|
||||
{ 460, -208 },
|
||||
{ 392, -232 }
|
||||
};
|
||||
|
||||
void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t first_sample, int32_t samples_to_do) {
|
||||
VGMSTREAMCHANNEL *ch1,*ch2;
|
||||
STREAMFILE *streamfile;
|
||||
int i, frames_in;
|
||||
size_t bytes_per_frame, samples_per_frame;
|
||||
off_t frame_offset;
|
||||
|
||||
ch1 = &vgmstream->ch[0];
|
||||
ch2 = &vgmstream->ch[1];
|
||||
streamfile = ch1->streamfile;
|
||||
|
||||
/* external interleave (variable size), stereo */
|
||||
bytes_per_frame = vgmstream->frame_size;
|
||||
samples_per_frame = (vgmstream->frame_size - 0x07*vgmstream->channels)*2 / vgmstream->channels + 2;
|
||||
frames_in = first_sample / samples_per_frame;
|
||||
first_sample = first_sample % samples_per_frame;
|
||||
|
||||
frame_offset = ch1->offset + frames_in*bytes_per_frame;
|
||||
|
||||
/* parse frame header */
|
||||
if (first_sample == 0) {
|
||||
ch1->adpcm_coef[0] = msadpcm_coefs[read_8bit(frame_offset+0x00,streamfile) & 0x07][0];
|
||||
ch1->adpcm_coef[1] = msadpcm_coefs[read_8bit(frame_offset+0x00,streamfile) & 0x07][1];
|
||||
ch2->adpcm_coef[0] = msadpcm_coefs[read_8bit(frame_offset+0x01,streamfile)][0];
|
||||
ch2->adpcm_coef[1] = msadpcm_coefs[read_8bit(frame_offset+0x01,streamfile)][1];
|
||||
ch1->adpcm_scale = read_16bitLE(frame_offset+0x02,streamfile);
|
||||
ch2->adpcm_scale = read_16bitLE(frame_offset+0x04,streamfile);
|
||||
ch1->adpcm_history1_16 = read_16bitLE(frame_offset+0x06,streamfile);
|
||||
ch2->adpcm_history1_16 = read_16bitLE(frame_offset+0x08,streamfile);
|
||||
ch1->adpcm_history2_16 = read_16bitLE(frame_offset+0x0a,streamfile);
|
||||
ch2->adpcm_history2_16 = read_16bitLE(frame_offset+0x0c,streamfile);
|
||||
}
|
||||
|
||||
/* write header samples (needed) */
|
||||
if (first_sample==0) {
|
||||
outbuf[0] = ch1->adpcm_history2_16;
|
||||
outbuf[1] = ch2->adpcm_history2_16;
|
||||
outbuf += 2;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
if (first_sample == 1 && samples_to_do > 0) {
|
||||
outbuf[0] = ch1->adpcm_history1_16;
|
||||
outbuf[1] = ch2->adpcm_history1_16;
|
||||
outbuf += 2;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
|
||||
/* decode nibbles */
|
||||
for (i = first_sample; i < first_sample+samples_to_do; i++) {
|
||||
int ch;
|
||||
|
||||
for (ch = 0; ch < 2; ch++) {
|
||||
VGMSTREAMCHANNEL *stream = &vgmstream->ch[ch];
|
||||
int32_t hist1,hist2, predicted;
|
||||
int sample_nibble = (ch == 0) ? /* L = high nibble first */
|
||||
get_high_nibble_signed(read_8bit(frame_offset+0x07*2+(i-2),streamfile)) :
|
||||
get_low_nibble_signed (read_8bit(frame_offset+0x07*2+(i-2),streamfile));
|
||||
|
||||
hist1 = stream->adpcm_history1_16;
|
||||
hist2 = stream->adpcm_history2_16;
|
||||
predicted = hist1*stream->adpcm_coef[0] + hist2*stream->adpcm_coef[1];
|
||||
predicted = predicted / 256;
|
||||
predicted = predicted + sample_nibble*stream->adpcm_scale;
|
||||
outbuf[0] = clamp16(predicted);
|
||||
|
||||
stream->adpcm_history2_16 = stream->adpcm_history1_16;
|
||||
stream->adpcm_history1_16 = outbuf[0];
|
||||
stream->adpcm_scale = (msadpcm_steps[sample_nibble & 0xf] * stream->adpcm_scale) / 256;
|
||||
if (stream->adpcm_scale < 0x10)
|
||||
stream->adpcm_scale = 0x10;
|
||||
|
||||
outbuf++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
VGMSTREAMCHANNEL *stream = &vgmstream->ch[channel];
|
||||
int i, frames_in;
|
||||
size_t bytes_per_frame, samples_per_frame;
|
||||
off_t frame_offset;
|
||||
|
||||
/* external interleave (variable size), mono */
|
||||
bytes_per_frame = vgmstream->frame_size;
|
||||
samples_per_frame = (vgmstream->frame_size - 0x07)*2 + 2;
|
||||
frames_in = first_sample / samples_per_frame;
|
||||
first_sample = first_sample % samples_per_frame;
|
||||
|
||||
frame_offset = stream->offset + frames_in*bytes_per_frame;
|
||||
|
||||
/* parse frame header */
|
||||
if (first_sample == 0) {
|
||||
stream->adpcm_coef[0] = msadpcm_coefs[read_8bit(frame_offset+0x00,stream->streamfile) & 0x07][0];
|
||||
stream->adpcm_coef[1] = msadpcm_coefs[read_8bit(frame_offset+0x00,stream->streamfile) & 0x07][1];
|
||||
stream->adpcm_scale = read_16bitLE(frame_offset+0x01,stream->streamfile);
|
||||
stream->adpcm_history1_16 = read_16bitLE(frame_offset+0x03,stream->streamfile);
|
||||
stream->adpcm_history2_16 = read_16bitLE(frame_offset+0x05,stream->streamfile);
|
||||
}
|
||||
|
||||
/* write header samples (needed) */
|
||||
if (first_sample == 0) {
|
||||
outbuf[0] = stream->adpcm_history2_16;
|
||||
outbuf += channelspacing;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
if (first_sample == 1 && samples_to_do > 0) {
|
||||
outbuf[0] = stream->adpcm_history1_16;
|
||||
outbuf += channelspacing;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
|
||||
/* decode nibbles */
|
||||
for (i = first_sample; i < first_sample+samples_to_do; i++) {
|
||||
int32_t hist1,hist2, predicted;
|
||||
int sample_nibble = (i & 1) ? /* high nibble first */
|
||||
get_low_nibble_signed (read_8bit(frame_offset+0x07+(i-2)/2,stream->streamfile)) :
|
||||
get_high_nibble_signed(read_8bit(frame_offset+0x07+(i-2)/2,stream->streamfile));
|
||||
|
||||
hist1 = stream->adpcm_history1_16;
|
||||
hist2 = stream->adpcm_history2_16;
|
||||
predicted = hist1*stream->adpcm_coef[0] + hist2*stream->adpcm_coef[1];
|
||||
predicted = predicted / 256;
|
||||
predicted = predicted + sample_nibble*stream->adpcm_scale;
|
||||
outbuf[0] = clamp16(predicted);
|
||||
|
||||
stream->adpcm_history2_16 = stream->adpcm_history1_16;
|
||||
stream->adpcm_history1_16 = outbuf[0];
|
||||
stream->adpcm_scale = (msadpcm_steps[sample_nibble & 0xf] * stream->adpcm_scale) / 256;
|
||||
if (stream->adpcm_scale < 0x10)
|
||||
stream->adpcm_scale = 0x10;
|
||||
|
||||
outbuf += channelspacing;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cricket Audio's MSADPCM, same thing with reversed hist and nibble order
|
||||
* (their tools may convert to float/others but internally it's all PCM16, from debugging). */
|
||||
void decode_msadpcm_ck(VGMSTREAM * vgmstream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
VGMSTREAMCHANNEL *stream = &vgmstream->ch[channel];
|
||||
int i, frames_in;
|
||||
size_t bytes_per_frame, samples_per_frame;
|
||||
off_t frame_offset;
|
||||
|
||||
/* external interleave (variable size), mono */
|
||||
bytes_per_frame = vgmstream->frame_size;
|
||||
samples_per_frame = (vgmstream->frame_size - 0x07)*2 + 2;
|
||||
frames_in = first_sample / samples_per_frame;
|
||||
first_sample = first_sample % samples_per_frame;
|
||||
|
||||
frame_offset = stream->offset + frames_in*bytes_per_frame;
|
||||
|
||||
/* parse frame header */
|
||||
if (first_sample == 0) {
|
||||
stream->adpcm_coef[0] = msadpcm_coefs[read_8bit(frame_offset+0x00,stream->streamfile) & 0x07][0];
|
||||
stream->adpcm_coef[1] = msadpcm_coefs[read_8bit(frame_offset+0x00,stream->streamfile) & 0x07][1];
|
||||
stream->adpcm_scale = read_16bitLE(frame_offset+0x01,stream->streamfile);
|
||||
stream->adpcm_history2_16 = read_16bitLE(frame_offset+0x03,stream->streamfile); /* hist2 first, unlike normal MSADPCM */
|
||||
stream->adpcm_history1_16 = read_16bitLE(frame_offset+0x05,stream->streamfile);
|
||||
}
|
||||
|
||||
/* write header samples (needed) */
|
||||
if (first_sample == 0) {
|
||||
outbuf[0] = stream->adpcm_history2_16;
|
||||
outbuf += channelspacing;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
if (first_sample == 1 && samples_to_do > 0) {
|
||||
outbuf[0] = stream->adpcm_history1_16;
|
||||
outbuf += channelspacing;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
|
||||
/* decode nibbles */
|
||||
for (i = first_sample; i < first_sample+samples_to_do; i++) {
|
||||
int32_t hist1,hist2, predicted;
|
||||
int sample_nibble = (i & 1) ? /* low nibble first, unlike normal MSADPCM */
|
||||
get_high_nibble_signed (read_8bit(frame_offset+0x07+(i-2)/2,stream->streamfile)) :
|
||||
get_low_nibble_signed(read_8bit(frame_offset+0x07+(i-2)/2,stream->streamfile));
|
||||
|
||||
hist1 = stream->adpcm_history1_16;
|
||||
hist2 = stream->adpcm_history2_16;
|
||||
predicted = hist1*stream->adpcm_coef[0] + hist2*stream->adpcm_coef[1];
|
||||
predicted = predicted >> 8; /* probably no difference vs MSADPCM */
|
||||
predicted = predicted + sample_nibble*stream->adpcm_scale;
|
||||
outbuf[0] = clamp16(predicted);
|
||||
|
||||
stream->adpcm_history2_16 = stream->adpcm_history1_16;
|
||||
stream->adpcm_history1_16 = outbuf[0];
|
||||
stream->adpcm_scale = (msadpcm_steps[sample_nibble & 0xf] * stream->adpcm_scale) >> 8;
|
||||
if (stream->adpcm_scale < 0x10)
|
||||
stream->adpcm_scale = 0x10;
|
||||
|
||||
outbuf += channelspacing;
|
||||
}
|
||||
}
|
||||
|
||||
long msadpcm_bytes_to_samples(long bytes, int block_size, int channels) {
|
||||
if (block_size <= 0 || channels <= 0) return 0;
|
||||
return (bytes / block_size) * (block_size - (7-1)*channels) * 2 / channels
|
||||
+ ((bytes % block_size) ? ((bytes % block_size) - (7-1)*channels) * 2 / channels : 0);
|
||||
}
|
||||
|
||||
/* test if MSADPCM coefs were re-defined (possible in theory but not used in practice) */
|
||||
int msadpcm_check_coefs(STREAMFILE *sf, off_t offset) {
|
||||
int i;
|
||||
int count = read_16bitLE(offset, sf);
|
||||
if (count != 7) {
|
||||
VGM_LOG("MSADPCM: bad count %i at %lx\n", count, offset);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
offset += 0x02;
|
||||
for (i = 0; i < 7; i++) {
|
||||
int16_t coef1 = read_16bitLE(offset + 0x00, sf);
|
||||
int16_t coef2 = read_16bitLE(offset + 0x02, sf);
|
||||
|
||||
if (coef1 != msadpcm_coefs[i][0] || coef2 != msadpcm_coefs[i][1]) {
|
||||
VGM_LOG("MSADPCM: bad coef %i/%i vs %i/%i\n", coef1, coef2, msadpcm_coefs[i][0], msadpcm_coefs[i][1]);
|
||||
goto fail;
|
||||
}
|
||||
offset += 0x02 + 0x02;
|
||||
}
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
#include "../util.h"
|
||||
#include "coding.h"
|
||||
|
||||
|
||||
static const int16_t msadpcm_steps[16] = {
|
||||
230, 230, 230, 230,
|
||||
307, 409, 512, 614,
|
||||
768, 614, 512, 409,
|
||||
307, 230, 230, 230
|
||||
};
|
||||
|
||||
static const int16_t msadpcm_coefs[7][2] = {
|
||||
{ 256, 0 },
|
||||
{ 512, -256 },
|
||||
{ 0, 0 },
|
||||
{ 192, 64 },
|
||||
{ 240, 0 },
|
||||
{ 460, -208 },
|
||||
{ 392, -232 }
|
||||
};
|
||||
|
||||
void decode_msadpcm_stereo(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t first_sample, int32_t samples_to_do) {
|
||||
VGMSTREAMCHANNEL *ch1,*ch2;
|
||||
STREAMFILE *streamfile;
|
||||
int i, frames_in;
|
||||
size_t bytes_per_frame, samples_per_frame;
|
||||
off_t frame_offset;
|
||||
|
||||
ch1 = &vgmstream->ch[0];
|
||||
ch2 = &vgmstream->ch[1];
|
||||
streamfile = ch1->streamfile;
|
||||
|
||||
/* external interleave (variable size), stereo */
|
||||
bytes_per_frame = vgmstream->frame_size;
|
||||
samples_per_frame = (vgmstream->frame_size - 0x07*vgmstream->channels)*2 / vgmstream->channels + 2;
|
||||
frames_in = first_sample / samples_per_frame;
|
||||
first_sample = first_sample % samples_per_frame;
|
||||
|
||||
frame_offset = ch1->offset + frames_in*bytes_per_frame;
|
||||
|
||||
/* parse frame header */
|
||||
if (first_sample == 0) {
|
||||
ch1->adpcm_coef[0] = msadpcm_coefs[read_8bit(frame_offset+0x00,streamfile) & 0x07][0];
|
||||
ch1->adpcm_coef[1] = msadpcm_coefs[read_8bit(frame_offset+0x00,streamfile) & 0x07][1];
|
||||
ch2->adpcm_coef[0] = msadpcm_coefs[read_8bit(frame_offset+0x01,streamfile)][0];
|
||||
ch2->adpcm_coef[1] = msadpcm_coefs[read_8bit(frame_offset+0x01,streamfile)][1];
|
||||
ch1->adpcm_scale = read_16bitLE(frame_offset+0x02,streamfile);
|
||||
ch2->adpcm_scale = read_16bitLE(frame_offset+0x04,streamfile);
|
||||
ch1->adpcm_history1_16 = read_16bitLE(frame_offset+0x06,streamfile);
|
||||
ch2->adpcm_history1_16 = read_16bitLE(frame_offset+0x08,streamfile);
|
||||
ch1->adpcm_history2_16 = read_16bitLE(frame_offset+0x0a,streamfile);
|
||||
ch2->adpcm_history2_16 = read_16bitLE(frame_offset+0x0c,streamfile);
|
||||
}
|
||||
|
||||
/* write header samples (needed) */
|
||||
if (first_sample==0) {
|
||||
outbuf[0] = ch1->adpcm_history2_16;
|
||||
outbuf[1] = ch2->adpcm_history2_16;
|
||||
outbuf += 2;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
if (first_sample == 1 && samples_to_do > 0) {
|
||||
outbuf[0] = ch1->adpcm_history1_16;
|
||||
outbuf[1] = ch2->adpcm_history1_16;
|
||||
outbuf += 2;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
|
||||
/* decode nibbles */
|
||||
for (i = first_sample; i < first_sample+samples_to_do; i++) {
|
||||
int ch;
|
||||
|
||||
for (ch = 0; ch < 2; ch++) {
|
||||
VGMSTREAMCHANNEL *stream = &vgmstream->ch[ch];
|
||||
int32_t hist1,hist2, predicted;
|
||||
int sample_nibble = (ch == 0) ? /* L = high nibble first */
|
||||
get_high_nibble_signed(read_8bit(frame_offset+0x07*2+(i-2),streamfile)) :
|
||||
get_low_nibble_signed (read_8bit(frame_offset+0x07*2+(i-2),streamfile));
|
||||
|
||||
hist1 = stream->adpcm_history1_16;
|
||||
hist2 = stream->adpcm_history2_16;
|
||||
predicted = hist1*stream->adpcm_coef[0] + hist2*stream->adpcm_coef[1];
|
||||
predicted = predicted / 256;
|
||||
predicted = predicted + sample_nibble*stream->adpcm_scale;
|
||||
outbuf[0] = clamp16(predicted);
|
||||
|
||||
stream->adpcm_history2_16 = stream->adpcm_history1_16;
|
||||
stream->adpcm_history1_16 = outbuf[0];
|
||||
stream->adpcm_scale = (msadpcm_steps[sample_nibble & 0xf] * stream->adpcm_scale) / 256;
|
||||
if (stream->adpcm_scale < 0x10)
|
||||
stream->adpcm_scale = 0x10;
|
||||
|
||||
outbuf++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void decode_msadpcm_mono(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
VGMSTREAMCHANNEL *stream = &vgmstream->ch[channel];
|
||||
int i, frames_in;
|
||||
size_t bytes_per_frame, samples_per_frame;
|
||||
off_t frame_offset;
|
||||
|
||||
/* external interleave (variable size), mono */
|
||||
bytes_per_frame = vgmstream->frame_size;
|
||||
samples_per_frame = (vgmstream->frame_size - 0x07)*2 + 2;
|
||||
frames_in = first_sample / samples_per_frame;
|
||||
first_sample = first_sample % samples_per_frame;
|
||||
|
||||
frame_offset = stream->offset + frames_in*bytes_per_frame;
|
||||
|
||||
/* parse frame header */
|
||||
if (first_sample == 0) {
|
||||
stream->adpcm_coef[0] = msadpcm_coefs[read_8bit(frame_offset+0x00,stream->streamfile) & 0x07][0];
|
||||
stream->adpcm_coef[1] = msadpcm_coefs[read_8bit(frame_offset+0x00,stream->streamfile) & 0x07][1];
|
||||
stream->adpcm_scale = read_16bitLE(frame_offset+0x01,stream->streamfile);
|
||||
stream->adpcm_history1_16 = read_16bitLE(frame_offset+0x03,stream->streamfile);
|
||||
stream->adpcm_history2_16 = read_16bitLE(frame_offset+0x05,stream->streamfile);
|
||||
}
|
||||
|
||||
/* write header samples (needed) */
|
||||
if (first_sample == 0) {
|
||||
outbuf[0] = stream->adpcm_history2_16;
|
||||
outbuf += channelspacing;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
if (first_sample == 1 && samples_to_do > 0) {
|
||||
outbuf[0] = stream->adpcm_history1_16;
|
||||
outbuf += channelspacing;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
|
||||
/* decode nibbles */
|
||||
for (i = first_sample; i < first_sample+samples_to_do; i++) {
|
||||
int32_t hist1,hist2, predicted;
|
||||
int sample_nibble = (i & 1) ? /* high nibble first */
|
||||
get_low_nibble_signed (read_8bit(frame_offset+0x07+(i-2)/2,stream->streamfile)) :
|
||||
get_high_nibble_signed(read_8bit(frame_offset+0x07+(i-2)/2,stream->streamfile));
|
||||
|
||||
hist1 = stream->adpcm_history1_16;
|
||||
hist2 = stream->adpcm_history2_16;
|
||||
predicted = hist1*stream->adpcm_coef[0] + hist2*stream->adpcm_coef[1];
|
||||
predicted = predicted / 256;
|
||||
predicted = predicted + sample_nibble*stream->adpcm_scale;
|
||||
outbuf[0] = clamp16(predicted);
|
||||
|
||||
stream->adpcm_history2_16 = stream->adpcm_history1_16;
|
||||
stream->adpcm_history1_16 = outbuf[0];
|
||||
stream->adpcm_scale = (msadpcm_steps[sample_nibble & 0xf] * stream->adpcm_scale) / 256;
|
||||
if (stream->adpcm_scale < 0x10)
|
||||
stream->adpcm_scale = 0x10;
|
||||
|
||||
outbuf += channelspacing;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cricket Audio's MSADPCM, same thing with reversed hist and nibble order
|
||||
* (their tools may convert to float/others but internally it's all PCM16, from debugging). */
|
||||
void decode_msadpcm_ck(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
VGMSTREAMCHANNEL *stream = &vgmstream->ch[channel];
|
||||
int i, frames_in;
|
||||
size_t bytes_per_frame, samples_per_frame;
|
||||
off_t frame_offset;
|
||||
|
||||
/* external interleave (variable size), mono */
|
||||
bytes_per_frame = vgmstream->frame_size;
|
||||
samples_per_frame = (vgmstream->frame_size - 0x07)*2 + 2;
|
||||
frames_in = first_sample / samples_per_frame;
|
||||
first_sample = first_sample % samples_per_frame;
|
||||
|
||||
frame_offset = stream->offset + frames_in*bytes_per_frame;
|
||||
|
||||
/* parse frame header */
|
||||
if (first_sample == 0) {
|
||||
stream->adpcm_coef[0] = msadpcm_coefs[read_8bit(frame_offset+0x00,stream->streamfile) & 0x07][0];
|
||||
stream->adpcm_coef[1] = msadpcm_coefs[read_8bit(frame_offset+0x00,stream->streamfile) & 0x07][1];
|
||||
stream->adpcm_scale = read_16bitLE(frame_offset+0x01,stream->streamfile);
|
||||
stream->adpcm_history2_16 = read_16bitLE(frame_offset+0x03,stream->streamfile); /* hist2 first, unlike normal MSADPCM */
|
||||
stream->adpcm_history1_16 = read_16bitLE(frame_offset+0x05,stream->streamfile);
|
||||
}
|
||||
|
||||
/* write header samples (needed) */
|
||||
if (first_sample == 0) {
|
||||
outbuf[0] = stream->adpcm_history2_16;
|
||||
outbuf += channelspacing;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
if (first_sample == 1 && samples_to_do > 0) {
|
||||
outbuf[0] = stream->adpcm_history1_16;
|
||||
outbuf += channelspacing;
|
||||
first_sample++;
|
||||
samples_to_do--;
|
||||
}
|
||||
|
||||
/* decode nibbles */
|
||||
for (i = first_sample; i < first_sample+samples_to_do; i++) {
|
||||
int32_t hist1,hist2, predicted;
|
||||
int sample_nibble = (i & 1) ? /* low nibble first, unlike normal MSADPCM */
|
||||
get_high_nibble_signed (read_8bit(frame_offset+0x07+(i-2)/2,stream->streamfile)) :
|
||||
get_low_nibble_signed(read_8bit(frame_offset+0x07+(i-2)/2,stream->streamfile));
|
||||
|
||||
hist1 = stream->adpcm_history1_16;
|
||||
hist2 = stream->adpcm_history2_16;
|
||||
predicted = hist1*stream->adpcm_coef[0] + hist2*stream->adpcm_coef[1];
|
||||
predicted = predicted >> 8; /* probably no difference vs MSADPCM */
|
||||
predicted = predicted + sample_nibble*stream->adpcm_scale;
|
||||
outbuf[0] = clamp16(predicted);
|
||||
|
||||
stream->adpcm_history2_16 = stream->adpcm_history1_16;
|
||||
stream->adpcm_history1_16 = outbuf[0];
|
||||
stream->adpcm_scale = (msadpcm_steps[sample_nibble & 0xf] * stream->adpcm_scale) >> 8;
|
||||
if (stream->adpcm_scale < 0x10)
|
||||
stream->adpcm_scale = 0x10;
|
||||
|
||||
outbuf += channelspacing;
|
||||
}
|
||||
}
|
||||
|
||||
long msadpcm_bytes_to_samples(long bytes, int block_size, int channels) {
|
||||
if (block_size <= 0 || channels <= 0) return 0;
|
||||
return (bytes / block_size) * (block_size - (7-1)*channels) * 2 / channels
|
||||
+ ((bytes % block_size) ? ((bytes % block_size) - (7-1)*channels) * 2 / channels : 0);
|
||||
}
|
||||
|
||||
/* test if MSADPCM coefs were re-defined (possible in theory but not used in practice) */
|
||||
int msadpcm_check_coefs(STREAMFILE* sf, off_t offset) {
|
||||
int i;
|
||||
int count = read_16bitLE(offset, sf);
|
||||
if (count != 7) {
|
||||
VGM_LOG("MSADPCM: bad count %i at %lx\n", count, offset);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
offset += 0x02;
|
||||
for (i = 0; i < 7; i++) {
|
||||
int16_t coef1 = read_16bitLE(offset + 0x00, sf);
|
||||
int16_t coef2 = read_16bitLE(offset + 0x02, sf);
|
||||
|
||||
if (coef1 != msadpcm_coefs[i][0] || coef2 != msadpcm_coefs[i][1]) {
|
||||
VGM_LOG("MSADPCM: bad coef %i/%i vs %i/%i\n", coef1, coef2, msadpcm_coefs[i][0], msadpcm_coefs[i][1]);
|
||||
goto fail;
|
||||
}
|
||||
offset += 0x02 + 0x02;
|
||||
}
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,207 +1,207 @@
|
||||
#include <math.h>
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* PSVita ADPCM table */
|
||||
static const int16_t hevag_coefs[128][4] = {
|
||||
{ 0, 0, 0, 0 },
|
||||
{ 7680, 0, 0, 0 },
|
||||
{ 14720, -6656, 0, 0 },
|
||||
{ 12544, -7040, 0, 0 },
|
||||
{ 15616, -7680, 0, 0 },
|
||||
{ 14731, -7059, 0, 0 },
|
||||
{ 14507, -7366, 0, 0 },
|
||||
{ 13920, -7522, 0, 0 },
|
||||
{ 13133, -7680, 0, 0 },
|
||||
{ 12028, -7680, 0, 0 },
|
||||
{ 10764, -7680, 0, 0 },
|
||||
{ 9359, -7680, 0, 0 },
|
||||
{ 7832, -7680, 0, 0 },
|
||||
{ 6201, -7680, 0, 0 },
|
||||
{ 4488, -7680, 0, 0 },
|
||||
{ 2717, -7680, 0, 0 },
|
||||
{ 910, -7680, 0, 0 },
|
||||
{ -910, -7680, 0, 0 },
|
||||
{ -2717, -7680, 0, 0 },
|
||||
{ -4488, -7680, 0, 0 },
|
||||
{ -6201, -7680, 0, 0 },
|
||||
{ -7832, -7680, 0, 0 },
|
||||
{ -9359, -7680, 0, 0 },
|
||||
{ -10764, -7680, 0, 0 },
|
||||
{ -12028, -7680, 0, 0 },
|
||||
{ -13133, -7680, 0, 0 },
|
||||
{ -13920, -7522, 0, 0 },
|
||||
{ -14507, -7366, 0, 0 },
|
||||
{ -14731, -7059, 0, 0 },
|
||||
{ 5376, -9216, 3328, -3072 },
|
||||
{ -6400, -7168, -3328, -2304 },
|
||||
{ -10496, -7424, -3584, -1024 },
|
||||
{ -167, -2722, -494, -541 },
|
||||
{ -7430, -2221, -2298, 424 },
|
||||
{ -8001, -3166, -2814, 289 },
|
||||
{ 6018, -4750, 2649, -1298 },
|
||||
{ 3798, -6946, 3875, -1216 },
|
||||
{ -8237, -2596, -2071, 227 },
|
||||
{ 9199, 1982, -1382, -2316 },
|
||||
{ 13021, -3044, -3792, 1267 },
|
||||
{ 13112, -4487, -2250, 1665 },
|
||||
{ -1668, -3744, -6456, 840 },
|
||||
{ 7819, -4328, 2111, -506 },
|
||||
{ 9571, -1336, -757, 487 },
|
||||
{ 10032, -2562, 300, 199 },
|
||||
{ -4745, -4122, -5486, -1493 },
|
||||
{ -5896, 2378, -4787, -6947 },
|
||||
{ -1193, -9117, -1237, -3114 },
|
||||
{ 2783, -7108, -1575, -1447 },
|
||||
{ -7334, -2062, -2212, 446 },
|
||||
{ 6127, -2577, -315, -18 },
|
||||
{ 9457, -1858, 102, 258 },
|
||||
{ 7876, -4483, 2126, -538 },
|
||||
{ -7172, -1795, -2069, 482 },
|
||||
{ -7358, -2102, -2233, 440 },
|
||||
{ -9170, -3509, -2674, -391 },
|
||||
{ -2638, -2647, -1929, -1637 },
|
||||
{ 1873, 9183, 1860, -5746 },
|
||||
{ 9214, 1859, -1124, -2427 },
|
||||
{ 13204, -3012, -4139, 1370 },
|
||||
{ 12437, -4792, -256, 622 },
|
||||
{ -2653, -1144, -3182, -6878 },
|
||||
{ 9331, -1048, -828, 507 },
|
||||
{ 1642, -620, -946, -4229 },
|
||||
{ 4246, -7585, -533, -2259 },
|
||||
{ -8988, -3891, -2807, 44 },
|
||||
{ -2562, -2735, -1730, -1899 },
|
||||
{ 3182, -483, -714, -1421 },
|
||||
{ 7937, -3844, 2821, -1019 },
|
||||
{ 10069, -2609, 314, 195 },
|
||||
{ 8400, -3297, 1551, -155 },
|
||||
{ -8529, -2775, -2432, -336 },
|
||||
{ 9477, -1882, 108, 256 },
|
||||
{ 75, -2241, -298, -6937 },
|
||||
{ -9143, -4160, -2963, 5 },
|
||||
{ -7270, -1958, -2156, 460 },
|
||||
{ -2740, 3745, 5936, -1089 },
|
||||
{ 8993, 1948, -683, -2704 },
|
||||
{ 13101, -2835, -3854, 1055 },
|
||||
{ 9543, -1961, 130, 250 },
|
||||
{ 5272, -4270, 3124, -3157 },
|
||||
{ -7696, -3383, -2907, -456 },
|
||||
{ 7309, 2523, 434, -2461 },
|
||||
{ 10275, -2867, 391, 172 },
|
||||
{ 10940, -3721, 665, 97 },
|
||||
{ 24, -310, -1262, 320 },
|
||||
{ -8122, -2411, -2311, -271 },
|
||||
{ -8511, -3067, -2337, 163 },
|
||||
{ 326, -3846, 419, -933 },
|
||||
{ 8895, 2194, -541, -2880 },
|
||||
{ 12073, -1876, -2017, -601 },
|
||||
{ 8729, -3423, 1674, -169 },
|
||||
{ 12950, -3847, -3007, 1946 },
|
||||
{ 10038, -2570, 302, 198 },
|
||||
{ 9385, -2757, 1008, 41 },
|
||||
{ -4720, -5006, -2852, -1161 },
|
||||
{ 7869, -4326, 2135, -501 },
|
||||
{ 2450, -8597, 1299, -2780 },
|
||||
{ 10192, -2763, 360, 181 },
|
||||
{ 11313, -4213, 833, 53 },
|
||||
{ 10154, -2716, 345, 185 },
|
||||
{ 9638, -1417, -737, 482 },
|
||||
{ 3854, -4554, 2843, -3397 },
|
||||
{ 6699, -5659, 2249, -1074 },
|
||||
{ 11082, -3908, 728, 80 },
|
||||
{ -1026, -9810, -805, -3462 },
|
||||
{ 10396, -3746, 1367, -96 },
|
||||
{ 10287, 988, -1915, -1437 },
|
||||
{ 7953, 3878, -764, -3263 },
|
||||
{ 12689, -3375, -3354, 2079 },
|
||||
{ 6641, 3166, 231, -2089 },
|
||||
{ -2348, -7354, -1944, -4122 },
|
||||
{ 9290, -4039, 1885, -246 },
|
||||
{ 4633, -6403, 1748, -1619 },
|
||||
{ 11247, -4125, 802, 61 },
|
||||
{ 9807, -2284, 219, 222 },
|
||||
{ 9736, -1536, -706, 473 },
|
||||
{ 8440, -3436, 1562, -176 },
|
||||
{ 9307, -1021, -835, 509 },
|
||||
{ 1698, -9025, 688, -3037 },
|
||||
{ 10214, -2791, 368, 179 },
|
||||
{ 8390, 3248, -758, -2989 },
|
||||
{ 7201, 3316, 46, -2614 },
|
||||
{ -88, -7809, -538, -4571 },
|
||||
{ 6193, -5189, 2760, -1245 },
|
||||
{ 12325, -1290, -3284, 253 },
|
||||
{ 13064, -4075, -2824, 1877 },
|
||||
{ 5333, 2999, 775, -1132 }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sony's HEVAG (High Efficiency VAG) ADPCM, used in PSVita games (hardware decoded).
|
||||
* Evolution of the regular VAG (same flags and frames), uses 4 history samples and a bigger table.
|
||||
*
|
||||
* Original research and algorithm by id-daemon / daemon1.
|
||||
*/
|
||||
void decode_hevag(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
uint8_t frame[0x10] = {0};
|
||||
off_t frame_offset;
|
||||
int i, frames_in, sample_count = 0;
|
||||
size_t bytes_per_frame, samples_per_frame;
|
||||
int coef_index, shift_factor, flag;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int32_t hist2 = stream->adpcm_history2_32;
|
||||
int32_t hist3 = stream->adpcm_history3_32;
|
||||
int32_t hist4 = stream->adpcm_history4_32;
|
||||
|
||||
|
||||
/* external interleave (fixed size), mono */
|
||||
bytes_per_frame = 0x10;
|
||||
samples_per_frame = (bytes_per_frame - 0x02) * 2; /* always 28 */
|
||||
frames_in = first_sample / samples_per_frame;
|
||||
first_sample = first_sample % samples_per_frame;
|
||||
|
||||
/* parse frame header */
|
||||
frame_offset = stream->offset + bytes_per_frame * frames_in;
|
||||
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
|
||||
coef_index = (frame[0] >> 4) & 0xf;
|
||||
shift_factor = (frame[0] >> 0) & 0xf;
|
||||
coef_index = ((frame[1] >> 0) & 0xf0) | coef_index;
|
||||
flag = (frame[1] >> 0) & 0xf; /* same flags */
|
||||
|
||||
VGM_ASSERT_ONCE(coef_index > 127 || shift_factor > 12, "HEVAG: in+correct coefs/shift at %x\n", (uint32_t)frame_offset);
|
||||
if (coef_index > 127)
|
||||
coef_index = 127; /* ? */
|
||||
if (shift_factor > 12)
|
||||
shift_factor = 9; /* ? */
|
||||
|
||||
shift_factor = 20 - shift_factor;
|
||||
/* decode nibbles */
|
||||
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||
int32_t sample = 0;
|
||||
|
||||
if (flag < 0x07) { /* with flag 0x07 decoded sample must be 0 */
|
||||
uint8_t nibbles = frame[0x02 + i/2];
|
||||
|
||||
sample = (i&1 ? /* low nibble first */
|
||||
get_high_nibble_signed(nibbles):
|
||||
get_low_nibble_signed(nibbles)) << shift_factor; /*scale*/
|
||||
sample = ((hist1 * hevag_coefs[coef_index][0] +
|
||||
hist2 * hevag_coefs[coef_index][1] +
|
||||
hist3 * hevag_coefs[coef_index][2] +
|
||||
hist4 * hevag_coefs[coef_index][3]) >> 5) + sample;
|
||||
sample >>= 8;
|
||||
}
|
||||
|
||||
outbuf[sample_count] = clamp16(sample); /*clamping*/
|
||||
sample_count += channelspacing;
|
||||
|
||||
hist4 = hist3;
|
||||
hist3 = hist2;
|
||||
hist2 = hist1;
|
||||
hist1 = sample;
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
stream->adpcm_history2_32 = hist2;
|
||||
stream->adpcm_history3_32 = hist3;
|
||||
stream->adpcm_history4_32 = hist4;
|
||||
}
|
||||
#include <math.h>
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* PSVita ADPCM table */
|
||||
static const int16_t hevag_coefs[128][4] = {
|
||||
{ 0, 0, 0, 0 },
|
||||
{ 7680, 0, 0, 0 },
|
||||
{ 14720, -6656, 0, 0 },
|
||||
{ 12544, -7040, 0, 0 },
|
||||
{ 15616, -7680, 0, 0 },
|
||||
{ 14731, -7059, 0, 0 },
|
||||
{ 14507, -7366, 0, 0 },
|
||||
{ 13920, -7522, 0, 0 },
|
||||
{ 13133, -7680, 0, 0 },
|
||||
{ 12028, -7680, 0, 0 },
|
||||
{ 10764, -7680, 0, 0 },
|
||||
{ 9359, -7680, 0, 0 },
|
||||
{ 7832, -7680, 0, 0 },
|
||||
{ 6201, -7680, 0, 0 },
|
||||
{ 4488, -7680, 0, 0 },
|
||||
{ 2717, -7680, 0, 0 },
|
||||
{ 910, -7680, 0, 0 },
|
||||
{ -910, -7680, 0, 0 },
|
||||
{ -2717, -7680, 0, 0 },
|
||||
{ -4488, -7680, 0, 0 },
|
||||
{ -6201, -7680, 0, 0 },
|
||||
{ -7832, -7680, 0, 0 },
|
||||
{ -9359, -7680, 0, 0 },
|
||||
{ -10764, -7680, 0, 0 },
|
||||
{ -12028, -7680, 0, 0 },
|
||||
{ -13133, -7680, 0, 0 },
|
||||
{ -13920, -7522, 0, 0 },
|
||||
{ -14507, -7366, 0, 0 },
|
||||
{ -14731, -7059, 0, 0 },
|
||||
{ 5376, -9216, 3328, -3072 },
|
||||
{ -6400, -7168, -3328, -2304 },
|
||||
{ -10496, -7424, -3584, -1024 },
|
||||
{ -167, -2722, -494, -541 },
|
||||
{ -7430, -2221, -2298, 424 },
|
||||
{ -8001, -3166, -2814, 289 },
|
||||
{ 6018, -4750, 2649, -1298 },
|
||||
{ 3798, -6946, 3875, -1216 },
|
||||
{ -8237, -2596, -2071, 227 },
|
||||
{ 9199, 1982, -1382, -2316 },
|
||||
{ 13021, -3044, -3792, 1267 },
|
||||
{ 13112, -4487, -2250, 1665 },
|
||||
{ -1668, -3744, -6456, 840 },
|
||||
{ 7819, -4328, 2111, -506 },
|
||||
{ 9571, -1336, -757, 487 },
|
||||
{ 10032, -2562, 300, 199 },
|
||||
{ -4745, -4122, -5486, -1493 },
|
||||
{ -5896, 2378, -4787, -6947 },
|
||||
{ -1193, -9117, -1237, -3114 },
|
||||
{ 2783, -7108, -1575, -1447 },
|
||||
{ -7334, -2062, -2212, 446 },
|
||||
{ 6127, -2577, -315, -18 },
|
||||
{ 9457, -1858, 102, 258 },
|
||||
{ 7876, -4483, 2126, -538 },
|
||||
{ -7172, -1795, -2069, 482 },
|
||||
{ -7358, -2102, -2233, 440 },
|
||||
{ -9170, -3509, -2674, -391 },
|
||||
{ -2638, -2647, -1929, -1637 },
|
||||
{ 1873, 9183, 1860, -5746 },
|
||||
{ 9214, 1859, -1124, -2427 },
|
||||
{ 13204, -3012, -4139, 1370 },
|
||||
{ 12437, -4792, -256, 622 },
|
||||
{ -2653, -1144, -3182, -6878 },
|
||||
{ 9331, -1048, -828, 507 },
|
||||
{ 1642, -620, -946, -4229 },
|
||||
{ 4246, -7585, -533, -2259 },
|
||||
{ -8988, -3891, -2807, 44 },
|
||||
{ -2562, -2735, -1730, -1899 },
|
||||
{ 3182, -483, -714, -1421 },
|
||||
{ 7937, -3844, 2821, -1019 },
|
||||
{ 10069, -2609, 314, 195 },
|
||||
{ 8400, -3297, 1551, -155 },
|
||||
{ -8529, -2775, -2432, -336 },
|
||||
{ 9477, -1882, 108, 256 },
|
||||
{ 75, -2241, -298, -6937 },
|
||||
{ -9143, -4160, -2963, 5 },
|
||||
{ -7270, -1958, -2156, 460 },
|
||||
{ -2740, 3745, 5936, -1089 },
|
||||
{ 8993, 1948, -683, -2704 },
|
||||
{ 13101, -2835, -3854, 1055 },
|
||||
{ 9543, -1961, 130, 250 },
|
||||
{ 5272, -4270, 3124, -3157 },
|
||||
{ -7696, -3383, -2907, -456 },
|
||||
{ 7309, 2523, 434, -2461 },
|
||||
{ 10275, -2867, 391, 172 },
|
||||
{ 10940, -3721, 665, 97 },
|
||||
{ 24, -310, -1262, 320 },
|
||||
{ -8122, -2411, -2311, -271 },
|
||||
{ -8511, -3067, -2337, 163 },
|
||||
{ 326, -3846, 419, -933 },
|
||||
{ 8895, 2194, -541, -2880 },
|
||||
{ 12073, -1876, -2017, -601 },
|
||||
{ 8729, -3423, 1674, -169 },
|
||||
{ 12950, -3847, -3007, 1946 },
|
||||
{ 10038, -2570, 302, 198 },
|
||||
{ 9385, -2757, 1008, 41 },
|
||||
{ -4720, -5006, -2852, -1161 },
|
||||
{ 7869, -4326, 2135, -501 },
|
||||
{ 2450, -8597, 1299, -2780 },
|
||||
{ 10192, -2763, 360, 181 },
|
||||
{ 11313, -4213, 833, 53 },
|
||||
{ 10154, -2716, 345, 185 },
|
||||
{ 9638, -1417, -737, 482 },
|
||||
{ 3854, -4554, 2843, -3397 },
|
||||
{ 6699, -5659, 2249, -1074 },
|
||||
{ 11082, -3908, 728, 80 },
|
||||
{ -1026, -9810, -805, -3462 },
|
||||
{ 10396, -3746, 1367, -96 },
|
||||
{ 10287, 988, -1915, -1437 },
|
||||
{ 7953, 3878, -764, -3263 },
|
||||
{ 12689, -3375, -3354, 2079 },
|
||||
{ 6641, 3166, 231, -2089 },
|
||||
{ -2348, -7354, -1944, -4122 },
|
||||
{ 9290, -4039, 1885, -246 },
|
||||
{ 4633, -6403, 1748, -1619 },
|
||||
{ 11247, -4125, 802, 61 },
|
||||
{ 9807, -2284, 219, 222 },
|
||||
{ 9736, -1536, -706, 473 },
|
||||
{ 8440, -3436, 1562, -176 },
|
||||
{ 9307, -1021, -835, 509 },
|
||||
{ 1698, -9025, 688, -3037 },
|
||||
{ 10214, -2791, 368, 179 },
|
||||
{ 8390, 3248, -758, -2989 },
|
||||
{ 7201, 3316, 46, -2614 },
|
||||
{ -88, -7809, -538, -4571 },
|
||||
{ 6193, -5189, 2760, -1245 },
|
||||
{ 12325, -1290, -3284, 253 },
|
||||
{ 13064, -4075, -2824, 1877 },
|
||||
{ 5333, 2999, 775, -1132 }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sony's HEVAG (High Efficiency VAG) ADPCM, used in PSVita games (hardware decoded).
|
||||
* Evolution of the regular VAG (same flags and frames), uses 4 history samples and a bigger table.
|
||||
*
|
||||
* Original research and algorithm by id-daemon / daemon1.
|
||||
*/
|
||||
void decode_hevag(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
uint8_t frame[0x10] = {0};
|
||||
off_t frame_offset;
|
||||
int i, frames_in, sample_count = 0;
|
||||
size_t bytes_per_frame, samples_per_frame;
|
||||
int coef_index, shift_factor, flag;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int32_t hist2 = stream->adpcm_history2_32;
|
||||
int32_t hist3 = stream->adpcm_history3_32;
|
||||
int32_t hist4 = stream->adpcm_history4_32;
|
||||
|
||||
|
||||
/* external interleave (fixed size), mono */
|
||||
bytes_per_frame = 0x10;
|
||||
samples_per_frame = (bytes_per_frame - 0x02) * 2; /* always 28 */
|
||||
frames_in = first_sample / samples_per_frame;
|
||||
first_sample = first_sample % samples_per_frame;
|
||||
|
||||
/* parse frame header */
|
||||
frame_offset = stream->offset + bytes_per_frame * frames_in;
|
||||
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
|
||||
coef_index = (frame[0] >> 4) & 0xf;
|
||||
shift_factor = (frame[0] >> 0) & 0xf;
|
||||
coef_index = ((frame[1] >> 0) & 0xf0) | coef_index;
|
||||
flag = (frame[1] >> 0) & 0xf; /* same flags */
|
||||
|
||||
VGM_ASSERT_ONCE(coef_index > 127 || shift_factor > 12, "HEVAG: in+correct coefs/shift at %x\n", (uint32_t)frame_offset);
|
||||
if (coef_index > 127)
|
||||
coef_index = 127; /* ? */
|
||||
if (shift_factor > 12)
|
||||
shift_factor = 9; /* ? */
|
||||
|
||||
shift_factor = 20 - shift_factor;
|
||||
/* decode nibbles */
|
||||
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||
int32_t sample = 0;
|
||||
|
||||
if (flag < 0x07) { /* with flag 0x07 decoded sample must be 0 */
|
||||
uint8_t nibbles = frame[0x02 + i/2];
|
||||
|
||||
sample = (i&1 ? /* low nibble first */
|
||||
get_high_nibble_signed(nibbles):
|
||||
get_low_nibble_signed(nibbles)) << shift_factor; /*scale*/
|
||||
sample = ((hist1 * hevag_coefs[coef_index][0] +
|
||||
hist2 * hevag_coefs[coef_index][1] +
|
||||
hist3 * hevag_coefs[coef_index][2] +
|
||||
hist4 * hevag_coefs[coef_index][3]) >> 5) + sample;
|
||||
sample >>= 8;
|
||||
}
|
||||
|
||||
outbuf[sample_count] = clamp16(sample); /*clamping*/
|
||||
sample_count += channelspacing;
|
||||
|
||||
hist4 = hist3;
|
||||
hist3 = hist2;
|
||||
hist2 = hist1;
|
||||
hist1 = sample;
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
stream->adpcm_history2_32 = hist2;
|
||||
stream->adpcm_history3_32 = hist3;
|
||||
stream->adpcm_history4_32 = hist4;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,162 +1,162 @@
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
// todo this is based on Kazzuya's old code; different emus (PCSX, Mame, Mednafen, etc) do
|
||||
// XA coefs int math in different ways (see comments below), not 100% accurate.
|
||||
// May be implemented like the SNES/SPC700 BRR.
|
||||
|
||||
/* XA ADPCM gain values */
|
||||
#if 0
|
||||
static const float K0[4] = { 0.0, 0.9375, 1.796875, 1.53125 };
|
||||
static const float K1[4] = { 0.0, 0.0, -0.8125, -0.859375 };
|
||||
#endif
|
||||
/* K0/1 floats to int, -K*2^10 = -K*(1<<10) = -K*1024 */
|
||||
static const int IK0[4] = { 0, -960, -1840, -1568 };
|
||||
static const int IK1[4] = { 0, 0, 832, 880 };
|
||||
|
||||
/* Sony XA ADPCM, defined for CD-DA/CD-i in the "Red Book" (private) or "Green Book" (public) specs.
|
||||
* The algorithm basically is BRR (Bit Rate Reduction) from the SNES SPC700, while the data layout is new.
|
||||
*
|
||||
* Decoding is defined in diagrams, roughly as:
|
||||
* pcm = clamp( signed_nibble * 2^(12-range) + K0[index]*hist1 + K1[index]*hist2 )
|
||||
* - Range (12-range=shift) and filter index are renewed every ~28 samples.
|
||||
* - nibble is expanded to a signed 16b sample, reimplemented as:
|
||||
* short sample = ((nibble << 12) & 0xf000) >> shift
|
||||
* or: int sample = ((nibble << 28) & 0xf0000000) >> (shift + N)
|
||||
* - K0/K1 are float coefs are typically redefined with int math in various ways, with non-equivalent rounding:
|
||||
* (sample + K0*2^N*hist1 + K1*2^N*hist2 + [(2^N)/2]) / 2^N
|
||||
* (sample + K0*2^N*hist1 + K1*2^N*hist2 + [(2^N)/2]) >> N
|
||||
* sample + (K0*2^N*hist1 + K1*2^N*hist2)>>N
|
||||
* sample + (K0*2^N*hist1)>>N + (K1*2^N*hist2)>>N
|
||||
* etc
|
||||
* (rounding differences should be inaudible, so public implementations may be approximations)
|
||||
*
|
||||
* Various XA descendants (PS-ADPCM, EA-XA, NGC DTK, FADPCM, etc) do filters/rounding slightly
|
||||
* differently, maybe using one of the above methods in software/CPU, but in XA's case may be done
|
||||
* like the SNES/SPC700 BRR, with specific per-filter ops.
|
||||
* int coef tables commonly use N = 6 or 8, so K0 0.9375*64 = 60 or 0.9375*256 = 240
|
||||
* PS1 XA is apparently upsampled and interpolated to 44100, vgmstream doesn't simulate this.
|
||||
*
|
||||
* XA has an 8-bit decoding and "emphasis" modes, that no PS1 game actually uses, but apparently
|
||||
* are supported by the CD hardware and will play if found.
|
||||
*
|
||||
* Info (Green Book): https://www.lscdweb.com/data/downloadables/2/8/cdi_may94_r2.pdf
|
||||
* BRR info (no$sns): http://problemkaputt.de/fullsnes.htm#snesapudspbrrsamples
|
||||
* (bsnes): https://github.com/byuu/bsnes/blob/master/bsnes/sfc/dsp/SPC_DSP.cpp#L316
|
||||
*/
|
||||
|
||||
void decode_xa(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
uint8_t frame[0x80] = {0};
|
||||
off_t frame_offset;
|
||||
int i,j, sp_pos, frames_in, samples_done = 0, sample_count = 0;
|
||||
size_t bytes_per_frame, samples_per_frame;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int32_t hist2 = stream->adpcm_history2_32;
|
||||
|
||||
|
||||
/* data layout (mono):
|
||||
* - CD-XA audio is divided into sectors ("audio blocks"), each with 18 size 0x80 frames
|
||||
* (handled externally, this decoder only gets frames)
|
||||
* - a frame ("sound group") is divided into 8 subframes ("sound unit"), with
|
||||
* subframe headers ("sound parameters") first then subframe nibbles ("sound data")
|
||||
* - headers: 0..3 + repeat 0..3 + 4..7 + repeat 4..7 (where N = subframe N header)
|
||||
* (repeats may be for error correction, though probably unused)
|
||||
* - nibbles: 32b with nibble0 for subframes 0..8, 32b with nibble1 for subframes 0..8, etc
|
||||
* (low first: 32b = sf1-n0 sf0-n0 sf3-n0 sf2-n0 sf5-n0 sf4-n0 sf7-n0 sf6-n0, etc)
|
||||
*
|
||||
* stereo layout is the same but alternates channels: subframe 0/2/4/6=L, subframe 1/3/5/7=R
|
||||
*
|
||||
* example:
|
||||
* subframe 0: header @ 0x00 or 0x04, 28 nibbles (low) @ 0x10,14,18,1c,20 ... 7c
|
||||
* subframe 1: header @ 0x01 or 0x05, 28 nibbles (high) @ 0x10,14,18,1c,20 ... 7c
|
||||
* subframe 2: header @ 0x02 or 0x06, 28 nibbles (low) @ 0x11,15,19,1d,21 ... 7d
|
||||
* ...
|
||||
* subframe 7: header @ 0x0b or 0x0f, 28 nibbles (high) @ 0x13,17,1b,1f,23 ... 7f
|
||||
*/
|
||||
|
||||
/* external interleave (fixed size), mono/stereo */
|
||||
bytes_per_frame = 0x80;
|
||||
samples_per_frame = 28*8 / channelspacing;
|
||||
frames_in = first_sample / samples_per_frame;
|
||||
first_sample = first_sample % samples_per_frame;
|
||||
|
||||
/* parse frame header */
|
||||
frame_offset = stream->offset + bytes_per_frame * frames_in;
|
||||
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
|
||||
|
||||
VGM_ASSERT(get_32bitBE(frame+0x0) != get_32bitBE(frame+0x4) || get_32bitBE(frame+0x8) != get_32bitBE(frame+0xC),
|
||||
"bad frames at %x\n", (uint32_t)frame_offset);
|
||||
|
||||
|
||||
/* decode subframes */
|
||||
for (i = 0; i < 8 / channelspacing; i++) {
|
||||
int32_t coef1, coef2;
|
||||
uint8_t coef_index, shift_factor;
|
||||
|
||||
/* parse current subframe (sound unit)'s header (sound parameters) */
|
||||
sp_pos = 0x04 + i*channelspacing + channel;
|
||||
coef_index = (frame[sp_pos] >> 4) & 0xf;
|
||||
shift_factor = (frame[sp_pos] >> 0) & 0xf;
|
||||
|
||||
VGM_ASSERT(coef_index > 4 || shift_factor > 12, "XA: incorrect coefs/shift at %x\n", (uint32_t)frame_offset + sp_pos);
|
||||
if (coef_index > 4)
|
||||
coef_index = 0; /* only 4 filters are used, rest is apparently 0 */
|
||||
if (shift_factor > 12)
|
||||
shift_factor = 9; /* supposedly, from Nocash PSX docs */
|
||||
|
||||
coef1 = IK0[coef_index];
|
||||
coef2 = IK1[coef_index];
|
||||
|
||||
|
||||
/* decode subframe nibbles */
|
||||
for(j = 0; j < 28; j++) {
|
||||
uint8_t nibbles;
|
||||
int32_t new_sample;
|
||||
|
||||
int su_pos = (channelspacing==1) ?
|
||||
0x10 + j*0x04 + (i/2) : /* mono */
|
||||
0x10 + j*0x04 + i; /* stereo */
|
||||
int get_high_nibble = (channelspacing==1) ?
|
||||
(i&1) : /* mono (even subframes = low, off subframes = high) */
|
||||
(channel == 1); /* stereo (L channel / even subframes = low, R channel / odd subframes = high) */
|
||||
|
||||
/* skip half decodes to make sure hist isn't touched (kinda hack-ish) */
|
||||
if (!(sample_count >= first_sample && samples_done < samples_to_do)) {
|
||||
sample_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
nibbles = frame[su_pos];
|
||||
|
||||
new_sample = get_high_nibble ?
|
||||
(nibbles >> 4) & 0x0f :
|
||||
(nibbles >> 0) & 0x0f;
|
||||
|
||||
new_sample = (int16_t)((new_sample << 12) & 0xf000) >> shift_factor; /* 16b sign extend + scale */
|
||||
new_sample = new_sample << 4;
|
||||
new_sample = new_sample - ((coef1*hist1 + coef2*hist2) >> 10);
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = new_sample; /* must go before clamp, somehow */
|
||||
new_sample = new_sample >> 4;
|
||||
new_sample = clamp16(new_sample);
|
||||
|
||||
outbuf[samples_done * channelspacing] = new_sample;
|
||||
samples_done++;
|
||||
|
||||
sample_count++;
|
||||
}
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
stream->adpcm_history2_32 = hist2;
|
||||
}
|
||||
|
||||
size_t xa_bytes_to_samples(size_t bytes, int channels, int is_blocked, int is_form2) {
|
||||
if (is_blocked) {
|
||||
return (bytes / 0x930) * (28*8/ channels) * (is_form2 ? 18 : 16);
|
||||
}
|
||||
else {
|
||||
return (bytes / 0x80) * (28*8 / channels);
|
||||
}
|
||||
}
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
// todo this is based on Kazzuya's old code; different emus (PCSX, Mame, Mednafen, etc) do
|
||||
// XA coefs int math in different ways (see comments below), not 100% accurate.
|
||||
// May be implemented like the SNES/SPC700 BRR.
|
||||
|
||||
/* XA ADPCM gain values */
|
||||
#if 0
|
||||
static const float K0[4] = { 0.0, 0.9375, 1.796875, 1.53125 };
|
||||
static const float K1[4] = { 0.0, 0.0, -0.8125, -0.859375 };
|
||||
#endif
|
||||
/* K0/1 floats to int, -K*2^10 = -K*(1<<10) = -K*1024 */
|
||||
static const int IK0[4] = { 0, -960, -1840, -1568 };
|
||||
static const int IK1[4] = { 0, 0, 832, 880 };
|
||||
|
||||
/* Sony XA ADPCM, defined for CD-DA/CD-i in the "Red Book" (private) or "Green Book" (public) specs.
|
||||
* The algorithm basically is BRR (Bit Rate Reduction) from the SNES SPC700, while the data layout is new.
|
||||
*
|
||||
* Decoding is defined in diagrams, roughly as:
|
||||
* pcm = clamp( signed_nibble * 2^(12-range) + K0[index]*hist1 + K1[index]*hist2 )
|
||||
* - Range (12-range=shift) and filter index are renewed every ~28 samples.
|
||||
* - nibble is expanded to a signed 16b sample, reimplemented as:
|
||||
* short sample = ((nibble << 12) & 0xf000) >> shift
|
||||
* or: int sample = ((nibble << 28) & 0xf0000000) >> (shift + N)
|
||||
* - K0/K1 are float coefs are typically redefined with int math in various ways, with non-equivalent rounding:
|
||||
* (sample + K0*2^N*hist1 + K1*2^N*hist2 + [(2^N)/2]) / 2^N
|
||||
* (sample + K0*2^N*hist1 + K1*2^N*hist2 + [(2^N)/2]) >> N
|
||||
* sample + (K0*2^N*hist1 + K1*2^N*hist2)>>N
|
||||
* sample + (K0*2^N*hist1)>>N + (K1*2^N*hist2)>>N
|
||||
* etc
|
||||
* (rounding differences should be inaudible, so public implementations may be approximations)
|
||||
*
|
||||
* Various XA descendants (PS-ADPCM, EA-XA, NGC DTK, FADPCM, etc) do filters/rounding slightly
|
||||
* differently, maybe using one of the above methods in software/CPU, but in XA's case may be done
|
||||
* like the SNES/SPC700 BRR, with specific per-filter ops.
|
||||
* int coef tables commonly use N = 6 or 8, so K0 0.9375*64 = 60 or 0.9375*256 = 240
|
||||
* PS1 XA is apparently upsampled and interpolated to 44100, vgmstream doesn't simulate this.
|
||||
*
|
||||
* XA has an 8-bit decoding and "emphasis" modes, that no PS1 game actually uses, but apparently
|
||||
* are supported by the CD hardware and will play if found.
|
||||
*
|
||||
* Info (Green Book): https://www.lscdweb.com/data/downloadables/2/8/cdi_may94_r2.pdf
|
||||
* BRR info (no$sns): http://problemkaputt.de/fullsnes.htm#snesapudspbrrsamples
|
||||
* (bsnes): https://github.com/byuu/bsnes/blob/master/bsnes/sfc/dsp/SPC_DSP.cpp#L316
|
||||
*/
|
||||
|
||||
void decode_xa(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
uint8_t frame[0x80] = {0};
|
||||
off_t frame_offset;
|
||||
int i,j, sp_pos, frames_in, samples_done = 0, sample_count = 0;
|
||||
size_t bytes_per_frame, samples_per_frame;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int32_t hist2 = stream->adpcm_history2_32;
|
||||
|
||||
|
||||
/* data layout (mono):
|
||||
* - CD-XA audio is divided into sectors ("audio blocks"), each with 18 size 0x80 frames
|
||||
* (handled externally, this decoder only gets frames)
|
||||
* - a frame ("sound group") is divided into 8 subframes ("sound unit"), with
|
||||
* subframe headers ("sound parameters") first then subframe nibbles ("sound data")
|
||||
* - headers: 0..3 + repeat 0..3 + 4..7 + repeat 4..7 (where N = subframe N header)
|
||||
* (repeats may be for error correction, though probably unused)
|
||||
* - nibbles: 32b with nibble0 for subframes 0..8, 32b with nibble1 for subframes 0..8, etc
|
||||
* (low first: 32b = sf1-n0 sf0-n0 sf3-n0 sf2-n0 sf5-n0 sf4-n0 sf7-n0 sf6-n0, etc)
|
||||
*
|
||||
* stereo layout is the same but alternates channels: subframe 0/2/4/6=L, subframe 1/3/5/7=R
|
||||
*
|
||||
* example:
|
||||
* subframe 0: header @ 0x00 or 0x04, 28 nibbles (low) @ 0x10,14,18,1c,20 ... 7c
|
||||
* subframe 1: header @ 0x01 or 0x05, 28 nibbles (high) @ 0x10,14,18,1c,20 ... 7c
|
||||
* subframe 2: header @ 0x02 or 0x06, 28 nibbles (low) @ 0x11,15,19,1d,21 ... 7d
|
||||
* ...
|
||||
* subframe 7: header @ 0x0b or 0x0f, 28 nibbles (high) @ 0x13,17,1b,1f,23 ... 7f
|
||||
*/
|
||||
|
||||
/* external interleave (fixed size), mono/stereo */
|
||||
bytes_per_frame = 0x80;
|
||||
samples_per_frame = 28*8 / channelspacing;
|
||||
frames_in = first_sample / samples_per_frame;
|
||||
first_sample = first_sample % samples_per_frame;
|
||||
|
||||
/* parse frame header */
|
||||
frame_offset = stream->offset + bytes_per_frame * frames_in;
|
||||
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
|
||||
|
||||
VGM_ASSERT(get_32bitBE(frame+0x0) != get_32bitBE(frame+0x4) || get_32bitBE(frame+0x8) != get_32bitBE(frame+0xC),
|
||||
"bad frames at %x\n", (uint32_t)frame_offset);
|
||||
|
||||
|
||||
/* decode subframes */
|
||||
for (i = 0; i < 8 / channelspacing; i++) {
|
||||
int32_t coef1, coef2;
|
||||
uint8_t coef_index, shift_factor;
|
||||
|
||||
/* parse current subframe (sound unit)'s header (sound parameters) */
|
||||
sp_pos = 0x04 + i*channelspacing + channel;
|
||||
coef_index = (frame[sp_pos] >> 4) & 0xf;
|
||||
shift_factor = (frame[sp_pos] >> 0) & 0xf;
|
||||
|
||||
VGM_ASSERT(coef_index > 4 || shift_factor > 12, "XA: incorrect coefs/shift at %x\n", (uint32_t)frame_offset + sp_pos);
|
||||
if (coef_index > 4)
|
||||
coef_index = 0; /* only 4 filters are used, rest is apparently 0 */
|
||||
if (shift_factor > 12)
|
||||
shift_factor = 9; /* supposedly, from Nocash PSX docs */
|
||||
|
||||
coef1 = IK0[coef_index];
|
||||
coef2 = IK1[coef_index];
|
||||
|
||||
|
||||
/* decode subframe nibbles */
|
||||
for(j = 0; j < 28; j++) {
|
||||
uint8_t nibbles;
|
||||
int32_t new_sample;
|
||||
|
||||
int su_pos = (channelspacing==1) ?
|
||||
0x10 + j*0x04 + (i/2) : /* mono */
|
||||
0x10 + j*0x04 + i; /* stereo */
|
||||
int get_high_nibble = (channelspacing==1) ?
|
||||
(i&1) : /* mono (even subframes = low, off subframes = high) */
|
||||
(channel == 1); /* stereo (L channel / even subframes = low, R channel / odd subframes = high) */
|
||||
|
||||
/* skip half decodes to make sure hist isn't touched (kinda hack-ish) */
|
||||
if (!(sample_count >= first_sample && samples_done < samples_to_do)) {
|
||||
sample_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
nibbles = frame[su_pos];
|
||||
|
||||
new_sample = get_high_nibble ?
|
||||
(nibbles >> 4) & 0x0f :
|
||||
(nibbles >> 0) & 0x0f;
|
||||
|
||||
new_sample = (int16_t)((new_sample << 12) & 0xf000) >> shift_factor; /* 16b sign extend + scale */
|
||||
new_sample = new_sample << 4;
|
||||
new_sample = new_sample - ((coef1*hist1 + coef2*hist2) >> 10);
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = new_sample; /* must go before clamp, somehow */
|
||||
new_sample = new_sample >> 4;
|
||||
new_sample = clamp16(new_sample);
|
||||
|
||||
outbuf[samples_done * channelspacing] = new_sample;
|
||||
samples_done++;
|
||||
|
||||
sample_count++;
|
||||
}
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
stream->adpcm_history2_32 = hist2;
|
||||
}
|
||||
|
||||
size_t xa_bytes_to_samples(size_t bytes, int channels, int is_blocked, int is_form2) {
|
||||
if (is_blocked) {
|
||||
return (bytes / 0x930) * (28*8/ channels) * (is_form2 ? 18 : 16);
|
||||
}
|
||||
else {
|
||||
return (bytes / 0x80) * (28*8 / channels);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef _FSB_ENCRYPTED_STREAMFILE_H_
|
||||
#define _FSB_ENCRYPTED_H_
|
||||
|
||||
#define FSB_KEY_MAX 128 /* probably 32 */
|
||||
#define FSB_KEY_MAX 0x10000 //0x168
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
Loading…
x
Reference in New Issue
Block a user