From 30a4dd0e09e699c985e4a22b729265e3f7832616 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 28 Nov 2021 14:01:22 +0100 Subject: [PATCH] Add WiiU .XWS [Ninja Gaiden 3 Razor's Edge (WiiU)] --- src/formats.c | 1 + src/meta/kwb.c | 40 +++++++++++++++++++++++++++++----------- src/meta/meta.h | 1 + src/meta/ngc_dsp_std.c | 35 ++++++++++++++++++++++++++++++++++- src/vgmstream.c | 1 + src/vgmstream.h | 1 + 6 files changed, 67 insertions(+), 12 deletions(-) diff --git a/src/formats.c b/src/formats.c index 8572d87d..e604de75 100644 --- a/src/formats.c +++ b/src/formats.c @@ -1383,6 +1383,7 @@ static const meta_info meta_info_list[] = { {meta_LOPU_FB, "French-Bread LOPU header"}, {meta_LPCM_FB, "French-Bread LPCM header"}, {meta_WBK, "Treyarch WBK header"}, + {meta_DSP_APEX, "Koei Tecmo APEX header"}, }; void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) { diff --git a/src/meta/kwb.c b/src/meta/kwb.c index 1d922564..950de9a2 100644 --- a/src/meta/kwb.c +++ b/src/meta/kwb.c @@ -1,7 +1,7 @@ #include "meta.h" #include "../coding/coding.h" -typedef enum { PCM16, MSADPCM, DSP_HEAD, DSP_BODY, AT9, MSF, XMA2 } kwb_codec; +typedef enum { PCM16, MSADPCM, DSP_HEAD, DSP_BODY, AT9, MSF_APEX, XMA2 } kwb_codec; typedef struct { int big_endian; @@ -18,8 +18,8 @@ typedef struct { int loop_flag; int block_size; - off_t stream_offset; - size_t stream_size; + uint32_t stream_offset; + uint32_t stream_size; off_t dsp_offset; //off_t name_offset; @@ -121,20 +121,38 @@ static VGMSTREAM* init_vgmstream_koei_wavebank(kwb_header* kwb, STREAMFILE* sf_h read_s32 = kwb->big_endian ? read_s32be : read_s32le; /* container */ - if (kwb->codec == MSF) { + if (kwb->codec == MSF_APEX) { if (kwb->stream_offset == 0) { vgmstream = init_vgmstream_silence(0,0,0); /* dummy, whatevs */ if (!vgmstream) goto fail; } else { STREAMFILE* temp_sf = NULL; + init_vgmstream_t init_vgmstream = NULL; + const char* fake_ext; + uint32_t id; + + + id = read_u32be(kwb->stream_offset, sf_h); + if ((id & 0xFFFFFF00) == get_id32be("MSF\0")) { /* PS3 */ + kwb->stream_size = read_u32(kwb->stream_offset + 0x0c, sf_h) + 0x40; + fake_ext = "msf"; + init_vgmstream = init_vgmstream_msf; + } + else if (id == get_id32be("APEX")) { /* WiiU */ + kwb->stream_size = read_u32(kwb->stream_offset + 0x04, sf_h); /* not padded */ + fake_ext = "dsp"; + init_vgmstream = init_vgmstream_dsp_apex; + } + else { + vgm_logi("KWB: unknown type %x at %x\n", id, kwb->stream_offset); + goto fail; + } - kwb->stream_size = read_u32(kwb->stream_offset + 0x0c, sf_h) + 0x40; - - temp_sf = setup_subfile_streamfile(sf_h, kwb->stream_offset, kwb->stream_size, "msf"); + temp_sf = setup_subfile_streamfile(sf_h, kwb->stream_offset, kwb->stream_size, fake_ext); if (!temp_sf) goto fail; - vgmstream = init_vgmstream_msf(temp_sf); + vgmstream = init_vgmstream(temp_sf); close_streamfile(temp_sf); if (!vgmstream) goto fail; } @@ -641,9 +659,9 @@ static int parse_type_msfbank(kwb_header* kwb, off_t offset, STREAMFILE* sf) { relative_subsong = kwb->target_subsong - current_subsongs; header_offset = offset + 0x30 + (relative_subsong-1) * 0x04; - /* just a dumb table pointing to MSF, entries can be dummy */ + /* just a dumb table pointing to MSF/APEX, entries can be dummy */ kwb->stream_offset = read_u32be(header_offset, sf); - kwb->codec = MSF; + kwb->codec = MSF_APEX; kwb->stream_offset += offset; @@ -728,7 +746,7 @@ static int parse_type_xwsfile(kwb_header* kwb, off_t offset, STREAMFILE* sf) { goto fail; } else { - VGM_LOG("XWS: unknown type %x at head=%x, body=%x\n", entry_type, head_offset, body_offset); + vgm_logi("XWS: unknown type %x at head=%x, body=%x\n", entry_type, head_offset, body_offset); goto fail; } } diff --git a/src/meta/meta.h b/src/meta/meta.h index 15f1db0b..19541b02 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -64,6 +64,7 @@ VGMSTREAM* init_vgmstream_dsp_wiiadpcm(STREAMFILE* sf); VGMSTREAM* init_vgmstream_dsp_cwac(STREAMFILE* sf); VGMSTREAM* init_vgmstream_idsp_tose(STREAMFILE* sf); VGMSTREAM* init_vgmstream_dsp_kwa(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_dsp_apex(STREAMFILE* sf); VGMSTREAM * init_vgmstream_csmp(STREAMFILE *streamFile); diff --git a/src/meta/ngc_dsp_std.c b/src/meta/ngc_dsp_std.c index 7807de13..ddd50a39 100644 --- a/src/meta/ngc_dsp_std.c +++ b/src/meta/ngc_dsp_std.c @@ -1461,7 +1461,6 @@ VGMSTREAM* init_vgmstream_dsp_kwa(STREAMFILE* sf) { if (read_u32be(0x00,sf) != 3) goto fail; - /* .dsp: assumed */ if (!check_extensions(sf, "kwa")) goto fail; @@ -1484,3 +1483,37 @@ VGMSTREAM* init_vgmstream_dsp_kwa(STREAMFILE* sf) { fail: return NULL; } + + +/* APEX - interleaved dsp [Ninja Gaiden 3 Razor's Edge (WiiU)] */ +VGMSTREAM* init_vgmstream_dsp_apex(STREAMFILE* sf) { + dsp_meta dspm = {0}; + uint32_t stream_size; + + /* checks */ + if (!is_id32be(0x00,sf, "APEX")) + goto fail; + + /* .dsp: assumed */ + if (!check_extensions(sf, "dsp")) + goto fail; + + dspm.max_channels = 2; + stream_size = read_u32be(0x04,sf); + /* 0x08: 1? */ + dspm.channels = read_u16be(0x0a,sf); + /* 0x0c: channel size? */ + + dspm.interleave = 0x08; + dspm.header_offset = 0x20; + dspm.header_spacing = 0x60; + dspm.start_offset = dspm.header_offset + dspm.header_spacing * 2; + /* second DSP header exists even for mono files, but has no coefs */ + + dspm.interleave_last = (stream_size / dspm.channels) % dspm.interleave; + + dspm.meta_type = meta_DSP_APEX; + return init_vgmstream_dsp_common(sf, &dspm); +fail: + return NULL; +} diff --git a/src/vgmstream.c b/src/vgmstream.c index 76d1a6a6..25a5dd1e 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -526,6 +526,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_lopu_fb, init_vgmstream_lpcm_fb, init_vgmstream_wbk, + init_vgmstream_dsp_apex, /* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */ diff --git a/src/vgmstream.h b/src/vgmstream.h index 63f4081b..126ab0ed 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -753,6 +753,7 @@ typedef enum { meta_LOPU_FB, meta_LPCM_FB, meta_WBK, + meta_DSP_APEX, } meta_t;