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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,105 +1,53 @@
#include "meta.h"
#include <ctype.h>
#include <stdbool.h>
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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -397,6 +397,7 @@
<string>ap</string>
<string>apc</string>
<string>as4</string>
<string>asbin</string>
<string>asd</string>
<string>asf</string>
<string>asr</string>
@ -423,6 +424,7 @@
<string>bar</string>
<string>bcstm</string>
<string>bcwav</string>
<string>bcv</string>
<string>bd3</string>
<string>bdsp</string>
<string>bfstm</string>
@ -435,6 +437,7 @@
<string>bik</string>
<string>bika</string>
<string>bik2</string>
<string>binka</string>
<string>bk2</string>
<string>bkr</string>
<string>blk</string>
@ -456,7 +459,6 @@
<string>cads</string>
<string>caf</string>
<string>cbd2</string>
<string>ccc</string>
<string>cd</string>
<string>cfn</string>
<string>chd</string>
@ -468,6 +470,7 @@
<string>cpk</string>
<string>cps</string>
<string>csa</string>
<string>csb</string>
<string>csmp</string>
<string>cvs</string>
<string>cwav</string>
@ -504,6 +507,7 @@
<string>exa</string>
<string>ezw</string>
<string>fag</string>
<string>fcb</string>
<string>fda</string>
<string>ffw</string>
<string>filp</string>
@ -575,6 +579,7 @@
<string>kces</string>
<string>kcey</string>
<string>km9</string>
<string>kma</string>
<string>kmx</string>
<string>kovs</string>
<string>kno</string>
@ -596,6 +601,7 @@
<string>lac3</string>
<string>lasf</string>
<string>lbin</string>
<string>ldat</string>
<string>leg</string>
<string>lep</string>
<string>lflac</string>
@ -737,7 +743,6 @@
<string>rws</string>
<string>rwsd</string>
<string>rwx</string>
<string>rxw</string>
<string>rxx</string>
<string>s14</string>
<string>s3s</string>
@ -796,6 +801,7 @@
<string>smp</string>
<string>smpl</string>
<string>smv</string>
<string>snb</string>
<string>snd</string>
<string>snds</string>
<string>sng</string>