Add EA SCHl Saturn + MT10 mono/int; changed Maxis_ADPCM to Maxis_MT10

Also fixed some issues with ADPCM hist in EA SCHl blocks
This commit is contained in:
bnnm 2017-07-08 00:27:36 +02:00
parent a493a8f09d
commit cce72d7aa5
9 changed files with 326 additions and 261 deletions

View File

@ -283,6 +283,7 @@ DECLARE_MULTIPLE_FILE_TYPE("SVS Audio File (*.SVS)", svs);
DECLARE_MULTIPLE_FILE_TYPE("SWAG Audio File (*.SWAG)", swag);
DECLARE_MULTIPLE_FILE_TYPE("SWAV Audio File (*.SWAV)", swav);
DECLARE_MULTIPLE_FILE_TYPE("SWD Audio File (*.SWD)", swd);
DECLARE_MULTIPLE_FILE_TYPE("SX Audio File (*.SX)", sx);
DECLARE_MULTIPLE_FILE_TYPE("SXD Audio File (*.SXD)", sxd);
DECLARE_MULTIPLE_FILE_TYPE("SXD2 Audio File (*.SXD2)", sxd2);

View File

@ -75,8 +75,9 @@ void init_get_high_nibble(VGMSTREAM * vgmstream);
/* ea_decoder */
void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_ea_mt10(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_maxis_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_ea_mt10(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_ea_mt10_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_maxis_mt10(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
/* sdx2_decoder */
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);

View File

@ -1,7 +1,7 @@
#include "coding.h"
#include "../util.h"
/* Various EA ADPCM codecs */
/* Various EA ADPCM codecs evolved from CDXA */
static const int32_t EA_XA_TABLE[28] = {
0,0,240,0,
@ -13,21 +13,21 @@ static const int32_t EA_XA_TABLE[28] = {
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
static const int EA_TABLE[20] = {
0, 240, 460, 392,
0, 0, -208, -220,
0, 1, 3, 4,
7, 8, 10, 11,
0, -1, -3, -4
};
/* EA EAXA, evolved from CDXA */
/* EA's main ADPCM, inconsistently called EAXA or EA-XA */
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
int32_t coef1, coef2;
int i, shift;
off_t channel_offset = stream->channel_start_offset; /* suboffset within frame */
first_sample = first_sample%28;
@ -45,7 +45,7 @@ void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing
channel_offset+=2;
}
// Only increment offset on complete frame
/* Only increment offset on complete frame */
if (channel_offset-stream->channel_start_offset == (2*28)+5)
stream->channel_start_offset += (2*28)+5;
@ -66,98 +66,125 @@ void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing
stream->adpcm_history2_32 = stream->adpcm_history1_32;
stream->adpcm_history1_32 = sample;
}
channel_offset += i/2;
channel_offset+=i/2;
// Only increment offset on complete frame
if(channel_offset - stream->channel_start_offset == 0x0F)
/* 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) {
/* EA MicroTalk 10:1 stereo (aka "EA ADPCM") */
void decode_ea_mt10(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;
VGMSTREAMCHANNEL *stream = &(vgmstream->ch[channel]);
off_t channel_offset=stream->channel_start_offset;
int32_t coef1, coef2;
int i, sample_count, shift;
off_t channel_offset = stream->channel_start_offset; /* suboffset within frame */
int hn = (channel==0); /* high nibble marker for stereo subinterleave, ch0/L=high nibble, ch1/R=low nibble */
vgmstream->get_high_nibble = !vgmstream->get_high_nibble; /* for stereo subinterleave, L=high nibble, R=low nibble */
first_sample = first_sample % 28;
first_sample = first_sample%28;
/* header */ //todo mono/interleave decoder
/* header (coefs ch0+ch1 + shift ch0+ch1) */
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];
coef1 = EA_TABLE[(hn ? frame_info >> 4 : frame_info & 0x0F) + 0];
coef2 = EA_TABLE[(hn ? frame_info >> 4 : frame_info & 0x0F) + 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;
shift = (hn ? frame_info >> 4 : 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;
uint8_t sample_byte, sample_nibble;
int32_t sample;
off_t byte_offset = (stream->offset + channel_offset + i);
sample_byte = (uint8_t)read_8bit(stream->offset+channel_offset+i,stream->streamfile);
sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile);
sample_nibble = (hn ? sample_byte >> 4 : sample_byte & 0x0F);
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;
sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */
sample = (sample + 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;
channel_offset += i;
// Only increment offset on complete frame
if(channel_offset-stream->channel_start_offset==0x1E)
stream->channel_start_offset+=0x1E;
/* Only increment offset on complete frame */
if(channel_offset - stream->channel_start_offset == 0x1E)
stream->channel_start_offset += 0x1E;
}
/* EA MicroTalk 10:1 mono/interleave */
void decode_ea_mt10_int(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;
off_t channel_offset = stream->channel_start_offset; /* suboffset within frame */
/* EA MicroTalk 5:1, unknown variation */
first_sample = first_sample % 28;
/* header (coefs+shift ch0) */
frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile);
channel_offset++;
coef1 = EA_TABLE[(frame_info >> 4) + 0];
coef2 = EA_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 sample;
off_t byte_offset = (stream->offset + channel_offset + i/2);
sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile);
sample_nibble = (!(i%2) ? sample_byte >> 4 : sample_byte & 0x0F); /* i=even > high nibble */
sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */
sample = (sample + 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/2;
/* Only increment offset on complete frame */
if(channel_offset - stream->channel_start_offset == 0x0F)
stream->channel_start_offset += 0x0F;
}
/* EA MicroTalk 5:1, unknown variation with optional PCM blocks */
//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) {
/* Maxis MicroTalk 10:1 (mono+stereo), differing slightly in the header layout in stereo mode */
void decode_maxis_mt10(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;
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;
int32_t coef1, coef2;
int i, sample_count, shift;
off_t channel_offset = stream->channel_start_offset;
int frameSize = channelspacing*15; /* mono samples have a frame of 15, stereo files have frames of 30 */
first_sample = first_sample%28;
frame_info = read_8bit(channel_offset,stream->streamfile);
/* header (coefs+shift ch0 + coefs+shift ch1) */
frame_info = read_8bit(channel_offset,stream->streamfile);
channel_offset += channelspacing;
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;
/* samples */
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t sample_byte;
uint8_t sample_byte, sample_nibble;
int32_t sample;
off_t byte_offset = (stream->offset + channel_offset);
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;
sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile);
sample_nibble = (i&1) ? sample_byte & 0x0F : sample_byte >> 4;
sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */
sample = (sample + 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;
@ -166,13 +193,11 @@ void decode_maxis_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspaci
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;
/* Only increment offset on complete frame */
if (channel_offset - stream->channel_start_offset == frameSize) {
stream->channel_start_offset += frameSize;
stream->offset=0;
}
}

View File

@ -275,6 +275,7 @@ static const char* extension_list[] = {
"swag",
"swav",
"swd",
"sx",
"sxd",
"sxd2",
@ -421,6 +422,8 @@ static const coding_info coding_info_list[] = {
{coding_XBOX_int, "XBOX 4-bit IMA ADPCM (interleaved)"},
{coding_EA_XA, "Electronic Arts EA-XA 4-bit ADPCM"},
{coding_EA_MT10, "Electronic Arts MicroTalk (10:1) 4-bit ADPCM"},
{coding_EA_MT10_int, "Electronic Arts MicroTalk (10:1) 4-bit ADPCM (interleaved)"},
{coding_MAXIS_MT10, "Maxis MicroTalk (10:1) 4-bit ADPCM"},
{coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"},
{coding_SDX2_int, "Squareroot-delta-exact (SDX2) 8-bit DPCM with 1 byte interleave"},
{coding_CBD2, "Cuberoot-delta-exact (CBD2) 8-bit DPCM"},
@ -428,7 +431,6 @@ static const coding_info coding_info_list[] = {
{coding_DVI_IMA, "Intel DVI 4-bit IMA ADPCM"},
{coding_DVI_IMA_int, "Intel DVI 4-bit IMA ADPCM (interleaved)"},
{coding_EACS_IMA, "EACS 4-bit IMA ADPCM"},
{coding_MAXIS_ADPCM, "Maxis XA ADPCM"},
{coding_IMA_int, "IMA 4-bit ADPCM (interleaved)"},
{coding_IMA, "IMA 4-bit ADPCM"},
{coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"},

View File

@ -1,164 +1,183 @@
#include "layout.h"
#include "../coding/coding.h"
#include "../vgmstream.h"
/* set up for the block at the given offset */
void ea_schl_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
uint32_t id;
size_t file_size, block_size = 0, block_samples;
int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE;
init_get_high_nibble(vgmstream); /* swap nibble for codecs with stereo subinterleave */
/* find target block ID and skip the rest */
file_size = get_streamfile_size(streamFile);
while (block_offset < file_size) {
id = read_32bitBE(block_offset+0x00,streamFile);
block_size = read_32bitLE(block_offset+0x04,streamFile);
if (block_size > 0xF0000000) /* size size is always LE, except in early MAC apparently */
block_size = read_32bitBE(block_offset+0x04,streamFile);
if (id == 0x5343446C) /* "SCDl" data block found */
break;
block_offset += block_size; /* size includes header */
/* Some EA files concat many small subfiles, for mapped music (.map/lin), so after SCEl
* there may be a new SCHl. We'll find it and pretend they are a single stream. */
if (id == 0x5343456C && block_offset + 0x80 > file_size)
return;
if (id == 0x5343456C) { /* "SCEl" end block found */
/* Usually there is padding between SCEl and SCHl (aligned to 0x80) */
block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* also 32b-aligned */
for (i = 0; i < 0x80 / 4; i++) {
id = read_32bitBE(block_offset,streamFile);
if (id == 0x5343486C) /* "SCHl" new header block found */
break; /* next loop will parse and skip it */
block_offset += 0x04;
}
}
if (block_offset > file_size)
return;
if (id == 0 || id == 0xFFFFFFFF)
return; /* probably hit padding or EOF */
}
if (block_offset > file_size)
return;
/* use num_samples from header if possible; don't calc as rarely data may have padding (ex. PCM8) or not possible (ex. MP3) */
switch(vgmstream->coding_type) {
case coding_PSX:
block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels);
break;
default:
block_samples = read_32bit(block_offset+0x08,streamFile);
break;
}
/* set new channel offsets */
switch(vgmstream->coding_type) {
case coding_PSX:
for (i = 0; i < vgmstream->channels; i++) {
size_t interleave = ((block_size-0x10)/vgmstream->channels) * i;
vgmstream->ch[i].offset = block_offset + 0x10 + interleave;
}
/* at 0x08/0x0c: unknown */
break;
default:
for (i = 0; i < vgmstream->channels; i++) {
off_t channel_start;
if (vgmstream->coding_type == coding_EA_MT10 && vgmstream->codec_version == 0)
channel_start = 0; /* MT10 R1 (codec1 v0) uses stereo, R2 (codec2 v1+) interleaved mono */
else
channel_start = read_32bit(block_offset+0x0C+(0x04*i),streamFile);
vgmstream->ch[i].offset = block_offset + 0x0C+(0x04*vgmstream->channels) + channel_start;
}
break;
}
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset + block_size;
vgmstream->current_block_size = 0;
vgmstream->current_block_samples = block_samples;
/* read ADPCM history (there is a small diff vs decoded hist) */
if (vgmstream->coding_type == coding_NGC_DSP
|| (vgmstream->coding_type == coding_EA_XA && vgmstream->codec_version == 0)
) {
//int16_t (*read_16bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_16bitBE : read_16bitLE;
for (i = 0; i < vgmstream->channels; i++) {
/* makes the output glitchy in rare cases (Harry Potter and the Chamber of Secrets (Xbox)) */
//vgmstream->ch[i].adpcm_history2_32 = read_16bit(vgmstream->ch[i].offset+0x00,streamFile);
//vgmstream->ch[i].adpcm_history1_32 = read_16bit(vgmstream->ch[i].offset+0x02,streamFile);
vgmstream->ch[i].offset += 4;
}
}
/* reset channel sub offset */
if (vgmstream->coding_type == coding_EA_MT10 || vgmstream->coding_type == coding_EA_XA) {
for(i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].channel_start_offset=0;
}
}
}
void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
off_t block_size=vgmstream->current_block_size;
if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) {
block_offset+=0x0C;
}
vgmstream->current_block_offset = block_offset;
if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E64) { /* 1Snd */
block_offset+=4;
if(vgmstream->ea_platform==0)
block_size=read_32bitLE(vgmstream->current_block_offset+0x04,
vgmstream->ch[0].streamfile);
else
block_size=read_32bitBE(vgmstream->current_block_offset+0x04,
vgmstream->ch[0].streamfile);
block_offset+=4;
}
vgmstream->current_block_size=block_size-8;
if(vgmstream->coding_type==coding_EACS_IMA) {
init_get_high_nibble(vgmstream);
vgmstream->current_block_size=read_32bitLE(block_offset,vgmstream->ch[0].streamfile);
for(i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset+0x04+i*4,vgmstream->ch[0].streamfile);
vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset+0x04+i*4+(4*vgmstream->channels),vgmstream->ch[0].streamfile);
vgmstream->ch[i].offset = block_offset+0x14;
}
} else {
if(vgmstream->coding_type==coding_PSX) {
for (i=0;i<vgmstream->channels;i++)
vgmstream->ch[i].offset = vgmstream->current_block_offset+8+(i*(vgmstream->current_block_size/2));
} else {
for (i=0;i<vgmstream->channels;i++) {
if(vgmstream->coding_type==coding_PCM16LE_int)
vgmstream->ch[i].offset = block_offset+(i*2);
else
vgmstream->ch[i].offset = block_offset+i;
}
}
vgmstream->current_block_size/=vgmstream->channels;
}
vgmstream->next_block_offset = vgmstream->current_block_offset +
(off_t)block_size;
}
#include "layout.h"
#include "../coding/coding.h"
#include "../vgmstream.h"
/* set up for the block at the given offset */
void ea_schl_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
uint32_t id;
size_t file_size, block_size = 0, block_samples;
int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE;
int16_t (*read_16bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_16bitBE : read_16bitLE;
/* find target block ID and skip the rest */
file_size = get_streamfile_size(streamFile);
while (block_offset < file_size) {
id = read_32bitBE(block_offset+0x00,streamFile);
block_size = read_32bitLE(block_offset+0x04,streamFile);
if (block_size > 0x00F00000) /* size size is always LE, except in early SS/MAC */
block_size = read_32bitBE(block_offset+0x04,streamFile);
if (id == 0x5343446C) /* "SCDl" data block found */
break;
block_offset += block_size; /* size includes header */
/* Some EA files concat many small subfiles, for mapped music (.map/lin), so after SCEl
* there may be a new SCHl. We'll find it and pretend they are a single stream. */
if (id == 0x5343456C && block_offset + 0x80 > file_size)
return;
if (id == 0x5343456C) { /* "SCEl" end block found */
/* Usually there is padding between SCEl and SCHl (aligned to 0x80) */
block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* also 32b-aligned */
for (i = 0; i < 0x80 / 4; i++) {
id = read_32bitBE(block_offset,streamFile);
if (id == 0x5343486C) /* "SCHl" new header block found */
break; /* next loop will parse and skip it */
block_offset += 0x04;
}
}
if (block_offset > file_size)
return;
if (id == 0 || id == 0xFFFFFFFF)
return; /* probably hit padding or EOF */
}
if (block_offset > file_size)
return;
/* use num_samples from header if possible; don't calc as rarely data may have padding (ex. PCM8) or not possible (ex. MP3) */
switch(vgmstream->coding_type) {
case coding_PSX:
block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels);
break;
default:
block_samples = read_32bit(block_offset+0x08,streamFile);
break;
}
/* set new channel offsets and ADPCM history */
/* ADPCM hist could be considered part of the stream/decoder (some EAXA decoders call it "EAXA R1" when it has hist), and BNKs
* (with no blocks) also have them in the first offset. To simplify and since DSP also have them, we read them here instead. */
switch(vgmstream->coding_type) {
/* id, size, unk1, unk2, interleaved data */
case coding_PSX:
for (i = 0; i < vgmstream->channels; i++) {
size_t interleave = (block_size-0x10) / vgmstream->channels;
vgmstream->ch[i].offset = block_offset + 0x10 + i*interleave;
}
/* 0x08/0x0c: unknown (doesn't look like hist or offsets, as 1ch files has them too) */
break;
/* id, size, samples, hists-per-channel, stereo/interleaved data */
case coding_EA_MT10:
case coding_EA_MT10_int:
for (i = 0; i < vgmstream->channels; i++) {
int is_interleaved = vgmstream->coding_type == coding_EA_MT10_int;
size_t interleave;
/* read ADPCM history from all channels before data */
vgmstream->ch[i].adpcm_history1_32 = read_16bit(block_offset + 0x0C + (i*0x04) + 0x00,streamFile);
vgmstream->ch[i].adpcm_history2_32 = read_16bit(block_offset + 0x0C + (i*0x04) + 0x02,streamFile);
/* the block can have padding so find the channel size from num_samples */
interleave = is_interleaved ? (block_samples / 28 * 0x0f) : 0;
vgmstream->ch[i].offset = block_offset + 0x0c + vgmstream->channels*0x04 + i*interleave;
}
break;
/* id, size, samples, offsets-per-channel, interleaved data (w/ optional hist per channel) */
default:
for (i = 0; i < vgmstream->channels; i++) {
off_t channel_start = read_32bit(block_offset + 0x0C + (0x04*i),streamFile);
vgmstream->ch[i].offset = block_offset + 0x0C + (0x04*vgmstream->channels) + channel_start;
}
/* read ADPCM history before each channel if needed (there is a small diff vs decoded hist) */
if ((vgmstream->coding_type == coding_NGC_DSP) ||
(vgmstream->coding_type == coding_EA_XA && vgmstream->codec_version == 0)) {
for (i = 0; i < vgmstream->channels; i++) {
vgmstream->ch[i].adpcm_history1_32 = read_16bit(vgmstream->ch[i].offset+0x00,streamFile);
vgmstream->ch[i].adpcm_history3_32 = read_16bit(vgmstream->ch[i].offset+0x02,streamFile);
vgmstream->ch[i].offset += 4;
}
}
break;
}
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset + block_size;
vgmstream->current_block_samples = block_samples;
vgmstream->current_block_size = 0; /* uses current_block_samples instead */
/* reset channel sub offset for codecs using it */
if (vgmstream->coding_type == coding_EA_MT10
|| vgmstream->coding_type == coding_EA_MT10_int
|| vgmstream->coding_type == coding_EA_XA) {
for(i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].channel_start_offset=0;
}
}
}
void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
off_t block_size=vgmstream->current_block_size;
if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) {
block_offset+=0x0C;
}
vgmstream->current_block_offset = block_offset;
if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E64) { /* 1Snd */
block_offset+=4;
if(vgmstream->ea_platform==0)
block_size=read_32bitLE(vgmstream->current_block_offset+0x04,
vgmstream->ch[0].streamfile);
else
block_size=read_32bitBE(vgmstream->current_block_offset+0x04,
vgmstream->ch[0].streamfile);
block_offset+=4;
}
vgmstream->current_block_size=block_size-8;
if(vgmstream->coding_type==coding_EACS_IMA) {
init_get_high_nibble(vgmstream); /* swap nibble marker for codecs with stereo subinterleave */
vgmstream->current_block_size=read_32bitLE(block_offset,vgmstream->ch[0].streamfile);
for(i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset+0x04+i*4,vgmstream->ch[0].streamfile);
vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset+0x04+i*4+(4*vgmstream->channels),vgmstream->ch[0].streamfile);
vgmstream->ch[i].offset = block_offset+0x14;
}
} else {
if(vgmstream->coding_type==coding_PSX) {
for (i=0;i<vgmstream->channels;i++)
vgmstream->ch[i].offset = vgmstream->current_block_offset+8+(i*(vgmstream->current_block_size/2));
} else {
for (i=0;i<vgmstream->channels;i++) {
if(vgmstream->coding_type==coding_PCM16LE_int)
vgmstream->ch[i].offset = block_offset+(i*2);
else
vgmstream->ch[i].offset = block_offset+i;
}
}
vgmstream->current_block_size/=vgmstream->channels;
}
vgmstream->next_block_offset = vgmstream->current_block_offset +
(off_t)block_size;
}

View File

@ -15,7 +15,7 @@
#define EA_PLATFORM_PSX 0x01
#define EA_PLATFORM_N64 0x02
#define EA_PLATFORM_MAC 0x03
//#define EA_PLATFORM_SAT 0x04 // ?
#define EA_PLATFORM_SAT 0x04
#define EA_PLATFORM_PS2 0x05
#define EA_PLATFORM_GC_WII 0x06 // reused later for Wii
#define EA_PLATFORM_XBOX 0x07
@ -26,9 +26,9 @@
/* codec constants (undefined are probably reserved, ie.- sx.exe encodes PCM24/DVI but no platform decodes them) */
/* CODEC1 values were used early, then they migrated to CODEC2 values */
#define EA_CODEC1_NONE -1
//#define EA_CODEC1_S16BE 0x00 //LE too?
//#define EA_CODEC1_S16BE 0x00 //LE too?
//#define EA_CODEC1_VAG 0x01
#define EA_CODEC1_MT10 0x07 // Need for Speed 2 PC
#define EA_CODEC1_MT10 0x07 // Need for Speed 2 PC, Fifa 98 SAT
//#define EA_CODEC1_N64 ?
#define EA_CODEC2_NONE -1
@ -84,7 +84,7 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) {
/* check extension; exts don't seem enforced by EA's tools, but usually:
* STR/ASF/MUS ~early, EAM ~mid, SNG/AUD ~late, rest uncommon/one game (ex. STRM: MySims Kingdom Wii) */
if (!check_extensions(streamFile,"str,asf,mus,eam,sng,aud,strm,xa,xsf,exa,stm"))
if (!check_extensions(streamFile,"str,asf,mus,eam,sng,aud,sx,strm,xa,xsf,exa,stm"))
goto fail;
/* check header */
@ -95,7 +95,7 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) {
goto fail;
header_size = read_32bitLE(0x04,streamFile);
if (header_size > 0xF0000000) /* size is always LE, except in early MAC apparently */
if (header_size > 0x00F00000) /* size is always LE, except in early SS/MAC */
header_size = read_32bitBE(0x04,streamFile);
memset(&ea,0,sizeof(ea_header));
@ -132,7 +132,10 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) {
break;
case EA_CODEC2_MT10: /* MicroTalk (10:1), aka EA ADPCM (stereo or interleaved) */
vgmstream->coding_type = coding_EA_MT10;
if (ea.codec_version==1 || ea.channels == 1)
vgmstream->coding_type = coding_EA_MT10_int;
else
vgmstream->coding_type = coding_EA_MT10;
break;
case EA_CODEC2_S8: /* PCM8 */
@ -211,7 +214,6 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) {
ea_schl_block_update(start_offset,vgmstream);
return vgmstream;
fail:
@ -395,6 +397,7 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
case 0xFF: /* header end (then 0-padded) */
is_header_end = 1;
/* offset always 32 padded (ex SHOW.eam) */
break;
default:
@ -403,7 +406,8 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
}
}
if (ea->id && ea->id != 0x65) /* very rarely not specified (FIFA 14) */
/* always 0x65 for non-BNK streams, rarely not specified (FIFA 14, some BNKs) */
if (ea->id && ea->id != 0x65)
goto fail;
if (ea->channels > EA_MAX_CHANNELS)
goto fail;
@ -426,6 +430,7 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
case EA_PLATFORM_PSX: ea->version = EA_VERSION_V0; break; // assumed
case EA_PLATFORM_N64: ea->version = EA_VERSION_V0; break; // assumed
case EA_PLATFORM_MAC: ea->version = EA_VERSION_V0; break;
case EA_PLATFORM_SAT: ea->version = EA_VERSION_V0; break;
case EA_PLATFORM_PS2: ea->version = EA_VERSION_V1; break;
case EA_PLATFORM_GC_WII: ea->version = EA_VERSION_V2; break;
case EA_PLATFORM_XBOX: ea->version = EA_VERSION_V2; break;
@ -475,6 +480,7 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
case EA_PLATFORM_PSX: ea->sample_rate = 22050; break;
case EA_PLATFORM_N64: ea->sample_rate = 22050; break;
case EA_PLATFORM_MAC: ea->sample_rate = 22050; break;
case EA_PLATFORM_SAT: ea->sample_rate = 22050; break;
case EA_PLATFORM_PS2: ea->sample_rate = 22050; break;
case EA_PLATFORM_GC_WII: ea->sample_rate = 24000; break;
case EA_PLATFORM_XBOX: ea->sample_rate = 24000; break;
@ -490,6 +496,7 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
/* affects blocks/codecs */
if (ea->platform == EA_PLATFORM_N64
|| ea->platform == EA_PLATFORM_MAC
|| ea->platform == EA_PLATFORM_SAT
|| ea->platform == EA_PLATFORM_GC_WII
|| ea->platform == EA_PLATFORM_X360
|| ea->platform == EA_PLATFORM_GENERIC) {
@ -498,8 +505,9 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
/* config MT/EAXA variations */
if (ea->codec2 == EA_CODEC2_MT10) {
if (ea->version > EA_VERSION_V0)
ea->codec_version = 1; /* 0=stereo (early), 1:interleaved */
if (ea->version > EA_VERSION_V0 ||
(ea->platform == EA_PLATFORM_SAT && ea->version == EA_VERSION_V0))
ea->codec_version = 1; /* 0=stereo (early), 1=interleaved */
}
else if (ea->codec2 == EA_CODEC2_EAXA) {
/* console EAXA V2 uses hist, as does PC/MAC V1 */
@ -530,8 +538,7 @@ static int get_ea_total_samples(STREAMFILE* streamFile, off_t start_offset, cons
id = read_32bitBE(block_offset+0x00,streamFile);
block_size = read_32bitLE(block_offset+0x04,streamFile);
VGM_ASSERT(block_size > 0xF0000000, "EA: BE block size in MAC\n");
if (block_size > 0xF0000000) /* size is always LE, except in early MAC apparently */
if (block_size > 0x00F00000) /* size is always LE, except in early SS/MAC */
block_size = read_32bitBE(block_offset+0x04,streamFile);
if (id == 0x5343446C) { /* "SCDl" data block found */
@ -589,7 +596,7 @@ static off_t get_ea_mpeg_start_offset(STREAMFILE* streamFile, off_t start_offset
id = read_32bitBE(block_offset+0x00,streamFile);
block_size = read_32bitLE(block_offset+0x04,streamFile);
if (block_size > 0xF0000000) /* size is always LE, except in early MAC apparently */
if (block_size > 0x00F00000) /* size is always LE, except in early SS/MAC */
block_size = read_32bitBE(block_offset+0x04,streamFile);
if (id == 0x5343446C) { /* "SCDl" data block found */

View File

@ -29,7 +29,7 @@ VGMSTREAM * init_vgmstream_maxis_xa(STREAMFILE *streamFile) {
start_offset = 0x18;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x0C,streamFile);
vgmstream->coding_type = coding_MAXIS_ADPCM;
vgmstream->coding_type = coding_MAXIS_MT10;
vgmstream->num_samples = read_32bitLE(0x04,streamFile)/2/channel_count;
if (loop_flag) {
@ -37,7 +37,6 @@ VGMSTREAM * init_vgmstream_maxis_xa(STREAMFILE *streamFile) {
vgmstream->loop_end_sample = (read_32bitBE(0x0C,streamFile)-start_offset)/8/channel_count*14;
}
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_MAXIS_XA;

View File

@ -1044,10 +1044,11 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_XBOX_int:
case coding_FSB_IMA:
return 64;
case coding_EA_MT10:
case coding_EA_MT10_int:
case coding_EA_XA:
return 28;
case coding_MAXIS_ADPCM:
case coding_EA_MT10:
case coding_MAXIS_MT10:
return 14*vgmstream->channels;
case coding_WS:
/* only works if output sample size is 8 bit, which always is for WS ADPCM */
@ -1189,10 +1190,12 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_XBOX_int:
case coding_FSB_IMA:
return 36;
case coding_MAXIS_ADPCM:
return 15*vgmstream->channels;
case coding_EA_MT10:
return 30;
return 0x1E;
case coding_EA_MT10_int:
return 0x0F;
case coding_MAXIS_MT10:
return 0x0F*vgmstream->channels;
case coding_EA_XA:
return 1; // the frame is variant in size
case coding_WS:
@ -1492,14 +1495,21 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
break;
case coding_EA_MT10:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_ea_mt10(vgmstream,buffer+samples_written*vgmstream->channels+chan,
decode_ea_mt10(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do,chan);
}
break;
case coding_MAXIS_ADPCM:
case coding_EA_MT10_int:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_maxis_adpcm(vgmstream,buffer+samples_written*vgmstream->channels+chan,
decode_ea_mt10_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do,chan);
}
break;
case coding_MAXIS_MT10:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_maxis_mt10(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do,chan);
}

View File

@ -105,9 +105,10 @@ typedef enum {
coding_PSX_cfg, /* Sony PS ADPCM with configurable frame size (FF XI, SGXD type 5, Bizarre Creations) */
coding_HEVAG, /* Sony PSVita ADPCM */
coding_EA_MT10, /* Electronic Arts MicroTalk (10:1) ADPCM ('EA ADPCM')*/
coding_EA_MT10, /* Electronic Arts MicroTalk (10:1) ADPCM (stereo) aka EA ADPCM */
coding_EA_MT10_int, /* Electronic Arts MicroTalk (10:1) ADPCM (mono/interleave) */
coding_MAXIS_MT10, /* Maxis MicroTalk (10:1) ADPCM */
coding_EA_XA, /* Electronic Arts EA-XA ADPCM */
coding_MAXIS_ADPCM, /* Maxis ADPCM */
coding_XBOX, /* XBOX IMA ADPCM */
coding_XBOX_int, /* XBOX IMA ADPCM (interleaved) */