From 5b863393b887b10c53eb3dc91b38d88e1997fa8f Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 5 Nov 2017 18:12:28 +0100 Subject: [PATCH] Fix some OPUS + looping [Ultra Street Fighter 2, Disgaea 5] --- src/formats.c | 2 +- src/meta/nsw_opus.c | 46 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/formats.c b/src/formats.c index d62beb01..562b7266 100644 --- a/src/formats.c +++ b/src/formats.c @@ -901,7 +901,7 @@ static const meta_info meta_info_list[] = { {meta_BINK, "RAD Game Tools Bink header"}, {meta_EA_SNU, "Electronic Arts SNU header"}, {meta_AWC, "Rockstar AWC header"}, - {meta_NSW_OPUS, ".OPUS header"}, + {meta_NSW_OPUS, "Nintendo Switch OPUS header"}, {meta_PC_AL2, "Illwinter Game Design AL2 raw header"}, {meta_PC_AST, "Capcom AST (PC) header"}, {meta_UBI_SB, "Ubisoft SBx header"}, diff --git a/src/meta/nsw_opus.c b/src/meta/nsw_opus.c index 9339d477..a0e8ca07 100644 --- a/src/meta/nsw_opus.c +++ b/src/meta/nsw_opus.c @@ -2,30 +2,61 @@ #include "../util.h" #include "../coding/coding.h" -/* .OPUS - from Lego City Undercover (Switch) */ +/* .OPUS - from Switch games (Lego City Undercover, Ultra SF II, Disgaea 5) */ VGMSTREAM * init_vgmstream_nsw_opus(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; int loop_flag = 0, channel_count; + int num_samples = 0, loop_start = 0, loop_end = 0; + off_t offset = 0; /* check extension, case insensitive */ if ( !check_extensions(streamFile,"opus")) /* no relation to Ogg Opus */ goto fail; - if (read_32bitBE(0x00,streamFile) != 0x01000080) + /* variations, maybe custom */ + if (read_32bitBE(0x00,streamFile) == 0x01000080) { /* Lego City Undercover */ + offset = 0x00; + } + else if ((read_32bitBE(0x04,streamFile) == 0x00000000 && read_32bitBE(0x0c,streamFile) == 0x00000000) || + (read_32bitBE(0x04,streamFile) == 0xFFFFFFFF && read_32bitBE(0x0c,streamFile) == 0xFFFFFFFF)) { /* Disgaea 5 */ + offset = 0x10; + + loop_start = read_32bitLE(0x00,streamFile); + loop_end = read_32bitLE(0x08,streamFile); + } + else if (read_32bitLE(0x04,streamFile) == 0x02) { /* Ultra Street Fighter II */ + offset = read_32bitLE(0x1c,streamFile); + + num_samples = read_32bitLE(0x00,streamFile); + loop_start = read_32bitLE(0x08,streamFile); + loop_end = read_32bitLE(0x0c,streamFile); + } + else { + offset = 0x00; + } + + if (read_32bitBE(offset + 0x00,streamFile) != 0x01000080) goto fail; - start_offset = 0x28; - channel_count = read_8bit(0x09,streamFile); /* assumed */ - /* other values in the header: no idea */ + start_offset = offset + 0x28; + channel_count = read_8bit(offset + 0x09,streamFile); /* assumed */ + /* 0x0a: packet size if CBR?, other values: no idea */ + + loop_flag = (loop_end > 0); /* -1 when not set */ + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - vgmstream->sample_rate = read_32bitLE(0x0c,streamFile); + vgmstream->sample_rate = read_32bitLE(offset + 0x0c,streamFile); vgmstream->meta_type = meta_NSW_OPUS; + vgmstream->num_samples = num_samples; + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; + #ifdef VGM_USE_FFMPEG { uint8_t buf[0x100]; @@ -47,7 +78,8 @@ VGMSTREAM * init_vgmstream_nsw_opus(STREAMFILE *streamFile) { vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; - vgmstream->num_samples = switch_opus_get_samples(start_offset, data_size, vgmstream->sample_rate, streamFile); + if (vgmstream->num_samples == 0) + vgmstream->num_samples = switch_opus_get_samples(start_offset, data_size, vgmstream->sample_rate, streamFile); } #else goto fail;