Redo EA-XMA with custom IO for fixes [Skate (X360), NFS: MW (X360)]

This commit is contained in:
bnnm 2018-08-25 12:48:55 +02:00
parent d8758f0cb5
commit e3255344cf
2 changed files with 82 additions and 36 deletions

View File

@ -483,6 +483,7 @@ typedef struct {
} eaac_header;
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *streamData, eaac_header *eaac);
static layered_layout_data* build_layered_eaaudiocore_eaxma(STREAMFILE *streamFile, eaac_header *eaac);
/* EA newest header from RwAudioCore (RenderWare?) / EAAudioCore library (still generated by sx.exe).
@ -508,7 +509,6 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
/* rest is optional, depends on used flags and codec (handled below) */
eaac.stream_offset = start_offset;
/* V0: SNR+SNS, V1: SPR+SPS (no apparent differences, other than block flags) */
if (eaac.version != EAAC_VERSION_V0 && eaac.version != EAAC_VERSION_V1) {
VGM_LOG("EA EAAC: unknown version\n");
@ -586,28 +586,10 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
#ifdef VGM_USE_FFMPEG
case EAAC_CODEC_EAXMA: { /* "EXm0": EA-XMA [Dante's Inferno (X360)] */
uint8_t buf[0x100];
int bytes, block_size, block_count;
size_t stream_size, virtual_size;
ffmpeg_custom_config cfg = {0};
stream_size = get_streamfile_size(streamData) - eaac.stream_offset; //todo not correct for banks
virtual_size = ffmpeg_get_eaxma_virtual_size(vgmstream->channels, eaac.streamed, eaac.stream_offset,stream_size, streamData);
block_size = 0x10000; /* todo unused and not correctly done by the parser */
block_count = stream_size / block_size + (stream_size % block_size ? 1 : 0);
bytes = ffmpeg_make_riff_xma2(buf, 0x100, vgmstream->num_samples, virtual_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
if (bytes <= 0) goto fail;
cfg.type = FFMPEG_EA_XMA;
cfg.virtual_size = virtual_size;
cfg.channels = vgmstream->channels;
vgmstream->codec_data = init_ffmpeg_config(streamData, buf,bytes, eaac.stream_offset,stream_size, &cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_data = build_layered_eaaudiocore_eaxma(streamData, &eaac);
if (!vgmstream->layout_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->layout_type = layout_layered;
break;
}
#endif
@ -783,3 +765,69 @@ fail:
free_layout_segmented(data);
return NULL;
}
static layered_layout_data* build_layered_eaaudiocore_eaxma(STREAMFILE *streamData, eaac_header *eaac) {
layered_layout_data* data = NULL;
STREAMFILE* temp_streamFile = NULL;
int i, layers = (eaac->channels+1) / 2;
/* init layout */
data = init_layout_layered(layers);
if (!data) goto fail;
/* open each layer subfile (1/2ch streams: 2ch+2ch..+1ch or 2ch+2ch..+2ch).
* EA-XMA uses completely separate 1/2ch streams, unlike standard XMA that interleaves 1/2ch streams
* with a skip counter to reinterleave (so EA-XMA streams don't have skips set) */
for (i = 0; i < layers; i++) {
int layer_channels = (i+1 == layers && eaac->channels % 2 == 1) ? 1 : 2; /* last layer can be 1/2ch */
/* build the layer VGMSTREAM */
data->layers[i] = allocate_vgmstream(layer_channels, eaac->loop_flag);
if (!data->layers[i]) goto fail;
data->layers[i]->sample_rate = eaac->sample_rate;
data->layers[i]->num_samples = eaac->num_samples;
data->layers[i]->loop_start_sample = eaac->loop_start;
data->layers[i]->loop_end_sample = eaac->loop_end;
#ifdef VGM_USE_FFMPEG
{
uint8_t buf[0x100];
int bytes, block_size, block_count;
size_t stream_size;
temp_streamFile = setup_eaac_streamfile(streamData, eaac->version, eaac->codec, eaac->streamed,i,layers, eaac->stream_offset);
if (!temp_streamFile) goto fail;
stream_size = get_streamfile_size(temp_streamFile);
block_size = 0x10000; /* unused */
block_count = stream_size / block_size + (stream_size % block_size ? 1 : 0);
bytes = ffmpeg_make_riff_xma2(buf, 0x100, data->layers[i]->num_samples, stream_size, data->layers[i]->channels, data->layers[i]->sample_rate, block_count, block_size);
data->layers[i]->codec_data = init_ffmpeg_header_offset(temp_streamFile, buf,bytes, 0x00, stream_size);
if (!data->layers[i]->codec_data) goto fail;
data->layers[i]->coding_type = coding_FFmpeg;
data->layers[i]->layout_type = layout_none;
}
#else
goto fail;
#endif
if ( !vgmstream_open_stream(data->layers[i], temp_streamFile, 0x00) ) {
goto fail;
}
}
/* setup layered VGMSTREAMs */
if (!setup_layout_layered(data))
goto fail;
close_streamfile(temp_streamFile);
return data;
fail:
close_streamfile(temp_streamFile);
free_layout_layered(data);
return NULL;
}

View File

@ -66,13 +66,12 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
}
switch(data->codec) {
#if 0
case 0x03: { /* EA-XMA */
/* block format: 0x04=num-samples, (size*4 + N XMA packets) per stream (with 1/2ch XMA headers) */
int i;
data->skip_size = 0x04 + 0x04;
for (i = 0; i < data->stream_number - 1; i++) {
for (i = 0; i < data->stream_number; i++) {
data->skip_size += read_32bitBE(data->physical_offset+data->skip_size, streamfile) / 4;
}
data->data_size = read_32bitBE(data->physical_offset+data->skip_size, streamfile) / 4; /* why size*4...? */
@ -82,7 +81,7 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
data->extra_size = XMA_FRAME_SIZE - (data->data_size % XMA_FRAME_SIZE);
break;
}
#endif
case 0x05: /* EALayer3 v1 */
case 0x06: /* EALayer3 v2 "PCM" */
case 0x07: /* EALayer3 v2 "Spike" */
@ -121,7 +120,6 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
bytes_consumed = offset - data->logical_offset;
switch(data->codec) {
#if 0
case 0x03: { /* EA-XMA */
if (bytes_consumed < data->data_size) { /* offset falls within actual data */
to_read = data->data_size - bytes_consumed;
@ -138,7 +136,7 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
}
break;
}
#endif
default:
to_read = data->data_size - bytes_consumed;
if (to_read > length)
@ -175,7 +173,7 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
/* get size of the logical stream */
while (physical_offset < max_physical_offset) {
uint32_t block_flag, block_size, data_size, skip_size;
//int i;
int i;
block_flag = (uint8_t)read_8bit(physical_offset+0x00,streamfile);
block_size = read_32bitBE(physical_offset+0x00,streamfile) & 0x00FFFFFF;
@ -193,10 +191,9 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
break; /* unknown block */
switch(data->codec) {
#if 0
case 0x03: /* EA-XMA */
skip_size = 0x04 + 0x04;
for (i = 0; i < data->stream_number - 1; i++) {
for (i = 0; i < data->stream_number; i++) {
skip_size += read_32bitBE(physical_offset + skip_size, streamfile) / 4; /* why size*4...? */
}
data_size = read_32bitBE(physical_offset + skip_size, streamfile) / 4;
@ -205,7 +202,7 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
if (data_size % XMA_FRAME_SIZE)
data_size += XMA_FRAME_SIZE - (data_size % XMA_FRAME_SIZE); /* extra padding */
break;
#endif
case 0x05: /* EALayer3 v1 */
case 0x06: /* EALayer3 v2 "PCM" */
case 0x07: /* EALayer3 v2 "Spike" */
@ -239,6 +236,12 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
break; /* stop on last block */
}
/* logical size can be bigger in EA-XMA though */
if (physical_offset > get_streamfile_size(streamfile)) {
VGM_LOG("EA EAAC: wrong size %lx\n", physical_offset);
return 0;
}
data->logical_size = logical_size;
return data->logical_size;
}
@ -264,11 +267,6 @@ static STREAMFILE* setup_eaac_streamfile(STREAMFILE *streamFile, int version, in
io_data.physical_offset = stream_offset;
io_data.logical_size = eaac_io_size(streamFile, &io_data); /* force init */
if (io_data.logical_size > get_streamfile_size(streamFile)) {
VGM_LOG("EA EAAC: wrong logical size\n");
goto fail;
}
/* setup subfile */
new_streamFile = open_wrap_streamfile(streamFile);
if (!new_streamFile) goto fail;