diff --git a/Frameworks/vgmstream/vgmstream/ext_libs/celt/celt_fsb.h b/Frameworks/vgmstream/vgmstream/ext_includes/celt/celt_fsb.h similarity index 77% rename from Frameworks/vgmstream/vgmstream/ext_libs/celt/celt_fsb.h rename to Frameworks/vgmstream/vgmstream/ext_includes/celt/celt_fsb.h index 3dca7fb9e..3c1cfaac3 100644 --- a/Frameworks/vgmstream/vgmstream/ext_libs/celt/celt_fsb.h +++ b/Frameworks/vgmstream/vgmstream/ext_includes/celt/celt_fsb.h @@ -57,15 +57,15 @@ /** State of the decoder. One decoder state is needed for each stream. It is initialised once at the beginning of the stream. Do *not* re-initialise the state for every frame */ -typedef struct CELT0061Decoder CELT0061Decoder; -typedef struct CELT0110Decoder CELT0110Decoder; +typedef struct CELTDecoder0061 CELTDecoder0061; +typedef struct CELTDecoder CELTDecoder0110; /** The mode contains all the information necessary to create an encoder. Both the encoder and decoder need to be initialised with exactly the same mode, otherwise the quality will be very bad */ -typedef struct CELT0061Mode CELT0061Mode; -typedef struct CELT0110Mode CELT0110Mode; +typedef struct CELTMode0061 CELTMode0061; +typedef struct CELTMode0110 CELTMode0110; /* Mode calls */ @@ -80,19 +80,19 @@ typedef struct CELT0110Mode CELT0110Mode; @param error Returned error code (if NULL, no error will be returned) @return A newly created mode */ -EXPORT CELT0061Mode *celt_0061_mode_create(celt_int32 Fs, int channels, int frame_size, int *error); -EXPORT CELT0110Mode *celt_0110_mode_create(celt_int32 Fs, int frame_size, int *error); +/*EXPORT*/ CELTMode0061 *celt_mode_create_0061(celt_int32 Fs, int channels, int frame_size, int *error); +/*EXPORT*/ CELTMode0110 *celt_mode_create_0110(celt_int32 Fs, int frame_size, int *error); /** Destroys a mode struct. Only call this after all encoders and decoders using this mode are destroyed as well. @param mode Mode to be destroyed */ -EXPORT void celt_0061_mode_destroy(CELT0061Mode *mode); -EXPORT void celt_0110_mode_destroy(CELT0110Mode *mode); +/*EXPORT*/ void celt_mode_destroy_0061(CELTMode0061 *mode); +/*EXPORT*/ void celt_mode_destroy_0110(CELTMode0110 *mode); /** Query information from a mode */ -EXPORT int celt_0061_mode_info(const CELT0061Mode *mode, int request, celt_int32 *value); -EXPORT int celt_0110_mode_info(const CELT0110Mode *mode, int request, celt_int32 *value); +/*EXPORT*/ int celt_mode_info_0061(const CELTMode0061 *mode, int request, celt_int32 *value); +/*EXPORT*/ int celt_mode_info_0110(const CELTMode0110 *mode, int request, celt_int32 *value); /* Decoder stuff */ @@ -105,14 +105,14 @@ EXPORT int celt_0110_mode_info(const CELT0110Mode *mode, int request, celt_int32 @param error Returns an error code @return Newly created decoder state. */ -EXPORT CELT0061Decoder *celt_0061_decoder_create(const CELT0061Mode *mode); -EXPORT CELT0110Decoder *celt_0110_decoder_create_custom(const CELT0110Mode *mode, int channels, int *error); +/*EXPORT*/ CELTDecoder0061 *celt_decoder_create_0061(const CELTMode0061 *mode); +/*EXPORT*/ CELTDecoder0110 *celt_decoder_create_custom_0110(const CELTMode0110 *mode, int channels, int *error); /** Destroys a a decoder state. @param st Decoder state to be destroyed */ -EXPORT void celt_0061_decoder_destroy(CELT0061Decoder *st); -EXPORT void celt_0110_decoder_destroy(CELT0110Decoder *st); +/*EXPORT*/ void celt_decoder_destroy_0061(CELTDecoder0061 *st); +/*EXPORT*/ void celt_decoder_destroy_0110(CELTDecoder0110 *st); /** Decodes a frame of audio. @param st Decoder state @@ -123,8 +123,8 @@ EXPORT void celt_0110_decoder_destroy(CELT0110Decoder *st); returned here in 16-bit PCM format (native endian). @return Error code. */ -EXPORT int celt_0061_decode(CELT0061Decoder *st, const unsigned char *data, int len, celt_int16 *pcm); -EXPORT int celt_0110_decode(CELT0110Decoder *st, const unsigned char *data, int len, celt_int16 *pcm, int frame_size); +/*EXPORT*/ int celt_decode_0061(CELTDecoder0061 *st, const unsigned char *data, int len, celt_int16 *pcm); +/*EXPORT*/ int celt_decode_0110(CELTDecoder0110 *st, const unsigned char *data, int len, celt_int16 *pcm, int frame_size); diff --git a/Frameworks/vgmstream/vgmstream/ext_libs/celt/celt_types.h b/Frameworks/vgmstream/vgmstream/ext_includes/celt/celt_types.h similarity index 100% rename from Frameworks/vgmstream/vgmstream/ext_libs/celt/celt_types.h rename to Frameworks/vgmstream/vgmstream/ext_includes/celt/celt_types.h diff --git a/Frameworks/vgmstream/vgmstream/ext_libs/celt-0110/ecintrin.h b/Frameworks/vgmstream/vgmstream/ext_libs/celt-0110/ecintrin.h deleted file mode 100644 index 0348e6d75..000000000 --- a/Frameworks/vgmstream/vgmstream/ext_libs/celt-0110/ecintrin.h +++ /dev/null @@ -1,140 +0,0 @@ -/* Copyright (c) 2003-2008 Timothy B. Terriberry - Copyright (c) 2008 Xiph.Org Foundation */ -/* - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - - Neither the name of the Xiph.org Foundation nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/*Some common macros for potential platform-specific optimization.*/ -#include -#include -#if !defined(_ecintrin_H) -# define _ecintrin_H (1) - -/*Some specific platforms may have optimized intrinsic or inline assembly - versions of these functions which can substantially improve performance. - We define macros for them to allow easy incorporation of these non-ANSI - features.*/ - -/*Note that we do not provide a macro for abs(), because it is provided as a - library function, which we assume is translated into an intrinsic to avoid - the function call overhead and then implemented in the smartest way for the - target platform. - With modern gcc (4.x), this is true: it uses cmov instructions if the - architecture supports it and branchless bit-twiddling if it does not (the - speed difference between the two approaches is not measurable). - Interestingly, the bit-twiddling method was patented in 2000 (US 6,073,150) - by Sun Microsystems, despite prior art dating back to at least 1996: - http://web.archive.org/web/19961201174141/www.x86.org/ftp/articles/pentopt/PENTOPT.TXT - On gcc 3.x, however, our assumption is not true, as abs() is translated to a - conditional jump, which is horrible on deeply piplined architectures (e.g., - all consumer architectures for the past decade or more) when the sign cannot - be reliably predicted.*/ - -/*Modern gcc (4.x) can compile the naive versions of min and max with cmov if - given an appropriate architecture, but the branchless bit-twiddling versions - are just as fast, and do not require any special target architecture. - Earlier gcc versions (3.x) compiled both code to the same assembly - instructions, because of the way they represented ((_b)>(_a)) internally.*/ -#define EC_MAXI(_a,_b) ((_a)-((_a)-(_b)&-((_b)>(_a)))) -#define EC_MINI(_a,_b) ((_a)+((_b)-(_a)&-((_b)<(_a)))) -/*This has a chance of compiling branchless, and is just as fast as the - bit-twiddling method, which is slightly less portable, since it relies on a - sign-extended rightshift, which is not guaranteed by ANSI (but present on - every relevant platform).*/ -#define EC_SIGNI(_a) (((_a)>0)-((_a)<0)) -/*Slightly more portable than relying on a sign-extended right-shift (which is - not guaranteed by ANSI), and just as fast, since gcc (3.x and 4.x both) - compile it into the right-shift anyway.*/ -#define EC_SIGNMASK(_a) (-((_a)<0)) -/*Clamps an integer into the given range. - If _a>_c, then the lower bound _a is respected over the upper bound _c (this - behavior is required to meet our documented API behavior). - _a: The lower bound. - _b: The value to clamp. - _c: The upper boud.*/ -#define EC_CLAMPI(_a,_b,_c) (EC_MAXI(_a,EC_MINI(_b,_c))) - - -/*Count leading zeros. - This macro should only be used for implementing ec_ilog(), if it is defined. - All other code should use EC_ILOG() instead.*/ -#if defined(_MSC_VER) -# include -static __inline int ec_bsr(unsigned long _x){ - unsigned long ret; - _BitScanReverse(&ret,_x); - return (int)ret; -} -# define EC_CLZ0 (1) -# define EC_CLZ(_x) (-ec_bsr(_x)) -#elif defined(ENABLE_TI_DSPLIB) -# include "dsplib.h" -# define EC_CLZ0 (31) -# define EC_CLZ(_x) (_lnorm(x)) -#elif defined(__GNUC_PREREQ) -# if __GNUC_PREREQ(3,4) -# if INT_MAX>=2147483647 -# define EC_CLZ0 ((int)sizeof(unsigned)*CHAR_BIT) -# define EC_CLZ(_x) (__builtin_clz(_x)) -# elif LONG_MAX>=2147483647L -# define EC_CLZ0 ((int)sizeof(unsigned long)*CHAR_BIT) -# define EC_CLZ(_x) (__builtin_clzl(_x)) -# endif -# endif -#endif - -#if defined(EC_CLZ) -/*Note that __builtin_clz is not defined when _x==0, according to the gcc - documentation (and that of the BSR instruction that implements it on x86). - The majority of the time we can never pass it zero. - When we need to, it can be special cased.*/ -# define EC_ILOG(_x) (EC_CLZ0-EC_CLZ(_x)) -#else -static int ec_ilog2(celt_uint32 _v){ - int ret; - int m; - ret=!!_v; - m=!!(_v&0xFFFF0000)<<4; - _v>>=m; - ret|=m; - m=!!(_v&0xFF00)<<3; - _v>>=m; - ret|=m; - m=!!(_v&0xF0)<<2; - _v>>=m; - ret|=m; - m=!!(_v&0xC)<<1; - _v>>=m; - ret|=m; - ret+=!!(_v&0x2); - return ret; -} -# define EC_ILOG(_x) (ec_ilog2(_x)) -#endif - -#endif diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c index 35d013ded..cd7cae7d2 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c @@ -369,7 +369,7 @@ ffmpeg_codec_data* init_ffmpeg_header_offset_subsong(STREAMFILE* sf, uint8_t* he #if 0 /* derive info */ data->sampleRate = data->codecCtx->sample_rate; - data->channels = data->codecCtx->channels; + data->channels = data->codecCtx->ch_layout.nb_channels; //data->codecCtx->channels; data->bitrate = (int)(data->codecCtx->bit_rate); data->blockAlign = data->codecCtx->block_align; data->frameSize = data->codecCtx->frame_size; @@ -739,7 +739,11 @@ static void samples_dblp_to_s16(sample_t* obuf, double** inbuf, int ichs, int sa } static void copy_samples(ffmpeg_codec_data* data, sample_t* outbuf, int samples_to_do) { +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 24, 100) int channels = data->codecCtx->channels; +#else + int channels = data->codecCtx->ch_layout.nb_channels; +#endif int is_planar = av_sample_fmt_is_planar(data->codecCtx->sample_fmt) && (channels > 1); void* ibuf; @@ -976,19 +980,39 @@ void ffmpeg_set_skip_samples(ffmpeg_codec_data* data, int skip_samples) { /* returns channel layout if set */ uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data* data) { if (!data || !data->codecCtx) return 0; - return (uint32_t)data->codecCtx->channel_layout; /* uint64 but there ain't so many speaker mappings */ + +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 24, 100) + /* uint64 but there aren't so many speaker mappings */ + return (uint32_t)data->codecCtx->channel_layout; +#else + /* new API is not very clear so maybe there is a better way */ + if (data->codecCtx->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) + return 0; + if (data->codecCtx->ch_layout.order == AV_CHANNEL_ORDER_NATIVE) { + return (uint32_t)data->codecCtx->ch_layout.u.mask; + } + + /* other options: not handled for now */ + return 0; +#endif } + /* yet another hack to fix codecs that encode channels in different order and reorder on decoder * but FFmpeg doesn't do it automatically * (maybe should be done via mixing, but could clash with other stuff?) */ void ffmpeg_set_channel_remapping(ffmpeg_codec_data* data, int *channel_remap) { int i; +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 24, 100) + int channels = data->codecCtx->channels; +#else + int channels = data->codecCtx->ch_layout.nb_channels; +#endif - if (data->codecCtx->channels > 32) + if (channels > 32) return; - for (i = 0; i < data->codecCtx->channels; i++) { + for (i = 0; i < channels; i++) { data->channel_remap[i] = channel_remap[i]; } data->channel_remap_set = 1; @@ -1056,7 +1080,13 @@ int ffmpeg_get_sample_rate(ffmpeg_codec_data* data) { int ffmpeg_get_channels(ffmpeg_codec_data* data) { if (!data || !data->codecCtx) return 0; - return data->codecCtx->channels; +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 24, 100) + int channels = data->codecCtx->channels; +#else + int channels = data->codecCtx->ch_layout.nb_channels; +#endif + + return channels; } int ffmpeg_get_subsong_count(ffmpeg_codec_data* data) { diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c index bdb4ca2b7..36f643ef7 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c @@ -778,10 +778,16 @@ static ffmpeg_codec_data* init_ffmpeg_custom_opus_config(STREAMFILE* sf, off_t s ffmpeg_data = init_ffmpeg_offset(temp_sf, 0x00, get_streamfile_size(temp_sf)); if (!ffmpeg_data) goto fail; - /* FFmpeg + libopus: skips samples, notifies skip in codecCtx->delay (not in stream->skip_samples) - * FFmpeg + opus: *doesn't* skip, also notifies skip in codecCtx->delay, hurray (possibly fixed in recent versions) - * FFmpeg + opus is audibly buggy with some low bitrate SSB Ultimate files */ - //ffmpeg_set_skip_samples(ffmpeg_data, skip); + /* FFmpeg + libopus: skips samples, notifies skip in codecCtx->delay/initial_padding (not in stream->skip_samples) + * FFmpeg + opus: skip samples but loses them on reset/seek to 0, also notifies skip in codecCtx->delay/initial_padding */ + { + /* quick fix for non-libopus (not sure how to detect better since both share AV_CODEC_ID_OPUS)*/ + const char* name = ffmpeg_get_codec_name(ffmpeg_data); + if (name && (name[0] == 'O' || name[0] == 'o')) { /* "Opus" vs "libopus" */ + //ffmpeg_set_skip_samples(ffmpeg_data, cfg->skip); /* can't overwrite internal decoder skip */ + ffmpeg_set_force_seek(ffmpeg_data); + } + } close_streamfile(temp_sf); return ffmpeg_data; diff --git a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils_ahx.c b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils_ahx.c index 03da22858..2a9a01f42 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils_ahx.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils_ahx.c @@ -189,7 +189,7 @@ fail: #define AHX_KEY_BUFFER 0x2000 -#define AHX_KEY_TEST_FRAMES 15 /* wrong keys may work ok in some frames */ +#define AHX_KEY_TEST_FRAMES 20 /* wrong keys may work ok in some frames */ /* check if current key ends properly in frame syncs */ int test_ahx_key(STREAMFILE* sf, off_t offset, crikey_t* crikey) { diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c index 21a202585..152e600b8 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c @@ -3,6 +3,7 @@ #include "../util.h" #ifdef VGM_USE_VORBIS +#define OV_EXCLUDE_STATIC_CALLBACKS #include #define OGG_DEFAULT_BITSTREAM 0 diff --git a/Frameworks/vgmstream/vgmstream/src/coding/sdx2_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/sdx2_decoder.c index ff662cdc0..a36b536e2 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/sdx2_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/sdx2_decoder.c @@ -3,7 +3,11 @@ #include "../util.h" /* SDX2 - 2:1 Squareroot-delta-exact compression */ -/* CBD2 - 2:1 Cuberoot-delta-exact compression (from the unreleased 3DO M2) */ +/* CBD2 - 2:1 Cuberoot-delta-exact compression (from 3DO/Konami M2) */ + +/* Original code is implemented with ops in a custom DSP (DSPP) with a variation of FORTH + * (rather than tables), in the "3DO M2 Portfolio OS", so could be converted to plain calcs. */ + /* for (i=-128;i<128;i++) { squares[i+128] = i<0?(-i*i)*2:(i*i)*2; } */ static int16_t squares[256] = { @@ -34,6 +38,7 @@ static int16_t squares[256] = { }; /* +// original DSP ops, seems equivalent to (i * i * i) / 64 for (uint16_t i = 0; i < 0x100; i += 1) { int16_t v = i; v -= 0x80; @@ -83,7 +88,8 @@ static void decode_delta_exact(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int int8_t sample_byte = read_8bit(stream->offset+i,stream->streamfile); int16_t sample; - if (!(sample_byte & 1)) hist = 0; + if (!(sample_byte & 1)) /* even: "exact mode" (value as-is), odd: "delta mode" */ + hist = 0; sample = hist + table[sample_byte+128]; hist = outbuf[sample_count] = clamp16(sample); @@ -102,7 +108,8 @@ static void decode_delta_exact_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int8_t sample_byte = read_8bit(stream->offset+i*channelspacing,stream->streamfile); int16_t sample; - if (!(sample_byte & 1)) hist = 0; + if (!(sample_byte & 1)) /* even: "exact mode" (value as-is), odd: "delta mode" */ + hist = 0; sample = hist + table[sample_byte+128]; hist = outbuf[sample_count] = clamp16(sample); diff --git a/Frameworks/vgmstream/vgmstream/src/formats.c b/Frameworks/vgmstream/vgmstream/src/formats.c index 307030edd..c6a27e730 100644 --- a/Frameworks/vgmstream/vgmstream/src/formats.c +++ b/Frameworks/vgmstream/vgmstream/src/formats.c @@ -70,6 +70,7 @@ static const char* extension_list[] = { "ap", "apc", "as4", + "asbin", "asd", "asf", "asr", @@ -145,6 +146,7 @@ static const char* extension_list[] = { "cpk", "cps", "csa", //txth/reserved [LEGO Racers 2 (PS2)] + "csb", "csmp", "cvs", //txth/reserved [Aladdin in Nasira's Revenge (PS1)] "cwav", @@ -263,6 +265,7 @@ static const char* extension_list[] = { "kces", "kcey", //fake extension/header id for .pcm (renamed, to be removed) "km9", + "kma", //txth/reserved [Dynasty Warriors 7: Empires (PS3)] "kmx", "kovs", //fake extension/header id for .kvs "kno", @@ -285,6 +288,7 @@ static const char* extension_list[] = { "lac3", //fake extension for .ac3, FFmpeg/not parsed "lasf", //fake extension for .asf (various) "lbin", //fake extension for .bin (various) + "ldat", //fake extension for .dat "leg", "lep", "lflac", //fake extension for .flac, FFmpeg/not parsed @@ -1276,8 +1280,6 @@ static const meta_info meta_info_list[] = { {meta_PC_FLX, "Ultima IX .FLX header"}, {meta_MOGG, "Harmonix Music Systems MOGG Vorbis"}, {meta_OGG_VORBIS, "Ogg Vorbis header"}, - {meta_OGG_SLI, "Ogg Vorbis header (.sli looping)"}, - {meta_OPUS_SLI, "Ogg Opus header (.sli looping)"}, {meta_OGG_SFL, "Ogg Vorbis header (SFPL looping)"}, {meta_OGG_KOVS, "Ogg Vorbis header (KOVS)"}, {meta_OGG_encrypted, "Ogg Vorbis header (encrypted)"}, diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_thp.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_thp.c index 494b86f57..36e34e6c9 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked_thp.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_thp.c @@ -8,15 +8,15 @@ void block_update_thp(off_t block_offset, VGMSTREAM* vgmstream) { off_t audio_offset; size_t next_block_size, video_size; - next_block_size = read_u32be(block_offset + 0x00, sf); - /* 0x04: frame size previous */ + next_block_size = read_u32be(block_offset + 0x00, sf); /* block may have padding, so need to save for next time */ + /* 0x04: previous frame size */ video_size = read_u32be(block_offset + 0x08,sf); /* 0x0c: audio size */ audio_offset = block_offset + 0x10 + video_size; vgmstream->current_block_offset = block_offset; - vgmstream->next_block_offset = block_offset + vgmstream->full_block_size; + vgmstream->next_block_offset = block_offset + vgmstream->full_block_size; /* use prev saved data */ vgmstream->full_block_size = next_block_size; /* block samples can be smaller than block size, normally in the last block, @@ -27,9 +27,10 @@ void block_update_thp(off_t block_offset, VGMSTREAM* vgmstream) { audio_offset += 0x08; for (i = 0; i < vgmstream->channels; i++) { + /* always size of 2 channels even in mono [WarioWare Inc. (GC)] */ off_t coef_offset = audio_offset + i*0x20; - off_t hist_offset = audio_offset + vgmstream->channels*0x20 + i*0x04; - off_t data_offset = audio_offset + 2*0x24 + i*vgmstream->current_block_size; /* reserved for 2 even in mono [WarioWare Inc. (GC)] */ + off_t hist_offset = audio_offset + 2*0x20 + i*0x04; + off_t data_offset = audio_offset + 2*0x24 + i*vgmstream->current_block_size; for (j = 0; j < 16; j++) { vgmstream->ch[i].adpcm_coef[j] = read_s16be(coef_offset + (j*0x02),sf); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/aax.c b/Frameworks/vgmstream/vgmstream/src/meta/aax.c index 3e509faae..f2ae78142 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/aax.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/aax.c @@ -133,91 +133,3 @@ fail: free_layout_segmented(data); return NULL; } - - -/* CRI's UTF wrapper around DSP [Sonic Colors sfx (Wii), NiGHTS: Journey of Dreams sfx (Wii)] */ -VGMSTREAM* init_vgmstream_utf_dsp(STREAMFILE* sf) { - VGMSTREAM* vgmstream = NULL; - off_t start_offset; - uint8_t loop_flag = 0, channels; - uint32_t sample_rate, num_samples, loop_start, loop_end, interleave; - uint32_t data_offset, data_size, header_offset, header_size; - utf_context* utf = NULL; - - - /* checks */ - if (!is_id32be(0x00,sf, "@UTF")) - goto fail; - - /* .aax: assumed - * (extensionless): extracted names inside csb/cpk often don't have extensions */ - if (!check_extensions(sf, "aax,")) - goto fail; - - /* .aax contains a simple UTF table with one row and various columns being header info */ - { - int rows; - const char* name; - uint32_t table_offset = 0x00; - - - utf = utf_open(sf, table_offset, &rows, &name); - if (!utf) goto fail; - - if (strcmp(name, "ADPCM_WII") != 0) - goto fail; - - if (rows != 1) - goto fail; - - if (!utf_query_u32(utf, 0, "sfreq", &sample_rate)) - goto fail; - if (!utf_query_u32(utf, 0, "nsmpl", &num_samples)) - goto fail; - if (!utf_query_u8(utf, 0, "nch", &channels)) - goto fail; - if (!utf_query_u8(utf, 0, "lpflg", &loop_flag)) /* full loops */ - goto fail; - /* for some reason data is stored before header */ - if (!utf_query_data(utf, 0, "data", &data_offset, &data_size)) - goto fail; - if (!utf_query_data(utf, 0, "header", &header_offset, &header_size)) - goto fail; - - if (channels < 1 || channels > 2) - goto fail; - if (header_size != channels * 0x60) - goto fail; - - start_offset = data_offset; - interleave = (data_size+7) / 8 * 8 / channels; - - loop_start = read_32bitBE(header_offset + 0x10, sf); - loop_end = read_32bitBE(header_offset + 0x14, sf); - } - - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channels, loop_flag); - if (!vgmstream) goto fail; - - vgmstream->sample_rate = sample_rate; - vgmstream->num_samples = num_samples; - vgmstream->loop_start_sample = dsp_nibbles_to_samples(loop_start); - vgmstream->loop_end_sample = dsp_nibbles_to_samples(loop_end) + 1; - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = interleave; - vgmstream->meta_type = meta_UTF_DSP; - - dsp_read_coefs_be(vgmstream, sf, header_offset+0x1c, 0x60); - - if (!vgmstream_open_stream(vgmstream, sf, start_offset)) - goto fail; - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/adx_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/adx_keys.h index 7ddb2d438..f74f8cf84 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/adx_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/adx_keys.h @@ -204,6 +204,9 @@ static const adxkey_info adxkey8_list[] = { /* Shoujo Yoshitsune-den Ni - Toki wo Koeru Chigiri (PS2) */ {0x62d7,0x483d,0x4fb7, "YOSHI2",0}, + + /* Junjou Romantica - Koi no Doki Doki Daisakusen (PS2) (Marvelous) */ + {0x5827,0x612d,0x5585, "Endress-SETSUNAI!",0}, }; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bfwav.c b/Frameworks/vgmstream/vgmstream/src/meta/bfwav.c index e348367e8..c79230383 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/bfwav.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/bfwav.c @@ -280,10 +280,11 @@ static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) { /* 0x0c: ADPCM offset (from channel info offset), 0xFFFFFFFF otherwise */ /* 0x10: padding */ - if (read_u16(chnf_offset + 0x00, sf) != 0x1F00) + /* 3DS doesn't seem to check this, allow for odd bcwavs from rstmcpp */ + if ((read_u16(chnf_offset + 0x00, sf) & 0x1F00) != 0x1F00) /* (ex. 0x1F01) */ goto fail; chdt_offset = read_u32(chnf_offset + 0x04, sf) + data_offset + 0x08; - coef_offset = read_u32(chnf_offset + 0x0c, sf) + chnf_offset; + coef_offset = read_u32(chnf_offset + 0x0c, sf) + chnf_offset; /* usually after all channel info but will allow any position */ break; default: diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bnk_sony.c b/Frameworks/vgmstream/vgmstream/src/meta/bnk_sony.c index 13476ba70..4f83ddb9c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/bnk_sony.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/bnk_sony.c @@ -131,6 +131,7 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) { case 0x0d: /* Polara (Vita), Crypt of the Necrodancer (Vita) */ case 0x0e: /* Yakuza 6's Puyo Puyo (PS4) */ case 0x0f: /* Ikaruga (PS4) */ + case 0x10: /* Ginga Force (PS4) */ table1_offset = sblk_offset + read_u32(sblk_offset+0x18,sf); table2_offset = sblk_offset + read_u32(sblk_offset+0x1c,sf); table3_offset = sblk_offset + read_u32(sblk_offset+0x2c,sf); @@ -305,6 +306,7 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) { case 0x0d: case 0x0e: case 0x0f: + case 0x10: flags = read_u8 (table3_offset+table3_entry_offset+0x12,sf); stream_offset = read_u32(table3_offset+table3_entry_offset+0x44,sf); stream_size = read_u32(table3_offset+table3_entry_offset+0x48,sf); @@ -325,6 +327,8 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) { case 0x09: case 0x0d: case 0x0e: + case 0x0f: + case 0x10: /* find if this sound has an assigned name in table1 */ for (i = 0; i < section_entries; i++) { uint32_t entry_offset = read_u16(table1_offset+(i*table1_entry_size)+table1_suboffset+0x00,sf); @@ -479,6 +483,7 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) { case 0x0d: case 0x0e: case 0x0f: + case 0x10: type = read_u16(start_offset+0x00,sf); if (read_u32(start_offset+0x04,sf) != 0x01) /* type? */ goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/csb.c b/Frameworks/vgmstream/vgmstream/src/meta/csb.c index 832117502..75f79408c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/csb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/csb.c @@ -7,8 +7,7 @@ VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; STREAMFILE* temp_sf = NULL; - off_t subfile_offset; - size_t subfile_size; + uint32_t subfile_offset, subfile_size; utf_context* utf = NULL; utf_context* utf_sdl = NULL; int total_subsongs, target_subsong = sf->stream_index; @@ -17,10 +16,10 @@ VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) { /* checks */ - if (!check_extensions(sf, "csb")) - goto fail; if (!is_id32be(0x00,sf, "@UTF")) goto fail; + if (!check_extensions(sf, "csb")) + goto fail; /* .csb is an early, simpler version of .acb+awk (see acb.c) used until ~2013? * Can stream from .cpk but this only loads memory data. */ @@ -115,9 +114,7 @@ VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) { goto fail; } - //;VGM_LOG("CSB: subfile offset=%lx + %x\n", subfile_offset, subfile_size); - - + //;VGM_LOG("CSB: subfile offset=%x + %x\n", subfile_offset, subfile_size); temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "aax"); if (!temp_sf) goto fail; @@ -128,6 +125,11 @@ VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) { if (!vgmstream) goto fail; break; + case 2: /* AHX */ + vgmstream = init_vgmstream_utf_ahx(temp_sf); + if (!vgmstream) goto fail; + break; + case 4: /* ADPCM_WII */ vgmstream = init_vgmstream_utf_dsp(temp_sf); if (!vgmstream) goto fail; @@ -153,3 +155,147 @@ fail: close_vgmstream(vgmstream); return NULL; } + + +/* CRI's UTF wrapper around DSP [Sonic Colors (Wii)-sfx, NiGHTS: Journey of Dreams (Wii)-sfx] */ +VGMSTREAM* init_vgmstream_utf_dsp(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + off_t start_offset; + uint8_t loop_flag = 0, channels; + uint32_t sample_rate, num_samples, loop_start, loop_end, interleave; + uint32_t data_offset, data_size, header_offset, header_size; + utf_context* utf = NULL; + + + /* checks */ + if (!is_id32be(0x00,sf, "@UTF")) + goto fail; + + /* .aax: assumed + * (extensionless): extracted names inside csb/cpk often don't have extensions */ + if (!check_extensions(sf, "aax,")) + goto fail; + + /* contains a simple UTF table with one row and various columns being header info */ + { + int rows; + const char* name; + uint32_t table_offset = 0x00; + + + utf = utf_open(sf, table_offset, &rows, &name); + if (!utf) goto fail; + + if (strcmp(name, "ADPCM_WII") != 0) + goto fail; + + if (rows != 1) + goto fail; + + if (!utf_query_u32(utf, 0, "sfreq", &sample_rate)) + goto fail; + if (!utf_query_u32(utf, 0, "nsmpl", &num_samples)) + goto fail; + if (!utf_query_u8(utf, 0, "nch", &channels)) + goto fail; + if (!utf_query_u8(utf, 0, "lpflg", &loop_flag)) /* full loops */ + goto fail; + /* for some reason data is stored before header */ + if (!utf_query_data(utf, 0, "data", &data_offset, &data_size)) + goto fail; + if (!utf_query_data(utf, 0, "header", &header_offset, &header_size)) + goto fail; + + if (channels < 1 || channels > 2) + goto fail; + if (header_size != channels * 0x60) + goto fail; + + start_offset = data_offset; + interleave = (data_size+7) / 8 * 8 / channels; + + loop_start = read_32bitBE(header_offset + 0x10, sf); + loop_end = read_32bitBE(header_offset + 0x14, sf); + } + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = num_samples; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(loop_start); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(loop_end) + 1; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + vgmstream->meta_type = meta_UTF_DSP; + + dsp_read_coefs_be(vgmstream, sf, header_offset+0x1c, 0x60); + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + utf_close(utf); + return vgmstream; + +fail: + utf_close(utf); + close_vgmstream(vgmstream); + return NULL; +} + +/* CRI's UTF wrapper around AHX [Yakuza: Dead Souls (PS3)-voices] */ +VGMSTREAM* init_vgmstream_utf_ahx(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + STREAMFILE* temp_sf = NULL; + uint32_t subfile_offset, subfile_size; + utf_context* utf = NULL; + + + /* checks */ + if (!is_id32be(0x00,sf, "@UTF")) + goto fail; + + /* .aax: assumed + * (extensionless): extracted names inside csb/cpk often don't have extensions */ + if (!check_extensions(sf, "aax,")) + goto fail; + + /* contains a simple UTF table with one row and offset+size info */ + { + int rows; + const char* name; + uint32_t table_offset = 0x00; + + utf = utf_open(sf, table_offset, &rows, &name); + if (!utf) goto fail; + + if (strcmp(name, "AHX") != 0) + goto fail; + + if (rows != 1) + goto fail; + + if (!utf_query_data(utf, 0, "data", &subfile_offset, &subfile_size)) + goto fail; + } + + //;VGM_LOG("UTF_AHX: subfile offset=%x + %x\n", subfile_offset, subfile_size); + temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "ahx"); + if (!temp_sf) goto fail; + + vgmstream = init_vgmstream_ahx(temp_sf); + if (!vgmstream) goto fail; + + utf_close(utf); + close_streamfile(temp_sf); + return vgmstream; + +fail: + utf_close(utf); + close_streamfile(temp_sf); + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb_encrypted.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb_encrypted.c index de7c773f8..3c974ae7e 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb_encrypted.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb_encrypted.c @@ -25,7 +25,10 @@ VGMSTREAM* init_vgmstream_fsb_encrypted(STREAMFILE* sf) { uint8_t key[FSB_KEY_MAX]; size_t key_size = read_key_file(key, FSB_KEY_MAX, sf); - test_fsbkey(sf, key, key_size, MODE_FSBS_ALL); + if (key_size) { + vgmstream = test_fsbkey(sf, key, key_size, MODE_FSBS_ALL); + return vgmstream; + } } @@ -65,22 +68,22 @@ static VGMSTREAM* test_fsbkey(STREAMFILE* sf, const uint8_t* key, size_t key_siz if (!vc && test_std) { temp_sf = setup_fsb_streamfile(sf, key, key_size, 0); if (!temp_sf) return NULL; + //;dump_streamfile(temp_sf, 0); if (!vc && test_fsb4) vc = init_vgmstream_fsb(temp_sf); if (!vc && test_fsb5) vc = init_vgmstream_fsb5(temp_sf); - //;if (vgmstream) dump_streamfile(temp_sf, 0); close_streamfile(temp_sf); } if (!vc && test_alt) { temp_sf = setup_fsb_streamfile(sf, key, key_size, 1); if (!temp_sf) return NULL; + //;dump_streamfile(temp_sf, 1); if (!vc && test_fsb4) vc = init_vgmstream_fsb(temp_sf); if (!vc && test_fsb5) vc = init_vgmstream_fsb5(temp_sf); - //;if (vgmstream) dump_streamfile(temp_sf, 0); close_streamfile(temp_sf); } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/fsb_keys.h index 66e891ec9..3c26b6415 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb_keys.h @@ -68,7 +68,8 @@ static const fsbkey_info fsbkey_list[] = { { MODE_FSB5_STD, FSBKEY_ADD("4FB8CC894515617939F4E1B7D50972D27213B8E6") }, // Cult of the Lamb Demo (PC) { MODE_FSB5_STD, FSBKEY_ADD("X3EK%Bbga-%Y9HZZ%gkc*C512*$$DhRxWTGgjUG@=rUD") }, // Signalis (PC) { MODE_FSB5_STD, FSBKEY_ADD("281ad163160cfc16f9a22c6755a64fad") }, // Ash Echoes beta (Android) - + { MODE_FSB5_STD, FSBKEY_ADD("Aurogon666") }, // Afterimage demo (PC) + { MODE_FSB5_STD, FSBKEY_ADD("IfYouLikeThosesSoundsWhyNotRenumerateTheir2Authors?") }, // Blanc (PC/Switch) }; static const int fsbkey_list_count = sizeof(fsbkey_list) / sizeof(fsbkey_list[0]); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h index cc305f733..c50f1cc01 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h @@ -95,6 +95,8 @@ static const hcakey_info hcakey_list[] = { {9001712656335836006}, // 7CEC81F7C3091366 // Ikemen Vampire - Ijin-tachi to Koi no Yuuwaku (iOS/Android) + // Ikemen Villains (Android) + // Ikemen Prince (Android) {45152594117267709}, // 00A06A0B8D0C10FD // Super Robot Wars X-Omega (iOS/Android) @@ -449,6 +451,9 @@ static const hcakey_info hcakey_list[] = { {0x3613e2a7fdfc0784}, //music_0110027 {0xc239d244b6d3b722}, //music_0110028 {0x2575c136a260e723}, //music_0110029 + {0x22c6b455883b1c28}, //music_0110030 + {0xff2ae68fa067f80a}, //music_0110031 + {0x422ca19b0fa5c7c0}, //music_0110032 {0xfb647d074e53fab6}, //music_0120001 {0xc24049b9f7ed3105}, //music_0120002 {0xdc128f2fd48bf4b}, //music_0120003 @@ -487,6 +492,9 @@ static const hcakey_info hcakey_list[] = { {0x2822bba0a5c4f18c}, //music_0210015 {0xff579d3fcfa8453a}, //music_0210016 {0x3caa61e8b958f6d8}, //music_0210017 + {0xe38b758bcadfc621}, //music_0210018 + {0x3399e970670db2ba}, //music_0210019 + {0x1cb76530af356c05}, //music_0210020 {0x15bb78c31db0a0b6}, //music_0220001 {0x59b1257242c40109}, //music_0220002 {0xdb402bd08d522f34}, //music_0220003 @@ -526,6 +534,9 @@ static const hcakey_info hcakey_list[] = { {0x22e33db9b5625a96}, //music_0310016 {0xb78070802414de7a}, //music_0310017 {0x572aeeed86655119}, //music_0310018 + {0x86ca86794400f49d}, //music_0310019 + {0x7a2bbc195b9bfac1}, //music_0310020 + {0x1c1f029bb47594b1}, //music_0310021 {0xb921c3992807dadd}, //music_0320001 {0x38ad99a045dc971f}, //music_0320002 {0xf616642579ba5850}, //music_0320003 @@ -544,6 +555,7 @@ static const hcakey_info hcakey_list[] = { {0x2df608ef06aca41c}, //music_0320016 {0x641af19c287d4a2e}, //music_0320017 {0x82de7b71b30d7bc2}, //music_0320019 + {0x100b7ca3075996fe}, //music_0320020 {0x776c4aded0bca5d1}, //music_0410001 {0xb7bff4fbf66be43f}, //music_0410002 {0x904f50c5ce8ec6e4}, //music_0410003 @@ -560,6 +572,10 @@ static const hcakey_info hcakey_list[] = { {0xd8cdd53589ad3634}, //music_0410014 {0x88007190e0bfa1ce}, //music_0410015 {0x6fccdd5c3d0d6e3e}, //music_0410016 + {0x9d8037d7bfb3fc1d}, //music_0410017 + {0x685b5601a43b6c60}, //music_0410018 + {0x75927596a180f3e3}, //music_0410019 + {0xc3d36676d54255c5}, //music_0410020 {0x5d1f3fdbbb036f8d}, //music_0420001 {0xc04264e8f34ad5c0}, //music_0420002 {0x8f0e96b4f71f724f}, //music_0420003 @@ -597,6 +613,8 @@ static const hcakey_info hcakey_list[] = { {0x7878df60f0549c4}, //music_0510017 {0x8e5b7068022828e0}, //music_0510018 {0xb069a5c5e2d93edf}, //music_0510019 + {0x30f9dcefa450733a}, //music_0510020 + {0xf85695960e2dcb7f}, //music_0510021 {0x15f82c1617013c36}, //music_0520001 {0xc7da8e6f0e2fe399}, //music_0520002 {0xe350bffcdc9cb686}, //music_0520003 @@ -633,6 +651,10 @@ static const hcakey_info hcakey_list[] = { {0x3aa02e0a37543b5c}, //music_0610017 {0xc451f1deddae08ca}, //music_0610018 {0xc0fa6669d9904919}, //music_0610019 + {0x4ad7fd8dafaa58a9}, //music_0610020 + {0x7aece54359beac21}, //music_0610021 + {0x7c9332be25e5c95a}, //music_0610022 + {0x415eef25f84e8c2e}, //music_0610023 {0x8258ddd6a1d0849b}, //music_0620001 {0x1dd21a1244ca12f1}, //music_0620002 {0xfdec74b23d8b494b}, //music_0620003 @@ -652,7 +674,15 @@ static const hcakey_info hcakey_list[] = { {0x5c1195d8afcb1901}, //music_0620017 {0x1ad8db767d9ba4a7}, //music_0620018 {0x9bc820aa161b0f08}, //music_0620019 + {0xd1df27a57399613e}, //music_0810001 + {0xd37ec4cb304e16ae}, //music_0810002 + {0x1e99d14d97ab82c5}, //music_0820001 + {0x5bf7cefecda8bcb2}, //music_0820002 + {0x9cf7ab0ccafa374e}, //music_0820003 {0x972b52f3dfaa387a}, //music_0910001 + {0x407a4b6c3dcf2509}, //music_0910002 + {0x4683c57919dbdeee}, //music_0920001 + {0x126d0d20ad7f0401}, //music_0920002 {0x2a47feac8dc3ca9c}, //music_3010001 {0x9ebbaf63ffe9d9ef}, //music_3010002 {0xe553dba6592293d8}, //music_3010003 @@ -669,6 +699,11 @@ static const hcakey_info hcakey_list[] = { {0xef257f41a265a0af}, //music_3010015 {0x5e23d8a2488bc715}, //music_3010016 {0x198cc607e20dd264}, //music_3010017 + {0x31a9ab25b5dff424}, //music_3010018 + {0x17f53cfa841f41b5}, //music_3010020 + {0x4992a33be3ba81dd}, //music_3010021 + {0x86d0ab836f09a599}, //music_3010022 + {0x157f20b466d75228}, //music_3010024 {0xfd3ea450350d666f}, //music_3020001 {0x5e91a3790c32e2b3}, //music_3020002 {0x358adfd1bbd3a95e}, //music_3020003 @@ -683,6 +718,12 @@ static const hcakey_info hcakey_list[] = { {0x98c7a1d1c45df640}, //music_3020013 {0x3d01826fe053ddda}, //music_3020014 {0xa6a6426caed68f7c}, //music_3020015 + {0x34cc16f635101f02}, //music_3020016 + {0x4429ed54ca45a36d}, //music_3020018 + {0xcc935f3ebbb7bb94}, //music_3020019 + {0x4a1d57f0db140c12}, //music_3020020 + {0x8ddea25a12f93099}, //music_3020022 + {0xf754248dcd46287e}, //music_3020023 {0xdfad847a86a126bb}, //music_5030001 {0x711ef85045b8c26e}, //music_5030002 {0xff7640b46d72b337}, //music_5030003 @@ -782,6 +823,8 @@ static const hcakey_info hcakey_list[] = { {0xc3a72539b831ea6e}, //music_5030097 {0x8bc6b7b7a2d2bba3}, //music_5030098 {0xdbb0f41e90b30452}, //music_5030099 + {0x2eb141954bb3bd25}, //music_5030101 + {0xaee2837e71b2bb97}, //music_5030102 {0x444dda6d55d76095}, //music_5040001 {0xcbf4f1324081e0a6}, //music_5040002 {0xf1db3c1d9542063a}, //music_5040003 @@ -960,12 +1003,14 @@ static const hcakey_info hcakey_list[] = { {0x6f321adde08396e3}, //music_5050163 {0x58afa6381eeb1425}, //music_5050164 {0x751daf7d1a5401cb}, //music_5050165 + {0xff2ea77b81c3ff6}, //music_5050166 {0xbd6b66823f854f68}, //music_5050167 {0xceb902b93eba45d8}, //music_5050168 {0x2550e145b93723ae}, //music_5050169 {0xb512188a55b8b698}, //music_5050170 {0x26e5bf2c66a9898d}, //music_5050171 {0xd93d0a1764e85d4d}, //music_5050176 + {0xff8c5c13833b1049}, //music_5050177 {0x59efd868058a402e}, //music_5050178 {0x93075c0fbb31f463}, //music_5050179 {0xdedb6ae518faac3d}, //music_5050180 @@ -975,12 +1020,35 @@ static const hcakey_info hcakey_list[] = { {0xbd2f4b5ab481d300}, //music_5050184 {0x1a253c2f40a38917}, //music_5050185 {0xc735e9f28243ea8a}, //music_5050186 + {0x8137f876a1a8850b}, //music_5050187 + {0x82bd2fef6ad49c01}, //music_5050188 + {0xe77f67dd5b7aed71}, //music_5050189 + {0x2896fe0212b06d81}, //music_5050190 + {0xe60abdb973ad274a}, //music_5050191 + {0xe84e1005c5eeab22}, //music_5050192 + {0x1374b00b87c43440}, //music_5050193 + {0xf9b45750656b28bd}, //music_5050194 + {0x32f55efe2bd0a4fd}, //music_5050195 + {0x9092a8ef4ebacb7f}, //music_5050196 + {0x39a04e2ebc026177}, //music_5050197 + {0x1c848089b2d1a7b6}, //music_5050198 + {0x24feeee9ce287093}, //music_5050199 + {0x4226eb6f52ad4637}, //music_5050200 + {0x59ab358c5cded7c4}, //music_5050201 + {0x29ca209dae13020a}, //music_5050202 + {0x7fe1bc7cbda4a457}, //music_5050203 + {0x928964b93fce5bc9}, //music_5050204 + {0x58a46c0179f0d6ff}, //music_5050205 + {0x929ca6a5e8e0445}, //music_5050206 + {0xf0de6097ea78513c}, //music_5050207 + {0xcde0de0e1216bdea}, //music_5050208 {0x52c250eade92393b}, //music_9010001 {0xf66e6bb5b0599b07}, //music_9010002 {0x8582b5a60dbbf948}, //music_9010003 + {0x5bb84b8a5677046f}, //music_9010004 {0xfea0d6adff136868}, //music_9050001 {0x19480b946279507a}, //music_9050002 - + // Mini 4WD Hyper Dash Grand Prix (Android) {7957824642808300098}, // 6E6FDF59AB704242 @@ -1093,16 +1161,29 @@ static const hcakey_info hcakey_list[] = { {97648135}, // 0000000005d1fe07 // CHUNITHM International Version (AC) - {33426922444908636}, // 0076C19BDE43685C + {33426922444908636}, // 0076C19BDE43685C // Star Ocean: The Divine Force (PC) - {68308868861462528}, // 00f2ae8de77f0800 + {68308868861462528}, // 00f2ae8de77f0800 // Sin Chronicle (Android) - {4385672148314579020}, // 3CDD0995259D604C + {4385672148314579020}, // 3CDD0995259D604C // The Eminence in Shadow: Master of Garden (Android) - {8115775984160473168}, // 70A1074224880050 + {8115775984160473168}, // 70A1074224880050 + + // Punishing: Gray Raven (Android)-newer assets + {62855594017927612}, // 00DF4ED46995B1BC + + // Dragon Quest The Adventure of Dai: A Hero's Bonds (Android) + {503876638109847402}, // 06FE2121F927CF6A (in criware decryptor init code, xor of 2 strings) + + // Love Live! School Idol Festival 2 MIRACLE LIVE (Android) + {5067530812966687744}, // 46537c6ceb39d400 + + // 404 Game RE:SET Prologue Demo (Android) + {21588207721978971}, // 004CB25C4C9B1C5B + }; #endif/*_HCA_KEYS_H_*/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ktsc.c b/Frameworks/vgmstream/vgmstream/src/meta/ktsc.c index e438075c4..d7cc3de54 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ktsc.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ktsc.c @@ -6,23 +6,24 @@ /* KTSC - Koei Tecmo KTSR container */ VGMSTREAM* init_vgmstream_ktsc(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; - STREAMFILE *temp_sf = NULL; + STREAMFILE* temp_sf = NULL; int target_subsong = sf->stream_index, total_subsongs; - off_t offset, subfile_offset; - size_t subfile_size; + uint32_t offset, subfile_offset, subfile_size; /* checks */ - /* .ktsl2asbin: common [Atelier Ryza (PC)] */ - if (!check_extensions(sf, "ktsl2asbin")) + if (!is_id32be(0x00, sf, "KTSC")) + goto fail; + if (read_u32be(0x04, sf) != 0x01000001) /* version? */ + goto fail; + + /* .ktsl2asbin: common [Atelier Ryza (PC)] + * .asbin: Warriors Orochi 4 (PC) (assumed) */ + if (!check_extensions(sf, "ktsl2asbin,asbin")) goto fail; /* KTSC is a container of KTSRs, but can't be extracted easily as they use absolute pointers to the * same stream companion file. KTSRs may have subsongs, but only seem to have 1, so use KTSC's subsongs. */ - if (read_u32be(0x00, sf) != 0x4B545343) /* "KTSC" */ - goto fail; - if (read_u32be(0x04, sf) != 0x01000001) /* version? */ - goto fail; if (target_subsong == 0) target_subsong = 1; total_subsongs = read_u32le(0x08, sf); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ktsr.c b/Frameworks/vgmstream/vgmstream/src/meta/ktsr.c index 125ce2d70..0ef57293d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ktsr.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ktsr.c @@ -49,8 +49,9 @@ VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf) { goto fail; if (read_u32be(0x04, sf) != 0x777B481A) /* hash(?) id: 0x777B481A=as, 0x0294DDFC=st, 0xC638E69E=gc */ goto fail; - /* .ktsl2asbin: common [Atelier Ryza (PC/Switch), Nioh (PC)] */ - if (!check_extensions(sf, "ktsl2asbin")) + /* .ktsl2asbin: common [Atelier Ryza (PC/Switch), Nioh (PC)] + * .asbin: Warriors Orochi 4 (PC) */ + if (!check_extensions(sf, "ktsl2asbin,asbin")) goto fail; /* KTSR can be a memory file (ktsl2asbin), streams (ktsl2stbin) and global config (ktsl2gcbin) @@ -65,9 +66,10 @@ VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf) { /* open companion body */ if (ktsr.is_external) { - sf_b = open_streamfile_by_ext(sf, "ktsl2stbin"); + const char* companion_ext = check_extensions(sf, "asbin") ? "stbin" : "ktsl2stbin"; + sf_b = open_streamfile_by_ext(sf, companion_ext); if (!sf_b) { - vgm_logi("KTSR: companion file '*.ktsl2stbin' not found\n"); + vgm_logi("KTSR: companion file '*.%s' not found\n", companion_ext); goto fail; } } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/kwb.c b/Frameworks/vgmstream/vgmstream/src/meta/kwb.c index 3317938f4..b7a1474e6 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/kwb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/kwb.c @@ -153,7 +153,7 @@ static VGMSTREAM* init_vgmstream_koei_wavebank(kwb_header* kwb, STREAMFILE* sf_h init_vgmstream = init_vgmstream_dsp_apex; } else { - vgm_logi("KWB: unknown type %x at %x\n", id, kwb->stream_offset); + vgm_logi("KWB: unknown type id=%x at offset=%x\n", id, kwb->stream_offset); goto fail; } @@ -652,7 +652,7 @@ static int parse_type_msfbank(kwb_header* kwb, off_t offset, STREAMFILE* sf) { /* this is just like XWSF, abridged: */ int entries, current_subsongs, relative_subsong; off_t header_offset; - + entries = read_u32be(offset + 0x14, sf); current_subsongs = kwb->total_subsongs; @@ -675,18 +675,18 @@ static int parse_type_msfbank(kwb_header* kwb, off_t offset, STREAMFILE* sf) { // return 0; } -static int parse_type_xwsfile(kwb_header* kwb, off_t offset, STREAMFILE* sf) { - off_t table1_offset, table2_offset; +static int parse_type_xwsfile(kwb_header* kwb, uint32_t offset, STREAMFILE* sf) { + uint32_t table1_offset, table2_offset; int i, chunks, chunks2; uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL; - if (!(is_id32be(offset + 0x00, sf, "XWSF") && is_id32be(offset + 0x04, sf, "ILE\0")) && - !(is_id32be(offset + 0x00, sf, "tdpa") && is_id32be(offset + 0x04, sf, "ck\0\0"))) + if (!(is_id64be(offset + 0x00, sf, "XWSFILE\0")) && + !(is_id64be(offset + 0x00, sf, "tdpack\0\0"))) goto fail; kwb->big_endian = read_u8(offset + 0x08, sf) == 0xFF; - /* 0x0a: version? (0100: NG2/NG3 PS3, 0101: DoA LR PC) */ + /* 0x0a: version? (0100: NG2/NG3 PS3, 0101: DoA LR PC, NG2/3 PC) */ read_u32 = kwb->big_endian ? read_u32be : read_u32le; @@ -706,52 +706,56 @@ static int parse_type_xwsfile(kwb_header* kwb, off_t offset, STREAMFILE* sf) { i = 0; while (i < chunks) { - uint32_t entry_type, head_offset, body_offset, head_size; + uint32_t entry_type, head_offset, head_size; //;VGM_LOG("XWS: entry %i/%i\n", i, chunks); - /* NG2/NG3 PS3 have table1+2, DoA LR PC removes table2 and includes body offset in entries */ + /* NG2/NG3 PS3/PC have table1+2, DoA LR PC doesn't (not very useful) */ if (table2_offset) { - head_offset = read_u32(offset + table1_offset + i * 0x04 + 0x00, sf); - head_size = read_u32(offset + table2_offset + i * 0x04 + 0x00, sf); - body_offset = head_offset; - i += 1; - - /* sometimes has file end offset as entry with no size*/ - if (!head_size) + head_offset = read_u32(offset + table1_offset + i * 0x04, sf); + head_size = read_u32(offset + table2_offset + i * 0x04, sf); + if (!head_size) { /* sometimes has file end offset as entry with no size (NG PS3)*/ + i += 1; continue; + } } else { - head_offset = read_u32(offset + table1_offset + i * 0x04 + 0x00, sf); - body_offset = read_u32(offset + table1_offset + i * 0x04 + 0x04, sf); - i += 2; + head_offset = read_u32(offset + table1_offset + i * 0x04, sf); } - if (!head_offset) /* just in case */ + if (!head_offset) { /* just in case */ + i += 1; continue; - + } head_offset += offset; - body_offset += offset; entry_type = read_u32be(head_offset + 0x00, sf); - //;VGM_LOG("XWS: head=%x, body=%x\n", head_offset, body_offset); + //;VGM_LOG("XWS: head=%x\n", head_offset); if (entry_type == get_id32be("XWSF")) { /* + "ILE\0" */ + i += 1; if (!parse_type_xwsfile(kwb, head_offset, sf)) goto fail; } else if (entry_type == get_id32be("CUEB") || entry_type < 0x100) { - ; /* CUE-like info (may start with 0 or a low number instead) */ + i += 1; + /* CUE-like info (may start with 0 or a low number instead) */ } else if (entry_type == get_id32be("MSFB")) { /* + "ANK\0" */ + i += 1; if (!parse_type_msfbank(kwb, head_offset, sf)) goto fail; } else if (entry_type == get_id32be("KWB2")) { + /* NG2/3 PC, DoA LR PC goes head,body,... */ + uint32_t body_offset = read_u32(offset + table1_offset + i * 0x04 + 0x04, sf); + body_offset += offset; + i += 2; + if (!parse_type_kwb2(kwb, head_offset, body_offset, sf)) goto fail; } else { - vgm_logi("XWS: unknown type %x at head=%x, body=%x\n", entry_type, head_offset, body_offset); + vgm_logi("XWS: unknown chunk %i (%x) with head=%x at %x\n", i, entry_type, head_offset, offset); goto fail; } } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/meta.h b/Frameworks/vgmstream/vgmstream/src/meta/meta.h index fe608631f..3e1c7c4da 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h @@ -160,7 +160,7 @@ VGMSTREAM * init_vgmstream_mp4_aac(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_mp4_aac_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size); #endif -VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE * streamFile); +VGMSTREAM* init_vgmstream_sli_loops(STREAMFILE* sf); VGMSTREAM * init_vgmstream_sfl_ogg(STREAMFILE * streamFile); @@ -359,8 +359,6 @@ VGMSTREAM * init_vgmstream_wii_sng(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile); - VGMSTREAM * init_vgmstream_ngc_ffcc_str(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_sat_baka(STREAMFILE *streamFile); @@ -880,7 +878,9 @@ VGMSTREAM* init_vgmstream_xssb(STREAMFILE *sf); VGMSTREAM* init_vgmstream_xma_ue3(STREAMFILE *sf); -VGMSTREAM* init_vgmstream_csb(STREAMFILE *sf); +VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_utf_dsp(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_utf_ahx(STREAMFILE* sf); VGMSTREAM *init_vgmstream_fwse(STREAMFILE *streamFile); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/musx.c b/Frameworks/vgmstream/vgmstream/src/meta/musx.c index 99e616654..09ccde691 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/musx.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/musx.c @@ -519,7 +519,8 @@ static int parse_musx(STREAMFILE* sf, musx_header* musx) { case 0x44415434: /* "DAT4" */ case 0x44415435: /* "DAT5" */ case 0x44415438: /* "DAT8" */ - /* found on PS3/Wii (but not always?) */ + case 0x44415439: /* "DAT9" [Disney Infinity (X360)] */ + /* found on PS3/Wii/X360 (but not always?) */ musx->stream_size = read_u32le(0x44, sf); musx->channels = read_u32le(0x48, sf); musx->sample_rate = read_u32le(0x4c, sf); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/nus3audio.c b/Frameworks/vgmstream/vgmstream/src/meta/nus3audio.c index ff74c4ca8..10e11f8ad 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/nus3audio.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/nus3audio.c @@ -1,43 +1,43 @@ #include "meta.h" #include "../coding/coding.h" -typedef enum { IDSP, OPUS, RIFF, } nus3audio_codec; +typedef enum { IDSP, OPUS, RIFF, BNSF, } nus3audio_codec; /* .nus3audio - Namco's newest newest audio container [Super Smash Bros. Ultimate (Switch), Mobile Suit Gundam: Extreme Vs. Maxi Boost ON (PS4)] */ VGMSTREAM* init_vgmstream_nus3audio(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; STREAMFILE* temp_sf = NULL; - off_t subfile_offset = 0, name_offset = 0; - size_t subfile_size = 0; + uint32_t subfile_offset = 0, subfile_size = 0, name_offset = 0; nus3audio_codec codec; const char* fake_ext = NULL; int total_subsongs, target_subsong = sf->stream_index, found = 0; /* checks */ - if (!check_extensions(sf, "nus3audio")) - goto fail; - if (read_u32be(0x00,sf) != 0x4E555333) /* "NUS3" */ + if (!is_id32be(0x00,sf, "NUS3")) goto fail; if (read_u32le(0x04,sf) + 0x08 != get_streamfile_size(sf)) goto fail; - if (read_u32be(0x08,sf) != 0x41554449) /* "AUDI" */ + if (!is_id32be(0x08,sf, "AUDI")) + goto fail; + + if (!check_extensions(sf, "nus3audio")) goto fail; /* parse existing chunks */ { - off_t offset = 0x0c; - size_t file_size = get_streamfile_size(sf); + uint32_t offset = 0x0c; + uint32_t file_size = get_streamfile_size(sf); uint32_t codec_id = 0; total_subsongs = 0; while (offset < file_size) { - uint32_t chunk_id = read_u32be(offset+0x00, sf); - size_t chunk_size = read_u32le(offset+0x04, sf); + uint32_t chunk_type = read_u32be(offset+0x00, sf); + uint32_t chunk_size = read_u32le(offset+0x04, sf); - switch(chunk_id) { + switch(chunk_type) { case 0x494E4458: /* "INDX": audio index */ total_subsongs = read_u32le(offset+0x08 + 0x00,sf); if (target_subsong == 0) target_subsong = 1; @@ -70,8 +70,8 @@ VGMSTREAM* init_vgmstream_nus3audio(STREAMFILE* sf) { goto fail; } - /* handle dummy entries, ex. Gundam EvM (PS4) */ - if (subfile_offset == 0 && subfile_size == 0) { + /* handle dummy entries (offset may be 0 or first entry), ex. Gundam EvM (PS4) */ + if (subfile_size == 0) { vgmstream = init_vgmstream_silence(0, 0, 0); if (!vgmstream) goto fail; @@ -80,7 +80,7 @@ VGMSTREAM* init_vgmstream_nus3audio(STREAMFILE* sf) { return vgmstream; } - + codec_id = read_u32be(subfile_offset, sf); switch(codec_id) { @@ -96,8 +96,12 @@ VGMSTREAM* init_vgmstream_nus3audio(STREAMFILE* sf) { codec = RIFF; fake_ext = "wav"; break; + case 0x424E5346: /* "BNSF" [gundam Extreme Vs 2 (AC)-multichannel] */ + codec = BNSF; + fake_ext = "bnsf"; + break; default: - VGM_LOG("NUS3AUDIO: unknown codec %x\n", codec_id); + vgm_logi("NUS3AUDIO: unknown codec (report)\n"); goto fail; } } @@ -120,6 +124,10 @@ VGMSTREAM* init_vgmstream_nus3audio(STREAMFILE* sf) { vgmstream = init_vgmstream_riff(temp_sf); if (!vgmstream) goto fail; break; + case BNSF: + vgmstream = init_vgmstream_bnsf(temp_sf); + if (!vgmstream) goto fail; + break; default: goto fail; } @@ -136,5 +144,3 @@ fail: close_vgmstream(vgmstream); return NULL; } - - diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_mic.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_mic.c index d403e7fe4..88d149b47 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_mic.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_mic.c @@ -20,7 +20,7 @@ VGMSTREAM* init_vgmstream_mic_koei(STREAMFILE* sf) { channels = read_u32le(0x08,sf); if (channels > 4) goto fail; /* 1/2/4 are known */ interleave = read_u32le(0x0c,sf); - if (interleave != 0x10) goto fail; + if (interleave != 0x10 && interleave != 0x20) goto fail; loop_end = read_s32le(0x10,sf); loop_start = read_s32le(0x14,sf); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/rfrm.c b/Frameworks/vgmstream/vgmstream/src/meta/rfrm.c index edf1a2ebf..4108f591c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/rfrm.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/rfrm.c @@ -1,110 +1,235 @@ -#include "meta.h" -#include "../coding/coding.h" - -/* RFTM - Retro Studios format [Donkey Kong Country Tropical Freeze (WiiU/Switch)] */ -VGMSTREAM *init_vgmstream_rfrm(STREAMFILE *streamFile) { - VGMSTREAM *vgmstream = NULL; - off_t fmta_offset = 0, data_offset = 0, header_offset, start_offset; - size_t data_size = 0, interleave; - int loop_flag, channel_count, version; - int big_endian; - int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; - int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL; - - - /* checks */ - if (!check_extensions(streamFile, "csmp")) - goto fail; - - if (read_32bitBE(0x00, streamFile) != 0x5246524D) /* "RFRM" */ - goto fail; - /* 0x08: file size but not exact */ - if (read_32bitBE(0x14, streamFile) != 0x43534D50) /* "CSMP" */ - goto fail; - version = read_32bitBE(0x18,streamFile); /* assumed, also at 0x1c */ - - if (version == 0x0a) { /* Wii U */ - read_32bit = read_32bitBE; - read_16bit = read_16bitBE; - big_endian = 1; - } - else if (version == 0x12) { /* Switch */ - read_32bit = read_32bitLE; - read_16bit = read_16bitLE; - big_endian = 0; - } - else { - goto fail; - } - - - /* parse chunks (always BE) */ - { - off_t chunk_offset = 0x20; - off_t file_size = get_streamfile_size(streamFile); - - while (chunk_offset < file_size) { - uint32_t chunk_type = read_32bitBE(chunk_offset+0x00,streamFile); - size_t chunk_size = read_32bitBE(chunk_offset+0x08,streamFile); /* maybe 64b from 0x04? */ - - switch(chunk_type) { - case 0x464D5441: /* "FMTA" */ - fmta_offset = chunk_offset + 0x18; - break; - case 0x44415441: /* "DATA" */ - data_offset = chunk_offset + 0x18; - data_size = chunk_size; - break; - default: /* known: "LABL" (usually before "FMTA"), "META" (usually after "DATA") */ - break; - } - - chunk_offset += 0x18 + chunk_size; - } - - if (!fmta_offset || !data_offset || !data_size) - goto fail; - } - - - /* parse FMTA / DATA (fully interleaved standard DSPs) */ - channel_count = read_8bit(fmta_offset+0x00, streamFile); - /* FMTA 0x08: channel mapping */ - - header_offset = data_offset; - if (version == 0x0a) { - size_t align = 0x03; /* possibly 32b align */ - header_offset += align; - data_size -= align; - } - start_offset = header_offset + 0x60; - loop_flag = read_16bit(header_offset + 0x0C, streamFile); - interleave = data_size / channel_count; - - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count, loop_flag); - if (!vgmstream) goto fail; - - vgmstream->meta_type = meta_RFRM; - vgmstream->sample_rate = read_32bit(header_offset + 0x08, streamFile); - vgmstream->num_samples = read_32bit(header_offset + 0x00, streamFile); - vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bit(header_offset + 0x10, streamFile)); - vgmstream->loop_end_sample = dsp_nibbles_to_samples(read_32bit(header_offset + 0x14, streamFile)) + 1; - if (vgmstream->loop_end_sample > vgmstream->num_samples) /* ? */ - vgmstream->loop_end_sample = vgmstream->num_samples; - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = interleave; - dsp_read_coefs(vgmstream, streamFile, header_offset + 0x1C, interleave, big_endian); - dsp_read_hist (vgmstream, streamFile, header_offset + 0x40, interleave, big_endian); - - if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) - goto fail; - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} +#include "meta.h" +#include "../coding/coding.h" + +/* RFTM - Retro Studios format [Metroid Prime Remastered] */ +static VGMSTREAM* init_vgmstream_rfrm_mpr(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + off_t fmta_offset = 0, data_offset = 0, ras3_offset = 0, header_offset, start_offset; + size_t data_size = 0, interleave; + int loop_flag, channels; + int loop_start, loop_end, padding; + + /* checks */ + if (!is_id32be(0x00, sf, "RFRM")) + goto fail; + /* 0x08: file size but not exact */ + if (!is_id32be(0x14, sf, "CSMP")) + goto fail; + + if (!check_extensions(sf, "csmp")) + goto fail; + + if (read_32bitLE(0x18,sf) != 0x1F) /* assumed, also at 0x1c */ + goto fail; + + + /* parse chunks (always BE) */ + { + off_t chunk_offset = 0x20; + off_t file_size = get_streamfile_size(sf); + + while (chunk_offset < file_size) { + uint32_t chunk_type = read_32bitBE(chunk_offset + 0x00,sf); + size_t chunk_size = read_32bitLE(chunk_offset + 0x08,sf); + + switch(chunk_type) { + case 0x464D5441: /* "FMTA" */ + fmta_offset = chunk_offset + 0x18; + chunk_offset += 5 + 0x18 + chunk_size; + break; + case 0x44415441: /* "DATA" */ + data_offset = chunk_offset + 0x18; + data_size = read_32bitLE(chunk_offset + 0x04, sf); + /* we're done here, DATA is the last chunk */ + chunk_offset = file_size; + break; + case 0x52415333: /* "RAS3" */ + ras3_offset = chunk_offset + 0x18; + chunk_offset += 60; + break; + case 0x43524D53: /* CRMS */ + chunk_offset += 9 + 0x18 + chunk_size + read_32bitLE(chunk_offset + 0x18 + chunk_size + 5, sf); + break; + default: + goto fail; + } + } + + if (!fmta_offset || !data_offset || !data_size) + goto fail; + } + + + /* parse FMTA / DATA (fully interleaved standard DSPs) */ + channels = read_8bit(fmta_offset + 0x00, sf); + if (channels == 0) goto fail; /* div by zero */ + /* FMTA 0x08: channel mapping */ + + header_offset = data_offset; + start_offset = header_offset + 0x80 * channels; + loop_flag = read_16bitLE(header_offset + 0x0C, sf); + interleave = data_size / channels; + + if (ras3_offset) { + int block_size = read_32bitLE(ras3_offset + 0x00, sf); + int block_samples = read_32bitLE(ras3_offset + 0x8, sf); + int loop_start_block = read_32bitLE(ras3_offset + 0x14, sf); + int loop_start_sample = read_32bitLE(ras3_offset + 0x18, sf); + int loop_end_block = read_32bitLE(ras3_offset + 0x1C, sf); + int loop_end_sample = read_32bitLE(ras3_offset + 0x20, sf); + padding = read_32bitLE(ras3_offset + 0x0C, sf); + + loop_start = loop_start_block * block_samples + loop_start_sample - padding; + loop_end = loop_end_block * block_samples + loop_end_sample - padding; + if ((loop_start || loop_end) && (loop_start < loop_end)) + loop_flag = 1; + + interleave = block_size / channels; + } else { + loop_start = dsp_nibbles_to_samples(read_32bitLE(header_offset + 0x10, sf)); + loop_end = dsp_nibbles_to_samples(read_32bitLE(header_offset + 0x14, sf)) + 1; + } + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_RFRM; + vgmstream->sample_rate = read_32bitLE(header_offset + 0x08, sf); + vgmstream->num_samples = read_32bitLE(header_offset + 0x00, sf); + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; + if (vgmstream->loop_end_sample > vgmstream->num_samples) /* ? */ + vgmstream->loop_end_sample = vgmstream->num_samples; + + if (ras3_offset) { + int padding_bytes = padding / 14 * 8; /* round to frames */ + vgmstream->interleave_first_block_size = interleave - padding_bytes; + vgmstream->interleave_first_skip = padding_bytes; + start_offset += padding_bytes; + } + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + dsp_read_coefs(vgmstream, sf, header_offset + 0x1C, 0x80, 0); + dsp_read_hist (vgmstream, sf, header_offset + 0x40, 0x80, 0); + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + +/* RFTM - Retro Studios format [Donkey Kong Country Tropical Freeze (WiiU/Switch)] */ +VGMSTREAM* init_vgmstream_rfrm(STREAMFILE* sf) { + VGMSTREAM *vgmstream = NULL; + off_t fmta_offset = 0, data_offset = 0, header_offset, start_offset; + size_t data_size = 0, interleave; + int loop_flag, channels, version; + int big_endian; + int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; + int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL; + + /* checks */ + if (!is_id32be(0x00, sf, "RFRM")) + goto fail; + /* 0x08: file size but not exact */ + if (!is_id32be(0x14, sf, "CSMP")) + goto fail; + + if (!check_extensions(sf, "csmp")) + goto fail; + + version = read_32bitBE(0x18,sf); /* assumed, also at 0x1c */ + if (version == 0x0a) { /* Wii U */ + read_32bit = read_32bitBE; + read_16bit = read_16bitBE; + big_endian = 1; + } + else if (version == 0x12) { /* Switch */ + read_32bit = read_32bitLE; + read_16bit = read_16bitLE; + big_endian = 0; + } + else if (version == 0x1F000000) { /* Metroid Prime Remastered */ + return init_vgmstream_rfrm_mpr(sf); + } + else { + goto fail; + } + + + /* parse chunks (always BE) */ + { + off_t chunk_offset = 0x20; + off_t file_size = get_streamfile_size(sf); + + while (chunk_offset < file_size) { + uint32_t chunk_type = read_32bitBE(chunk_offset+0x00,sf); + size_t chunk_size = read_32bitBE(chunk_offset+0x08,sf); /* maybe 64b from 0x04? */ + + switch(chunk_type) { + case 0x464D5441: /* "FMTA" */ + fmta_offset = chunk_offset + 0x18; + break; + case 0x44415441: /* "DATA" */ + data_offset = chunk_offset + 0x18; + data_size = chunk_size; + break; + default: /* known: "LABL" (usually before "FMTA"), "META" (usually after "DATA") */ + break; + } + + chunk_offset += 0x18 + chunk_size; + } + + if (!fmta_offset || !data_offset || !data_size) + goto fail; + } + + + /* parse FMTA / DATA (fully interleaved standard DSPs) */ + channels = read_8bit(fmta_offset+0x00, sf); + /* FMTA 0x08: channel mapping */ + + header_offset = data_offset; + if (version == 0x0a) { + size_t align = 0x03; /* possibly 32b align */ + header_offset += align; + data_size -= align; + } + start_offset = header_offset + 0x60; + loop_flag = read_16bit(header_offset + 0x0C, sf); + interleave = data_size / channels; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_RFRM; + vgmstream->sample_rate = read_32bit(header_offset + 0x08, sf); + vgmstream->num_samples = read_32bit(header_offset + 0x00, sf); + vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bit(header_offset + 0x10, sf)); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(read_32bit(header_offset + 0x14, sf)) + 1; + if (vgmstream->loop_end_sample > vgmstream->num_samples) /* ? */ + vgmstream->loop_end_sample = vgmstream->num_samples; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + dsp_read_coefs(vgmstream, sf, header_offset + 0x1C, interleave, big_endian); + dsp_read_hist (vgmstream, sf, header_offset + 0x40, interleave, big_endian); + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/riff.c b/Frameworks/vgmstream/vgmstream/src/meta/riff.c index b58d8bb1c..a46bf91f3 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/riff.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/riff.c @@ -378,8 +378,9 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) { * .p1d: Farming Simulator 15 (Vita)[ATRAC9] * .xms: Ty the Tasmanian Tiger (Xbox) * .mus: Burnout Legends/Dominator (PSP) + * .dat/ldat: RollerCoaster Tycoon 1/2 (PC) */ - if (!check_extensions(sf, "wav,lwav,xwav,mwv,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv,wvx,str,at3,rws,aud,at9,ckd,saf,ima,nsa,pcm,xvag,ogg,logg,p1d,xms,mus")) { + if (!check_extensions(sf, "wav,lwav,xwav,mwv,da,dax,cd,med,snd,adx,adp,xss,xsew,adpcm,adw,wd,,sbv,wvx,str,at3,rws,aud,at9,ckd,saf,ima,nsa,pcm,xvag,ogg,logg,p1d,xms,mus,dat,ldat")) { goto fail; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sdrh.c b/Frameworks/vgmstream/vgmstream/src/meta/sdrh.c index e5aaa54c9..88d43035a 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sdrh.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sdrh.c @@ -126,6 +126,17 @@ VGMSTREAM* init_vgmstream_sdrh_new(STREAMFILE* sf) { break; +#ifdef VGM_USE_MPEG + case 5: { /* No More Heroes (PS3) (rare, BAITO_GOMIHORI.XSE) */ + mpeg_custom_config cfg = {0}; + cfg.data_size = stream_size; + + vgmstream->codec_data = init_mpeg_custom(sf, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_STANDARD, &cfg); + if (!vgmstream->codec_data) goto fail; + vgmstream->layout_type = layout_none; + break; + } +#endif #ifdef VGM_USE_FFMPEG case 1: { /* Mindjack (X360), Moon Diver (X360) */ int block_size = 0x10000; /* XWAV new default */ @@ -145,10 +156,15 @@ VGMSTREAM* init_vgmstream_sdrh_new(STREAMFILE* sf) { break; } - case 7: { /* Mindjack (PS3) */ + case 6: /* No More Heroes (PS3) */ + case 7: /* No More Heroes (PS3), Mindjack (PS3) */ + case 8: { /* No More Heroes (PS3) */ int block_align, encoder_delay; - block_align = 0x98 * vgmstream->channels; + /* fixed for all rates? doesn't happen with other codecs, some files are 48000 already */ + vgmstream->sample_rate = 48000; + + block_align = (codec == 8 ? 0xC0 : codec == 0x07 ? 0x98 : 0x60) * vgmstream->channels; encoder_delay = 1024 + 69*2; /* observed default, but seems files run out of space */ vgmstream->codec_data = init_ffmpeg_atrac3_raw(sf, start_offset, stream_size, vgmstream->num_samples, vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sli.c b/Frameworks/vgmstream/vgmstream/src/meta/sli.c index b4a994c05..d8b3ca795 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sli.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sli.c @@ -1,105 +1,53 @@ #include "meta.h" #include +#include +static bool get_loops(STREAMFILE* sf, int32_t* p_loop_start, int32_t* p_loop_end); -/* .sli+ogg/opus - KiriKiri engine / WaveLoopManager loop points loader [Fate/Stay Night (PC), World End Economica (PC)] */ -VGMSTREAM* init_vgmstream_sli_ogg(STREAMFILE* sf) { +/* .sli+ogg/opus/wav - KiriKiri engine / WaveLoopManager loop points loader [Fate/Stay Night (PC), World End Economica (PC)] */ +VGMSTREAM* init_vgmstream_sli_loops(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; STREAMFILE* sf_data = NULL; - int32_t loop_start = -1, loop_length = -1; - int32_t loop_from = -1, loop_to = -1; + int32_t loop_start = 0, loop_end = 0; + VGMSTREAM* (*init_vgmstream)(STREAMFILE* sf) = NULL; /* checks */ if (!check_extensions(sf, "sli")) goto fail; { - /* try with file.ogg/opus.sli=header and file.ogg/opus=data */ + /* try with file.ogg/opus/wav.sli=header and file.ogg/opus/wav=data */ char basename[PATH_LIMIT]; get_streamfile_basename(sf,basename,PATH_LIMIT); sf_data = open_streamfile_by_filename(sf, basename); if (!sf_data) goto fail; } - if (!is_id32be(0x00, sf_data, "OggS")) - goto fail; - - /* let the real initer do the parsing */ - if (is_id32be(0x1c, sf_data, "Opus")) { /* Sabbat of the Witch (PC) */ - vgmstream = init_vgmstream_ogg_opus(sf_data); - if (!vgmstream) goto fail; - - /* somehow sli+opus use 0 encoder delay in the OpusHead (to simplify looping?) */ - vgmstream->meta_type = meta_OPUS_SLI; - } - else { /* Fate/Stay Night (PC) */ - vgmstream = init_vgmstream_ogg_vorbis(sf_data); - if (!vgmstream) goto fail; - - vgmstream->meta_type = meta_OGG_SLI; - } - - - /* find loop text */ - { - char line[PATH_LIMIT]; - size_t bytes_read; - off_t sli_offset; - int line_ok; - - sli_offset = 0; - while ((loop_start == -1 || loop_length == -1) && sli_offset < get_streamfile_size(sf)) { - char *endptr, *foundptr; - - bytes_read = read_line(line, sizeof(line), sli_offset, sf, &line_ok); - if (!line_ok) goto fail; - sli_offset += bytes_read; - /* files may be padded with 0s */ - - /* comments in v2.0 [Sabbath of the Witch (PC), KARAKARA (PC)] */ - if (line[0] == '#') - continue; - - if (memcmp("LoopStart=", line,10) == 0 && line[10] != '\0') { - loop_start = strtol(line + 10, &endptr, 10); - if (*endptr != '\0') { - loop_start = -1; /* if it didn't parse cleanly */ - } - } - else if (memcmp("LoopLength=", line, 11) == 0 && line[11] != '\0') { - loop_length = strtol(line + 11, &endptr, 10); - if (*endptr != '\0') { - loop_length = -1; /* if it didn't parse cleanly */ - } - } - - /* a completely different format ("#2.00"?), can be handled similarly */ - if ((foundptr = strstr(line,"To=")) != NULL && isdigit(foundptr[3])) { - loop_to = strtol(foundptr + 3, &endptr, 10); - if (*endptr != ';') { - loop_to = -1; - } - } - if ((foundptr = strstr(line,"From=")) != NULL && isdigit(foundptr[5])) { - loop_from = strtol(foundptr + 5, &endptr, 10); - if (*endptr != ';') { - loop_from = -1; - } - } - + if (is_id32be(0x00, sf_data, "OggS")) { + if (is_id32be(0x1c, sf_data, "Opus")) { /* Sabbat of the Witch (PC) */ + init_vgmstream = init_vgmstream_ogg_opus; + /* somehow sli+opus use 0 encoder delay in the OpusHead (to simplify looping?) */ + } + else { /* Fate/Stay Night (PC) */ + init_vgmstream = init_vgmstream_ogg_vorbis; } } - - if (loop_start != -1 && loop_length != -1) { /* v1 */ - vgmstream_force_loop(vgmstream, 1, loop_start, loop_start + loop_length); - } - else if (loop_from != -1 && loop_to != -1) { /* v2 */ - vgmstream_force_loop(vgmstream, 1, loop_to, loop_from); + else if (is_id32be(0x00, sf_data, "RIFF")) { + /* Perfect Cherry Blossom Trial+ (PC) (RIFF created by extractor?) */ + init_vgmstream = init_vgmstream_riff; } else { - goto fail; /* if there's no loop points the .sli wasn't valid */ + goto fail; } + vgmstream = init_vgmstream(sf_data); + if (!vgmstream) goto fail; + + if (!get_loops(sf, &loop_start, &loop_end)) + goto fail; + + vgmstream_force_loop(vgmstream, 1, loop_start, loop_end); + close_streamfile(sf_data); return vgmstream; @@ -108,3 +56,71 @@ fail: close_vgmstream(vgmstream); return NULL; } + + +static bool get_loops(STREAMFILE* sf, int32_t* p_loop_start, int32_t* p_loop_end) { + int32_t loop_start = -1, loop_length = -1; + int32_t loop_from = -1, loop_to = -1; + + char line[PATH_LIMIT]; + size_t bytes_read; + off_t sli_offset; + int line_ok; + + sli_offset = 0; + while ((loop_start == -1 || loop_length == -1) && sli_offset < get_streamfile_size(sf)) { + char *endptr, *foundptr; + + bytes_read = read_line(line, sizeof(line), sli_offset, sf, &line_ok); + if (!line_ok) goto fail; + sli_offset += bytes_read; + /* files may be padded with 0s */ + + /* comments in v2.0 [Sabbath of the Witch (PC), KARAKARA (PC)] */ + if (line[0] == '#') + continue; + + if (memcmp("LoopStart=", line,10) == 0 && line[10] != '\0') { + loop_start = strtol(line + 10, &endptr, 10); + if (*endptr != '\0') { + loop_start = -1; /* if it didn't parse cleanly */ + } + } + else if (memcmp("LoopLength=", line, 11) == 0 && line[11] != '\0') { + loop_length = strtol(line + 11, &endptr, 10); + if (*endptr != '\0') { + loop_length = -1; /* if it didn't parse cleanly */ + } + } + + /* a completely different format ("#2.00"?), can be handled similarly */ + if ((foundptr = strstr(line,"To=")) != NULL && isdigit(foundptr[3])) { + loop_to = strtol(foundptr + 3, &endptr, 10); + if (*endptr != ';') { + loop_to = -1; + } + } + if ((foundptr = strstr(line,"From=")) != NULL && isdigit(foundptr[5])) { + loop_from = strtol(foundptr + 5, &endptr, 10); + if (*endptr != ';') { + loop_from = -1; + } + } + } + + if (loop_start != -1 && loop_length != -1) { /* v1 */ + *p_loop_start = loop_start; + *p_loop_end = loop_start + loop_length; + } + else if (loop_from != -1 && loop_to != -1) { /* v2 */ + *p_loop_start = loop_to; + *p_loop_end = loop_from; + } + else { + goto fail; /* if there's no loop points the .sli wasn't valid */ + } + + return true; +fail: + return false; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/swav.c b/Frameworks/vgmstream/vgmstream/src/meta/swav.c index f487e4cb1..6fdaa5a48 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/swav.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/swav.c @@ -16,8 +16,8 @@ VGMSTREAM* init_vgmstream_swav(STREAMFILE* sf) { if (!is_id32be(0x00,sf, "SWAV")) goto fail; - /* .swav: standard - * .adpcm: Merlin - A Servant of Two Masters (DS) */ + /* .swav: standard [found inside .sdat but SDK can create them] + * .adpcm: Merlin - A Servant of Two Masters (DS) [external] */ if (!check_extensions(sf, "swav,adpcm")) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_ckd.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_ckd.c index 6f76a4d16..47cf74d5c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_ckd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_ckd.c @@ -56,6 +56,10 @@ VGMSTREAM* init_vgmstream_ubi_ckd(STREAMFILE* sf) { } else if (find_chunk_be(sf, 0x6461744C,first_offset,0, &chunk_offset,&chunk_size)) { /* "datL" */ /* mono "datL" or full interleave with a "datR" after the "datL" (no check, pretend it exists) */ start_offset = chunk_offset; + + /* chunks follow RIFF's spec of "odd sizes treated as even" [Rayman Origins (Wii)-420_hud~sfx_endofmap_discoloop.wav.ckd] */ + if (chunk_size % 0x02 != 0) + chunk_size += 0x01; data_size = chunk_size * channels; interleave = (0x4+0x4) + chunk_size; /* don't forget to skip the "datR"+size chunk */ } else { diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c index 2a830ab07..e201e03dd 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c @@ -250,8 +250,8 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, uint32_t offset, uint read_u32_t read_u32 = hx->big_endian ? read_u32be : read_u32le; read_s32_t read_s32 = hx->big_endian ? read_s32be : read_s32le; read_u16_t read_u16 = hx->big_endian ? read_u16be : read_u16le; - off_t riff_offset, riff_size, chunk_offset, stream_adjust = 0, resource_size; - size_t chunk_size; + uint32_t riff_offset, riff_size, stream_adjust = 0, resource_size, chunk_size; + off_t chunk_offset; int cue_flag = 0; //todo cleanup/unify common readings @@ -339,7 +339,7 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, uint32_t offset, uint break; default: - VGM_LOG("ubi hx: unknown stream mode %x\n", hx->stream_mode); + VGM_LOG("ubi hx: unknown wave mode %x\n", hx->stream_mode); goto fail; } @@ -423,14 +423,28 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, uint32_t offset, uint if ((strcmp(hx->class_name, "CXBoxStaticHWWaveFileIdObj") == 0 || strcmp(hx->class_name, "CXBoxStreamHWWaveFileIdObj") == 0) && !hx->big_endian) { /* micro header: some mix of channels + block size + sample rate + flags, unsure of which bits */ - hx->codec = XIMA; + /* 0x00: ? */ - hx->channels = read_u8(offset + 0x01, sf); /* upper 2 bits? */ - switch(hx->channels) { - case 0x48: hx->channels = 1; break; - case 0x90: hx->channels = 2; break; + uint8_t flags = read_u8(offset + 0x01, sf); + switch(flags) { + case 0x05: // b00000101 /* XIII (Xbox)-beta 2002-12 */ + hx->channels = 1; + hx->codec = PCM; + break; + case 0x09: // b00001001 /* XIII (Xbox)-beta 2002-12 */ + hx->channels = 2; + hx->codec = PCM; + break; + case 0x48: // b01001000 + hx->channels = 1; + hx->codec = XIMA; + break; + case 0x90: // b10010000 + hx->channels = 2; + hx->codec = XIMA; + break; default: - VGM_LOG("ubi hx: channel type %x\n", hx->channels); + VGM_LOG("ubi hx: channel flags %x\n", flags); goto fail; } hx->sample_rate = (read_u16(offset + 0x02, sf) & 0x7FFFu) << 1u; /* ??? */ @@ -473,6 +487,7 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, uint32_t offset, uint switch(hx->stream_mode) { case 0x00: /* static (smaller internal file) [XIII (Xbox)] */ + case 0x02: /* static (smaller internal file) [XIII-beta (Xbox)] */ hx->stream_offset += offset; break; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wave.c b/Frameworks/vgmstream/vgmstream/src/meta/wave.c index 554a97438..8e93089fe 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/wave.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/wave.c @@ -16,8 +16,9 @@ VGMSTREAM* init_vgmstream_wave(STREAMFILE* sf) { /* checks */ if (!is_id32be(0x00,sf, "VAW3") && /* Happy Feet Two (3DS) */ - read_u32le(0x00,sf) != 0xE5B7ECFE && /* common (LE) */ - read_u32be(0x00,sf) != 0xE5B7ECFE) /* used? */ + read_u32le(0x00,sf) != 0xE5B7ECFE && /* common LE (hashed something?) */ + read_u32be(0x00,sf) != 0xE5B7ECFE && + read_u32be(0x00,sf) != 0xC9FB0C03) /* NDS [Lalaloopsy, Adventure Time: HIKWYSOG (DS)] */ goto fail; /* 0x04: version? common=0, VAW3=2 */ @@ -51,15 +52,15 @@ VGMSTREAM* init_vgmstream_wave(STREAMFILE* sf) { start_offset = read_u32(0x20, sf); interleave = read_u32(0x24, sf); /* typically half data_size */ - extradata_offset = read_u32(0x28, sf); /* OR: extradata size (always 0x2c) */ + extradata_offset = read_u32(0x28, sf); /* always 0x2c */ loop_flag = (loop_start > 0); /* some songs (ex. Adventure Time's m_candykingdom_overworld.wave) do full loops, but there is no way * to tell them apart from sfx/voices, so we try to detect if it's long enough. */ if(!loop_flag && loop_start == 0 && loop_end == num_samples /* full loop */ - && channels > 1 - && num_samples > 20*sample_rate) { /* in seconds */ + && (channels > 1 || (channels == 1 && start_offset <= 0x40)) + && num_samples > 30*sample_rate) { /* in seconds */ loop_flag = 1; } @@ -75,22 +76,37 @@ VGMSTREAM* init_vgmstream_wave(STREAMFILE* sf) { vgmstream->meta_type = meta_WAVE; - /* not sure if there are other codecs but anyway */ + /* not sure if there are other codecs but anyway (based also see wave-segmented) */ switch(codec) { case 0x02: - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = interleave; + /* DS games use IMA, no apparent flag (could also test ID) */ + if (start_offset <= 0x40) { + vgmstream->coding_type = coding_IMA_int; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; - /* ADPCM setup: 0x20 coefs + 0x06 initial ps/hist1/hist2 + 0x06 loop ps/hist1/hist2, per channel */ - dsp_read_coefs(vgmstream, sf, extradata_offset+0x00, 0x2c, big_endian); - dsp_read_hist(vgmstream, sf, extradata_offset+0x22, 0x2c, big_endian); + /* extradata: + * 0x00: base hist? (only seen 0) + * 0x02: base step? (only seen 0) + * 0x04: loop hist? + * 0x06: loop step? + */ + } + else { + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + + /* ADPCM setup: 0x20 coefs + 0x06 initial ps/hist1/hist2 + 0x06 loop ps/hist1/hist2, per channel */ + dsp_read_coefs(vgmstream, sf, extradata_offset+0x00, 0x2c, big_endian); + dsp_read_hist(vgmstream, sf, extradata_offset+0x22, 0x2c, big_endian); + } break; default: goto fail; } - if (!vgmstream_open_stream(vgmstream,sf,start_offset)) + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) goto fail; return vgmstream; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xwav.c b/Frameworks/vgmstream/vgmstream/src/meta/xwav.c index 1c54d5df6..2af1fea75 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xwav.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xwav.c @@ -91,15 +91,21 @@ VGMSTREAM* init_vgmstream_xwav_new(STREAMFILE* sf) { break; } - case 7: { /* Moon Diver (PS3) */ + case 6: /* (used? same as SDRH) */ + case 7: /* Moon Diver (PS3) */ + case 8: { /* No More Heroes (PS3) */ int block_align, encoder_delay; - data_size = read_u32be(0x54,sf); - block_align = 0x98 * vgmstream->channels; + /* fixed for all rates? doesn't happen with other codecs, some files are 48000 already */ + vgmstream->sample_rate = 48000; + + block_align = (codec == 8 ? 0xC0 : codec == 0x07 ? 0x98 : 0x60) * vgmstream->channels; encoder_delay = 1024 + 69*2; /* observed default, matches XMA (needed as many files start with garbage) */ + + data_size = read_u32be(0x54,sf); vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_align) - encoder_delay; /* original samples break looping in some files otherwise */ - vgmstream->codec_data = init_ffmpeg_atrac3_raw(sf, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay); + vgmstream->codec_data = init_ffmpeg_atrac3_raw(sf, start_offset, data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xwb.c b/Frameworks/vgmstream/vgmstream/src/meta/xwb.c index fe841e25f..307719daf 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xwb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xwb.c @@ -32,24 +32,24 @@ typedef struct { int version; /* segments */ - off_t base_offset; - size_t base_size; - off_t entry_offset; - size_t entry_size; - off_t names_offset; - size_t names_size; - size_t names_entry_size; - off_t extra_offset; - size_t extra_size; - off_t data_offset; - size_t data_size; + uint32_t base_offset; + uint32_t base_size; + uint32_t entry_offset; + uint32_t entry_size; + uint32_t names_offset; + uint32_t names_size; + uint32_t names_entry_size; + uint32_t extra_offset; + uint32_t extra_size; + uint32_t data_offset; + uint32_t data_size; - off_t stream_offset; - size_t stream_size; + uint32_t stream_offset; + uint32_t stream_size; uint32_t base_flags; - size_t entry_elem_size; - size_t entry_alignment; + uint32_t entry_elem_size; + uint32_t entry_alignment; int total_subsongs; uint32_t entry_flags; @@ -97,7 +97,7 @@ VGMSTREAM* init_vgmstream_xwb(STREAMFILE* sf) { * .xna: Touhou Makukasai ~ Fantasy Danmaku Festival (PC) * (extensionless): Ikaruga (X360/PC), Grabbed by the Ghoulies (Xbox) * .bd: Fatal Frame 2 (Xbox) */ - if (!check_extensions(sf,"xwb,xna,bd")) + if (!check_extensions(sf,"xwb,xna,bd,")) goto fail; xwb.little_endian = is_id32be(0x00,sf, "WBND"); /* Xbox/PC */ @@ -362,6 +362,11 @@ VGMSTREAM* init_vgmstream_xwb(STREAMFILE* sf) { /* Stardew Valley (Vita), Owlboy (PS4): standard RIFF with ATRAC9 */ xwb.codec = ATRAC9_RIFF; } + else if (xwb.version == XACT1_1_MAX && xwb.codec == WMA + && read_u32be(xwb.stream_offset, sf) != 0x3026B275) { /* WMA/asf tag */ + /* Jumper: Griffin's Story (X360): partial hijack (LE on X360 and early version + XMA2) */ + xwb.codec = XMA2; + } /* test loop after the above fixes */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xwma.c b/Frameworks/vgmstream/vgmstream/src/meta/xwma.c index acd924dd9..3fd64c982 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xwma.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xwma.c @@ -31,8 +31,11 @@ VGMSTREAM* init_vgmstream_xwma(STREAMFILE* sf) { if (!is_id32be(0x08,sf, "XWMA")) goto fail; /* .xwma: standard - * .xwm: The Elder Scrolls: Skyrim (PC), Blade Arcus from Shining (PC) */ - if (!check_extensions(sf, "xwma,xwm")) + * .xwm: The Elder Scrolls: Skyrim (PC), Blade Arcus from Shining (PC) + * .xma: Castle Crashers (PC) + * .wma/lwma: BattleBlock Theater (PC) + */ + if (!check_extensions(sf, "xwma,xwm,xma,wma,lwma")) goto fail; { diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.c b/Frameworks/vgmstream/vgmstream/src/vgmstream.c index c4478df0b..a2f6a6c48 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.c @@ -525,6 +525,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_bigrp, init_vgmstream_sscf_encrypted, init_vgmstream_s_p_sth, + init_vgmstream_utf_ahx, /* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */ init_vgmstream_scd_pcm, @@ -536,7 +537,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_mic_koei, init_vgmstream_seb, init_vgmstream_ps2_pnb, - init_vgmstream_sli_ogg, + init_vgmstream_sli_loops, init_vgmstream_tgc, /* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ diff --git a/Info.plist.template b/Info.plist.template index 8d5e0b8c0..2efb0cb92 100644 --- a/Info.plist.template +++ b/Info.plist.template @@ -397,6 +397,7 @@ ap apc as4 + asbin asd asf asr @@ -423,6 +424,7 @@ bar bcstm bcwav + bcv bd3 bdsp bfstm @@ -435,6 +437,7 @@ bik bika bik2 + binka bk2 bkr blk @@ -456,7 +459,6 @@ cads caf cbd2 - ccc cd cfn chd @@ -468,6 +470,7 @@ cpk cps csa + csb csmp cvs cwav @@ -504,6 +507,7 @@ exa ezw fag + fcb fda ffw filp @@ -575,6 +579,7 @@ kces kcey km9 + kma kmx kovs kno @@ -596,6 +601,7 @@ lac3 lasf lbin + ldat leg lep lflac @@ -737,7 +743,6 @@ rws rwsd rwx - rxw rxx s14 s3s @@ -796,6 +801,7 @@ smp smpl smv + snb snd snds sng