mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 16:30:54 +01:00
Fix EA-MT looping for all cases [SSX3 (PS2)]
This commit is contained in:
parent
37d7fe83c4
commit
c045d41670
@ -166,7 +166,8 @@ void decode_derf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
||||
|
||||
|
||||
/* ea_mt_decoder*/
|
||||
ea_mt_codec_data *init_ea_mt(int channels, int type, int reset_sample);
|
||||
ea_mt_codec_data *init_ea_mt(int channels, int type);
|
||||
ea_mt_codec_data *init_ea_mt_loops(int channels, int pcm_blocks, int loop_sample, off_t *loop_offsets);
|
||||
void decode_ea_mt(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel);
|
||||
void reset_ea_mt(VGMSTREAM * vgmstream);
|
||||
void flush_ea_mt(VGMSTREAM *vgmstream);
|
||||
|
@ -23,10 +23,12 @@ 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 reset_sample;
|
||||
int samples_done;
|
||||
int samples_discard;
|
||||
void* utk_context;
|
||||
@ -34,8 +36,11 @@ struct ea_mt_codec_data {
|
||||
|
||||
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(int channels, int pcm_blocks, int reset_sample) {
|
||||
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;
|
||||
|
||||
@ -48,7 +53,9 @@ ea_mt_codec_data *init_ea_mt(int channels, int pcm_blocks, int reset_sample) {
|
||||
utk_init(data[i].utk_context);
|
||||
|
||||
data[i].pcm_blocks = pcm_blocks;
|
||||
data[i].reset_sample = reset_sample;
|
||||
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);
|
||||
}
|
||||
@ -75,9 +82,9 @@ void decode_ea_mt(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, in
|
||||
int samples_to_get = ch_data->samples_filled;
|
||||
|
||||
/* don't go past loop, to reset decoder */
|
||||
if (ch_data->reset_sample > 0 && ch_data->samples_done < ch_data->reset_sample &&
|
||||
ch_data->samples_done + samples_to_get > ch_data->reset_sample)
|
||||
samples_to_get = ch_data->reset_sample - ch_data->samples_done;
|
||||
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 */
|
||||
@ -106,12 +113,14 @@ void decode_ea_mt(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, in
|
||||
|
||||
/* 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->reset_sample > 0 && ch_data->samples_done == ch_data->reset_sample) {
|
||||
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) */
|
||||
|
||||
//todo when loop start is < 432 decoder seems to have problems
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -146,11 +155,10 @@ static void flush_ea_mt_offsets(VGMSTREAM *vgmstream, int is_start, int samples_
|
||||
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); //todo
|
||||
utk_reset(ctx);
|
||||
ctx->parsed_header = 0;
|
||||
data[i].samples_done = 0;
|
||||
}
|
||||
|
@ -90,6 +90,7 @@ typedef struct {
|
||||
|
||||
off_t offsets[EA_MAX_CHANNELS];
|
||||
off_t coefs[EA_MAX_CHANNELS];
|
||||
off_t loops[EA_MAX_CHANNELS];
|
||||
|
||||
int big_endian;
|
||||
int loop_flag;
|
||||
@ -594,7 +595,7 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
|
||||
}
|
||||
}
|
||||
else if (vgmstream->channels > 1 && ea->codec2 == EA_CODEC2_GCADPCM && ea->offsets[0] == ea->offsets[1]) {
|
||||
/* pcstream+gcadpcm with sx.exe v2, this is probably an bug (even with this parts of the wave are off) */
|
||||
/* pcstream+gcadpcm with sx.exe v2, this is probably a bug (even with this parts of the wave are off) */
|
||||
int interleave = (vgmstream->num_samples / 14 * 8); /* full interleave */
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
ea->offsets[i] = ea->offsets[0] + interleave*i;
|
||||
@ -702,8 +703,15 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
|
||||
use_pcm_blocks = 1;
|
||||
}
|
||||
|
||||
/* make relative loops absolute for the decoder */
|
||||
if (ea->loop_flag) {
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
ea->loops[i] += ea->offsets[0];
|
||||
}
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_EA_MT;
|
||||
vgmstream->codec_data = init_ea_mt(vgmstream->channels, use_pcm_blocks, ea->loop_start);
|
||||
vgmstream->codec_data = init_ea_mt_loops(vgmstream->channels, use_pcm_blocks, ea->loop_start, ea->loops);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
break;
|
||||
}
|
||||
@ -861,6 +869,8 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be
|
||||
uint8_t patch_type = read_8bit(offset,streamFile);
|
||||
offset++;
|
||||
|
||||
//;off_t test_offset = offset;
|
||||
//;VGM_LOG("EA SCHl: patch=%02x at %lx, value=%x\n", patch_type, offset-1, read_patch(streamFile, &test_offset));
|
||||
switch(patch_type) {
|
||||
case 0x00: /* signals non-default block rate and maybe other stuff; or padding after 0xFF */
|
||||
if (!is_header_end)
|
||||
@ -873,7 +883,7 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be
|
||||
case 0x08: /* release envelope (BNK only) */
|
||||
case 0x09: /* related to playback envelope (BNK only) */
|
||||
case 0x0A: /* bend range (BNK only) */
|
||||
case 0x0B: /* unknown (always 0x02) */
|
||||
case 0x0B: /* bank channels (or, offsets[] size; defaults to 1 if not present, removed in sx.exe v3) */
|
||||
case 0x0C: /* pan offset (BNK only) */
|
||||
case 0x0D: /* random pan offset range (BNK only) */
|
||||
case 0x0E: /* volume (BNK only) */
|
||||
@ -885,19 +895,17 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be
|
||||
case 0x14: /* emdedded user data (free size/value) */
|
||||
case 0x15: /* unknown, rare (BNK only) [Need for Speed: High Stakes (PS1)] */
|
||||
case 0x19: /* related to playback envelope (BNK only) */
|
||||
case 0x1A: /* unknown and very rare (BNK only) [SSX 3 (PS2)] */
|
||||
case 0x1B: /* unknown (movie only?) */
|
||||
case 0x1C: /* initial envelope volume (BNK only) */
|
||||
case 0x1D: /* unknown, rare [NASCAR 06 (Xbox)] */
|
||||
case 0x1E:
|
||||
case 0x1E: /* related to ch1? (BNK only) */
|
||||
case 0x1F:
|
||||
case 0x20:
|
||||
case 0x21:
|
||||
case 0x21: /* related to ch2? (BNK only) */
|
||||
case 0x22:
|
||||
case 0x23:
|
||||
case 0x24: /* master random detune range (BNK only) */
|
||||
case 0x25: /* unknown */
|
||||
case 0x26: /* unknown, rare [FIFA 07 (Xbox)] */
|
||||
read_patch(streamFile, &offset);
|
||||
break;
|
||||
|
||||
@ -933,7 +941,7 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be
|
||||
ea->loop_start = read_patch(streamFile, &offset);
|
||||
break;
|
||||
case 0x87: /* loop end sample */
|
||||
ea->loop_end = read_patch(streamFile, &offset);
|
||||
ea->loop_end = read_patch(streamFile, &offset) + 1; /* sx.exe does +1 */
|
||||
break;
|
||||
|
||||
/* channel offsets (BNK only), can be the equal for all channels or interleaved; not necessarily contiguous */
|
||||
@ -981,6 +989,25 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be
|
||||
read_patch(streamFile, &offset);
|
||||
break;
|
||||
|
||||
case 0x1A: /* EA-MT/EA-XA relative loop offset of ch1 */
|
||||
ea->loops[0] = read_patch(streamFile, &offset);
|
||||
break;
|
||||
case 0x26: /* EA-MT/EA-XA relative loop offset of ch2 */
|
||||
ea->loops[1] = read_patch(streamFile, &offset);
|
||||
break;
|
||||
case 0x27: /* EA-MT/EA-XA relative loop offset of ch3 */
|
||||
ea->loops[2] = read_patch(streamFile, &offset);
|
||||
break;
|
||||
case 0x28: /* EA-MT/EA-XA relative loop offset of ch4 */
|
||||
ea->loops[3] = read_patch(streamFile, &offset);
|
||||
break;
|
||||
case 0x29: /* EA-MT/EA-XA relative loop offset of ch5 */
|
||||
ea->loops[4] = read_patch(streamFile, &offset);
|
||||
break;
|
||||
case 0x2a: /* EA-MT/EA-XA relative loop offset of ch6 */
|
||||
ea->loops[5] = read_patch(streamFile, &offset);
|
||||
break;
|
||||
|
||||
case 0x8A: /* long padding (always 0x00000000) */
|
||||
case 0x8B: /* also padding? [Need for Speed: Hot Pursuit 2 (PC)] */
|
||||
case 0x8C: /* flags (ex. play type = 01=static/02=dynamic | spatialize = 20=pan/etc) */
|
||||
|
@ -86,7 +86,7 @@ VGMSTREAM * init_vgmstream_flx(STREAMFILE *streamFile) {
|
||||
case 0x02: /* EA-MT (voices) */
|
||||
vgmstream->coding_type = coding_EA_MT;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->codec_data = init_ea_mt(vgmstream->channels, 0, 0);
|
||||
vgmstream->codec_data = init_ea_mt(vgmstream->channels, 0);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
|
||||
vgmstream->num_samples = read_32bitLE(start_offset,streamFile);
|
||||
|
@ -34,7 +34,7 @@ VGMSTREAM * init_vgmstream_utk(STREAMFILE *streamFile) {
|
||||
vgmstream->num_samples = read_32bitLE(0x04, streamFile) / 2; /* PCM size */
|
||||
vgmstream->coding_type = coding_EA_MT;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->codec_data = init_ea_mt(vgmstream->channels, 0, 0);
|
||||
vgmstream->codec_data = init_ea_mt(vgmstream->channels, 0);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
|
Loading…
Reference in New Issue
Block a user