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. /** State of the decoder. One decoder state is needed for each stream.
It is initialised once at the beginning of the stream. Do *not* It is initialised once at the beginning of the stream. Do *not*
re-initialise the state for every frame */ re-initialise the state for every frame */
typedef struct CELT0061Decoder CELT0061Decoder; typedef struct CELTDecoder0061 CELTDecoder0061;
typedef struct CELT0110Decoder CELT0110Decoder; typedef struct CELTDecoder CELTDecoder0110;
/** The mode contains all the information necessary to create an /** The mode contains all the information necessary to create an
encoder. Both the encoder and decoder need to be initialised encoder. Both the encoder and decoder need to be initialised
with exactly the same mode, otherwise the quality will be very with exactly the same mode, otherwise the quality will be very
bad */ bad */
typedef struct CELT0061Mode CELT0061Mode; typedef struct CELTMode0061 CELTMode0061;
typedef struct CELT0110Mode CELT0110Mode; typedef struct CELTMode0110 CELTMode0110;
/* Mode calls */ /* Mode calls */
@ -80,19 +80,19 @@ typedef struct CELT0110Mode CELT0110Mode;
@param error Returned error code (if NULL, no error will be returned) @param error Returned error code (if NULL, no error will be returned)
@return A newly created mode @return A newly created mode
*/ */
EXPORT CELT0061Mode *celt_0061_mode_create(celt_int32 Fs, int channels, int frame_size, int *error); /*EXPORT*/ CELTMode0061 *celt_mode_create_0061(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*/ CELTMode0110 *celt_mode_create_0110(celt_int32 Fs, int frame_size, int *error);
/** Destroys a mode struct. Only call this after all encoders and /** Destroys a mode struct. Only call this after all encoders and
decoders using this mode are destroyed as well. decoders using this mode are destroyed as well.
@param mode Mode to be destroyed @param mode Mode to be destroyed
*/ */
EXPORT void celt_0061_mode_destroy(CELT0061Mode *mode); /*EXPORT*/ void celt_mode_destroy_0061(CELTMode0061 *mode);
EXPORT void celt_0110_mode_destroy(CELT0110Mode *mode); /*EXPORT*/ void celt_mode_destroy_0110(CELTMode0110 *mode);
/** Query information from a mode */ /** Query information from a mode */
EXPORT int celt_0061_mode_info(const CELT0061Mode *mode, int request, celt_int32 *value); /*EXPORT*/ int celt_mode_info_0061(const CELTMode0061 *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_0110(const CELTMode0110 *mode, int request, celt_int32 *value);
/* Decoder stuff */ /* 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 @param error Returns an error code
@return Newly created decoder state. @return Newly created decoder state.
*/ */
EXPORT CELT0061Decoder *celt_0061_decoder_create(const CELT0061Mode *mode); /*EXPORT*/ CELTDecoder0061 *celt_decoder_create_0061(const CELTMode0061 *mode);
EXPORT CELT0110Decoder *celt_0110_decoder_create_custom(const CELT0110Mode *mode, int channels, int *error); /*EXPORT*/ CELTDecoder0110 *celt_decoder_create_custom_0110(const CELTMode0110 *mode, int channels, int *error);
/** Destroys a a decoder state. /** Destroys a a decoder state.
@param st Decoder state to be destroyed @param st Decoder state to be destroyed
*/ */
EXPORT void celt_0061_decoder_destroy(CELT0061Decoder *st); /*EXPORT*/ void celt_decoder_destroy_0061(CELTDecoder0061 *st);
EXPORT void celt_0110_decoder_destroy(CELT0110Decoder *st); /*EXPORT*/ void celt_decoder_destroy_0110(CELTDecoder0110 *st);
/** Decodes a frame of audio. /** Decodes a frame of audio.
@param st Decoder state @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). returned here in 16-bit PCM format (native endian).
@return Error code. @return Error code.
*/ */
EXPORT int celt_0061_decode(CELT0061Decoder *st, const unsigned char *data, int len, celt_int16 *pcm); /*EXPORT*/ int celt_decode_0061(CELTDecoder0061 *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_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 #if 0
/* derive info */ /* derive info */
data->sampleRate = data->codecCtx->sample_rate; 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->bitrate = (int)(data->codecCtx->bit_rate);
data->blockAlign = data->codecCtx->block_align; data->blockAlign = data->codecCtx->block_align;
data->frameSize = data->codecCtx->frame_size; 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) { 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; 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); int is_planar = av_sample_fmt_is_planar(data->codecCtx->sample_fmt) && (channels > 1);
void* ibuf; void* ibuf;
@ -976,19 +980,39 @@ void ffmpeg_set_skip_samples(ffmpeg_codec_data* data, int skip_samples) {
/* returns channel layout if set */ /* returns channel layout if set */
uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data* data) { uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data* data) {
if (!data || !data->codecCtx) return 0; 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 /* yet another hack to fix codecs that encode channels in different order and reorder on decoder
* but FFmpeg doesn't do it automatically * but FFmpeg doesn't do it automatically
* (maybe should be done via mixing, but could clash with other stuff?) */ * (maybe should be done via mixing, but could clash with other stuff?) */
void ffmpeg_set_channel_remapping(ffmpeg_codec_data* data, int *channel_remap) { void ffmpeg_set_channel_remapping(ffmpeg_codec_data* data, int *channel_remap) {
int i; 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; 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[i] = channel_remap[i];
} }
data->channel_remap_set = 1; 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) { int ffmpeg_get_channels(ffmpeg_codec_data* data) {
if (!data || !data->codecCtx) if (!data || !data->codecCtx)
return 0; 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) { 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)); ffmpeg_data = init_ffmpeg_offset(temp_sf, 0x00, get_streamfile_size(temp_sf));
if (!ffmpeg_data) goto fail; if (!ffmpeg_data) goto fail;
/* FFmpeg + libopus: skips samples, notifies skip in codecCtx->delay (not in stream->skip_samples) /* FFmpeg + libopus: skips samples, notifies skip in codecCtx->delay/initial_padding (not in stream->skip_samples)
* FFmpeg + opus: *doesn't* skip, also notifies skip in codecCtx->delay, hurray (possibly fixed in recent versions) * FFmpeg + opus: skip samples but loses them on reset/seek to 0, also notifies skip in codecCtx->delay/initial_padding */
* FFmpeg + opus is audibly buggy with some low bitrate SSB Ultimate files */ {
//ffmpeg_set_skip_samples(ffmpeg_data, skip); /* 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); close_streamfile(temp_sf);
return ffmpeg_data; return ffmpeg_data;

View File

@ -189,7 +189,7 @@ fail:
#define AHX_KEY_BUFFER 0x2000 #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 */ /* check if current key ends properly in frame syncs */
int test_ahx_key(STREAMFILE* sf, off_t offset, crikey_t* crikey) { int test_ahx_key(STREAMFILE* sf, off_t offset, crikey_t* crikey) {

View File

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

View File

@ -3,7 +3,11 @@
#include "../util.h" #include "../util.h"
/* SDX2 - 2:1 Squareroot-delta-exact compression */ /* 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; } */ /* for (i=-128;i<128;i++) { squares[i+128] = i<0?(-i*i)*2:(i*i)*2; } */
static int16_t squares[256] = { 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) { for (uint16_t i = 0; i < 0x100; i += 1) {
int16_t v = i; int16_t v = i;
v -= 0x80; 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); int8_t sample_byte = read_8bit(stream->offset+i,stream->streamfile);
int16_t sample; 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]; sample = hist + table[sample_byte+128];
hist = outbuf[sample_count] = clamp16(sample); 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); int8_t sample_byte = read_8bit(stream->offset+i*channelspacing,stream->streamfile);
int16_t sample; 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]; sample = hist + table[sample_byte+128];
hist = outbuf[sample_count] = clamp16(sample); hist = outbuf[sample_count] = clamp16(sample);

View File

@ -70,6 +70,7 @@ static const char* extension_list[] = {
"ap", "ap",
"apc", "apc",
"as4", "as4",
"asbin",
"asd", "asd",
"asf", "asf",
"asr", "asr",
@ -145,6 +146,7 @@ static const char* extension_list[] = {
"cpk", "cpk",
"cps", "cps",
"csa", //txth/reserved [LEGO Racers 2 (PS2)] "csa", //txth/reserved [LEGO Racers 2 (PS2)]
"csb",
"csmp", "csmp",
"cvs", //txth/reserved [Aladdin in Nasira's Revenge (PS1)] "cvs", //txth/reserved [Aladdin in Nasira's Revenge (PS1)]
"cwav", "cwav",
@ -263,6 +265,7 @@ static const char* extension_list[] = {
"kces", "kces",
"kcey", //fake extension/header id for .pcm (renamed, to be removed) "kcey", //fake extension/header id for .pcm (renamed, to be removed)
"km9", "km9",
"kma", //txth/reserved [Dynasty Warriors 7: Empires (PS3)]
"kmx", "kmx",
"kovs", //fake extension/header id for .kvs "kovs", //fake extension/header id for .kvs
"kno", "kno",
@ -285,6 +288,7 @@ static const char* extension_list[] = {
"lac3", //fake extension for .ac3, FFmpeg/not parsed "lac3", //fake extension for .ac3, FFmpeg/not parsed
"lasf", //fake extension for .asf (various) "lasf", //fake extension for .asf (various)
"lbin", //fake extension for .bin (various) "lbin", //fake extension for .bin (various)
"ldat", //fake extension for .dat
"leg", "leg",
"lep", "lep",
"lflac", //fake extension for .flac, FFmpeg/not parsed "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_PC_FLX, "Ultima IX .FLX header"},
{meta_MOGG, "Harmonix Music Systems MOGG Vorbis"}, {meta_MOGG, "Harmonix Music Systems MOGG Vorbis"},
{meta_OGG_VORBIS, "Ogg Vorbis header"}, {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_SFL, "Ogg Vorbis header (SFPL looping)"},
{meta_OGG_KOVS, "Ogg Vorbis header (KOVS)"}, {meta_OGG_KOVS, "Ogg Vorbis header (KOVS)"},
{meta_OGG_encrypted, "Ogg Vorbis header (encrypted)"}, {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; off_t audio_offset;
size_t next_block_size, video_size; size_t next_block_size, video_size;
next_block_size = read_u32be(block_offset + 0x00, sf); next_block_size = read_u32be(block_offset + 0x00, sf); /* block may have padding, so need to save for next time */
/* 0x04: frame size previous */ /* 0x04: previous frame size */
video_size = read_u32be(block_offset + 0x08,sf); video_size = read_u32be(block_offset + 0x08,sf);
/* 0x0c: audio size */ /* 0x0c: audio size */
audio_offset = block_offset + 0x10 + video_size; audio_offset = block_offset + 0x10 + video_size;
vgmstream->current_block_offset = block_offset; 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; vgmstream->full_block_size = next_block_size;
/* block samples can be smaller than block size, normally in the last block, /* 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; audio_offset += 0x08;
for (i = 0; i < vgmstream->channels; i++) { 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 coef_offset = audio_offset + i*0x20;
off_t hist_offset = audio_offset + vgmstream->channels*0x20 + i*0x04; off_t hist_offset = audio_offset + 2*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 data_offset = audio_offset + 2*0x24 + i*vgmstream->current_block_size;
for (j = 0; j < 16; j++) { for (j = 0; j < 16; j++) {
vgmstream->ch[i].adpcm_coef[j] = read_s16be(coef_offset + (j*0x02),sf); vgmstream->ch[i].adpcm_coef[j] = read_s16be(coef_offset + (j*0x02),sf);

View File

@ -133,91 +133,3 @@ fail:
free_layout_segmented(data); free_layout_segmented(data);
return NULL; 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) */ /* Shoujo Yoshitsune-den Ni - Toki wo Koeru Chigiri (PS2) */
{0x62d7,0x483d,0x4fb7, "YOSHI2",0}, {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 */ /* 0x0c: ADPCM offset (from channel info offset), 0xFFFFFFFF otherwise */
/* 0x10: padding */ /* 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; goto fail;
chdt_offset = read_u32(chnf_offset + 0x04, sf) + data_offset + 0x08; 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; break;
default: default:

View File

@ -131,6 +131,7 @@ VGMSTREAM* init_vgmstream_bnk_sony(STREAMFILE* sf) {
case 0x0d: /* Polara (Vita), Crypt of the Necrodancer (Vita) */ case 0x0d: /* Polara (Vita), Crypt of the Necrodancer (Vita) */
case 0x0e: /* Yakuza 6's Puyo Puyo (PS4) */ case 0x0e: /* Yakuza 6's Puyo Puyo (PS4) */
case 0x0f: /* Ikaruga (PS4) */ case 0x0f: /* Ikaruga (PS4) */
case 0x10: /* Ginga Force (PS4) */
table1_offset = sblk_offset + read_u32(sblk_offset+0x18,sf); table1_offset = sblk_offset + read_u32(sblk_offset+0x18,sf);
table2_offset = sblk_offset + read_u32(sblk_offset+0x1c,sf); table2_offset = sblk_offset + read_u32(sblk_offset+0x1c,sf);
table3_offset = sblk_offset + read_u32(sblk_offset+0x2c,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 0x0d:
case 0x0e: case 0x0e:
case 0x0f: case 0x0f:
case 0x10:
flags = read_u8 (table3_offset+table3_entry_offset+0x12,sf); flags = read_u8 (table3_offset+table3_entry_offset+0x12,sf);
stream_offset = read_u32(table3_offset+table3_entry_offset+0x44,sf); stream_offset = read_u32(table3_offset+table3_entry_offset+0x44,sf);
stream_size = read_u32(table3_offset+table3_entry_offset+0x48,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 0x09:
case 0x0d: case 0x0d:
case 0x0e: case 0x0e:
case 0x0f:
case 0x10:
/* find if this sound has an assigned name in table1 */ /* find if this sound has an assigned name in table1 */
for (i = 0; i < section_entries; i++) { for (i = 0; i < section_entries; i++) {
uint32_t entry_offset = read_u16(table1_offset+(i*table1_entry_size)+table1_suboffset+0x00,sf); 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 0x0d:
case 0x0e: case 0x0e:
case 0x0f: case 0x0f:
case 0x10:
type = read_u16(start_offset+0x00,sf); type = read_u16(start_offset+0x00,sf);
if (read_u32(start_offset+0x04,sf) != 0x01) /* type? */ if (read_u32(start_offset+0x04,sf) != 0x01) /* type? */
goto fail; goto fail;

View File

@ -7,8 +7,7 @@
VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) { VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL; STREAMFILE* temp_sf = NULL;
off_t subfile_offset; uint32_t subfile_offset, subfile_size;
size_t subfile_size;
utf_context* utf = NULL; utf_context* utf = NULL;
utf_context* utf_sdl = NULL; utf_context* utf_sdl = NULL;
int total_subsongs, target_subsong = sf->stream_index; int total_subsongs, target_subsong = sf->stream_index;
@ -17,10 +16,10 @@ VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) {
/* checks */ /* checks */
if (!check_extensions(sf, "csb"))
goto fail;
if (!is_id32be(0x00,sf, "@UTF")) if (!is_id32be(0x00,sf, "@UTF"))
goto fail; goto fail;
if (!check_extensions(sf, "csb"))
goto fail;
/* .csb is an early, simpler version of .acb+awk (see acb.c) used until ~2013? /* .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. */ * Can stream from .cpk but this only loads memory data. */
@ -115,9 +114,7 @@ VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) {
goto fail; 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"); temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "aax");
if (!temp_sf) goto fail; if (!temp_sf) goto fail;
@ -128,6 +125,11 @@ VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) {
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
break; break;
case 2: /* AHX */
vgmstream = init_vgmstream_utf_ahx(temp_sf);
if (!vgmstream) goto fail;
break;
case 4: /* ADPCM_WII */ case 4: /* ADPCM_WII */
vgmstream = init_vgmstream_utf_dsp(temp_sf); vgmstream = init_vgmstream_utf_dsp(temp_sf);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
@ -153,3 +155,147 @@ fail:
close_vgmstream(vgmstream); close_vgmstream(vgmstream);
return NULL; 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]; uint8_t key[FSB_KEY_MAX];
size_t key_size = read_key_file(key, FSB_KEY_MAX, sf); 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) { if (!vc && test_std) {
temp_sf = setup_fsb_streamfile(sf, key, key_size, 0); temp_sf = setup_fsb_streamfile(sf, key, key_size, 0);
if (!temp_sf) return NULL; if (!temp_sf) return NULL;
//;dump_streamfile(temp_sf, 0);
if (!vc && test_fsb4) vc = init_vgmstream_fsb(temp_sf); if (!vc && test_fsb4) vc = init_vgmstream_fsb(temp_sf);
if (!vc && test_fsb5) vc = init_vgmstream_fsb5(temp_sf); if (!vc && test_fsb5) vc = init_vgmstream_fsb5(temp_sf);
//;if (vgmstream) dump_streamfile(temp_sf, 0);
close_streamfile(temp_sf); close_streamfile(temp_sf);
} }
if (!vc && test_alt) { if (!vc && test_alt) {
temp_sf = setup_fsb_streamfile(sf, key, key_size, 1); temp_sf = setup_fsb_streamfile(sf, key, key_size, 1);
if (!temp_sf) return NULL; if (!temp_sf) return NULL;
//;dump_streamfile(temp_sf, 1);
if (!vc && test_fsb4) vc = init_vgmstream_fsb(temp_sf); if (!vc && test_fsb4) vc = init_vgmstream_fsb(temp_sf);
if (!vc && test_fsb5) vc = init_vgmstream_fsb5(temp_sf); if (!vc && test_fsb5) vc = init_vgmstream_fsb5(temp_sf);
//;if (vgmstream) dump_streamfile(temp_sf, 0);
close_streamfile(temp_sf); 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("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("X3EK%Bbga-%Y9HZZ%gkc*C512*$$DhRxWTGgjUG@=rUD") }, // Signalis (PC)
{ MODE_FSB5_STD, FSBKEY_ADD("281ad163160cfc16f9a22c6755a64fad") }, // Ash Echoes beta (Android) { 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]); 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 {9001712656335836006}, // 7CEC81F7C3091366
// Ikemen Vampire - Ijin-tachi to Koi no Yuuwaku (iOS/Android) // Ikemen Vampire - Ijin-tachi to Koi no Yuuwaku (iOS/Android)
// Ikemen Villains (Android)
// Ikemen Prince (Android)
{45152594117267709}, // 00A06A0B8D0C10FD {45152594117267709}, // 00A06A0B8D0C10FD
// Super Robot Wars X-Omega (iOS/Android) // Super Robot Wars X-Omega (iOS/Android)
@ -449,6 +451,9 @@ static const hcakey_info hcakey_list[] = {
{0x3613e2a7fdfc0784}, //music_0110027 {0x3613e2a7fdfc0784}, //music_0110027
{0xc239d244b6d3b722}, //music_0110028 {0xc239d244b6d3b722}, //music_0110028
{0x2575c136a260e723}, //music_0110029 {0x2575c136a260e723}, //music_0110029
{0x22c6b455883b1c28}, //music_0110030
{0xff2ae68fa067f80a}, //music_0110031
{0x422ca19b0fa5c7c0}, //music_0110032
{0xfb647d074e53fab6}, //music_0120001 {0xfb647d074e53fab6}, //music_0120001
{0xc24049b9f7ed3105}, //music_0120002 {0xc24049b9f7ed3105}, //music_0120002
{0xdc128f2fd48bf4b}, //music_0120003 {0xdc128f2fd48bf4b}, //music_0120003
@ -487,6 +492,9 @@ static const hcakey_info hcakey_list[] = {
{0x2822bba0a5c4f18c}, //music_0210015 {0x2822bba0a5c4f18c}, //music_0210015
{0xff579d3fcfa8453a}, //music_0210016 {0xff579d3fcfa8453a}, //music_0210016
{0x3caa61e8b958f6d8}, //music_0210017 {0x3caa61e8b958f6d8}, //music_0210017
{0xe38b758bcadfc621}, //music_0210018
{0x3399e970670db2ba}, //music_0210019
{0x1cb76530af356c05}, //music_0210020
{0x15bb78c31db0a0b6}, //music_0220001 {0x15bb78c31db0a0b6}, //music_0220001
{0x59b1257242c40109}, //music_0220002 {0x59b1257242c40109}, //music_0220002
{0xdb402bd08d522f34}, //music_0220003 {0xdb402bd08d522f34}, //music_0220003
@ -526,6 +534,9 @@ static const hcakey_info hcakey_list[] = {
{0x22e33db9b5625a96}, //music_0310016 {0x22e33db9b5625a96}, //music_0310016
{0xb78070802414de7a}, //music_0310017 {0xb78070802414de7a}, //music_0310017
{0x572aeeed86655119}, //music_0310018 {0x572aeeed86655119}, //music_0310018
{0x86ca86794400f49d}, //music_0310019
{0x7a2bbc195b9bfac1}, //music_0310020
{0x1c1f029bb47594b1}, //music_0310021
{0xb921c3992807dadd}, //music_0320001 {0xb921c3992807dadd}, //music_0320001
{0x38ad99a045dc971f}, //music_0320002 {0x38ad99a045dc971f}, //music_0320002
{0xf616642579ba5850}, //music_0320003 {0xf616642579ba5850}, //music_0320003
@ -544,6 +555,7 @@ static const hcakey_info hcakey_list[] = {
{0x2df608ef06aca41c}, //music_0320016 {0x2df608ef06aca41c}, //music_0320016
{0x641af19c287d4a2e}, //music_0320017 {0x641af19c287d4a2e}, //music_0320017
{0x82de7b71b30d7bc2}, //music_0320019 {0x82de7b71b30d7bc2}, //music_0320019
{0x100b7ca3075996fe}, //music_0320020
{0x776c4aded0bca5d1}, //music_0410001 {0x776c4aded0bca5d1}, //music_0410001
{0xb7bff4fbf66be43f}, //music_0410002 {0xb7bff4fbf66be43f}, //music_0410002
{0x904f50c5ce8ec6e4}, //music_0410003 {0x904f50c5ce8ec6e4}, //music_0410003
@ -560,6 +572,10 @@ static const hcakey_info hcakey_list[] = {
{0xd8cdd53589ad3634}, //music_0410014 {0xd8cdd53589ad3634}, //music_0410014
{0x88007190e0bfa1ce}, //music_0410015 {0x88007190e0bfa1ce}, //music_0410015
{0x6fccdd5c3d0d6e3e}, //music_0410016 {0x6fccdd5c3d0d6e3e}, //music_0410016
{0x9d8037d7bfb3fc1d}, //music_0410017
{0x685b5601a43b6c60}, //music_0410018
{0x75927596a180f3e3}, //music_0410019
{0xc3d36676d54255c5}, //music_0410020
{0x5d1f3fdbbb036f8d}, //music_0420001 {0x5d1f3fdbbb036f8d}, //music_0420001
{0xc04264e8f34ad5c0}, //music_0420002 {0xc04264e8f34ad5c0}, //music_0420002
{0x8f0e96b4f71f724f}, //music_0420003 {0x8f0e96b4f71f724f}, //music_0420003
@ -597,6 +613,8 @@ static const hcakey_info hcakey_list[] = {
{0x7878df60f0549c4}, //music_0510017 {0x7878df60f0549c4}, //music_0510017
{0x8e5b7068022828e0}, //music_0510018 {0x8e5b7068022828e0}, //music_0510018
{0xb069a5c5e2d93edf}, //music_0510019 {0xb069a5c5e2d93edf}, //music_0510019
{0x30f9dcefa450733a}, //music_0510020
{0xf85695960e2dcb7f}, //music_0510021
{0x15f82c1617013c36}, //music_0520001 {0x15f82c1617013c36}, //music_0520001
{0xc7da8e6f0e2fe399}, //music_0520002 {0xc7da8e6f0e2fe399}, //music_0520002
{0xe350bffcdc9cb686}, //music_0520003 {0xe350bffcdc9cb686}, //music_0520003
@ -633,6 +651,10 @@ static const hcakey_info hcakey_list[] = {
{0x3aa02e0a37543b5c}, //music_0610017 {0x3aa02e0a37543b5c}, //music_0610017
{0xc451f1deddae08ca}, //music_0610018 {0xc451f1deddae08ca}, //music_0610018
{0xc0fa6669d9904919}, //music_0610019 {0xc0fa6669d9904919}, //music_0610019
{0x4ad7fd8dafaa58a9}, //music_0610020
{0x7aece54359beac21}, //music_0610021
{0x7c9332be25e5c95a}, //music_0610022
{0x415eef25f84e8c2e}, //music_0610023
{0x8258ddd6a1d0849b}, //music_0620001 {0x8258ddd6a1d0849b}, //music_0620001
{0x1dd21a1244ca12f1}, //music_0620002 {0x1dd21a1244ca12f1}, //music_0620002
{0xfdec74b23d8b494b}, //music_0620003 {0xfdec74b23d8b494b}, //music_0620003
@ -652,7 +674,15 @@ static const hcakey_info hcakey_list[] = {
{0x5c1195d8afcb1901}, //music_0620017 {0x5c1195d8afcb1901}, //music_0620017
{0x1ad8db767d9ba4a7}, //music_0620018 {0x1ad8db767d9ba4a7}, //music_0620018
{0x9bc820aa161b0f08}, //music_0620019 {0x9bc820aa161b0f08}, //music_0620019
{0xd1df27a57399613e}, //music_0810001
{0xd37ec4cb304e16ae}, //music_0810002
{0x1e99d14d97ab82c5}, //music_0820001
{0x5bf7cefecda8bcb2}, //music_0820002
{0x9cf7ab0ccafa374e}, //music_0820003
{0x972b52f3dfaa387a}, //music_0910001 {0x972b52f3dfaa387a}, //music_0910001
{0x407a4b6c3dcf2509}, //music_0910002
{0x4683c57919dbdeee}, //music_0920001
{0x126d0d20ad7f0401}, //music_0920002
{0x2a47feac8dc3ca9c}, //music_3010001 {0x2a47feac8dc3ca9c}, //music_3010001
{0x9ebbaf63ffe9d9ef}, //music_3010002 {0x9ebbaf63ffe9d9ef}, //music_3010002
{0xe553dba6592293d8}, //music_3010003 {0xe553dba6592293d8}, //music_3010003
@ -669,6 +699,11 @@ static const hcakey_info hcakey_list[] = {
{0xef257f41a265a0af}, //music_3010015 {0xef257f41a265a0af}, //music_3010015
{0x5e23d8a2488bc715}, //music_3010016 {0x5e23d8a2488bc715}, //music_3010016
{0x198cc607e20dd264}, //music_3010017 {0x198cc607e20dd264}, //music_3010017
{0x31a9ab25b5dff424}, //music_3010018
{0x17f53cfa841f41b5}, //music_3010020
{0x4992a33be3ba81dd}, //music_3010021
{0x86d0ab836f09a599}, //music_3010022
{0x157f20b466d75228}, //music_3010024
{0xfd3ea450350d666f}, //music_3020001 {0xfd3ea450350d666f}, //music_3020001
{0x5e91a3790c32e2b3}, //music_3020002 {0x5e91a3790c32e2b3}, //music_3020002
{0x358adfd1bbd3a95e}, //music_3020003 {0x358adfd1bbd3a95e}, //music_3020003
@ -683,6 +718,12 @@ static const hcakey_info hcakey_list[] = {
{0x98c7a1d1c45df640}, //music_3020013 {0x98c7a1d1c45df640}, //music_3020013
{0x3d01826fe053ddda}, //music_3020014 {0x3d01826fe053ddda}, //music_3020014
{0xa6a6426caed68f7c}, //music_3020015 {0xa6a6426caed68f7c}, //music_3020015
{0x34cc16f635101f02}, //music_3020016
{0x4429ed54ca45a36d}, //music_3020018
{0xcc935f3ebbb7bb94}, //music_3020019
{0x4a1d57f0db140c12}, //music_3020020
{0x8ddea25a12f93099}, //music_3020022
{0xf754248dcd46287e}, //music_3020023
{0xdfad847a86a126bb}, //music_5030001 {0xdfad847a86a126bb}, //music_5030001
{0x711ef85045b8c26e}, //music_5030002 {0x711ef85045b8c26e}, //music_5030002
{0xff7640b46d72b337}, //music_5030003 {0xff7640b46d72b337}, //music_5030003
@ -782,6 +823,8 @@ static const hcakey_info hcakey_list[] = {
{0xc3a72539b831ea6e}, //music_5030097 {0xc3a72539b831ea6e}, //music_5030097
{0x8bc6b7b7a2d2bba3}, //music_5030098 {0x8bc6b7b7a2d2bba3}, //music_5030098
{0xdbb0f41e90b30452}, //music_5030099 {0xdbb0f41e90b30452}, //music_5030099
{0x2eb141954bb3bd25}, //music_5030101
{0xaee2837e71b2bb97}, //music_5030102
{0x444dda6d55d76095}, //music_5040001 {0x444dda6d55d76095}, //music_5040001
{0xcbf4f1324081e0a6}, //music_5040002 {0xcbf4f1324081e0a6}, //music_5040002
{0xf1db3c1d9542063a}, //music_5040003 {0xf1db3c1d9542063a}, //music_5040003
@ -960,12 +1003,14 @@ static const hcakey_info hcakey_list[] = {
{0x6f321adde08396e3}, //music_5050163 {0x6f321adde08396e3}, //music_5050163
{0x58afa6381eeb1425}, //music_5050164 {0x58afa6381eeb1425}, //music_5050164
{0x751daf7d1a5401cb}, //music_5050165 {0x751daf7d1a5401cb}, //music_5050165
{0xff2ea77b81c3ff6}, //music_5050166
{0xbd6b66823f854f68}, //music_5050167 {0xbd6b66823f854f68}, //music_5050167
{0xceb902b93eba45d8}, //music_5050168 {0xceb902b93eba45d8}, //music_5050168
{0x2550e145b93723ae}, //music_5050169 {0x2550e145b93723ae}, //music_5050169
{0xb512188a55b8b698}, //music_5050170 {0xb512188a55b8b698}, //music_5050170
{0x26e5bf2c66a9898d}, //music_5050171 {0x26e5bf2c66a9898d}, //music_5050171
{0xd93d0a1764e85d4d}, //music_5050176 {0xd93d0a1764e85d4d}, //music_5050176
{0xff8c5c13833b1049}, //music_5050177
{0x59efd868058a402e}, //music_5050178 {0x59efd868058a402e}, //music_5050178
{0x93075c0fbb31f463}, //music_5050179 {0x93075c0fbb31f463}, //music_5050179
{0xdedb6ae518faac3d}, //music_5050180 {0xdedb6ae518faac3d}, //music_5050180
@ -975,12 +1020,35 @@ static const hcakey_info hcakey_list[] = {
{0xbd2f4b5ab481d300}, //music_5050184 {0xbd2f4b5ab481d300}, //music_5050184
{0x1a253c2f40a38917}, //music_5050185 {0x1a253c2f40a38917}, //music_5050185
{0xc735e9f28243ea8a}, //music_5050186 {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 {0x52c250eade92393b}, //music_9010001
{0xf66e6bb5b0599b07}, //music_9010002 {0xf66e6bb5b0599b07}, //music_9010002
{0x8582b5a60dbbf948}, //music_9010003 {0x8582b5a60dbbf948}, //music_9010003
{0x5bb84b8a5677046f}, //music_9010004
{0xfea0d6adff136868}, //music_9050001 {0xfea0d6adff136868}, //music_9050001
{0x19480b946279507a}, //music_9050002 {0x19480b946279507a}, //music_9050002
// Mini 4WD Hyper Dash Grand Prix (Android) // Mini 4WD Hyper Dash Grand Prix (Android)
{7957824642808300098}, // 6E6FDF59AB704242 {7957824642808300098}, // 6E6FDF59AB704242
@ -1093,16 +1161,29 @@ static const hcakey_info hcakey_list[] = {
{97648135}, // 0000000005d1fe07 {97648135}, // 0000000005d1fe07
// CHUNITHM International Version (AC) // CHUNITHM International Version (AC)
{33426922444908636}, // 0076C19BDE43685C {33426922444908636}, // 0076C19BDE43685C
// Star Ocean: The Divine Force (PC) // Star Ocean: The Divine Force (PC)
{68308868861462528}, // 00f2ae8de77f0800 {68308868861462528}, // 00f2ae8de77f0800
// Sin Chronicle (Android) // Sin Chronicle (Android)
{4385672148314579020}, // 3CDD0995259D604C {4385672148314579020}, // 3CDD0995259D604C
// The Eminence in Shadow: Master of Garden (Android) // 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_*/ #endif/*_HCA_KEYS_H_*/

View File

@ -6,23 +6,24 @@
/* KTSC - Koei Tecmo KTSR container */ /* KTSC - Koei Tecmo KTSR container */
VGMSTREAM* init_vgmstream_ktsc(STREAMFILE* sf) { VGMSTREAM* init_vgmstream_ktsc(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
STREAMFILE *temp_sf = NULL; STREAMFILE* temp_sf = NULL;
int target_subsong = sf->stream_index, total_subsongs; int target_subsong = sf->stream_index, total_subsongs;
off_t offset, subfile_offset; uint32_t offset, subfile_offset, subfile_size;
size_t subfile_size;
/* checks */ /* checks */
/* .ktsl2asbin: common [Atelier Ryza (PC)] */ if (!is_id32be(0x00, sf, "KTSC"))
if (!check_extensions(sf, "ktsl2asbin")) 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; goto fail;
/* KTSC is a container of KTSRs, but can't be extracted easily as they use absolute pointers to the /* 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. */ * 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; if (target_subsong == 0) target_subsong = 1;
total_subsongs = read_u32le(0x08, sf); total_subsongs = read_u32le(0x08, sf);

View File

@ -49,8 +49,9 @@ VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf) {
goto fail; goto fail;
if (read_u32be(0x04, sf) != 0x777B481A) /* hash(?) id: 0x777B481A=as, 0x0294DDFC=st, 0xC638E69E=gc */ if (read_u32be(0x04, sf) != 0x777B481A) /* hash(?) id: 0x777B481A=as, 0x0294DDFC=st, 0xC638E69E=gc */
goto fail; goto fail;
/* .ktsl2asbin: common [Atelier Ryza (PC/Switch), Nioh (PC)] */ /* .ktsl2asbin: common [Atelier Ryza (PC/Switch), Nioh (PC)]
if (!check_extensions(sf, "ktsl2asbin")) * .asbin: Warriors Orochi 4 (PC) */
if (!check_extensions(sf, "ktsl2asbin,asbin"))
goto fail; goto fail;
/* KTSR can be a memory file (ktsl2asbin), streams (ktsl2stbin) and global config (ktsl2gcbin) /* 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 */ /* open companion body */
if (ktsr.is_external) { 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) { 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; 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; init_vgmstream = init_vgmstream_dsp_apex;
} }
else { 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; 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: */ /* this is just like XWSF, abridged: */
int entries, current_subsongs, relative_subsong; int entries, current_subsongs, relative_subsong;
off_t header_offset; off_t header_offset;
entries = read_u32be(offset + 0x14, sf); entries = read_u32be(offset + 0x14, sf);
current_subsongs = kwb->total_subsongs; current_subsongs = kwb->total_subsongs;
@ -675,18 +675,18 @@ static int parse_type_msfbank(kwb_header* kwb, off_t offset, STREAMFILE* sf) {
// return 0; // return 0;
} }
static int parse_type_xwsfile(kwb_header* kwb, off_t offset, STREAMFILE* sf) { static int parse_type_xwsfile(kwb_header* kwb, uint32_t offset, STREAMFILE* sf) {
off_t table1_offset, table2_offset; uint32_t table1_offset, table2_offset;
int i, chunks, chunks2; int i, chunks, chunks2;
uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL; uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL;
if (!(is_id32be(offset + 0x00, sf, "XWSF") && is_id32be(offset + 0x04, sf, "ILE\0")) && if (!(is_id64be(offset + 0x00, sf, "XWSFILE\0")) &&
!(is_id32be(offset + 0x00, sf, "tdpa") && is_id32be(offset + 0x04, sf, "ck\0\0"))) !(is_id64be(offset + 0x00, sf, "tdpack\0\0")))
goto fail; goto fail;
kwb->big_endian = read_u8(offset + 0x08, sf) == 0xFF; 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; 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; i = 0;
while (i < chunks) { 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); //;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) { if (table2_offset) {
head_offset = read_u32(offset + table1_offset + i * 0x04 + 0x00, sf); head_offset = read_u32(offset + table1_offset + i * 0x04, sf);
head_size = read_u32(offset + table2_offset + i * 0x04 + 0x00, sf); head_size = read_u32(offset + table2_offset + i * 0x04, sf);
body_offset = head_offset; if (!head_size) { /* sometimes has file end offset as entry with no size (NG PS3)*/
i += 1; i += 1;
/* sometimes has file end offset as entry with no size*/
if (!head_size)
continue; continue;
}
} }
else { else {
head_offset = read_u32(offset + table1_offset + i * 0x04 + 0x00, sf); head_offset = read_u32(offset + table1_offset + i * 0x04, sf);
body_offset = read_u32(offset + table1_offset + i * 0x04 + 0x04, sf);
i += 2;
} }
if (!head_offset) /* just in case */ if (!head_offset) { /* just in case */
i += 1;
continue; continue;
}
head_offset += offset; head_offset += offset;
body_offset += offset;
entry_type = read_u32be(head_offset + 0x00, sf); 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" */ if (entry_type == get_id32be("XWSF")) { /* + "ILE\0" */
i += 1;
if (!parse_type_xwsfile(kwb, head_offset, sf)) if (!parse_type_xwsfile(kwb, head_offset, sf))
goto fail; goto fail;
} }
else if (entry_type == get_id32be("CUEB") || entry_type < 0x100) { 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" */ else if (entry_type == get_id32be("MSFB")) { /* + "ANK\0" */
i += 1;
if (!parse_type_msfbank(kwb, head_offset, sf)) if (!parse_type_msfbank(kwb, head_offset, sf))
goto fail; goto fail;
} }
else if (entry_type == get_id32be("KWB2")) { 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)) if (!parse_type_kwb2(kwb, head_offset, body_offset, sf))
goto fail; goto fail;
} }
else { 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; 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); VGMSTREAM * init_vgmstream_mp4_aac_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size);
#endif #endif
VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE * streamFile); VGMSTREAM* init_vgmstream_sli_loops(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_sfl_ogg(STREAMFILE * streamFile); 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_aax(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ngc_ffcc_str(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ngc_ffcc_str(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sat_baka(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_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); 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 0x44415434: /* "DAT4" */
case 0x44415435: /* "DAT5" */ case 0x44415435: /* "DAT5" */
case 0x44415438: /* "DAT8" */ 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->stream_size = read_u32le(0x44, sf);
musx->channels = read_u32le(0x48, sf); musx->channels = read_u32le(0x48, sf);
musx->sample_rate = read_u32le(0x4c, sf); musx->sample_rate = read_u32le(0x4c, sf);

View File

@ -1,43 +1,43 @@
#include "meta.h" #include "meta.h"
#include "../coding/coding.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)] */ /* .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* init_vgmstream_nus3audio(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL; STREAMFILE* temp_sf = NULL;
off_t subfile_offset = 0, name_offset = 0; uint32_t subfile_offset = 0, subfile_size = 0, name_offset = 0;
size_t subfile_size = 0;
nus3audio_codec codec; nus3audio_codec codec;
const char* fake_ext = NULL; const char* fake_ext = NULL;
int total_subsongs, target_subsong = sf->stream_index, found = 0; int total_subsongs, target_subsong = sf->stream_index, found = 0;
/* checks */ /* checks */
if (!check_extensions(sf, "nus3audio")) if (!is_id32be(0x00,sf, "NUS3"))
goto fail;
if (read_u32be(0x00,sf) != 0x4E555333) /* "NUS3" */
goto fail; goto fail;
if (read_u32le(0x04,sf) + 0x08 != get_streamfile_size(sf)) if (read_u32le(0x04,sf) + 0x08 != get_streamfile_size(sf))
goto fail; goto fail;
if (read_u32be(0x08,sf) != 0x41554449) /* "AUDI" */ if (!is_id32be(0x08,sf, "AUDI"))
goto fail;
if (!check_extensions(sf, "nus3audio"))
goto fail; goto fail;
/* parse existing chunks */ /* parse existing chunks */
{ {
off_t offset = 0x0c; uint32_t offset = 0x0c;
size_t file_size = get_streamfile_size(sf); uint32_t file_size = get_streamfile_size(sf);
uint32_t codec_id = 0; uint32_t codec_id = 0;
total_subsongs = 0; total_subsongs = 0;
while (offset < file_size) { while (offset < file_size) {
uint32_t chunk_id = read_u32be(offset+0x00, sf); uint32_t chunk_type = read_u32be(offset+0x00, sf);
size_t chunk_size = read_u32le(offset+0x04, sf); uint32_t chunk_size = read_u32le(offset+0x04, sf);
switch(chunk_id) { switch(chunk_type) {
case 0x494E4458: /* "INDX": audio index */ case 0x494E4458: /* "INDX": audio index */
total_subsongs = read_u32le(offset+0x08 + 0x00,sf); total_subsongs = read_u32le(offset+0x08 + 0x00,sf);
if (target_subsong == 0) target_subsong = 1; if (target_subsong == 0) target_subsong = 1;
@ -70,8 +70,8 @@ VGMSTREAM* init_vgmstream_nus3audio(STREAMFILE* sf) {
goto fail; goto fail;
} }
/* handle dummy entries, ex. Gundam EvM (PS4) */ /* handle dummy entries (offset may be 0 or first entry), ex. Gundam EvM (PS4) */
if (subfile_offset == 0 && subfile_size == 0) { if (subfile_size == 0) {
vgmstream = init_vgmstream_silence(0, 0, 0); vgmstream = init_vgmstream_silence(0, 0, 0);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
@ -80,7 +80,7 @@ VGMSTREAM* init_vgmstream_nus3audio(STREAMFILE* sf) {
return vgmstream; return vgmstream;
} }
codec_id = read_u32be(subfile_offset, sf); codec_id = read_u32be(subfile_offset, sf);
switch(codec_id) { switch(codec_id) {
@ -96,8 +96,12 @@ VGMSTREAM* init_vgmstream_nus3audio(STREAMFILE* sf) {
codec = RIFF; codec = RIFF;
fake_ext = "wav"; fake_ext = "wav";
break; break;
case 0x424E5346: /* "BNSF" [gundam Extreme Vs 2 (AC)-multichannel] */
codec = BNSF;
fake_ext = "bnsf";
break;
default: default:
VGM_LOG("NUS3AUDIO: unknown codec %x\n", codec_id); vgm_logi("NUS3AUDIO: unknown codec (report)\n");
goto fail; goto fail;
} }
} }
@ -120,6 +124,10 @@ VGMSTREAM* init_vgmstream_nus3audio(STREAMFILE* sf) {
vgmstream = init_vgmstream_riff(temp_sf); vgmstream = init_vgmstream_riff(temp_sf);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
break; break;
case BNSF:
vgmstream = init_vgmstream_bnsf(temp_sf);
if (!vgmstream) goto fail;
break;
default: default:
goto fail; goto fail;
} }
@ -136,5 +144,3 @@ fail:
close_vgmstream(vgmstream); close_vgmstream(vgmstream);
return NULL; return NULL;
} }

View File

@ -20,7 +20,7 @@ VGMSTREAM* init_vgmstream_mic_koei(STREAMFILE* sf) {
channels = read_u32le(0x08,sf); channels = read_u32le(0x08,sf);
if (channels > 4) goto fail; /* 1/2/4 are known */ if (channels > 4) goto fail; /* 1/2/4 are known */
interleave = read_u32le(0x0c,sf); interleave = read_u32le(0x0c,sf);
if (interleave != 0x10) goto fail; if (interleave != 0x10 && interleave != 0x20) goto fail;
loop_end = read_s32le(0x10,sf); loop_end = read_s32le(0x10,sf);
loop_start = read_s32le(0x14,sf); loop_start = read_s32le(0x14,sf);

View File

@ -1,110 +1,235 @@
#include "meta.h" #include "meta.h"
#include "../coding/coding.h" #include "../coding/coding.h"
/* RFTM - Retro Studios format [Donkey Kong Country Tropical Freeze (WiiU/Switch)] */ /* RFTM - Retro Studios format [Metroid Prime Remastered] */
VGMSTREAM *init_vgmstream_rfrm(STREAMFILE *streamFile) { static VGMSTREAM* init_vgmstream_rfrm_mpr(STREAMFILE* sf) {
VGMSTREAM *vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
off_t fmta_offset = 0, data_offset = 0, header_offset, start_offset; off_t fmta_offset = 0, data_offset = 0, ras3_offset = 0, header_offset, start_offset;
size_t data_size = 0, interleave; size_t data_size = 0, interleave;
int loop_flag, channel_count, version; int loop_flag, channels;
int big_endian; int loop_start, loop_end, padding;
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;
/* checks */ /* 0x08: file size but not exact */
if (!check_extensions(streamFile, "csmp")) if (!is_id32be(0x14, sf, "CSMP"))
goto fail; goto fail;
if (read_32bitBE(0x00, streamFile) != 0x5246524D) /* "RFRM" */ if (!check_extensions(sf, "csmp"))
goto fail; goto fail;
/* 0x08: file size but not exact */
if (read_32bitBE(0x14, streamFile) != 0x43534D50) /* "CSMP" */ if (read_32bitLE(0x18,sf) != 0x1F) /* assumed, also at 0x1c */
goto fail; goto fail;
version = read_32bitBE(0x18,streamFile); /* assumed, also at 0x1c */
if (version == 0x0a) { /* Wii U */ /* parse chunks (always BE) */
read_32bit = read_32bitBE; {
read_16bit = read_16bitBE; off_t chunk_offset = 0x20;
big_endian = 1; off_t file_size = get_streamfile_size(sf);
}
else if (version == 0x12) { /* Switch */ while (chunk_offset < file_size) {
read_32bit = read_32bitLE; uint32_t chunk_type = read_32bitBE(chunk_offset + 0x00,sf);
read_16bit = read_16bitLE; size_t chunk_size = read_32bitLE(chunk_offset + 0x08,sf);
big_endian = 0;
} switch(chunk_type) {
else { case 0x464D5441: /* "FMTA" */
goto fail; fmta_offset = chunk_offset + 0x18;
} chunk_offset += 5 + 0x18 + chunk_size;
break;
case 0x44415441: /* "DATA" */
/* parse chunks (always BE) */ data_offset = chunk_offset + 0x18;
{ data_size = read_32bitLE(chunk_offset + 0x04, sf);
off_t chunk_offset = 0x20; /* we're done here, DATA is the last chunk */
off_t file_size = get_streamfile_size(streamFile); chunk_offset = file_size;
break;
while (chunk_offset < file_size) { case 0x52415333: /* "RAS3" */
uint32_t chunk_type = read_32bitBE(chunk_offset+0x00,streamFile); ras3_offset = chunk_offset + 0x18;
size_t chunk_size = read_32bitBE(chunk_offset+0x08,streamFile); /* maybe 64b from 0x04? */ chunk_offset += 60;
break;
switch(chunk_type) { case 0x43524D53: /* CRMS */
case 0x464D5441: /* "FMTA" */ chunk_offset += 9 + 0x18 + chunk_size + read_32bitLE(chunk_offset + 0x18 + chunk_size + 5, sf);
fmta_offset = chunk_offset + 0x18; break;
break; default:
case 0x44415441: /* "DATA" */ goto fail;
data_offset = chunk_offset + 0x18; }
data_size = chunk_size; }
break;
default: /* known: "LABL" (usually before "FMTA"), "META" (usually after "DATA") */ if (!fmta_offset || !data_offset || !data_size)
break; goto fail;
} }
chunk_offset += 0x18 + chunk_size;
} /* parse FMTA / DATA (fully interleaved standard DSPs) */
channels = read_8bit(fmta_offset + 0x00, sf);
if (!fmta_offset || !data_offset || !data_size) if (channels == 0) goto fail; /* div by zero */
goto fail; /* FMTA 0x08: channel mapping */
}
header_offset = data_offset;
start_offset = header_offset + 0x80 * channels;
/* parse FMTA / DATA (fully interleaved standard DSPs) */ loop_flag = read_16bitLE(header_offset + 0x0C, sf);
channel_count = read_8bit(fmta_offset+0x00, streamFile); interleave = data_size / channels;
/* FMTA 0x08: channel mapping */
if (ras3_offset) {
header_offset = data_offset; int block_size = read_32bitLE(ras3_offset + 0x00, sf);
if (version == 0x0a) { int block_samples = read_32bitLE(ras3_offset + 0x8, sf);
size_t align = 0x03; /* possibly 32b align */ int loop_start_block = read_32bitLE(ras3_offset + 0x14, sf);
header_offset += align; int loop_start_sample = read_32bitLE(ras3_offset + 0x18, sf);
data_size -= align; int loop_end_block = read_32bitLE(ras3_offset + 0x1C, sf);
} int loop_end_sample = read_32bitLE(ras3_offset + 0x20, sf);
start_offset = header_offset + 0x60; padding = read_32bitLE(ras3_offset + 0x0C, sf);
loop_flag = read_16bit(header_offset + 0x0C, streamFile);
interleave = data_size / channel_count; 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))
/* build the VGMSTREAM */ loop_flag = 1;
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail; interleave = block_size / channels;
} else {
vgmstream->meta_type = meta_RFRM; loop_start = dsp_nibbles_to_samples(read_32bitLE(header_offset + 0x10, sf));
vgmstream->sample_rate = read_32bit(header_offset + 0x08, streamFile); loop_end = dsp_nibbles_to_samples(read_32bitLE(header_offset + 0x14, sf)) + 1;
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; /* build the VGMSTREAM */
if (vgmstream->loop_end_sample > vgmstream->num_samples) /* ? */ vgmstream = allocate_vgmstream(channels, loop_flag);
vgmstream->loop_end_sample = vgmstream->num_samples; if (!vgmstream) goto fail;
vgmstream->coding_type = coding_NGC_DSP; vgmstream->meta_type = meta_RFRM;
vgmstream->layout_type = layout_interleave; vgmstream->sample_rate = read_32bitLE(header_offset + 0x08, sf);
vgmstream->interleave_block_size = interleave; vgmstream->num_samples = read_32bitLE(header_offset + 0x00, sf);
dsp_read_coefs(vgmstream, streamFile, header_offset + 0x1C, interleave, big_endian); vgmstream->loop_start_sample = loop_start;
dsp_read_hist (vgmstream, streamFile, header_offset + 0x40, interleave, big_endian); vgmstream->loop_end_sample = loop_end;
if (vgmstream->loop_end_sample > vgmstream->num_samples) /* ? */
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) vgmstream->loop_end_sample = vgmstream->num_samples;
goto fail;
return vgmstream; if (ras3_offset) {
int padding_bytes = padding / 14 * 8; /* round to frames */
fail: vgmstream->interleave_first_block_size = interleave - padding_bytes;
close_vgmstream(vgmstream); vgmstream->interleave_first_skip = padding_bytes;
return NULL; 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] * .p1d: Farming Simulator 15 (Vita)[ATRAC9]
* .xms: Ty the Tasmanian Tiger (Xbox) * .xms: Ty the Tasmanian Tiger (Xbox)
* .mus: Burnout Legends/Dominator (PSP) * .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; goto fail;
} }

View File

@ -126,6 +126,17 @@ VGMSTREAM* init_vgmstream_sdrh_new(STREAMFILE* sf) {
break; 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 #ifdef VGM_USE_FFMPEG
case 1: { /* Mindjack (X360), Moon Diver (X360) */ case 1: { /* Mindjack (X360), Moon Diver (X360) */
int block_size = 0x10000; /* XWAV new default */ int block_size = 0x10000; /* XWAV new default */
@ -145,10 +156,15 @@ VGMSTREAM* init_vgmstream_sdrh_new(STREAMFILE* sf) {
break; 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; 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 */ 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); 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 "meta.h"
#include <ctype.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)] */ /* .sli+ogg/opus/wav - KiriKiri engine / WaveLoopManager loop points loader [Fate/Stay Night (PC), World End Economica (PC)] */
VGMSTREAM* init_vgmstream_sli_ogg(STREAMFILE* sf) { VGMSTREAM* init_vgmstream_sli_loops(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
STREAMFILE* sf_data = NULL; STREAMFILE* sf_data = NULL;
int32_t loop_start = -1, loop_length = -1; int32_t loop_start = 0, loop_end = 0;
int32_t loop_from = -1, loop_to = -1; VGMSTREAM* (*init_vgmstream)(STREAMFILE* sf) = NULL;
/* checks */ /* checks */
if (!check_extensions(sf, "sli")) if (!check_extensions(sf, "sli"))
goto fail; 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]; char basename[PATH_LIMIT];
get_streamfile_basename(sf,basename,PATH_LIMIT); get_streamfile_basename(sf,basename,PATH_LIMIT);
sf_data = open_streamfile_by_filename(sf, basename); sf_data = open_streamfile_by_filename(sf, basename);
if (!sf_data) goto fail; if (!sf_data) goto fail;
} }
if (!is_id32be(0x00, sf_data, "OggS")) if (is_id32be(0x00, sf_data, "OggS")) {
goto fail; if (is_id32be(0x1c, sf_data, "Opus")) { /* Sabbat of the Witch (PC) */
init_vgmstream = init_vgmstream_ogg_opus;
/* let the real initer do the parsing */ /* somehow sli+opus use 0 encoder delay in the OpusHead (to simplify looping?) */
if (is_id32be(0x1c, sf_data, "Opus")) { /* Sabbat of the Witch (PC) */ }
vgmstream = init_vgmstream_ogg_opus(sf_data); else { /* Fate/Stay Night (PC) */
if (!vgmstream) goto fail; init_vgmstream = init_vgmstream_ogg_vorbis;
/* 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;
}
}
} }
} }
else if (is_id32be(0x00, sf_data, "RIFF")) {
if (loop_start != -1 && loop_length != -1) { /* v1 */ /* Perfect Cherry Blossom Trial+ (PC) (RIFF created by extractor?) */
vgmstream_force_loop(vgmstream, 1, loop_start, loop_start + loop_length); init_vgmstream = init_vgmstream_riff;
}
else if (loop_from != -1 && loop_to != -1) { /* v2 */
vgmstream_force_loop(vgmstream, 1, loop_to, loop_from);
} }
else { 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); close_streamfile(sf_data);
return vgmstream; return vgmstream;
@ -108,3 +56,71 @@ fail:
close_vgmstream(vgmstream); close_vgmstream(vgmstream);
return NULL; 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")) if (!is_id32be(0x00,sf, "SWAV"))
goto fail; goto fail;
/* .swav: standard /* .swav: standard [found inside .sdat but SDK can create them]
* .adpcm: Merlin - A Servant of Two Masters (DS) */ * .adpcm: Merlin - A Servant of Two Masters (DS) [external] */
if (!check_extensions(sf, "swav,adpcm")) if (!check_extensions(sf, "swav,adpcm"))
goto fail; 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" */ } 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) */ /* mono "datL" or full interleave with a "datR" after the "datL" (no check, pretend it exists) */
start_offset = chunk_offset; 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; data_size = chunk_size * channels;
interleave = (0x4+0x4) + chunk_size; /* don't forget to skip the "datR"+size chunk */ interleave = (0x4+0x4) + chunk_size; /* don't forget to skip the "datR"+size chunk */
} else { } 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_u32_t read_u32 = hx->big_endian ? read_u32be : read_u32le;
read_s32_t read_s32 = hx->big_endian ? read_s32be : read_s32le; read_s32_t read_s32 = hx->big_endian ? read_s32be : read_s32le;
read_u16_t read_u16 = hx->big_endian ? read_u16be : read_u16le; 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; uint32_t riff_offset, riff_size, stream_adjust = 0, resource_size, chunk_size;
size_t chunk_size; off_t chunk_offset;
int cue_flag = 0; int cue_flag = 0;
//todo cleanup/unify common readings //todo cleanup/unify common readings
@ -339,7 +339,7 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, uint32_t offset, uint
break; break;
default: 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; 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 || if ((strcmp(hx->class_name, "CXBoxStaticHWWaveFileIdObj") == 0 ||
strcmp(hx->class_name, "CXBoxStreamHWWaveFileIdObj") == 0) && !hx->big_endian) { strcmp(hx->class_name, "CXBoxStreamHWWaveFileIdObj") == 0) && !hx->big_endian) {
/* micro header: some mix of channels + block size + sample rate + flags, unsure of which bits */ /* micro header: some mix of channels + block size + sample rate + flags, unsure of which bits */
hx->codec = XIMA;
/* 0x00: ? */ /* 0x00: ? */
hx->channels = read_u8(offset + 0x01, sf); /* upper 2 bits? */ uint8_t flags = read_u8(offset + 0x01, sf);
switch(hx->channels) { switch(flags) {
case 0x48: hx->channels = 1; break; case 0x05: // b00000101 /* XIII (Xbox)-beta 2002-12 */
case 0x90: hx->channels = 2; break; 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: default:
VGM_LOG("ubi hx: channel type %x\n", hx->channels); VGM_LOG("ubi hx: channel flags %x\n", flags);
goto fail; goto fail;
} }
hx->sample_rate = (read_u16(offset + 0x02, sf) & 0x7FFFu) << 1u; /* ??? */ 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) { switch(hx->stream_mode) {
case 0x00: /* static (smaller internal file) [XIII (Xbox)] */ case 0x00: /* static (smaller internal file) [XIII (Xbox)] */
case 0x02: /* static (smaller internal file) [XIII-beta (Xbox)] */
hx->stream_offset += offset; hx->stream_offset += offset;
break; break;

View File

@ -16,8 +16,9 @@ VGMSTREAM* init_vgmstream_wave(STREAMFILE* sf) {
/* checks */ /* checks */
if (!is_id32be(0x00,sf, "VAW3") && /* Happy Feet Two (3DS) */ if (!is_id32be(0x00,sf, "VAW3") && /* Happy Feet Two (3DS) */
read_u32le(0x00,sf) != 0xE5B7ECFE && /* common (LE) */ read_u32le(0x00,sf) != 0xE5B7ECFE && /* common LE (hashed something?) */
read_u32be(0x00,sf) != 0xE5B7ECFE) /* used? */ read_u32be(0x00,sf) != 0xE5B7ECFE &&
read_u32be(0x00,sf) != 0xC9FB0C03) /* NDS [Lalaloopsy, Adventure Time: HIKWYSOG (DS)] */
goto fail; goto fail;
/* 0x04: version? common=0, VAW3=2 */ /* 0x04: version? common=0, VAW3=2 */
@ -51,15 +52,15 @@ VGMSTREAM* init_vgmstream_wave(STREAMFILE* sf) {
start_offset = read_u32(0x20, sf); start_offset = read_u32(0x20, sf);
interleave = read_u32(0x24, sf); /* typically half data_size */ 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); loop_flag = (loop_start > 0);
/* some songs (ex. Adventure Time's m_candykingdom_overworld.wave) do full loops, but there is no way /* 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. */ * to tell them apart from sfx/voices, so we try to detect if it's long enough. */
if(!loop_flag if(!loop_flag
&& loop_start == 0 && loop_end == num_samples /* full loop */ && loop_start == 0 && loop_end == num_samples /* full loop */
&& channels > 1 && (channels > 1 || (channels == 1 && start_offset <= 0x40))
&& num_samples > 20*sample_rate) { /* in seconds */ && num_samples > 30*sample_rate) { /* in seconds */
loop_flag = 1; loop_flag = 1;
} }
@ -75,22 +76,37 @@ VGMSTREAM* init_vgmstream_wave(STREAMFILE* sf) {
vgmstream->meta_type = meta_WAVE; 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) { switch(codec) {
case 0x02: case 0x02:
vgmstream->coding_type = coding_NGC_DSP; /* DS games use IMA, no apparent flag (could also test ID) */
vgmstream->layout_type = layout_interleave; if (start_offset <= 0x40) {
vgmstream->interleave_block_size = interleave; 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 */ /* extradata:
dsp_read_coefs(vgmstream, sf, extradata_offset+0x00, 0x2c, big_endian); * 0x00: base hist? (only seen 0)
dsp_read_hist(vgmstream, sf, extradata_offset+0x22, 0x2c, big_endian); * 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; break;
default: default:
goto fail; goto fail;
} }
if (!vgmstream_open_stream(vgmstream,sf,start_offset)) if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail; goto fail;
return vgmstream; return vgmstream;

View File

@ -91,15 +91,21 @@ VGMSTREAM* init_vgmstream_xwav_new(STREAMFILE* sf) {
break; 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; int block_align, encoder_delay;
data_size = read_u32be(0x54,sf); /* fixed for all rates? doesn't happen with other codecs, some files are 48000 already */
block_align = 0x98 * vgmstream->channels; 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) */ 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->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; if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;

View File

@ -32,24 +32,24 @@ typedef struct {
int version; int version;
/* segments */ /* segments */
off_t base_offset; uint32_t base_offset;
size_t base_size; uint32_t base_size;
off_t entry_offset; uint32_t entry_offset;
size_t entry_size; uint32_t entry_size;
off_t names_offset; uint32_t names_offset;
size_t names_size; uint32_t names_size;
size_t names_entry_size; uint32_t names_entry_size;
off_t extra_offset; uint32_t extra_offset;
size_t extra_size; uint32_t extra_size;
off_t data_offset; uint32_t data_offset;
size_t data_size; uint32_t data_size;
off_t stream_offset; uint32_t stream_offset;
size_t stream_size; uint32_t stream_size;
uint32_t base_flags; uint32_t base_flags;
size_t entry_elem_size; uint32_t entry_elem_size;
size_t entry_alignment; uint32_t entry_alignment;
int total_subsongs; int total_subsongs;
uint32_t entry_flags; uint32_t entry_flags;
@ -97,7 +97,7 @@ VGMSTREAM* init_vgmstream_xwb(STREAMFILE* sf) {
* .xna: Touhou Makukasai ~ Fantasy Danmaku Festival (PC) * .xna: Touhou Makukasai ~ Fantasy Danmaku Festival (PC)
* (extensionless): Ikaruga (X360/PC), Grabbed by the Ghoulies (Xbox) * (extensionless): Ikaruga (X360/PC), Grabbed by the Ghoulies (Xbox)
* .bd: Fatal Frame 2 (Xbox) */ * .bd: Fatal Frame 2 (Xbox) */
if (!check_extensions(sf,"xwb,xna,bd")) if (!check_extensions(sf,"xwb,xna,bd,"))
goto fail; goto fail;
xwb.little_endian = is_id32be(0x00,sf, "WBND"); /* Xbox/PC */ 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 */ /* Stardew Valley (Vita), Owlboy (PS4): standard RIFF with ATRAC9 */
xwb.codec = ATRAC9_RIFF; 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 */ /* test loop after the above fixes */

View File

@ -31,8 +31,11 @@ VGMSTREAM* init_vgmstream_xwma(STREAMFILE* sf) {
if (!is_id32be(0x08,sf, "XWMA")) if (!is_id32be(0x08,sf, "XWMA"))
goto fail; goto fail;
/* .xwma: standard /* .xwma: standard
* .xwm: The Elder Scrolls: Skyrim (PC), Blade Arcus from Shining (PC) */ * .xwm: The Elder Scrolls: Skyrim (PC), Blade Arcus from Shining (PC)
if (!check_extensions(sf, "xwma,xwm")) * .xma: Castle Crashers (PC)
* .wma/lwma: BattleBlock Theater (PC)
*/
if (!check_extensions(sf, "xwma,xwm,xma,wma,lwma"))
goto fail; goto fail;
{ {

View File

@ -525,6 +525,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_bigrp, init_vgmstream_bigrp,
init_vgmstream_sscf_encrypted, init_vgmstream_sscf_encrypted,
init_vgmstream_s_p_sth, 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) */ /* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */
init_vgmstream_scd_pcm, init_vgmstream_scd_pcm,
@ -536,7 +537,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_mic_koei, init_vgmstream_mic_koei,
init_vgmstream_seb, init_vgmstream_seb,
init_vgmstream_ps2_pnb, init_vgmstream_ps2_pnb,
init_vgmstream_sli_ogg, init_vgmstream_sli_loops,
init_vgmstream_tgc, init_vgmstream_tgc,
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ /* 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>ap</string>
<string>apc</string> <string>apc</string>
<string>as4</string> <string>as4</string>
<string>asbin</string>
<string>asd</string> <string>asd</string>
<string>asf</string> <string>asf</string>
<string>asr</string> <string>asr</string>
@ -423,6 +424,7 @@
<string>bar</string> <string>bar</string>
<string>bcstm</string> <string>bcstm</string>
<string>bcwav</string> <string>bcwav</string>
<string>bcv</string>
<string>bd3</string> <string>bd3</string>
<string>bdsp</string> <string>bdsp</string>
<string>bfstm</string> <string>bfstm</string>
@ -435,6 +437,7 @@
<string>bik</string> <string>bik</string>
<string>bika</string> <string>bika</string>
<string>bik2</string> <string>bik2</string>
<string>binka</string>
<string>bk2</string> <string>bk2</string>
<string>bkr</string> <string>bkr</string>
<string>blk</string> <string>blk</string>
@ -456,7 +459,6 @@
<string>cads</string> <string>cads</string>
<string>caf</string> <string>caf</string>
<string>cbd2</string> <string>cbd2</string>
<string>ccc</string>
<string>cd</string> <string>cd</string>
<string>cfn</string> <string>cfn</string>
<string>chd</string> <string>chd</string>
@ -468,6 +470,7 @@
<string>cpk</string> <string>cpk</string>
<string>cps</string> <string>cps</string>
<string>csa</string> <string>csa</string>
<string>csb</string>
<string>csmp</string> <string>csmp</string>
<string>cvs</string> <string>cvs</string>
<string>cwav</string> <string>cwav</string>
@ -504,6 +507,7 @@
<string>exa</string> <string>exa</string>
<string>ezw</string> <string>ezw</string>
<string>fag</string> <string>fag</string>
<string>fcb</string>
<string>fda</string> <string>fda</string>
<string>ffw</string> <string>ffw</string>
<string>filp</string> <string>filp</string>
@ -575,6 +579,7 @@
<string>kces</string> <string>kces</string>
<string>kcey</string> <string>kcey</string>
<string>km9</string> <string>km9</string>
<string>kma</string>
<string>kmx</string> <string>kmx</string>
<string>kovs</string> <string>kovs</string>
<string>kno</string> <string>kno</string>
@ -596,6 +601,7 @@
<string>lac3</string> <string>lac3</string>
<string>lasf</string> <string>lasf</string>
<string>lbin</string> <string>lbin</string>
<string>ldat</string>
<string>leg</string> <string>leg</string>
<string>lep</string> <string>lep</string>
<string>lflac</string> <string>lflac</string>
@ -737,7 +743,6 @@
<string>rws</string> <string>rws</string>
<string>rwsd</string> <string>rwsd</string>
<string>rwx</string> <string>rwx</string>
<string>rxw</string>
<string>rxx</string> <string>rxx</string>
<string>s14</string> <string>s14</string>
<string>s3s</string> <string>s3s</string>
@ -796,6 +801,7 @@
<string>smp</string> <string>smp</string>
<string>smpl</string> <string>smpl</string>
<string>smv</string> <string>smv</string>
<string>snb</string>
<string>snd</string> <string>snd</string>
<string>snds</string> <string>snds</string>
<string>sng</string> <string>sng</string>