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; } eaac_header;
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *streamData, eaac_header *eaac); 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). /* 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) */ /* rest is optional, depends on used flags and codec (handled below) */
eaac.stream_offset = start_offset; eaac.stream_offset = start_offset;
/* V0: SNR+SNS, V1: SPR+SPS (no apparent differences, other than block flags) */ /* V0: SNR+SNS, V1: SPR+SPS (no apparent differences, other than block flags) */
if (eaac.version != EAAC_VERSION_V0 && eaac.version != EAAC_VERSION_V1) { if (eaac.version != EAAC_VERSION_V0 && eaac.version != EAAC_VERSION_V1) {
VGM_LOG("EA EAAC: unknown version\n"); VGM_LOG("EA EAAC: unknown version\n");
@ -586,28 +586,10 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
case EAAC_CODEC_EAXMA: { /* "EXm0": EA-XMA [Dante's Inferno (X360)] */ case EAAC_CODEC_EAXMA: { /* "EXm0": EA-XMA [Dante's Inferno (X360)] */
uint8_t buf[0x100]; vgmstream->layout_data = build_layered_eaaudiocore_eaxma(streamData, &eaac);
int bytes, block_size, block_count; if (!vgmstream->layout_data) goto fail;
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->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_layered;
break; break;
} }
#endif #endif
@ -783,3 +765,69 @@ fail:
free_layout_segmented(data); free_layout_segmented(data);
return NULL; 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) { switch(data->codec) {
#if 0
case 0x03: { /* EA-XMA */ case 0x03: { /* EA-XMA */
/* block format: 0x04=num-samples, (size*4 + N XMA packets) per stream (with 1/2ch XMA headers) */ /* block format: 0x04=num-samples, (size*4 + N XMA packets) per stream (with 1/2ch XMA headers) */
int i; int i;
data->skip_size = 0x04 + 0x04; 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->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...? */ 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); data->extra_size = XMA_FRAME_SIZE - (data->data_size % XMA_FRAME_SIZE);
break; break;
} }
#endif
case 0x05: /* EALayer3 v1 */ case 0x05: /* EALayer3 v1 */
case 0x06: /* EALayer3 v2 "PCM" */ case 0x06: /* EALayer3 v2 "PCM" */
case 0x07: /* EALayer3 v2 "Spike" */ 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; bytes_consumed = offset - data->logical_offset;
switch(data->codec) { switch(data->codec) {
#if 0
case 0x03: { /* EA-XMA */ case 0x03: { /* EA-XMA */
if (bytes_consumed < data->data_size) { /* offset falls within actual data */ if (bytes_consumed < data->data_size) { /* offset falls within actual data */
to_read = data->data_size - bytes_consumed; 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; break;
} }
#endif
default: default:
to_read = data->data_size - bytes_consumed; to_read = data->data_size - bytes_consumed;
if (to_read > length) 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 */ /* get size of the logical stream */
while (physical_offset < max_physical_offset) { while (physical_offset < max_physical_offset) {
uint32_t block_flag, block_size, data_size, skip_size; 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_flag = (uint8_t)read_8bit(physical_offset+0x00,streamfile);
block_size = read_32bitBE(physical_offset+0x00,streamfile) & 0x00FFFFFF; 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 */ break; /* unknown block */
switch(data->codec) { switch(data->codec) {
#if 0
case 0x03: /* EA-XMA */ case 0x03: /* EA-XMA */
skip_size = 0x04 + 0x04; 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...? */ skip_size += read_32bitBE(physical_offset + skip_size, streamfile) / 4; /* why size*4...? */
} }
data_size = read_32bitBE(physical_offset + skip_size, streamfile) / 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) if (data_size % XMA_FRAME_SIZE)
data_size += XMA_FRAME_SIZE - (data_size % XMA_FRAME_SIZE); /* extra padding */ data_size += XMA_FRAME_SIZE - (data_size % XMA_FRAME_SIZE); /* extra padding */
break; break;
#endif
case 0x05: /* EALayer3 v1 */ case 0x05: /* EALayer3 v1 */
case 0x06: /* EALayer3 v2 "PCM" */ case 0x06: /* EALayer3 v2 "PCM" */
case 0x07: /* EALayer3 v2 "Spike" */ 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 */ 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; data->logical_size = logical_size;
return data->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.physical_offset = stream_offset;
io_data.logical_size = eaac_io_size(streamFile, &io_data); /* force init */ 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 */ /* setup subfile */
new_streamFile = open_wrap_streamfile(streamFile); new_streamFile = open_wrap_streamfile(streamFile);
if (!new_streamFile) goto fail; if (!new_streamFile) goto fail;