From 347507a775106fa6b8e49ac5ccf7f2b703ae52f1 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 11 Oct 2020 01:10:02 +0200 Subject: [PATCH] Add .wav DSP/OPUS [Dragon Quest (Switch)] --- src/formats.c | 1 + src/meta/meta.h | 81 ++++----- src/meta/ngc_dsp_std.c | 394 ++++++++++++++++++++++------------------- src/meta/opus.c | 218 ++++++++++++----------- src/vgmstream.c | 1 + src/vgmstream.h | 1 + 6 files changed, 366 insertions(+), 330 deletions(-) diff --git a/src/formats.c b/src/formats.c index 5504757e..954691cd 100644 --- a/src/formats.c +++ b/src/formats.c @@ -1314,6 +1314,7 @@ static const meta_info meta_info_list[] = { {meta_ADP_KONAMI, "Konami ADP header"}, {meta_SDRH, "feelplus SDRH header"}, {meta_WADY, "Marble WADY header"}, + {meta_DSP_SQEX, "Square Enix DSP header"}, }; void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) { diff --git a/src/meta/meta.h b/src/meta/meta.h index ccdd23c6..039bc8c8 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -26,34 +26,35 @@ VGMSTREAM * init_vgmstream_nds_strm(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ngc_adpdtk(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_ngc_mdsp_std(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_ngc_dsp_stm(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_ngc_mpdsp(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_idsp_namco(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_sadb(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_sadf(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_idsp_nl(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_wii_wsd(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_dsp_ddsp(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_wii_was(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_dsp_str_ig(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_dsp_xiii(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_dsp_cabelas(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_wii_ndp(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_ngc_dsp_aaap(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_dsp_dspw(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_ngc_dsp_iadp(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_dsp_mcadpcm(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_dsp_switch_audio(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_dsp_sps_n1(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_dsp_itl_ch(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_dsp_adpy(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_dsp_adpx(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_dsp_ds2(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_dsp_itl(STREAMFILE *streamFile); +VGMSTREAM* init_vgmstream_ngc_dsp_std(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_ngc_mdsp_std(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_ngc_dsp_stm(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_ngc_mpdsp(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_ngc_dsp_std_int(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_idsp_namco(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_sadb(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_sadf(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_idsp_tt(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_idsp_nl(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_wii_wsd(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_dsp_ddsp(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_wii_was(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_dsp_str_ig(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_dsp_xiii(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_dsp_cabelas(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_wii_ndp(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_ngc_dsp_aaap(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_dsp_dspw(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_ngc_dsp_iadp(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_dsp_mcadpcm(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_dsp_switch_audio(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_dsp_sps_n1(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_dsp_itl_ch(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_dsp_adpy(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_dsp_adpx(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_dsp_ds2(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_dsp_itl(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_dsp_sqex(STREAMFILE *sf); VGMSTREAM * init_vgmstream_csmp(STREAMFILE *streamFile); @@ -636,18 +637,18 @@ VGMSTREAM * init_vgmstream_stm(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_awc(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_opus_std(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_opus_n1(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_opus_capcom(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_opus_nop(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_opus_shinen(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_opus_nus3(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_opus_sps_n1(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_opus_nxa(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_opus_opusx(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_opus_prototype(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_opus_opusnx(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_opus_sqex(STREAMFILE* streamFile); +VGMSTREAM* init_vgmstream_opus_std(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_opus_n1(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_opus_capcom(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_opus_nop(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_opus_shinen(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_opus_nus3(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_opus_sps_n1(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_opus_nxa(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_opus_opusx(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_opus_prototype(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_opus_opusnx(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_opus_sqex(STREAMFILE* sf); VGMSTREAM * init_vgmstream_raw_al(STREAMFILE * streamFile); diff --git a/src/meta/ngc_dsp_std.c b/src/meta/ngc_dsp_std.c index bb785523..42df409a 100644 --- a/src/meta/ngc_dsp_std.c +++ b/src/meta/ngc_dsp_std.c @@ -28,15 +28,15 @@ struct dsp_header { }; /* read the above struct; returns nonzero on failure */ -static int read_dsp_header_endian(struct dsp_header *header, off_t offset, STREAMFILE *streamFile, int big_endian) { +static int read_dsp_header_endian(struct dsp_header *header, off_t offset, STREAMFILE* sf, int big_endian) { int32_t (*get_32bit)(const uint8_t *) = big_endian ? get_32bitBE : get_32bitLE; int16_t (*get_16bit)(const uint8_t *) = big_endian ? get_16bitBE : get_16bitLE; int i; uint8_t buf[0x4e]; - if (offset > get_streamfile_size(streamFile)) + if (offset > get_streamfile_size(sf)) return 1; - if (read_streamfile(buf, offset, 0x4e, streamFile) != 0x4e) + if (read_streamfile(buf, offset, 0x4e, sf) != 0x4e) return 1; header->sample_count = get_32bit(buf+0x00); header->nibble_count = get_32bit(buf+0x04); @@ -59,10 +59,10 @@ static int read_dsp_header_endian(struct dsp_header *header, off_t offset, STREA header->block_size = get_16bit(buf+0x4c); return 0; } -static int read_dsp_header(struct dsp_header *header, off_t offset, STREAMFILE *file) { +static int read_dsp_header(struct dsp_header *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(struct dsp_header *header, off_t offset, STREAMFILE* file) { return read_dsp_header_endian(header, offset, file, 0); } @@ -98,8 +98,8 @@ typedef struct { /* Common parser for most DSPs that are basically the same with minor changes. * Custom variants will just concatenate or interleave standard DSP headers and data, * so we make sure to validate read vs expected values, based on dsp_meta config. */ -static VGMSTREAM * init_vgmstream_dsp_common(STREAMFILE *streamFile, dsp_meta *dspm) { - VGMSTREAM * vgmstream = NULL; +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]; @@ -113,7 +113,7 @@ static VGMSTREAM * init_vgmstream_dsp_common(STREAMFILE *streamFile, dsp_meta *d /* load standard DSP header per channel */ { for (i = 0; i < dspm->channel_count; i++) { - if (read_dsp_header_endian(&ch_header[i], dspm->header_offset + i*dspm->header_spacing, streamFile, !dspm->little_endian)) + if (read_dsp_header_endian(&ch_header[i], dspm->header_offset + i*dspm->header_spacing, sf, !dspm->little_endian)) goto fail; } } @@ -156,7 +156,7 @@ static VGMSTREAM * init_vgmstream_dsp_common(STREAMFILE *streamFile, dsp_meta *d for (i = 0; i < channels; i++) { off_t channel_offset = dspm->start_offset + i*dspm->interleave; - if (ch_header[i].initial_ps != (uint8_t)read_8bit(channel_offset, streamFile)) + if (ch_header[i].initial_ps != (uint8_t)read_8bit(channel_offset, sf)) goto fail; } } @@ -174,7 +174,7 @@ static VGMSTREAM * init_vgmstream_dsp_common(STREAMFILE *streamFile, dsp_meta *d loop_offset = (loop_offset / dspm->interleave * dspm->interleave * channels) + (loop_offset % dspm->interleave); } - if (ch_header[i].loop_ps != (uint8_t)read_8bit(dspm->start_offset + i*dspm->interleave + loop_offset,streamFile)) + if (ch_header[i].loop_ps != (uint8_t)read_8bit(dspm->start_offset + i*dspm->interleave + loop_offset,sf)) goto fail; } } @@ -235,7 +235,7 @@ static VGMSTREAM * init_vgmstream_dsp_common(STREAMFILE *streamFile, dsp_meta *d } - if (!vgmstream_open_stream(vgmstream,streamFile,dspm->start_offset)) + if (!vgmstream_open_stream(vgmstream,sf,dspm->start_offset)) goto fail; return vgmstream; @@ -247,8 +247,8 @@ fail: /* ********************************* */ /* .dsp - standard dsp as generated by DSPADPCM.exe */ -VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; +VGMSTREAM* init_vgmstream_ngc_dsp_std(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; struct dsp_header header; const size_t header_size = 0x60; off_t start_offset; @@ -258,16 +258,16 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) { /* .dsp: standard * .adp: Dr. Muto/Battalion Wars (GC) mono files * (extensionless): Tony Hawk's Downhill Jam (Wii) */ - if (!check_extensions(streamFile, "dsp,adp,")) + if (!check_extensions(sf, "dsp,adp,")) goto fail; - if (read_dsp_header(&header, 0x00, streamFile)) + if (read_dsp_header(&header, 0x00, sf)) goto fail; channel_count = 1; start_offset = header_size; - if (header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile)) + if (header.initial_ps != (uint8_t)read_8bit(start_offset,sf)) goto fail; /* check initial predictor/scale */ if (header.format || header.gain) goto fail; /* check type==0 and gain==0 */ @@ -282,7 +282,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) { struct dsp_header header2; /* ignore headers one after another */ - ko = read_dsp_header(&header2, header_size, streamFile); + ko = read_dsp_header(&header2, header_size, sf); if (!ko && header.sample_count == header2.sample_count && header.nibble_count == header2.nibble_count && @@ -293,7 +293,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) { /* ignore headers after interleave [Ultimate Board Collection (Wii)] */ - ko = read_dsp_header(&header2, 0x10000, streamFile); + ko = read_dsp_header(&header2, 0x10000, sf); if (!ko && header.sample_count == header2.sample_count && header.nibble_count == header2.nibble_count && @@ -307,7 +307,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) { off_t loop_off; /* check loop predictor/scale */ loop_off = header.loop_start_offset/16*8; - if (header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) { + if (header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,sf)) { /* rarely won't match (ex ESPN 2002), not sure if header or calc problem, but doesn't seem to matter * (there may be a "click" when looping, or loop values may be too big and loop disabled anyway) */ VGM_LOG("DSP (std): bad loop_predictor\n"); @@ -341,7 +341,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) { vgmstream->ch[0].adpcm_history2_16 = header.initial_hist2; } - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + if (!vgmstream_open_stream(vgmstream,sf,start_offset)) goto fail; return vgmstream; @@ -351,8 +351,8 @@ fail: } /* .dsp - little endian dsp, possibly main Switch .dsp [LEGO Worlds (Switch)] */ -VGMSTREAM * init_vgmstream_ngc_dsp_std_le(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; +VGMSTREAM* init_vgmstream_ngc_dsp_std_le(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; struct dsp_header header; const size_t header_size = 0x60; off_t start_offset; @@ -360,16 +360,16 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std_le(STREAMFILE *streamFile) { /* checks */ /* .adpcm: LEGO Worlds */ - if (!check_extensions(streamFile, "adpcm")) + if (!check_extensions(sf, "adpcm")) goto fail; - if (read_dsp_header_le(&header, 0x00, streamFile)) + if (read_dsp_header_le(&header, 0x00, sf)) goto fail; channel_count = 1; start_offset = header_size; - if (header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile)) + if (header.initial_ps != (uint8_t)read_8bit(start_offset,sf)) goto fail; /* check initial predictor/scale */ if (header.format || header.gain) goto fail; /* check type==0 and gain==0 */ @@ -380,7 +380,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std_le(STREAMFILE *streamFile) { * predictor/scale check if the first byte is 0 */ { struct dsp_header header2; - read_dsp_header_le(&header2, header_size, streamFile); + read_dsp_header_le(&header2, header_size, sf); if (header.sample_count == header2.sample_count && header.nibble_count == header2.nibble_count && @@ -394,7 +394,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std_le(STREAMFILE *streamFile) { off_t loop_off; /* check loop predictor/scale */ loop_off = header.loop_start_offset/16*8; - if (header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) { + if (header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,sf)) { /* rarely won't match (ex ESPN 2002), not sure if header or calc problem, but doesn't seem to matter * (there may be a "click" when looping, or loop values may be too big and loop disabled anyway) */ VGM_LOG("DSP (std): bad loop_predictor\n"); @@ -428,7 +428,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std_le(STREAMFILE *streamFile) { vgmstream->ch[0].adpcm_history2_16 = header.initial_hist2; } - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + if (!vgmstream_open_stream(vgmstream,sf,start_offset)) goto fail; return vgmstream; @@ -438,28 +438,28 @@ fail: } /* .dsp - standard multi-channel dsp as generated by DSPADPCM.exe (later revisions) */ -VGMSTREAM * init_vgmstream_ngc_mdsp_std(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; +VGMSTREAM* init_vgmstream_ngc_mdsp_std(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; struct dsp_header header; const size_t header_size = 0x60; off_t start_offset; int i, c, channel_count; /* checks */ - if (!check_extensions(streamFile, "dsp,mdsp")) + if (!check_extensions(sf, "dsp,mdsp")) goto fail; - if (read_dsp_header(&header, 0x00, streamFile)) + if (read_dsp_header(&header, 0x00, sf)) goto fail; channel_count = header.channel_count==0 ? 1 : header.channel_count; start_offset = header_size * channel_count; /* named .dsp and no channels? likely another interleaved dsp */ - if (check_extensions(streamFile,"dsp") && header.channel_count == 0) + if (check_extensions(sf,"dsp") && header.channel_count == 0) goto fail; - if (header.initial_ps != (uint8_t)read_8bit(start_offset, streamFile)) + if (header.initial_ps != (uint8_t)read_8bit(start_offset, sf)) goto fail; /* check initial predictor/scale */ if (header.format || header.gain) goto fail; /* check type==0 and gain==0 */ @@ -483,7 +483,7 @@ VGMSTREAM * init_vgmstream_ngc_mdsp_std(STREAMFILE *streamFile) { vgmstream->interleave_last_block_size = (header.nibble_count / 2 % vgmstream->interleave_block_size + 7) / 8 * 8; for (i = 0; i < channel_count; i++) { - if (read_dsp_header(&header, header_size * i, streamFile)) goto fail; + if (read_dsp_header(&header, header_size * i, sf)) goto fail; /* adpcm coeffs/history */ for (c = 0; c < 16; c++) @@ -492,7 +492,7 @@ VGMSTREAM * init_vgmstream_ngc_mdsp_std(STREAMFILE *streamFile) { vgmstream->ch[i].adpcm_history2_16 = header.initial_hist2; } - if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) goto fail; return vgmstream; @@ -504,39 +504,39 @@ fail: /* ********************************* */ /* .stm - Intelligent Systems + others (same programmers) full interleaved dsp [Paper Mario TTYD (GC), Fire Emblem: POR (GC), Cubivore (GC)] */ -VGMSTREAM * init_vgmstream_ngc_dsp_stm(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_ngc_dsp_stm(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ /* .lstm/dsp: renamed to avoid hijacking Scream Tracker 2 Modules */ - if (!check_extensions(streamFile, "stm,lstm,dsp")) + if (!check_extensions(sf, "stm,lstm,dsp")) goto fail; - if (read_16bitBE(0x00, streamFile) != 0x0200) + if (read_16bitBE(0x00, sf) != 0x0200) goto fail; /* 0x02(2): sample rate, 0x08+: channel sizes/loop offsets? */ - dspm.channel_count = read_32bitBE(0x04, streamFile); + dspm.channel_count = read_32bitBE(0x04, sf); dspm.max_channels = 2; dspm.fix_looping = 1; dspm.header_offset = 0x40; dspm.header_spacing = 0x60; dspm.start_offset = 0x100; - dspm.interleave = (read_32bitBE(0x08, streamFile) + 0x20) / 0x20 * 0x20; /* strange rounding, but works */ + dspm.interleave = (read_32bitBE(0x08, sf) + 0x20) / 0x20 * 0x20; /* strange rounding, but works */ dspm.meta_type = meta_DSP_STM; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* .(mp)dsp - single header + interleaved dsp [Monopoly Party! (GC)] */ -VGMSTREAM * init_vgmstream_ngc_mpdsp(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_ngc_mpdsp(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ /* .mpdsp: renamed since standard .dsp would catch it otherwise */ - if (!check_extensions(streamFile, "mpdsp")) + if (!check_extensions(sf, "mpdsp")) goto fail; /* at 0x48 is extra data that could help differenciating these DSPs, but seems like @@ -553,18 +553,18 @@ VGMSTREAM * init_vgmstream_ngc_mpdsp(STREAMFILE *streamFile) { dspm.interleave = 0xf000; dspm.meta_type = meta_DSP_MPDSP; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* various dsp with differing extensions and interleave values */ -VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_ngc_dsp_std_int(STREAMFILE* sf) { dsp_meta dspm = {0}; char filename[PATH_LIMIT]; /* checks */ - if (!check_extensions(streamFile, "dsp,mss,gcm")) + if (!check_extensions(sf, "dsp,mss,gcm")) goto fail; dspm.channel_count = 2; @@ -575,16 +575,16 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile) { dspm.header_spacing = 0x60; dspm.start_offset = 0xc0; - streamFile->get_name(streamFile,filename,sizeof(filename)); + sf->get_name(sf,filename,sizeof(filename)); if (strlen(filename) > 7 && !strcasecmp("_lr.dsp",filename+strlen(filename)-7)) { //todo improve dspm.interleave = 0x14180; dspm.meta_type = meta_DSP_JETTERS; /* Bomberman Jetters (GC) */ - } else if (check_extensions(streamFile, "mss")) { + } else if (check_extensions(sf, "mss")) { dspm.interleave = 0x1000; dspm.meta_type = meta_DSP_MSS; /* Free Radical GC games */ /* Timesplitters 2 GC's ts2_atom_smasher_44_fx.mss differs slightly in samples but plays ok */ dspm.ignore_header_agreement = 1; - } else if (check_extensions(streamFile, "gcm")) { + } else if (check_extensions(sf, "gcm")) { /* older Traveller's Tales games [Lego Star Wars (GC), The Chronicles of Narnia (GC), Sonic R (GC)] */ dspm.interleave = 0x8000; dspm.meta_type = meta_DSP_GCM; @@ -592,19 +592,19 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile) { goto fail; } - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* IDSP - Namco header (from NUB/NUS3) + interleaved dsp [SSB4 (3DS), Tekken Tag Tournament 2 (WiiU)] */ -VGMSTREAM * init_vgmstream_idsp_namco(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_idsp_namco(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ - if (!check_extensions(streamFile, "idsp")) + if (!check_extensions(sf, "idsp")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x49445350) /* "IDSP" */ + if (read_32bitBE(0x00,sf) != 0x49445350) /* "IDSP" */ goto fail; dspm.max_channels = 8; @@ -612,52 +612,52 @@ VGMSTREAM * init_vgmstream_idsp_namco(STREAMFILE *streamFile) { dspm.fix_looping = 1; /* 0x04: null */ - dspm.channel_count = read_32bitBE(0x08, streamFile); + dspm.channel_count = read_32bitBE(0x08, sf); /* 0x0c: sample rate */ /* 0x10: num_samples */ /* 0x14: loop start */ /* 0x18: loop end */ - dspm.interleave = read_32bitBE(0x1c,streamFile); /* usually 0x10 */ - dspm.header_offset = read_32bitBE(0x20,streamFile); - dspm.header_spacing = read_32bitBE(0x24,streamFile); - dspm.start_offset = read_32bitBE(0x28,streamFile); + dspm.interleave = read_32bitBE(0x1c,sf); /* usually 0x10 */ + dspm.header_offset = read_32bitBE(0x20,sf); + dspm.header_spacing = read_32bitBE(0x24,sf); + dspm.start_offset = read_32bitBE(0x28,sf); /* Soul Calibur: Broken destiny (PSP), Taiko no Tatsujin: Atsumete Tomodachi Daisakusen (WiiU) */ if (dspm.interleave == 0) /* half interleave (happens sometimes), use channel size */ - dspm.interleave = read_32bitBE(0x2c,streamFile); + dspm.interleave = read_32bitBE(0x2c,sf); dspm.meta_type = meta_IDSP_NAMCO; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* sadb - Procyon Studio header + interleaved dsp [Shiren the Wanderer 3 (Wii), Disaster: Day of Crisis (Wii)] */ -VGMSTREAM * init_vgmstream_sadb(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_sadb(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ - if (!check_extensions(streamFile, "sad")) + if (!check_extensions(sf, "sad")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x73616462) /* "sadb" */ + if (read_32bitBE(0x00,sf) != 0x73616462) /* "sadb" */ goto fail; - dspm.channel_count = read_8bit(0x32, streamFile); + dspm.channel_count = read_8bit(0x32, sf); dspm.max_channels = 2; dspm.header_offset = 0x80; dspm.header_spacing = 0x60; - dspm.start_offset = read_32bitBE(0x48,streamFile); + dspm.start_offset = read_32bitBE(0x48,sf); dspm.interleave = 0x10; dspm.meta_type = meta_DSP_SADB; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* IDSP - Traveller's Tales header + interleaved dsps [Lego Batman (Wii), Lego Dimensions (Wii U)] */ -VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_idsp_tt(STREAMFILE* sf) { dsp_meta dspm = {0}; int version_main, version_sub; @@ -665,14 +665,14 @@ VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile) { /* .gcm: standard * .idsp: header id? * .wua: Lego Dimensions (Wii U) */ - if (!check_extensions(streamFile, "gcm,idsp,wua")) + if (!check_extensions(sf, "gcm,idsp,wua")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x49445350) /* "IDSP" */ + if (read_32bitBE(0x00,sf) != 0x49445350) /* "IDSP" */ goto fail; - version_main = read_32bitBE(0x04, streamFile); - version_sub = read_32bitBE(0x08, streamFile); /* extra check since there are other IDSPs */ + version_main = read_32bitBE(0x04, sf); + version_sub = read_32bitBE(0x08, sf); /* extra check since there are other IDSPs */ if (version_main == 0x01 && version_sub == 0xc8) { /* Transformers: The Game (Wii) */ dspm.channel_count = 2; @@ -694,7 +694,7 @@ VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile) { else if (version_main == 0x03 && version_sub == 0x12c) { /* Lego The Lord of the Rings (Wii) */ /* Lego Dimensions (Wii U) */ - dspm.channel_count = read_32bitBE(0x10, streamFile); + dspm.channel_count = read_32bitBE(0x10, sf); dspm.max_channels = 2; dspm.header_offset = 0x20; /* 0x14+: "I_AM_PADDING" */ @@ -705,22 +705,22 @@ VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile) { dspm.header_spacing = 0x60; dspm.start_offset = dspm.header_offset + 0x60 * dspm.channel_count; - dspm.interleave = read_32bitBE(0x0c, streamFile); + dspm.interleave = read_32bitBE(0x0c, sf); dspm.meta_type = meta_IDSP_TT; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* IDSP - from Next Level games [Super Mario Strikers (GC), Mario Strikers: Charged (Wii)] */ -VGMSTREAM * init_vgmstream_idsp_nl(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_idsp_nl(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ - if (!check_extensions(streamFile, "idsp")) + if (!check_extensions(sf, "idsp")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x49445350) /* "IDSP" */ + if (read_32bitBE(0x00,sf) != 0x49445350) /* "IDSP" */ goto fail; dspm.channel_count = 2; @@ -729,11 +729,11 @@ VGMSTREAM * init_vgmstream_idsp_nl(STREAMFILE *streamFile) { dspm.header_offset = 0x0c; dspm.header_spacing = 0x60; dspm.start_offset = dspm.header_offset + dspm.header_spacing*dspm.channel_count; - dspm.interleave = read_32bitBE(0x04,streamFile); + dspm.interleave = read_32bitBE(0x04,sf); /* 0x08: usable channel size */ { - size_t stream_size = get_streamfile_size(streamFile); - if (read_32bitBE(stream_size - 0x04,streamFile) == 0x30303030) + size_t stream_size = get_streamfile_size(sf); + if (read_32bitBE(stream_size - 0x04,sf) == 0x30303030) stream_size -= 0x14; /* remove padding */ stream_size -= dspm.start_offset; @@ -746,87 +746,87 @@ VGMSTREAM * init_vgmstream_idsp_nl(STREAMFILE *streamFile) { dspm.force_loop_seconds = 15; dspm.meta_type = meta_IDSP_NL; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* .wsd - Custom header + full interleaved dsp [Phantom Brave (Wii)] */ -VGMSTREAM * init_vgmstream_wii_wsd(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_wii_wsd(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ - if (!check_extensions(streamFile, "wsd")) + if (!check_extensions(sf, "wsd")) goto fail; - if (read_32bitBE(0x08,streamFile) != read_32bitBE(0x0c,streamFile)) /* channel sizes */ + if (read_32bitBE(0x08,sf) != read_32bitBE(0x0c,sf)) /* channel sizes */ goto fail; dspm.channel_count = 2; dspm.max_channels = 2; - dspm.header_offset = read_32bitBE(0x00,streamFile); - dspm.header_spacing = read_32bitBE(0x04,streamFile) - dspm.header_offset; + dspm.header_offset = read_32bitBE(0x00,sf); + dspm.header_spacing = read_32bitBE(0x04,sf) - dspm.header_offset; dspm.start_offset = dspm.header_offset + 0x60; dspm.interleave = dspm.header_spacing; dspm.meta_type = meta_DSP_WII_WSD; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* .ddsp - full interleaved dsp [The Sims 2 - Pets (Wii)] */ -VGMSTREAM * init_vgmstream_dsp_ddsp(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_dsp_ddsp(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ - if (!check_extensions(streamFile, "ddsp")) + if (!check_extensions(sf, "ddsp")) goto fail; dspm.channel_count = 2; dspm.max_channels = 2; dspm.header_offset = 0x00; - dspm.header_spacing = (get_streamfile_size(streamFile) / dspm.channel_count); + dspm.header_spacing = (get_streamfile_size(sf) / dspm.channel_count); dspm.start_offset = 0x60; dspm.interleave = dspm.header_spacing; dspm.meta_type = meta_DSP_DDSP; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* iSWS - Sumo Digital header + interleaved dsp [DiRT 2 (Wii), F1 2009 (Wii)] */ -VGMSTREAM * init_vgmstream_wii_was(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_wii_was(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ - if (!check_extensions(streamFile, "was,dsp,isws")) + if (!check_extensions(sf, "was,dsp,isws")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x69535753) /* "iSWS" */ + if (read_32bitBE(0x00,sf) != 0x69535753) /* "iSWS" */ goto fail; - dspm.channel_count = read_32bitBE(0x08,streamFile); + dspm.channel_count = read_32bitBE(0x08,sf); dspm.max_channels = 2; - dspm.header_offset = 0x08 + read_32bitBE(0x04,streamFile); + dspm.header_offset = 0x08 + read_32bitBE(0x04,sf); dspm.header_spacing = 0x60; dspm.start_offset = dspm.header_offset + dspm.channel_count*dspm.header_spacing; - dspm.interleave = read_32bitBE(0x10,streamFile); + dspm.interleave = read_32bitBE(0x10,sf); dspm.meta_type = meta_WII_WAS; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* .str - Infogrames raw interleaved dsp [Micro Machines (GC), Superman: Shadow of Apokolips (GC)] */ -VGMSTREAM * init_vgmstream_dsp_str_ig(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_dsp_str_ig(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ - if (!check_extensions(streamFile, "str")) + if (!check_extensions(sf, "str")) goto fail; dspm.channel_count = 2; @@ -838,17 +838,17 @@ VGMSTREAM * init_vgmstream_dsp_str_ig(STREAMFILE *streamFile) { dspm.interleave = 0x4000; dspm.meta_type = meta_DSP_STR_IG; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* .dsp - Ubisoft interleaved dsp with bad loop start [Speed Challenge: Jacques Villeneuve's Racing Vision (GC), XIII (GC)] */ -VGMSTREAM * init_vgmstream_dsp_xiii(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_dsp_xiii(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ - if (!check_extensions(streamFile, "dsp")) + if (!check_extensions(sf, "dsp")) goto fail; dspm.channel_count = 2; @@ -861,25 +861,25 @@ VGMSTREAM * init_vgmstream_dsp_xiii(STREAMFILE *streamFile) { dspm.interleave = 0x08; dspm.meta_type = meta_DSP_XIII; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* NPD - Icon Games header + subinterleaved DSPs [Vertigo (Wii), Build n' Race (Wii)] */ -VGMSTREAM * init_vgmstream_wii_ndp(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_wii_ndp(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ - if (!check_extensions(streamFile, "ndp")) + if (!check_extensions(sf, "ndp")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x4E445000) /* "NDP\0" */ + if (read_32bitBE(0x00,sf) != 0x4E445000) /* "NDP\0" */ goto fail; - if (read_32bitLE(0x08,streamFile) + 0x18 != get_streamfile_size(streamFile)) + if (read_32bitLE(0x08,sf) + 0x18 != get_streamfile_size(sf)) goto fail; /* 0x0c: sample rate */ - dspm.channel_count = read_32bitLE(0x10,streamFile); + dspm.channel_count = read_32bitLE(0x10,sf); dspm.max_channels = 2; dspm.header_offset = 0x18; @@ -888,25 +888,25 @@ VGMSTREAM * init_vgmstream_wii_ndp(STREAMFILE *streamFile) { dspm.interleave = 0x04; dspm.meta_type = meta_WII_NDP; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* Cabela's series (Magic Wand dev?) - header + interleaved dsp * [Cabela's Big Game Hunt 2005 Adventures (GC), Cabela's Outdoor Adventures (GC)] */ -VGMSTREAM * init_vgmstream_dsp_cabelas(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_dsp_cabelas(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ - if (!check_extensions(streamFile, "dsp")) + if (!check_extensions(sf, "dsp")) goto fail; /* has extra stuff in the reserved data, without it this meta may catch other DSPs it shouldn't */ - if (read_32bitBE(0x50,streamFile) == 0 || read_32bitBE(0x54,streamFile) == 0) + if (read_32bitBE(0x50,sf) == 0 || read_32bitBE(0x54,sf) == 0) goto fail; /* sfx are mono, but standard dsp will catch them tho */ - dspm.channel_count = read_32bitBE(0x00,streamFile) == read_32bitBE(0x60,streamFile) ? 2 : 1; + dspm.channel_count = read_32bitBE(0x00,sf) == read_32bitBE(0x60,sf) ? 2 : 1; dspm.max_channels = 2; dspm.force_loop = (dspm.channel_count > 1); @@ -916,49 +916,49 @@ VGMSTREAM * init_vgmstream_dsp_cabelas(STREAMFILE *streamFile) { dspm.interleave = 0x10; dspm.meta_type = meta_DSP_CABELAS; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* AAAp - Acclaim Austin Audio header + interleaved dsp [Vexx (GC), Turok: Evolution (GC)] */ -VGMSTREAM * init_vgmstream_ngc_dsp_aaap(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_ngc_dsp_aaap(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ - if (!check_extensions(streamFile, "dsp")) + if (!check_extensions(sf, "dsp")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x41414170) /* "AAAp" */ + if (read_32bitBE(0x00,sf) != 0x41414170) /* "AAAp" */ goto fail; - dspm.channel_count = read_16bitBE(0x06,streamFile); + dspm.channel_count = read_16bitBE(0x06,sf); dspm.max_channels = 2; dspm.header_offset = 0x08; dspm.header_spacing = 0x60; dspm.start_offset = dspm.header_offset + dspm.channel_count*dspm.header_spacing; - dspm.interleave = (uint16_t)read_16bitBE(0x04,streamFile); + dspm.interleave = (uint16_t)read_16bitBE(0x04,sf); dspm.meta_type = meta_NGC_DSP_AAAP; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* DSPW - Capcom header + full interleaved DSP [Sengoku Basara 3 (Wii), Monster Hunter 3 Ultimate (WiiU)] */ -VGMSTREAM * init_vgmstream_dsp_dspw(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_dsp_dspw(STREAMFILE* sf) { dsp_meta dspm = {0}; size_t data_size; /* check extension */ - if (!check_extensions(streamFile, "dspw")) + if (!check_extensions(sf, "dspw")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x44535057) /* "DSPW" */ + if (read_32bitBE(0x00,sf) != 0x44535057) /* "DSPW" */ goto fail; /* ignore time marker */ - data_size = read_32bitBE(0x08, streamFile); - if (read_32bitBE(data_size - 0x10, streamFile) == 0x74494D45) /* "tIME" */ + data_size = read_32bitBE(0x08, sf); + if (read_32bitBE(data_size - 0x10, sf) == 0x74494D45) /* "tIME" */ data_size -= 0x10; /* (ignore, 2 ints in YYYYMMDD hhmmss00) */ /* some files have a mrkr section with multiple loop regions added at the end (variable size) */ @@ -966,7 +966,7 @@ VGMSTREAM * init_vgmstream_dsp_dspw(STREAMFILE *streamFile) { off_t mrkr_offset = data_size - 0x04; off_t max_offset = data_size - 0x1000; while (mrkr_offset > max_offset) { - if (read_32bitBE(mrkr_offset, streamFile) != 0x6D726B72) { /* "mrkr" */ + if (read_32bitBE(mrkr_offset, sf) != 0x6D726B72) { /* "mrkr" */ mrkr_offset -= 0x04; } else { data_size = mrkr_offset; @@ -977,7 +977,7 @@ VGMSTREAM * init_vgmstream_dsp_dspw(STREAMFILE *streamFile) { data_size -= 0x20; /* header size */ /* 0x10: loop start, 0x14: loop end, 0x1c: num_samples */ - dspm.channel_count = read_32bitBE(0x18, streamFile); + dspm.channel_count = read_32bitBE(0x18, sf); dspm.max_channels = 6; /* 6ch in Monster Hunter 3 Ultimate */ dspm.header_offset = 0x20; @@ -986,74 +986,74 @@ VGMSTREAM * init_vgmstream_dsp_dspw(STREAMFILE *streamFile) { dspm.interleave = data_size / dspm.channel_count; dspm.meta_type = meta_DSP_DSPW; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* iadp - custom header + interleaved dsp [Dr. Muto (GC)] */ -VGMSTREAM * init_vgmstream_ngc_dsp_iadp(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_ngc_dsp_iadp(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ /* .adp: actual extension, .iadp: header id */ - if (!check_extensions(streamFile, "adp,iadp")) + if (!check_extensions(sf, "adp,iadp")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x69616470) /* "iadp" */ + if (read_32bitBE(0x00,sf) != 0x69616470) /* "iadp" */ goto fail; - dspm.channel_count = read_32bitBE(0x04,streamFile); + dspm.channel_count = read_32bitBE(0x04,sf); dspm.max_channels = 2; dspm.header_offset = 0x20; dspm.header_spacing = 0x60; - dspm.start_offset = read_32bitBE(0x1C,streamFile); - dspm.interleave = read_32bitBE(0x08,streamFile); + dspm.start_offset = read_32bitBE(0x1C,sf); + dspm.interleave = read_32bitBE(0x08,sf); dspm.meta_type = meta_NGC_DSP_IADP; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* .mcadpcm - Custom header + full interleaved dsp [Skyrim (Switch)] */ -VGMSTREAM * init_vgmstream_dsp_mcadpcm(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_dsp_mcadpcm(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ - if (!check_extensions(streamFile, "mcadpcm")) + if (!check_extensions(sf, "mcadpcm")) goto fail; /* could validate dsp sizes but only for +1ch, check_dsp_samples will do it anyway */ - //if (read_32bitLE(0x08,streamFile) != read_32bitLE(0x10,streamFile)) + //if (read_32bitLE(0x08,sf) != read_32bitLE(0x10,sf)) // goto fail; - dspm.channel_count = read_32bitLE(0x00,streamFile); + dspm.channel_count = read_32bitLE(0x00,sf); dspm.max_channels = 2; dspm.little_endian = 1; - dspm.header_offset = read_32bitLE(0x04,streamFile); + dspm.header_offset = read_32bitLE(0x04,sf); dspm.header_spacing = dspm.channel_count == 1 ? 0 : - read_32bitLE(0x0c,streamFile) - dspm.header_offset; /* channel 2 start, only with Nch */ + read_32bitLE(0x0c,sf) - dspm.header_offset; /* channel 2 start, only with Nch */ dspm.start_offset = dspm.header_offset + 0x60; dspm.interleave = dspm.header_spacing; dspm.meta_type = meta_DSP_MCADPCM; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* .switch_audio - UE4 standard LE header + full interleaved dsp [Gal Gun 2 (Switch)] */ -VGMSTREAM * init_vgmstream_dsp_switch_audio(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_dsp_switch_audio(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ /* .switch_audio: possibly UE4 class name rather than extension, .dsp: assumed */ - if (!check_extensions(streamFile, "switch_audio,dsp")) + if (!check_extensions(sf, "switch_audio,dsp")) goto fail; /* manual double header test */ - if (read_32bitLE(0x00, streamFile) == read_32bitLE(get_streamfile_size(streamFile) / 2, streamFile)) + if (read_32bitLE(0x00, sf) == read_32bitLE(get_streamfile_size(sf) / 2, sf)) dspm.channel_count = 2; else dspm.channel_count = 1; @@ -1061,28 +1061,28 @@ VGMSTREAM * init_vgmstream_dsp_switch_audio(STREAMFILE *streamFile) { dspm.little_endian = 1; dspm.header_offset = 0x00; - dspm.header_spacing = get_streamfile_size(streamFile) / dspm.channel_count; + dspm.header_spacing = get_streamfile_size(sf) / dspm.channel_count; dspm.start_offset = dspm.header_offset + 0x60; dspm.interleave = dspm.header_spacing; dspm.meta_type = meta_DSP_SWITCH_AUDIO; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* .vag - Nippon Ichi SPS wrapper [Penny-Punching Princess (Switch), Ys VIII (Switch)] */ -VGMSTREAM * init_vgmstream_dsp_sps_n1(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_dsp_sps_n1(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ /* .vag: Penny-Punching Princess (Switch) * .nlsd: Ys VIII (Switch) */ - if (!check_extensions(streamFile, "vag,nlsd")) + if (!check_extensions(sf, "vag,nlsd")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x08000000) /* file type (see other N1 SPS) */ + if (read_32bitBE(0x00,sf) != 0x08000000) /* file type (see other N1 SPS) */ goto fail; - if ((uint16_t)read_16bitLE(0x08,streamFile) != read_32bitLE(0x24,streamFile)) /* header has various repeated values */ + if ((uint16_t)read_16bitLE(0x08,sf) != read_32bitLE(0x24,sf)) /* header has various repeated values */ goto fail; dspm.channel_count = 1; @@ -1097,17 +1097,17 @@ VGMSTREAM * init_vgmstream_dsp_sps_n1(STREAMFILE *streamFile) { dspm.fix_loop_start = 1; dspm.meta_type = meta_DSP_VAG; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* .itl - from Chanrinko Hero (GC) */ -VGMSTREAM * init_vgmstream_dsp_itl_ch(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_dsp_itl_ch(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ - if (!check_extensions(streamFile, "itl")) + if (!check_extensions(sf, "itl")) goto fail; dspm.channel_count = 2; @@ -1121,26 +1121,26 @@ VGMSTREAM * init_vgmstream_dsp_itl_ch(STREAMFILE *streamFile) { dspm.fix_looping = 1; dspm.meta_type = meta_DSP_ITL; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* ADPY - AQUASTYLE wrapper [Touhou Genso Wanderer -Reloaded- (Switch)] */ -VGMSTREAM * init_vgmstream_dsp_adpy(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_dsp_adpy(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ - if (!check_extensions(streamFile, "adpcmx")) + if (!check_extensions(sf, "adpcmx")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x41445059) /* "ADPY" */ + if (read_32bitBE(0x00,sf) != 0x41445059) /* "ADPY" */ goto fail; /* 0x04(2): 1? */ /* 0x08: some size? */ /* 0x0c: null */ - dspm.channel_count = read_16bitLE(0x06,streamFile); + dspm.channel_count = read_16bitLE(0x06,sf); dspm.max_channels = 2; dspm.little_endian = 1; @@ -1150,56 +1150,56 @@ VGMSTREAM * init_vgmstream_dsp_adpy(STREAMFILE *streamFile) { dspm.interleave = 0x08; dspm.meta_type = meta_DSP_ADPY; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* ADPX - AQUASTYLE wrapper [Fushigi no Gensokyo: Lotus Labyrinth (Switch)] */ -VGMSTREAM * init_vgmstream_dsp_adpx(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_dsp_adpx(STREAMFILE* sf) { dsp_meta dspm = {0}; /* checks */ - if (!check_extensions(streamFile, "adpcmx")) + if (!check_extensions(sf, "adpcmx")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x41445058) /* "ADPX" */ + if (read_32bitBE(0x00,sf) != 0x41445058) /* "ADPX" */ goto fail; /* from 0x04 *6 are probably channel sizes, so max would be 6ch; this assumes 2ch */ - if (read_32bitLE(0x04,streamFile) != read_32bitLE(0x08,streamFile) && - read_32bitLE(0x0c,streamFile) != 0) + if (read_32bitLE(0x04,sf) != read_32bitLE(0x08,sf) && + read_32bitLE(0x0c,sf) != 0) goto fail; dspm.channel_count = 2; dspm.max_channels = 2; dspm.little_endian = 1; dspm.header_offset = 0x1c; - dspm.header_spacing = read_32bitLE(0x04,streamFile); + dspm.header_spacing = read_32bitLE(0x04,sf); dspm.start_offset = dspm.header_offset + 0x60; dspm.interleave = dspm.header_spacing; dspm.meta_type = meta_DSP_ADPX; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* .ds2 - LucasArts wrapper [Star Wars: Bounty Hunter (GC)] */ -VGMSTREAM * init_vgmstream_dsp_ds2(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_dsp_ds2(STREAMFILE* sf) { dsp_meta dspm = {0}; size_t file_size, channel_offset; /* checks */ /* .ds2: real extension, dsp: fake/renamed */ - if (!check_extensions(streamFile, "ds2,dsp")) + if (!check_extensions(sf, "ds2,dsp")) goto fail; - if (!(read_32bitBE(0x50,streamFile) == 0 && - read_32bitBE(0x54,streamFile) == 0 && - read_32bitBE(0x58,streamFile) == 0 && - read_32bitBE(0x5c,streamFile) != 0)) + if (!(read_32bitBE(0x50,sf) == 0 && + read_32bitBE(0x54,sf) == 0 && + read_32bitBE(0x58,sf) == 0 && + read_32bitBE(0x5c,sf) != 0)) goto fail; - file_size = get_streamfile_size(streamFile); - channel_offset = read_32bitBE(0x5c,streamFile); /* absolute offset to 2nd channel */ + file_size = get_streamfile_size(sf); + channel_offset = read_32bitBE(0x5c,sf); /* absolute offset to 2nd channel */ if (channel_offset < file_size / 2 || channel_offset > file_size) /* just to make sure */ goto fail; @@ -1213,23 +1213,23 @@ VGMSTREAM * init_vgmstream_dsp_ds2(STREAMFILE *streamFile) { dspm.interleave = channel_offset - dspm.start_offset; dspm.meta_type = meta_DSP_DS2; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } /* .itl - Incinerator Studios interleaved dsp [Cars Race-o-rama (Wii), MX vs ATV Untamed (Wii)] */ -VGMSTREAM * init_vgmstream_dsp_itl(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_dsp_itl(STREAMFILE* sf) { dsp_meta dspm = {0}; size_t stream_size; /* checks */ /* .itl: standard * .dsp: default to catch a similar file, not sure which devs */ - if (!check_extensions(streamFile, "itl,dsp")) + if (!check_extensions(sf, "itl,dsp")) goto fail; - stream_size = get_streamfile_size(streamFile); + stream_size = get_streamfile_size(sf); dspm.channel_count = 2; dspm.max_channels = 2; @@ -1244,7 +1244,37 @@ VGMSTREAM * init_vgmstream_dsp_itl(STREAMFILE *streamFile) { //todo some files end in half a frame and may click at the very end //todo when .dsp should refer to Ultimate Board Collection (Wii), not sure about dev dspm.meta_type = meta_DSP_ITL_i; - return init_vgmstream_dsp_common(streamFile, &dspm); + return init_vgmstream_dsp_common(sf, &dspm); +fail: + return NULL; +} + +/* .wav - Square Enix wrapper [Dragon Quest I-III (Switch)] */ +VGMSTREAM* init_vgmstream_dsp_sqex(STREAMFILE* sf) { + dsp_meta dspm = {0}; + + /* checks */ + if (!check_extensions(sf, "wav,lwav")) + goto fail; + if (read_u32be(0x00,sf) != 0x00000000) + goto fail; + + dspm.channel_count = read_u32le(0x04,sf); + dspm.header_offset = read_u32le(0x08,sf); + /* 0x0c: channel size */ + dspm.start_offset = dspm.header_offset + 0x60; + + if (dspm.channel_count > 1) { + dspm.interleave = read_u32le(0x10,sf) - dspm.header_offset; + dspm.header_spacing = dspm.interleave; + } + + + dspm.max_channels = 2; + dspm.little_endian = 1; + + dspm.meta_type = meta_DSP_SQEX; + return init_vgmstream_dsp_common(sf, &dspm); fail: return NULL; } diff --git a/src/meta/opus.c b/src/meta/opus.c index 932ecef2..e3b9769a 100644 --- a/src/meta/opus.c +++ b/src/meta/opus.c @@ -5,32 +5,32 @@ /* Nintendo OPUS - from Switch games, including header variations (not the same as Ogg Opus) */ -static VGMSTREAM * init_vgmstream_opus(STREAMFILE *streamFile, meta_t meta_type, off_t offset, int32_t num_samples, int32_t loop_start, int32_t loop_end) { - VGMSTREAM * vgmstream = NULL; +static VGMSTREAM* init_vgmstream_opus(STREAMFILE* sf, meta_t meta_type, off_t offset, int32_t num_samples, int32_t loop_start, int32_t loop_end) { + VGMSTREAM* vgmstream = NULL; off_t start_offset; int loop_flag = 0, channel_count; off_t data_offset, multichannel_offset = 0; size_t data_size, skip = 0; - if ((uint32_t)read_32bitLE(offset + 0x00,streamFile) != 0x80000001) + if ((uint32_t)read_32bitLE(offset + 0x00,sf) != 0x80000001) goto fail; - channel_count = read_8bit(offset + 0x09, streamFile); + channel_count = read_8bit(offset + 0x09, sf); /* 0x0a: packet size if CBR, 0 if VBR */ - data_offset = offset + read_32bitLE(offset + 0x10, streamFile); - skip = read_16bitLE(offset + 0x1c, streamFile); + data_offset = offset + read_32bitLE(offset + 0x10, sf); + skip = read_16bitLE(offset + 0x1c, sf); /* 0x1e: ? (seen in Lego Movie 2 (Switch)) */ /* recent >2ch info [Clannad (Switch)] */ - if ((uint32_t)read_32bitLE(offset + 0x20, streamFile) == 0x80000005) { + if ((uint32_t)read_32bitLE(offset + 0x20, sf) == 0x80000005) { multichannel_offset = offset + 0x20; } - if ((uint32_t)read_32bitLE(data_offset, streamFile) != 0x80000004) + if ((uint32_t)read_32bitLE(data_offset, sf) != 0x80000004) goto fail; - data_size = read_32bitLE(data_offset + 0x04, streamFile); + data_size = read_32bitLE(data_offset + 0x04, sf); start_offset = data_offset + 0x08; loop_flag = (loop_end > 0); /* -1 when not set */ @@ -41,7 +41,7 @@ static VGMSTREAM * init_vgmstream_opus(STREAMFILE *streamFile, meta_t meta_type, if (!vgmstream) goto fail; vgmstream->meta_type = meta_type; - vgmstream->sample_rate = read_32bitLE(offset + 0x0c,streamFile); + vgmstream->sample_rate = read_32bitLE(offset + 0x0c,sf); if (vgmstream->sample_rate == 16000) vgmstream->sample_rate = 48000; // Grandia HD Collection contains a false sample_rate in header vgmstream->num_samples = num_samples; @@ -59,28 +59,28 @@ static VGMSTREAM * init_vgmstream_opus(STREAMFILE *streamFile, meta_t meta_type, if (multichannel_offset && vgmstream->channels <= 8) { int i; - cfg.stream_count = read_8bit(multichannel_offset + 0x08,streamFile); - cfg.coupled_count = read_8bit(multichannel_offset + 0x09,streamFile); + cfg.stream_count = read_8bit(multichannel_offset + 0x08,sf); + cfg.coupled_count = read_8bit(multichannel_offset + 0x09,sf); for (i = 0; i < vgmstream->channels; i++) { - cfg.channel_mapping[i] = read_8bit(multichannel_offset + 0x0a + i,streamFile); + cfg.channel_mapping[i] = read_8bit(multichannel_offset + 0x0a + i,sf); } } - vgmstream->codec_data = init_ffmpeg_switch_opus_config(streamFile, start_offset,data_size, &cfg); + vgmstream->codec_data = init_ffmpeg_switch_opus_config(sf, start_offset,data_size, &cfg); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; vgmstream->channel_layout = ffmpeg_get_channel_layout(vgmstream->codec_data); if (vgmstream->num_samples == 0) { - vgmstream->num_samples = switch_opus_get_samples(start_offset, data_size, streamFile) - skip; + vgmstream->num_samples = switch_opus_get_samples(start_offset, data_size, sf) - skip; } } #else goto fail; #endif - if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + if ( !vgmstream_open_stream(vgmstream, sf, start_offset) ) goto fail; return vgmstream; @@ -91,20 +91,20 @@ fail: /* standard Switch Opus, Nintendo header + raw data (generated by opus_test.c?) [Lego City Undercover (Switch)] */ -VGMSTREAM * init_vgmstream_opus_std(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_opus_std(STREAMFILE* sf) { STREAMFILE * PSIFile = NULL; off_t offset; int num_samples, loop_start, loop_end; /* checks */ - if (!check_extensions(streamFile,"opus,lopus")) + if (!check_extensions(sf,"opus,lopus")) goto fail; offset = 0x00; /* BlazBlue: Cross Tag Battle (Switch) PSI Metadata for corresponding Opus */ /* Maybe future Arc System Works games will use this too? */ - PSIFile = open_streamfile_by_ext(streamFile, "psi"); + PSIFile = open_streamfile_by_ext(sf, "psi"); if (PSIFile) { num_samples = read_32bitLE(0x8C, PSIFile); loop_start = read_32bitLE(0x84, PSIFile); @@ -117,56 +117,56 @@ VGMSTREAM * init_vgmstream_opus_std(STREAMFILE *streamFile) { loop_end = 0; } - return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples,loop_start,loop_end); + return init_vgmstream_opus(sf, meta_OPUS, offset, num_samples,loop_start,loop_end); fail: return NULL; } /* Nippon1 variation [Disgaea 5 (Switch)] */ -VGMSTREAM * init_vgmstream_opus_n1(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_opus_n1(STREAMFILE* sf) { off_t offset; int num_samples, loop_start, loop_end; /* checks */ - if ( !check_extensions(streamFile,"opus,lopus")) + if ( !check_extensions(sf,"opus,lopus")) goto fail; - if (!((read_32bitBE(0x04,streamFile) == 0x00000000 && read_32bitBE(0x0c,streamFile) == 0x00000000) || - (read_32bitBE(0x04,streamFile) == 0xFFFFFFFF && read_32bitBE(0x0c,streamFile) == 0xFFFFFFFF))) + if (!((read_32bitBE(0x04,sf) == 0x00000000 && read_32bitBE(0x0c,sf) == 0x00000000) || + (read_32bitBE(0x04,sf) == 0xFFFFFFFF && read_32bitBE(0x0c,sf) == 0xFFFFFFFF))) goto fail; offset = 0x10; num_samples = 0; - loop_start = read_32bitLE(0x00,streamFile); - loop_end = read_32bitLE(0x08,streamFile); + loop_start = read_32bitLE(0x00,sf); + loop_end = read_32bitLE(0x08,sf); - return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples,loop_start,loop_end); + return init_vgmstream_opus(sf, meta_OPUS, offset, num_samples,loop_start,loop_end); fail: return NULL; } /* Capcom variation [Ultra Street Fighter II (Switch), Resident Evil: Revelations (Switch)] */ -VGMSTREAM * init_vgmstream_opus_capcom(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_opus_capcom(STREAMFILE* sf) { VGMSTREAM *vgmstream = NULL; off_t offset; int num_samples, loop_start, loop_end; int channel_count; /* checks */ - if ( !check_extensions(streamFile,"opus,lopus")) + if ( !check_extensions(sf,"opus,lopus")) goto fail; - channel_count = read_32bitLE(0x04,streamFile); + channel_count = read_32bitLE(0x04,sf); if (channel_count != 1 && channel_count != 2 && channel_count != 6) goto fail; /* unknown stream layout */ - num_samples = read_32bitLE(0x00,streamFile); + num_samples = read_32bitLE(0x00,sf); /* 0x04: channels, >2 uses interleaved streams (2ch+2ch+2ch) */ - loop_start = read_32bitLE(0x08,streamFile); - loop_end = read_32bitLE(0x0c,streamFile); + loop_start = read_32bitLE(0x08,sf); + loop_end = read_32bitLE(0x0c,sf); /* 0x10: frame size (with extra data) */ /* 0x14: extra chunk count */ /* 0x18: null */ - offset = read_32bitLE(0x1c,streamFile); + offset = read_32bitLE(0x1c,sf); /* 0x20-8: config? (0x0077C102 04000000 E107070C) */ /* 0x2c: some size? */ /* 0x30+: extra chunks (0x00: 0x7f, 0x04: num_sample), alt loop starts/regions? */ @@ -193,7 +193,7 @@ VGMSTREAM * init_vgmstream_opus_capcom(STREAMFILE *streamFile) { /* open each layer subfile */ for (i = 0; i < layers; i++) { - STREAMFILE* temp_sf = setup_opus_interleave_streamfile(streamFile, offset, i, layers); + STREAMFILE* temp_sf = setup_opus_interleave_streamfile(sf, offset, i, layers); if (!temp_sf) goto fail; data->layers[i] = init_vgmstream_opus(temp_sf, meta_OPUS, 0x00, num_samples,loop_start,loop_end); @@ -215,7 +215,7 @@ VGMSTREAM * init_vgmstream_opus_capcom(STREAMFILE *streamFile) { return vgmstream; } else { - return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples,loop_start,loop_end); + return init_vgmstream_opus(sf, meta_OPUS, offset, num_samples,loop_start,loop_end); } @@ -225,85 +225,85 @@ fail: } /* Procyon Studio variation [Xenoblade Chronicles 2 (Switch)] */ -VGMSTREAM * init_vgmstream_opus_nop(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_opus_nop(STREAMFILE* sf) { off_t offset; int num_samples, loop_start = 0, loop_end = 0, loop_flag; /* checks */ - if (!check_extensions(streamFile,"nop")) + if (!check_extensions(sf,"nop")) goto fail; - if (read_32bitBE(0x00, streamFile) != 0x73616466 || /* "sadf" */ - read_32bitBE(0x08, streamFile) != 0x6f707573) /* "opus" */ + if (read_32bitBE(0x00, sf) != 0x73616466 || /* "sadf" */ + read_32bitBE(0x08, sf) != 0x6f707573) /* "opus" */ goto fail; - offset = read_32bitLE(0x1c, streamFile); - num_samples = read_32bitLE(0x28, streamFile); - loop_flag = read_8bit(0x19, streamFile); + offset = read_32bitLE(0x1c, sf); + num_samples = read_32bitLE(0x28, sf); + loop_flag = read_8bit(0x19, sf); if (loop_flag) { - loop_start = read_32bitLE(0x2c, streamFile); - loop_end = read_32bitLE(0x30, streamFile); + loop_start = read_32bitLE(0x2c, sf); + loop_end = read_32bitLE(0x30, sf); } - return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples,loop_start,loop_end); + return init_vgmstream_opus(sf, meta_OPUS, offset, num_samples,loop_start,loop_end); fail: return NULL; } /* Shin'en variation [Fast RMX (Switch)] */ -VGMSTREAM * init_vgmstream_opus_shinen(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_opus_shinen(STREAMFILE* sf) { off_t offset = 0; int num_samples, loop_start, loop_end; /* checks */ - if ( !check_extensions(streamFile,"opus,lopus")) + if ( !check_extensions(sf,"opus,lopus")) goto fail; - if (read_32bitBE(0x08,streamFile) != 0x01000080) + if (read_32bitBE(0x08,sf) != 0x01000080) goto fail; offset = 0x08; num_samples = 0; - loop_start = read_32bitLE(0x00,streamFile); - loop_end = read_32bitLE(0x04,streamFile); /* 0 if no loop */ + loop_start = read_32bitLE(0x00,sf); + loop_end = read_32bitLE(0x04,sf); /* 0 if no loop */ if (loop_start > loop_end) goto fail; /* just in case */ - return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples,loop_start,loop_end); + return init_vgmstream_opus(sf, meta_OPUS, offset, num_samples,loop_start,loop_end); fail: return NULL; } /* Bandai Namco Opus (found in NUS3Banks) [Taiko no Tatsujin: Nintendo Switch Version!] */ -VGMSTREAM * init_vgmstream_opus_nus3(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_opus_nus3(STREAMFILE* sf) { off_t offset = 0; int num_samples = 0, loop_start = 0, loop_end = 0, loop_flag; /* checks */ /* .opus: header ID (they only exist inside .nus3bank) */ - if (!check_extensions(streamFile, "opus,lopus")) + if (!check_extensions(sf, "opus,lopus")) goto fail; - if (read_32bitBE(0x00, streamFile) != 0x4F505553) /* "OPUS" */ + if (read_32bitBE(0x00, sf) != 0x4F505553) /* "OPUS" */ goto fail; /* Here's an interesting quirk, OPUS header contains big endian values while the Nintendo Opus header and data that follows remain little endian as usual */ - offset = read_32bitBE(0x20, streamFile); - num_samples = read_32bitBE(0x08, streamFile); + offset = read_32bitBE(0x20, sf); + num_samples = read_32bitBE(0x08, sf); /* Check if there's a loop end value to determine loop_flag*/ - loop_flag = read_32bitBE(0x18, streamFile); + loop_flag = read_32bitBE(0x18, sf); if (loop_flag) { - loop_start = read_32bitBE(0x14, streamFile); - loop_end = read_32bitBE(0x18, streamFile); + loop_start = read_32bitBE(0x14, sf); + loop_end = read_32bitBE(0x18, sf); } - return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples, loop_start, loop_end); + return init_vgmstream_opus(sf, meta_OPUS, offset, num_samples, loop_start, loop_end); fail: return NULL; } /* Nippon Ichi SPS wrapper (non-segmented) [Ys VIII: Lacrimosa of Dana (Switch)] */ -VGMSTREAM * init_vgmstream_opus_sps_n1(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_opus_sps_n1(STREAMFILE* sf) { off_t offset; int num_samples, loop_start = 0, loop_end = 0, loop_flag; @@ -311,28 +311,28 @@ VGMSTREAM * init_vgmstream_opus_sps_n1(STREAMFILE *streamFile) { /* .sps: Labyrinth of Refrain: Coven of Dusk (Switch) * .nlsd: Disgaea Refine (Switch), Ys VIII (Switch) * .at9: void tRrLM(); //Void Terrarium (Switch) */ - if (!check_extensions(streamFile, "sps,nlsd,at9")) + if (!check_extensions(sf, "sps,nlsd,at9")) goto fail; - if (read_32bitBE(0x00, streamFile) != 0x09000000) /* file type (see other N1 SPS) */ + if (read_32bitBE(0x00, sf) != 0x09000000) /* file type (see other N1 SPS) */ goto fail; - num_samples = read_32bitLE(0x0C, streamFile); + num_samples = read_32bitLE(0x0C, sf); - if (read_32bitBE(0x1c, streamFile) == 0x01000080) { + if (read_32bitBE(0x1c, sf) == 0x01000080) { offset = 0x1C; /* older games loop section (remnant of segmented opus_sps_n1): */ - loop_start = read_32bitLE(0x10, streamFile); /* intro samples */ - loop_end = loop_start + read_32bitLE(0x14, streamFile); /* loop samples */ + loop_start = read_32bitLE(0x10, sf); /* intro samples */ + loop_end = loop_start + read_32bitLE(0x14, sf); /* loop samples */ /* 0x18: end samples (all must add up to num_samples) */ - loop_flag = read_32bitLE(0x18, streamFile); /* with loop disabled only loop_end has a value */ + loop_flag = read_32bitLE(0x18, sf); /* with loop disabled only loop_end has a value */ } else { offset = 0x18; /* newer games loop section: */ - loop_start = read_32bitLE(0x10, streamFile); - loop_end = read_32bitLE(0x14, streamFile); + loop_start = read_32bitLE(0x10, sf); + loop_end = read_32bitLE(0x14, sf); loop_flag = loop_start != loop_end; /* with loop disabled start and end are the same as num samples */ } @@ -341,29 +341,29 @@ VGMSTREAM * init_vgmstream_opus_sps_n1(STREAMFILE *streamFile) { loop_end = 0; } - return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples, loop_start, loop_end); + return init_vgmstream_opus(sf, meta_OPUS, offset, num_samples, loop_start, loop_end); fail: return NULL; } /* AQUASTYLE wrapper [Touhou Genso Wanderer -Reloaded- (Switch)] */ -VGMSTREAM * init_vgmstream_opus_opusx(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_opus_opusx(STREAMFILE* sf) { off_t offset; int num_samples, loop_start = 0, loop_end = 0; float modifier; /* checks */ - if (!check_extensions(streamFile, "opusx")) + if (!check_extensions(sf, "opusx")) goto fail; - if (read_32bitBE(0x00, streamFile) != 0x4F505553) /* "OPUS" */ + if (read_32bitBE(0x00, sf) != 0x4F505553) /* "OPUS" */ goto fail; offset = 0x10; /* values are for the original 44100 files, but Opus resamples to 48000 */ modifier = 48000.0f / 44100.0f; - num_samples = 0;//read_32bitLE(0x04, streamFile) * modifier; /* better use calc'd num_samples */ - loop_start = read_32bitLE(0x08, streamFile) * modifier; - loop_end = read_32bitLE(0x0c, streamFile) * modifier; + num_samples = 0;//read_32bitLE(0x04, sf) * modifier; /* better use calc'd num_samples */ + loop_start = read_32bitLE(0x08, sf) * modifier; + loop_end = read_32bitLE(0x0c, sf) * modifier; /* resampling calcs are slighly off and may to over num_samples, but by removing delay seems ok */ if (loop_start >= 120) { @@ -374,81 +374,83 @@ VGMSTREAM * init_vgmstream_opus_opusx(STREAMFILE *streamFile) { loop_end = 0; } - return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples, loop_start, loop_end); + return init_vgmstream_opus(sf, meta_OPUS, offset, num_samples, loop_start, loop_end); fail: return NULL; } /* Prototype variation [Clannad (Switch)] */ -VGMSTREAM * init_vgmstream_opus_prototype(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_opus_prototype(STREAMFILE* sf) { off_t offset = 0; int num_samples = 0, loop_start = 0, loop_end = 0, loop_flag; /* checks */ - if (!check_extensions(streamFile, "opus,lopus")) + if (!check_extensions(sf, "opus,lopus")) goto fail; - if (read_32bitBE(0x00, streamFile) != 0x4F505553 || /* "OPUS" */ - read_32bitBE(0x18, streamFile) != 0x01000080) + if (read_32bitBE(0x00, sf) != 0x4F505553 || /* "OPUS" */ + read_32bitBE(0x18, sf) != 0x01000080) goto fail; offset = 0x18; - num_samples = read_32bitLE(0x08, streamFile); + num_samples = read_32bitLE(0x08, sf); /* Check if there's a loop end value to determine loop_flag*/ - loop_flag = read_32bitLE(0x10, streamFile); + loop_flag = read_32bitLE(0x10, sf); if (loop_flag) { - loop_start = read_32bitLE(0x0C, streamFile); - loop_end = read_32bitLE(0x10, streamFile); + loop_start = read_32bitLE(0x0C, sf); + loop_end = read_32bitLE(0x10, sf); } - return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples, loop_start, loop_end); + return init_vgmstream_opus(sf, meta_OPUS, offset, num_samples, loop_start, loop_end); fail: return NULL; } /* Edelweiss variation [Astebreed (Switch)] */ -VGMSTREAM * init_vgmstream_opus_opusnx(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_opus_opusnx(STREAMFILE* sf) { off_t offset = 0; int num_samples = 0, loop_start = 0, loop_end = 0; /* checks */ - if (!check_extensions(streamFile, "opus,lopus")) + if (!check_extensions(sf, "opus,lopus")) goto fail; - if (read_64bitBE(0x00, streamFile) != 0x4F5055534E580000) /* "OPUSNX\0\0" */ + if (read_64bitBE(0x00, sf) != 0x4F5055534E580000) /* "OPUSNX\0\0" */ goto fail; offset = 0x10; - num_samples = 0; //read_32bitLE(0x08, streamFile); /* samples with encoder delay */ - if (read_32bitLE(0x0c, streamFile) != 0) + num_samples = 0; //read_32bitLE(0x08, sf); /* samples with encoder delay */ + if (read_32bitLE(0x0c, sf) != 0) goto fail; - return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples, loop_start, loop_end); + return init_vgmstream_opus(sf, meta_OPUS, offset, num_samples, loop_start, loop_end); fail: return NULL; } /* Square Enix variation [Dragon Quest I-III (Switch)] */ -VGMSTREAM * init_vgmstream_opus_sqex(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_opus_sqex(STREAMFILE* sf) { off_t offset = 0; int num_samples = 0, loop_start = 0, loop_end = 0, loop_flag; - + /* checks */ - if (!check_extensions(streamFile, "opus,lopus")) + /* .wav: default + * .opus: fake? */ + if (!check_extensions(sf, "wav,lwav,opus,lopus")) goto fail; - if (read_64bitBE(0x00, streamFile) != 0x0100000002000000) + if (read_u32be(0x00, sf) != 0x01000000) goto fail; - - offset = read_32bitLE(0x0C, streamFile); - num_samples = read_32bitLE(0x1C, streamFile); - - /* Check if there's a loop end value to determine loop_flag*/ - loop_flag = read_32bitLE(0x18, streamFile); + /* 0x04: channels */ + /* 0x08: data_size */ + offset = read_32bitLE(0x0C, sf); + num_samples = read_32bitLE(0x1C, sf); + + loop_flag = read_32bitLE(0x18, sf); if (loop_flag) { - loop_start = read_32bitLE(0x14, streamFile); - loop_end = read_32bitLE(0x18, streamFile); + loop_start = read_32bitLE(0x14, sf); + loop_end = read_32bitLE(0x18, sf); } - - return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples, loop_start, loop_end); + + return init_vgmstream_opus(sf, meta_OPUS, offset, num_samples, loop_start, loop_end); fail: return NULL; } diff --git a/src/vgmstream.c b/src/vgmstream.c index 0e8c162f..9b27442f 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -512,6 +512,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_xse_new, init_vgmstream_xse_old, init_vgmstream_wady, + init_vgmstream_dsp_sqex, /* 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 6f996a4a..ce533fd9 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -741,6 +741,7 @@ typedef enum { meta_ADP_KONAMI, meta_SDRH, meta_WADY, + meta_DSP_SQEX, } meta_t; /* standard WAVEFORMATEXTENSIBLE speaker positions */