From edcffe05c41e95dd25095d75e71921a0c346dff8 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 10 Aug 2024 23:48:36 +0200 Subject: [PATCH] Fix some custom/buggy .dsp --- src/meta/ngc_dsp_std.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/meta/ngc_dsp_std.c b/src/meta/ngc_dsp_std.c index 20d8e8d5..28461e49 100644 --- a/src/meta/ngc_dsp_std.c +++ b/src/meta/ngc_dsp_std.c @@ -1,11 +1,12 @@ #include "meta.h" #include "../layout/layout.h" #include "../coding/coding.h" +#include "../util/endianness.h" /* If these variables are packed properly in the struct (one after another) * then this is actually how they are laid out in the file, albeit big-endian */ -struct dsp_header { +typedef struct { uint32_t sample_count; /* 0x00 */ uint32_t nibble_count; /* 0x04 (includes frame headers) */ uint32_t sample_rate; /* 0x08 (generally 22/32/44/48kz but games like Wario World set 32028hz to adjust for GC's rate) */ @@ -26,13 +27,13 @@ struct dsp_header { uint16_t block_size; /* 0x4c */ /* padding/reserved up to 0x60, DSPADPCM.exe from GC adds garbage here (uninitialized MSVC memory?) * [ex. Batallion Wars (GC), Timesplitters 2 (GC)], 0xcccc...cccc with DSPADPCMD */ -}; +} dsp_header_t; /* read and do basic validations to the above struct */ -static bool read_dsp_header_endian(struct dsp_header *header, off_t offset, STREAMFILE* sf, int big_endian) { - uint32_t (*get_u32)(const uint8_t*) = big_endian ? get_u32be : get_u32le; - uint16_t (*get_u16)(const uint8_t*) = big_endian ? get_u16be : get_u16le; - int16_t (*get_s16)(const uint8_t*) = big_endian ? get_s16be : get_s16le; +static bool read_dsp_header_endian(dsp_header_t* header, off_t offset, STREAMFILE* sf, bool big_endian) { + get_u32_t get_u32 = big_endian ? get_u32be : get_u32le; + get_u16_t get_u16 = big_endian ? get_u16be : get_u16le; + get_s16_t get_s16 = big_endian ? get_s16be : get_s16le; uint8_t buf[0x60]; int zero_coefs; @@ -71,9 +72,11 @@ static bool read_dsp_header_endian(struct dsp_header *header, off_t offset, STRE header->loop_start_offset = get_u32(buf+0x10); header->loop_end_offset = get_u32(buf+0x14); + //TODO: test if games react to changed initial offset + /* Dr. Muto uses 0, and some custom Metroid Prime loop start, so probably ignored by the hardware */ header->initial_offset = get_u32(buf+0x18); - if (header->initial_offset != 2 && header->initial_offset != 0) - goto fail; /* Dr. Muto uses 0 */ + if (header->initial_offset != 2 && header->initial_offset != 0 && header->initial_offset != header->loop_start_offset) + goto fail; zero_coefs = 0; for (int i = 0; i < 16; i++) { @@ -110,10 +113,10 @@ static bool read_dsp_header_endian(struct dsp_header *header, off_t offset, STRE fail: return false; } -static int read_dsp_header_be(struct dsp_header *header, off_t offset, STREAMFILE* file) { +static int read_dsp_header_be(dsp_header_t *header, off_t offset, STREAMFILE* file) { return read_dsp_header_endian(header, offset, file, 1); } -static int read_dsp_header_le(struct dsp_header *header, off_t offset, STREAMFILE* file) { +static int read_dsp_header_le(dsp_header_t *header, off_t offset, STREAMFILE* file) { return read_dsp_header_endian(header, offset, file, 0); } @@ -154,7 +157,7 @@ static VGMSTREAM* init_vgmstream_dsp_common(STREAMFILE* sf, dsp_meta* dspm) { VGMSTREAM* vgmstream = NULL; int i, j; int loop_flag; - struct dsp_header ch_header[COMMON_DSP_MAX_CHANNELS]; + dsp_header_t ch_header[COMMON_DSP_MAX_CHANNELS]; if (dspm->channels > dspm->max_channels) @@ -306,7 +309,7 @@ fail: /* .dsp - standard mono dsp as generated by DSPADPCM.exe */ VGMSTREAM* init_vgmstream_ngc_dsp_std(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; - struct dsp_header header; + dsp_header_t header; const size_t header_size = 0x60; off_t start_offset; int i, channels; @@ -338,7 +341,7 @@ VGMSTREAM* init_vgmstream_ngc_dsp_std(STREAMFILE* sf) { // (but .dsp is the common case, so it'd be slower) { int ko; - struct dsp_header header2; + dsp_header_t header2; /* ignore headers one after another */ ko = !read_dsp_header_be(&header2, header_size, sf); @@ -427,7 +430,7 @@ fail: /* .dsp - little endian dsp, possibly main Switch .dsp [LEGO Worlds (Switch)] */ VGMSTREAM* init_vgmstream_ngc_dsp_std_le(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; - struct dsp_header header; + dsp_header_t header; const size_t header_size = 0x60; off_t start_offset; int i, channels; @@ -450,7 +453,7 @@ VGMSTREAM* init_vgmstream_ngc_dsp_std_le(STREAMFILE* sf) { * In many cases these will pass all the other checks, including the * predictor/scale check if the first byte is 0 */ { - struct dsp_header header2; + dsp_header_t header2; int ko; ko = !read_dsp_header_le(&header2, header_size, sf); @@ -510,7 +513,7 @@ fail: /* .dsp - standard multi-channel dsp as generated by DSPADPCM.exe (later revisions) */ VGMSTREAM* init_vgmstream_ngc_mdsp_std(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; - struct dsp_header header; + dsp_header_t header; const size_t header_size = 0x60; off_t start_offset; int i, c, channels;