From 14d4cd8651c04394c1400a15d370ec06ad05f469 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 18 Mar 2017 00:22:20 +0100 Subject: [PATCH] Add XWB size check; Techland's ATRAC3 [Nail'd, Sniper Ghost Warrior PS3] --- src/meta/xwb.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/meta/xwb.c b/src/meta/xwb.c index 0da9807e..86062a63 100644 --- a/src/meta/xwb.c +++ b/src/meta/xwb.c @@ -15,7 +15,7 @@ static const int32_t wma_block_align_index[] = { /*17*/ }; -typedef enum { PCM, XBOX_ADPCM, MS_ADPCM, XMA1, XMA2, WMA, XWMA } xact_codec; +typedef enum { PCM, XBOX_ADPCM, MS_ADPCM, XMA1, XMA2, WMA, XWMA, ATRAC3 } xact_codec; typedef struct { int little_endian; int xact; /* rough XACT version (1/2/3) */ @@ -103,8 +103,11 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) { //0x14: XACT1: none (ENTRYWAVEDATA), XACT2: EXTRA, XACT3: ENTRYNAMES suboff = xwb.xact >= 2 ? 0x08+0x08 : 0x08; xwb.data_offset = read_32bit(off+0x10+suboff, streamFile);//ENTRYWAVEDATA - xwb.data_size = read_32bit(off+0x10+suboff, streamFile); + xwb.data_size = read_32bit(off+0x14+suboff, streamFile); + /* for Silent Hill 4 Xbox fake XWB and Techland's XWB with no data */ + if (xwb.base_offset == 0) goto fail; + if (xwb.data_offset + xwb.data_size != get_streamfile_size(streamFile)) goto fail; /* read base entry (WAVEBANKDATA) */ off = xwb.base_offset; @@ -215,6 +218,17 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) { } } + /* Techland's bizarre format hijack (Nail'd, Sniper: Ghost Warrior PS3). + * Somehow they used XWB + ATRAC3 in their PS3 games, very creative */ + if (xwb.version == 0x10000 && xwb.codec == XMA2 /* v 0x10000 is used in their X360 games too */ + && (xwb.block_align == 0x60 || xwb.block_align == 0x98 || xwb.block_align == 0xc0) ) { + xwb.codec = ATRAC3; /* standard ATRAC3 blocks sizes; no other way to identify (other than reading data) */ + + /* num samples uses a modified entry_info format (maybe skip samples + samples? sfx use the standard format) + * ignore for now and just calc max samples */ //todo + xwb.num_samples = xwb.stream_size / (xwb.block_align * xwb.channels) * 1024; + } + /* fix samples */ if ((xwb.xact == 1 || xwb.xact == 2) && xwb.codec == PCM) { @@ -372,6 +386,24 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) { vgmstream->layout_type = layout_none; break; } + + case ATRAC3: { /* Techland extension */ + uint8_t buf[200]; + int bytes; + + int block_size = xwb.block_align * vgmstream->channels; + int joint_stereo = xwb.block_align == 0x60; /* untested, ATRAC3 default */ + int skip_samples = 0; /* unknown */ + + bytes = ffmpeg_make_riff_atrac3(buf, 200, vgmstream->num_samples, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, skip_samples); + if (bytes <= 0) goto fail; + + vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, xwb.stream_offset,xwb.stream_size); + if ( !vgmstream->codec_data ) goto fail; + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; + break; + } #endif default: