mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-12-21 02:45:52 +01:00
d85c033c9d
- eaxa_decoder to ea_decoder - ea_header to ea_schl - ea_block* to ea_schl_block*
179 lines
6.9 KiB
C
179 lines
6.9 KiB
C
#include "coding.h"
|
|
#include "../util.h"
|
|
|
|
/* Various EA ADPCM codecs */
|
|
|
|
static const int32_t EA_XA_TABLE[28] = {
|
|
0,0,240,0,
|
|
460,-208,0x0188,-220,
|
|
0x0000,0x0000,0x00F0,0x0000,
|
|
0x01CC,0x0000,0x0188,0x0000,
|
|
0x0000,0x0000,0x0000,0x0000,
|
|
-208,-1,-220,-1,
|
|
0x0000,0x0000,0x0000,0x3F70
|
|
};
|
|
|
|
static const int32_t EA_TABLE[20]= {
|
|
0x00000000, 0x000000F0, 0x000001CC, 0x00000188,
|
|
0x00000000, 0x00000000, 0xFFFFFF30, 0xFFFFFF24,
|
|
0x00000000, 0x00000001, 0x00000003, 0x00000004,
|
|
0x00000007, 0x00000008, 0x0000000A, 0x0000000B,
|
|
0x00000000, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFC
|
|
};
|
|
|
|
/* EA EAXA, evolved from CDXA */
|
|
void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
|
uint8_t frame_info;
|
|
int32_t sample_count;
|
|
int32_t coef1,coef2;
|
|
int i,shift;
|
|
off_t channel_offset = stream->channel_start_offset; //suboffset within channel
|
|
|
|
first_sample = first_sample%28;
|
|
|
|
/* header */
|
|
frame_info = (uint8_t)read_8bit(stream->offset+channel_offset,stream->streamfile);
|
|
channel_offset++;
|
|
|
|
if (frame_info == 0xEE) { /* PCM frame (used in later revisions), always BE */
|
|
stream->adpcm_history1_32 = read_16bitBE(stream->offset+channel_offset+0x00,stream->streamfile);
|
|
stream->adpcm_history2_32 = read_16bitBE(stream->offset+channel_offset+0x02,stream->streamfile);
|
|
channel_offset += 4;
|
|
|
|
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
|
outbuf[sample_count] = read_16bitBE(stream->offset+channel_offset,stream->streamfile);
|
|
channel_offset+=2;
|
|
}
|
|
|
|
// Only increment offset on complete frame
|
|
if (channel_offset-stream->channel_start_offset == (2*28)+5)
|
|
stream->channel_start_offset += (2*28)+5;
|
|
|
|
} else { /* ADPCM frame */
|
|
coef1 = EA_XA_TABLE[(((frame_info >> 4) & 0x0F) << 1)];
|
|
coef2 = EA_XA_TABLE[(((frame_info >> 4) & 0x0F) << 1) + 1];
|
|
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 = (uint8_t)read_8bit(stream->offset+channel_offset+i/2,stream->streamfile);
|
|
int32_t sample = ((((i&1?
|
|
sample_byte & 0x0F:
|
|
sample_byte >> 4
|
|
) << 0x1C) >> shift) +
|
|
(coef1 * stream->adpcm_history1_32) + (coef2 * stream->adpcm_history2_32)) >> 8;
|
|
|
|
outbuf[sample_count] = clamp16(sample);
|
|
stream->adpcm_history2_32 = stream->adpcm_history1_32;
|
|
stream->adpcm_history1_32 = sample;
|
|
}
|
|
|
|
channel_offset+=i/2;
|
|
|
|
// Only increment offset on complete frame
|
|
if(channel_offset - stream->channel_start_offset == 0x0F)
|
|
stream->channel_start_offset += 0x0F;
|
|
}
|
|
}
|
|
|
|
/* EA MicroTalk 10:1 (aka "EA ADPCM") */
|
|
void decode_ea_mt10(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
|
uint8_t frame_info;
|
|
int32_t sample_count;
|
|
int32_t coef1,coef2;
|
|
int i, shift;
|
|
VGMSTREAMCHANNEL *stream = &(vgmstream->ch[channel]);
|
|
off_t channel_offset=stream->channel_start_offset;
|
|
|
|
vgmstream->get_high_nibble = !vgmstream->get_high_nibble; /* for stereo subinterleave, L=high nibble, R=low nibble */
|
|
|
|
first_sample = first_sample%28;
|
|
|
|
/* header */ //todo mono/interleave decoder
|
|
frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile);
|
|
channel_offset++;
|
|
coef1 = EA_TABLE[(vgmstream->get_high_nibble ? frame_info & 0x0F: frame_info >> 4)];
|
|
coef2 = EA_TABLE[(vgmstream->get_high_nibble ? frame_info & 0x0F: frame_info >> 4) + 4];
|
|
|
|
frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile);
|
|
channel_offset++;
|
|
shift = (vgmstream->get_high_nibble ? frame_info & 0x0F : frame_info >> 4) + 8;
|
|
|
|
|
|
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
|
uint8_t sample_byte;
|
|
int32_t sample;
|
|
|
|
sample_byte = (uint8_t)read_8bit(stream->offset+channel_offset+i,stream->streamfile);
|
|
|
|
sample = ((((vgmstream->get_high_nibble?
|
|
sample_byte & 0x0F:
|
|
sample_byte >> 4
|
|
) << 0x1C) >> shift) +
|
|
(coef1 * stream->adpcm_history1_32) + (coef2 * stream->adpcm_history2_32) + 0x80) >> 8;
|
|
|
|
outbuf[sample_count] = clamp16(sample);
|
|
stream->adpcm_history2_32 = stream->adpcm_history1_32;
|
|
stream->adpcm_history1_32 = sample;
|
|
}
|
|
channel_offset+=i;
|
|
|
|
// Only increment offset on complete frame
|
|
if(channel_offset-stream->channel_start_offset==0x1E)
|
|
stream->channel_start_offset+=0x1E;
|
|
}
|
|
|
|
|
|
/* EA MicroTalk 5:1, unknown variation */
|
|
//void decode_ea_mt5(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel)
|
|
|
|
|
|
/* Maxis EAXA, yet another CDXA variation */
|
|
void decode_maxis_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
|
uint8_t frame_info;
|
|
int32_t sample_count;
|
|
int32_t coef1,coef2;
|
|
int i,shift;
|
|
int frameSize = channelspacing*15;//mono samples have a frame of 15, stereo files have frames of 30
|
|
VGMSTREAMCHANNEL *stream = &(vgmstream->ch[channel]);
|
|
off_t channel_offset=stream->channel_start_offset;
|
|
|
|
first_sample = first_sample%28;
|
|
frame_info = read_8bit(channel_offset,stream->streamfile);
|
|
|
|
coef1 = EA_TABLE[frame_info >> 4];
|
|
coef2 = EA_TABLE[(frame_info >> 4) + 4];
|
|
shift = (frame_info & 0x0F)+8;
|
|
|
|
channel_offset+=channelspacing;
|
|
//stream->offset = first_sample*channelspacing/2;
|
|
|
|
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
|
uint8_t sample_byte;
|
|
int32_t sample;
|
|
|
|
sample_byte = (uint8_t)read_8bit(stream->offset+channel_offset,stream->streamfile);
|
|
|
|
sample = (((((i&1)?
|
|
sample_byte & 0x0F:
|
|
sample_byte >> 4
|
|
) << 0x1C) >> shift) +
|
|
(coef1 * stream->adpcm_history1_32) + (coef2 * stream->adpcm_history2_32) + 0x80) >> 8;
|
|
|
|
outbuf[sample_count] = clamp16(sample);
|
|
stream->adpcm_history2_32 = stream->adpcm_history1_32;
|
|
stream->adpcm_history1_32 = sample;
|
|
|
|
if(i&1)
|
|
stream->offset+=channelspacing;
|
|
}
|
|
|
|
channel_offset+=i;
|
|
|
|
// Only increment offset on complete frame
|
|
|
|
if(channel_offset-stream->channel_start_offset==frameSize) {
|
|
stream->channel_start_offset+=frameSize;
|
|
stream->offset=0;
|
|
}
|
|
}
|