Updated VGMStream to r1831-27-ge6883cbd

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
main
Christopher Snowhill 2023-05-04 18:22:08 -07:00
parent dfa5f41984
commit d2adf39e04
No known key found for this signature in database
38 changed files with 871 additions and 584 deletions

View File

@ -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);

View File

@ -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 <math.h>
#include <limits.h>
#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 <intrin.h>
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

View File

@ -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) {

View File

@ -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;

View File

@ -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) {

View File

@ -3,6 +3,7 @@
#include "../util.h"
#ifdef VGM_USE_VORBIS
#define OV_EXCLUDE_STATIC_CALLBACKS
#include <vorbis/vorbisfile.h>
#define OGG_DEFAULT_BITSTREAM 0

View File

@ -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);

View File

@ -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)"},

View File

@ -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);

View File

@ -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;
}

View File

@ -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},
};

View File

@ -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:

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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]);

View File

@ -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_*/

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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;