Updated VGMStream to r1050-3668-g37cc1229

CQTexperiment
Christopher Snowhill 2021-04-10 16:30:36 -07:00
parent e603addc07
commit 7a0e007d08
13 changed files with 391 additions and 240 deletions

View File

@ -326,7 +326,6 @@
836F6FAF18BDC2190095E648 /* ngc_dsp_std.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7318BDC2180095E648 /* ngc_dsp_std.c */; };
836F6FB018BDC2190095E648 /* ngc_dsp_ygo.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7418BDC2180095E648 /* ngc_dsp_ygo.c */; };
836F6FB118BDC2190095E648 /* ngc_ffcc_str.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7518BDC2180095E648 /* ngc_ffcc_str.c */; };
836F6FB218BDC2190095E648 /* ngc_gcub.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7618BDC2180095E648 /* ngc_gcub.c */; };
836F6FB318BDC2190095E648 /* ngc_lps.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7718BDC2180095E648 /* ngc_lps.c */; };
836F6FB418BDC2190095E648 /* ngc_nst_dsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7818BDC2180095E648 /* ngc_nst_dsp.c */; };
836F6FB518BDC2190095E648 /* ngc_pdt.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E7918BDC2180095E648 /* ngc_pdt.c */; };
@ -353,7 +352,6 @@
836F6FD318BDC2190095E648 /* ps2_ccc.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9718BDC2180095E648 /* ps2_ccc.c */; };
836F6FD418BDC2190095E648 /* ps2_dxh.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9818BDC2180095E648 /* ps2_dxh.c */; };
836F6FD518BDC2190095E648 /* ps2_enth.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9918BDC2180095E648 /* ps2_enth.c */; };
836F6FD618BDC2190095E648 /* ps2_exst.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9A18BDC2180095E648 /* ps2_exst.c */; };
836F6FD718BDC2190095E648 /* ps2_filp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9B18BDC2180095E648 /* ps2_filp.c */; };
836F6FD818BDC2190095E648 /* ps2_gbts.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9C18BDC2180095E648 /* ps2_gbts.c */; };
836F6FD918BDC2190095E648 /* ps2_gcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E9D18BDC2180095E648 /* ps2_gcm.c */; };
@ -574,6 +572,10 @@
83AA7F8C2519C076004C5298 /* render.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA7F882519C076004C5298 /* render.c */; };
83AA7F8D2519C076004C5298 /* decode.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AA7F892519C076004C5298 /* decode.c */; };
83AB8C761E8072A100086084 /* x360_ast.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AB8C741E8072A100086084 /* x360_ast.c */; };
83AF2CC926226BA500538240 /* gcub.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AF2CC526226BA400538240 /* gcub.c */; };
83AF2CCA26226BA500538240 /* exst.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AF2CC626226BA400538240 /* exst.c */; };
83AF2CCB26226BA500538240 /* ogv_3rdeye.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AF2CC726226BA400538240 /* ogv_3rdeye.c */; };
83AF2CCC26226BA500538240 /* encrypted_bgm_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83AF2CC826226BA500538240 /* encrypted_bgm_streamfile.h */; };
83AFABBC23795202002F3947 /* xssb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AFABB923795201002F3947 /* xssb.c */; };
83AFABBD23795202002F3947 /* ea_eaac_opus_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83AFABBA23795202002F3947 /* ea_eaac_opus_streamfile.h */; };
83AFABBE23795202002F3947 /* isb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AFABBB23795202002F3947 /* isb.c */; };
@ -1084,7 +1086,6 @@
836F6E7318BDC2180095E648 /* ngc_dsp_std.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_dsp_std.c; sourceTree = "<group>"; };
836F6E7418BDC2180095E648 /* ngc_dsp_ygo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_dsp_ygo.c; sourceTree = "<group>"; };
836F6E7518BDC2180095E648 /* ngc_ffcc_str.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_ffcc_str.c; sourceTree = "<group>"; };
836F6E7618BDC2180095E648 /* ngc_gcub.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_gcub.c; sourceTree = "<group>"; };
836F6E7718BDC2180095E648 /* ngc_lps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_lps.c; sourceTree = "<group>"; };
836F6E7818BDC2180095E648 /* ngc_nst_dsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_nst_dsp.c; sourceTree = "<group>"; };
836F6E7918BDC2180095E648 /* ngc_pdt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ngc_pdt.c; sourceTree = "<group>"; };
@ -1111,7 +1112,6 @@
836F6E9718BDC2180095E648 /* ps2_ccc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_ccc.c; sourceTree = "<group>"; };
836F6E9818BDC2180095E648 /* ps2_dxh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_dxh.c; sourceTree = "<group>"; };
836F6E9918BDC2180095E648 /* ps2_enth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_enth.c; sourceTree = "<group>"; };
836F6E9A18BDC2180095E648 /* ps2_exst.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_exst.c; sourceTree = "<group>"; };
836F6E9B18BDC2180095E648 /* ps2_filp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_filp.c; sourceTree = "<group>"; };
836F6E9C18BDC2180095E648 /* ps2_gbts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_gbts.c; sourceTree = "<group>"; };
836F6E9D18BDC2180095E648 /* ps2_gcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_gcm.c; sourceTree = "<group>"; };
@ -1331,6 +1331,10 @@
83AA7F882519C076004C5298 /* render.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render.c; sourceTree = "<group>"; };
83AA7F892519C076004C5298 /* decode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = decode.c; sourceTree = "<group>"; };
83AB8C741E8072A100086084 /* x360_ast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x360_ast.c; sourceTree = "<group>"; };
83AF2CC526226BA400538240 /* gcub.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gcub.c; sourceTree = "<group>"; };
83AF2CC626226BA400538240 /* exst.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exst.c; sourceTree = "<group>"; };
83AF2CC726226BA400538240 /* ogv_3rdeye.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ogv_3rdeye.c; sourceTree = "<group>"; };
83AF2CC826226BA500538240 /* encrypted_bgm_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = encrypted_bgm_streamfile.h; sourceTree = "<group>"; };
83AFABB923795201002F3947 /* xssb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xssb.c; sourceTree = "<group>"; };
83AFABBA23795202002F3947 /* ea_eaac_opus_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ea_eaac_opus_streamfile.h; sourceTree = "<group>"; };
83AFABBB23795202002F3947 /* isb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = isb.c; sourceTree = "<group>"; };
@ -1804,9 +1808,11 @@
83EED5D1203A8BC7008BEB45 /* ea_swvr.c */,
8306B0C42098458D000302D4 /* ea_wve_ad10.c */,
8306B0BF2098458C000302D4 /* ea_wve_au00.c */,
83AF2CC826226BA500538240 /* encrypted_bgm_streamfile.h */,
83031ECE243C50DE00C3F3E0 /* encrypted.c */,
836F6E4918BDC2180095E648 /* exakt_sc.c */,
836F6E4A18BDC2180095E648 /* excitebots.c */,
83AF2CC626226BA400538240 /* exst.c */,
8349A8EF1FE6257C00E26435 /* ezw.c */,
832BF80821E05135006F50F1 /* fag.c */,
8373342023F60CDB00DE14DC /* fda.c */,
@ -1826,6 +1832,7 @@
834D3A6D19F47C98001C54F6 /* g1l.c */,
836F6E4D18BDC2180095E648 /* gca.c */,
836F6E4E18BDC2180095E648 /* gcsw.c */,
83AF2CC526226BA400538240 /* gcub.c */,
836F6E4F18BDC2180095E648 /* genh.c */,
8375737421F950EC00F01AF5 /* gin.c */,
836F6E5118BDC2180095E648 /* gsp_gsb.c */,
@ -1909,7 +1916,6 @@
836F6E7318BDC2180095E648 /* ngc_dsp_std.c */,
836F6E7418BDC2180095E648 /* ngc_dsp_ygo.c */,
836F6E7518BDC2180095E648 /* ngc_ffcc_str.c */,
836F6E7618BDC2180095E648 /* ngc_gcub.c */,
836F6E7718BDC2180095E648 /* ngc_lps.c */,
836F6E7818BDC2180095E648 /* ngc_nst_dsp.c */,
836F6E7918BDC2180095E648 /* ngc_pdt.c */,
@ -1933,6 +1939,7 @@
835C883522CC17BE001B4B3F /* ogg_vorbis_streamfile.h */,
83A21F7F201D8980000F04B9 /* ogg_vorbis.c */,
831BA60F1EAC61A500CF89B0 /* ogl.c */,
83AF2CC726226BA400538240 /* ogv_3rdeye.c */,
8349A8FB1FE6257F00E26435 /* omu.c */,
8306B0CD2098458E000302D4 /* opus_interleave_streamfile.h */,
8306B0CE2098458E000302D4 /* opus.c */,
@ -1961,7 +1968,6 @@
836F6E9818BDC2180095E648 /* ps2_dxh.c */,
83A8BAE125667AA7000F5F3F /* ps2_enth_streamfile.h */,
836F6E9918BDC2180095E648 /* ps2_enth.c */,
836F6E9A18BDC2180095E648 /* ps2_exst.c */,
836F6E9B18BDC2180095E648 /* ps2_filp.c */,
836F6E9C18BDC2180095E648 /* ps2_gbts.c */,
836F6E9D18BDC2180095E648 /* ps2_gcm.c */,
@ -2207,6 +2213,7 @@
83E7FD6125EF2B0C00683FD2 /* tac_decoder_lib.h in Headers */,
834FE0EC215C79ED000A5D3D /* kma9_streamfile.h in Headers */,
83E7FD6225EF2B0C00683FD2 /* tac_decoder_lib_ops.h in Headers */,
83AF2CCC26226BA500538240 /* encrypted_bgm_streamfile.h in Headers */,
8349A90F1FE6258200E26435 /* aix_streamfile.h in Headers */,
836F705718BDC2190095E648 /* util.h in Headers */,
83C7282722BC8C1500678B4A /* plugins.h in Headers */,
@ -2477,7 +2484,6 @@
836F702018BDC2190095E648 /* rkv.c in Sources */,
834FE0F4215C79ED000A5D3D /* wsi.c in Sources */,
836F703218BDC2190095E648 /* str_asr.c in Sources */,
836F6FB218BDC2190095E648 /* ngc_gcub.c in Sources */,
837CEB0223487F2C00E62A4A /* raw_int.c in Sources */,
836F702818BDC2190095E648 /* sat_dvi.c in Sources */,
832BF82D21E0514B006F50F1 /* nus3audio.c in Sources */,
@ -2516,6 +2522,7 @@
83C7281322BC893D00678B4A /* mta2.c in Sources */,
8306B0EF20984590000302D4 /* ubi_bao.c in Sources */,
836F6FBB18BDC2190095E648 /* ngca.c in Sources */,
83AF2CCA26226BA500538240 /* exst.c in Sources */,
8306B0E220984590000302D4 /* smv.c in Sources */,
8349A91E1FE6258200E26435 /* bar.c in Sources */,
834FE110215C79ED000A5D3D /* msv.c in Sources */,
@ -2534,6 +2541,7 @@
836F705818BDC2190095E648 /* vgmstream.c in Sources */,
835C883622CC17BE001B4B3F /* bwav.c in Sources */,
8349A90A1FE6258200E26435 /* sab.c in Sources */,
83AF2CC926226BA500538240 /* gcub.c in Sources */,
836F6F6818BDC2190095E648 /* ads.c in Sources */,
8306B08620984518000302D4 /* fadpcm_decoder.c in Sources */,
83AB8C761E8072A100086084 /* x360_ast.c in Sources */,
@ -2602,7 +2610,6 @@
836F702418BDC2190095E648 /* rwsd.c in Sources */,
830EBE142004656E0023AA10 /* ktss.c in Sources */,
836F6F6618BDC2190095E648 /* aax.c in Sources */,
836F6FD618BDC2190095E648 /* ps2_exst.c in Sources */,
8306B0BC20984552000302D4 /* blocked_vs.c in Sources */,
83AA7F812519C042004C5298 /* silence.c in Sources */,
834FE0B3215C798C000A5D3D /* acm_decoder_util.c in Sources */,
@ -2812,6 +2819,7 @@
83AA5D181F6E2F600020821C /* mpeg_custom_utils_awc.c in Sources */,
83031ED1243C50DF00C3F3E0 /* encrypted.c in Sources */,
834FE0FE215C79ED000A5D3D /* ps_headerless.c in Sources */,
83AF2CCB26226BA500538240 /* ogv_3rdeye.c in Sources */,
8306B0BB20984552000302D4 /* blocked_gsb.c in Sources */,
83031ECC243C50CC00C3F3E0 /* blocked_ubi_sce.c in Sources */,
836F6F7718BDC2190095E648 /* capdsp.c in Sources */,

View File

@ -369,6 +369,7 @@ static const char* extension_list[] = {
//"ogg", //common
"ogl",
"ogv",
"oma", //FFmpeg/not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA)
"omu",
//"opus", //common
@ -499,6 +500,7 @@ static const char* extension_list[] = {
"stream",
"strm",
"sts",
"sts_cp3",
"stx",
"svag",
"svs",
@ -930,7 +932,7 @@ static const meta_info meta_info_list[] = {
{meta_RAW_INT, "PS2 .int raw header"},
{meta_PS2_OMU, "Alter Echo OMU Header"},
{meta_DSP_STM, "Intelligent Systems STM header"},
{meta_PS2_EXST, "Sony EXST header"},
{meta_EXST, "Sony EXST header"},
{meta_SVAG_KCET, "Konami SVAG header"},
{meta_PS_HEADERLESS, "Headerless PS-ADPCM raw header"},
{meta_MIB_MIH, "Sony MultiStream MIH+MIB header"},
@ -1093,7 +1095,7 @@ static const meta_info meta_info_list[] = {
{meta_2DX9, "beatmania IIDX 2DX9 header"},
{meta_DSP_YGO, "Konami custom DSP Header"},
{meta_PS2_VGV, "Rune: Viking Warlord VGV Header"},
{meta_NGC_GCUB, "GCub Header"},
{meta_GCUB, "Sega GCub header"},
{meta_NGC_SCK_DSP, "The Scorpion King SCK Header"},
{meta_CAFF, "Apple Core Audio Format File header"},
{meta_PC_MXST, "Lego Island MxSt Header"},
@ -1347,6 +1349,7 @@ static const meta_info meta_info_list[] = {
{meta_TAC, "tri-Ace Codec header"},
{meta_IDSP_TOSE, "TOSE .IDSP header"},
{meta_DSP_KWA, "Kuju London .KWA header"},
{meta_OGV_3RDEYE, "3rdEye .OGV header"},
};
void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {

View File

@ -1,6 +1,7 @@
#include "meta.h"
#include "../coding/coding.h"
#include "ogg_vorbis_streamfile.h"
#include "encrypted_bgm_streamfile.h"
//todo fuse ogg encryptions and use generic names
@ -80,6 +81,32 @@ VGMSTREAM* init_vgmstream_encrypted(STREAMFILE* sf) {
return vgmstream;
}
if (check_extensions(sf,"bgm")) {
uint8_t keybuf[0x100];
size_t key_size;
off_t start;
/* Studio Ring games [Nanami to Konomi no Oshiete ABC (PC), Oyatsu no Jikan (PC)] */
if (id != get_id32be("RIFF"))
goto fail;
/* Standard RIFF xor'd past "data", sometimes including extra chunks like JUNK or smpl.
* If .bgm is added to riff.c this needs to be reworked so detection goes first, or bgm+bgmkey is
* rejected in riff.c (most files are rejected due to the xor'd extra chunks though). */
key_size = read_key_file(keybuf, sizeof(keybuf), sf);
if (key_size <= 0) goto fail;
if (!find_chunk_le(sf, get_id32be("data"), 0x0c, 0, &start, NULL))
goto fail;
temp_sf = setup_bgm_streamfile(sf, start, keybuf, key_size);
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_riff(temp_sf);
close_streamfile(temp_sf);
return vgmstream;
}
fail:
return NULL;

View File

@ -0,0 +1,52 @@
#ifndef _BGM_STREAMFILE_H_
#define _BGM_STREAMFILE_H_
#include "../streamfile.h"
typedef struct {
uint8_t key[0x100];
size_t key_len;
off_t start;
} bgm_io_data;
static size_t bgm_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_t length, bgm_io_data* data) {
int i, begin, pos;
size_t bytes = read_streamfile(dest, offset, length, sf);
/* decrypt data (xor) */
if (offset + length > data->start) {
if (offset < data->start) {
begin = data->start - offset;
pos = 0;
}
else {
begin = 0;
pos = offset - data->start;
}
for (i = begin; i < bytes; i++) {
dest[i] ^= data->key[(pos++) % data->key_len];
}
}
return bytes;
}
/* decrypts BGM stream */
static STREAMFILE* setup_bgm_streamfile(STREAMFILE *sf, off_t start, uint8_t* key, int key_len) {
STREAMFILE *new_sf = NULL;
bgm_io_data io_data = {0};
io_data.start = start;
io_data.key_len = key_len;
if (key_len > sizeof(io_data.key))
return NULL;
memcpy(io_data.key, key, key_len);
new_sf = open_wrap_streamfile(sf);
new_sf = open_io_streamfile_f(new_sf, &io_data, sizeof(bgm_io_data), bgm_io_read, NULL);
new_sf = open_fakename_streamfile_f(new_sf, NULL, "wav");
return new_sf;
}
#endif /* _BGM_STREAMFILE_H_ */

View File

@ -0,0 +1,103 @@
#include "meta.h"
#include "../coding/coding.h"
/* EXST - from Sony games [Shadow of the Colossus (PS2), Gacha Mecha Stadium Saru Battle (PS2)] */
VGMSTREAM* init_vgmstream_exst(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sf_body = NULL;
off_t start_offset;
int loop_flag, channels, sample_rate;
int32_t interleave, num_samples, loop_start, loop_end;
size_t data_size;
int is_cp3 = 0;
/* checks */
/* .sts+int: standard [Shadow of the Colossus (PS2)] (some fake .sts have manually joined header+body)
* .x: header+body [Ape Escape 3 (PS2)]
* .sts_cp3+int_cp3: Shadow of the Colossus (PS3) */
if (!check_extensions(sf, "sts,sts_cp3,x"))
goto fail;
if (!is_id32be(0x00,sf, "EXST"))
goto fail;
/* also detectable since PS2 .sts uses blocks and PS3 offsets */
is_cp3 = check_extensions(sf, "sts_cp3");
if (is_cp3)
sf_body = open_streamfile_by_ext(sf,"int_cp3");
else
sf_body = open_streamfile_by_ext(sf,"int");
if (sf_body) {
/* separate header+body (header is 0x78) */
start_offset = 0x00;
data_size = get_streamfile_size(sf_body);
}
else {
/* joint header+body (.x and assumed .sts) */
start_offset = 0x78;
data_size = get_streamfile_size(sf);
/* Gacharoku 2 has header+data but padded header (ELF has pointers + size to SOUND.PCK, and
* treats them as single files, no extension but there are Sg2ExStAdpcm* calls in the ELF) */
if ((data_size % 0x10) == 0)
start_offset = 0x80;
if (data_size <= start_offset)
goto fail;
data_size = data_size - start_offset;
}
channels = read_u16le(0x06,sf);
sample_rate = read_u32le(0x08,sf);
loop_flag = read_u32le(0x0C,sf);
loop_start = read_u32le(0x10,sf);
loop_end = read_u32le(0x14,sf);
/* 0x18: 0x24 config per channel? (volume+panning+etc?) */
/* rest is padding up to 0x78 */
if (!is_cp3) {
interleave = 0x400;
loop_flag = (loop_flag == 1);
num_samples = ps_bytes_to_samples(data_size, channels); /* same or very close to loop end */
loop_start = ps_bytes_to_samples(loop_start * interleave * channels, channels); /* blocks */
loop_end = ps_bytes_to_samples(loop_end * interleave * channels, channels); /* blocks */
}
else {
interleave = 0x10;
loop_flag = !(loop_start == 0 && loop_end == data_size); /* flag always set even for jingles */
num_samples = ps_bytes_to_samples(data_size, channels); /* not same as loop end */
loop_start = ps_bytes_to_samples(loop_start, channels); /* offset */
loop_end = ps_bytes_to_samples(loop_end, channels); /* offset */
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_EXST;
vgmstream->sample_rate = sample_rate;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
if (!vgmstream_open_stream(vgmstream, sf_body ? sf_body : sf, start_offset))
goto fail;
close_streamfile(sf_body);
return vgmstream;
fail:
close_streamfile(sf_body);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -0,0 +1,53 @@
#include "meta.h"
#include "../coding/coding.h"
/* GCub - found in Sega Soccer Slam (GC) */
VGMSTREAM* init_vgmstream_gcub(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int channels, loop_flag, sample_rate;
size_t data_size;
/* checks */
/* .wav: extension found in bigfile
* .gcub: header id */
if (!check_extensions(sf, "wav,lwav,gcub"))
goto fail;
if (!is_id32be(0x00,sf, "GCub"))
goto fail;
loop_flag = 0;
channels = read_u32be(0x04,sf);
sample_rate = read_u32be(0x08,sf);
data_size = read_u32be(0x0c,sf);
if (is_id32be(0x60,sf, "GCxx")) /* seen in sfx */
start_offset = 0x88;
else
start_offset = 0x60;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_GCUB;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channels);
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x8000;
dsp_read_coefs_be(vgmstream, sf, 0x10, 0x20);
/* 0x50: initial ps for ch1/2 (16b) */
/* 0x54: hist? (always blank) */
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -84,7 +84,7 @@ VGMSTREAM * init_vgmstream_ps2_rxw(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_raw_int(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ps2_exst(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_exst(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_svag_kcet(STREAMFILE *streamFile);
@ -416,7 +416,7 @@ VGMSTREAM * init_vgmstream_dsp_ygo(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ps2_vgv(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ngc_gcub(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_gcub(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_maxis_xa(STREAMFILE * streamFile);
@ -949,4 +949,6 @@ VGMSTREAM* init_vgmstream_mjb_mjh(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_tac(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ogv_3rdeye(STREAMFILE* sf);
#endif /*_META_H*/

View File

@ -1,103 +0,0 @@
#include "meta.h"
#include "../util.h"
/* GCUB - found in 'Sega Soccer Slam' */
VGMSTREAM * init_vgmstream_ngc_gcub(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("gcub",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x47437562) /* "GCub" */
goto fail;
loop_flag = 0;
channel_count = read_32bitBE(0x04,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
if (read_32bitBE(0x60,streamFile) == 0x47437878) /* "GCxx" */
{
start_offset = 0x88;
}
else
{
start_offset = 0x60;
}
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x08,streamFile);
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->num_samples = (read_32bitBE(0x0C,streamFile)-start_offset)/8/channel_count*14;
if (loop_flag) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = (read_32bitBE(0x0C,streamFile)-start_offset)/8/channel_count*14;
}
if (channel_count == 1)
{
vgmstream->layout_type = layout_none;
}
else
{
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x8000; // read_32bitBE(0x04,streamFile);
}
vgmstream->meta_type = meta_NGC_GCUB;
if (vgmstream->coding_type == coding_NGC_DSP) {
int i;
for (i=0;i<16;i++) {
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x10+i*2,streamFile);
}
if (vgmstream->channels == 2) {
for (i=0;i<16;i++) {
vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x30+i*2,streamFile);
}
}
}
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
/* The first channel */
vgmstream->ch[0].channel_start_offset=
vgmstream->ch[0].offset=start_offset;
/* The second channel */
if (channel_count == 2) {
vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!vgmstream->ch[1].streamfile) goto fail;
vgmstream->ch[1].channel_start_offset=
vgmstream->ch[1].offset=start_offset+vgmstream->interleave_block_size;
}
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -544,14 +544,15 @@ VGMSTREAM* init_vgmstream_ogg_vorbis_callbacks(STREAMFILE* sf, ov_callbacks* cal
loop_start = atol(strrchr(comment,'=')+1) * sample_rate / 1000; /* ms to samples */
loop_flag = (loop_start >= 0);
}
else if (strstr(comment,"COMMENT=- loopTime ") == comment) { /* Aristear Remain (PC) */
loop_start = atol(strrchr(comment,' ')+1) / 1000.0f * sample_rate; /* ms to samples */
else if (strstr(comment,"COMMENT=- loopTime ") == comment || /* Aristear Remain (PC) */
strstr(comment,"COMMENT=-loopTime ") == comment) { /* Hyakki Ryouran no Yakata x Kawarazaki-ke no Ichizoku (PC) */
loop_start = atol(strrchr(comment,'l')) / 1000.0f * sample_rate; /* ms to samples */
loop_flag = (loop_start >= 0);
/* files have all page granule positions -1 except a few close to loop. This throws off
* libvorbis seeking (that uses granules), so we need manual fix = slower. Could be detected
* by checking granules in the first new OggS pages (other games from same dev don't use
* loopTime not have wrong granules though) */
* by checking granules in the first new OggS pages (other games from the same dev don't use
* loopTime nor have wrong granules though) */
force_seek = 1;
}
@ -582,6 +583,8 @@ VGMSTREAM* init_vgmstream_ogg_vorbis_callbacks(STREAMFILE* sf, ov_callbacks* cal
vgmstream->coding_type = coding_OGG_VORBIS;
vgmstream->layout_type = layout_none;
vgmstream->meta_type = ovmi->meta_type;
if (!vgmstream->meta_type)
vgmstream->meta_type = meta_OGG_VORBIS;
vgmstream->sample_rate = sample_rate;
vgmstream->stream_size = stream_size;

View File

@ -0,0 +1,40 @@
#include "meta.h"
#include "../coding/coding.h"
/* OGV - .ogg container (not related to ogv video) [Bloody Rondo (PC)] */
VGMSTREAM* init_vgmstream_ogv_3rdeye(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t subfile_offset, subfile_size;
/* checks */
if (!check_extensions(sf,"ogv"))
goto fail;
if (!is_id32be(0x00,sf, "OGV\0"))
goto fail;
/* 0x04: PCM size */
subfile_size = read_u32le(0x08, sf);
/* 0x0c: "fmt" + RIFF fmt + "data" (w/ PCM size too) */
subfile_offset = 0x2c;
/* no loops (files bgm does full loops but sfx doesn't) */
#ifdef VGM_USE_VORBIS
{
ogg_vorbis_meta_info_t ovmi = {0};
ovmi.meta_type = meta_OGV_3RDEYE;
ovmi.stream_size = subfile_size;
vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, subfile_offset, &ovmi);
}
#else
goto fail;
#endif
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,73 +0,0 @@
#include "meta.h"
#include "../coding/coding.h"
/* EXST - from Sony games [Shadow of the Colossus (PS2), Gacha Mecha Stadium Saru Battle (PS2)] */
VGMSTREAM* init_vgmstream_ps2_exst(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sf_body = NULL;
off_t start_offset;
int loop_flag, channels, sample_rate;
size_t block_size, num_blocks, loop_start_block;
/* checks */
/* .sts+int: standard [Shadow of the Colossus (PS2)] (some fake .sts have manually joined header+body)
* .x: header+body [Ape Escape 3 (PS2)] */
if (!check_extensions(sf, "sts,x"))
goto fail;
if (!is_id32be(0x00,sf, "EXST"))
goto fail;
sf_body = open_streamfile_by_ext(sf,"int");
if (sf_body) {
/* separate header+body (header is 0x78) */
start_offset = 0x00;
}
else {
/* joint header+body */
start_offset = 0x78;
/* Gacharoku 2 has header+data but padded header (ELF has pointers + size to SOUND.PCK, and
* treats them as single files, no extension but there are Sg2ExStAdpcm* calls in the ELF) */
if ((get_streamfile_size(sf) % 0x10) == 0)
start_offset = 0x80;
if (get_streamfile_size(sf) < start_offset)
goto fail;
}
channels = read_u16le(0x06,sf);
sample_rate = read_u32le(0x08,sf);
loop_flag = read_u32le(0x0C,sf) == 1;
loop_start_block = read_u32le(0x10,sf);
num_blocks = read_u32le(0x14,sf);
/* 0x18: 0x24 config per channel? (volume+panning+etc?) */
/* rest is padding up to 0x78 */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_PS2_EXST;
vgmstream->sample_rate = sample_rate;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x400;
block_size = vgmstream->interleave_block_size * vgmstream->channels;
vgmstream->num_samples = ps_bytes_to_samples(num_blocks * block_size, channels);
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start_block * block_size, channels);
vgmstream->loop_end_sample = vgmstream->num_samples;
if (!vgmstream_open_stream(vgmstream, sf_body ? sf_body : sf, start_offset))
goto fail;
close_streamfile(sf_body);
return vgmstream;
fail:
close_streamfile(sf_body);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -5,6 +5,7 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include "vgmstream.h"
#include "meta/meta.h"
#include "layout/layout.h"
@ -46,7 +47,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_ps2_rxws,
init_vgmstream_ps2_rxw,
init_vgmstream_ngc_dsp_stm,
init_vgmstream_ps2_exst,
init_vgmstream_exst,
init_vgmstream_svag_kcet,
init_vgmstream_mib_mih,
init_vgmstream_ngc_mpdsp,
@ -211,7 +212,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_2dx9,
init_vgmstream_dsp_ygo,
init_vgmstream_ps2_vgv,
init_vgmstream_ngc_gcub,
init_vgmstream_gcub,
init_vgmstream_maxis_xa,
init_vgmstream_ngc_sck_dsp,
init_vgmstream_apple_caff,
@ -525,6 +526,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_tac,
init_vgmstream_idsp_tose,
init_vgmstream_dsp_kwa,
init_vgmstream_ogv_3rdeye,
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
@ -1330,6 +1332,33 @@ fail:
return;
}
/*******************************************************************************/
/* BITRATE */
/*******************************************************************************/
#define BITRATE_FILES_MAX 128 /* arbitrary max, but +100 segments have been observed */
typedef struct {
uint32_t hash[BITRATE_FILES_MAX]; /* already used streamfiles */
int subsong[BITRATE_FILES_MAX]; /* subsongs of those streamfiles (could be incorporated to the hash?) */
int count;
int count_max;
} bitrate_info_t;
static uint32_t hash_sf(STREAMFILE* sf) {
int i;
char path[PATH_LIMIT];
uint32_t hash = 2166136261;
get_streamfile_name(sf, path, sizeof(path));
/* our favorite garbo hash a.k.a FNV-1 32b */
for (i = 0; i < strlen(path); i++) {
char c = tolower(path[i]);
hash = (hash * 16777619) ^ (uint8_t)c;
}
return hash;
}
/* average bitrate helper to get STREAMFILE for a channel, since some codecs may use their own */
static STREAMFILE* get_vgmstream_average_bitrate_channel_streamfile(VGMSTREAM* vgmstream, int channel) {
@ -1368,18 +1397,18 @@ static STREAMFILE* get_vgmstream_average_bitrate_channel_streamfile(VGMSTREAM* v
return vgmstream->ch[channel].streamfile;
}
static int get_vgmstream_file_bitrate_from_size(size_t size, int sample_rate, int length_samples) {
static int get_vgmstream_file_bitrate_from_size(size_t size, int sample_rate, int32_t length_samples) {
if (sample_rate == 0 || length_samples == 0) return 0;
if (length_samples < 100) return 0; /* ignore stupid bitrates caused by some segments */
return (int)((int64_t)size * 8 * sample_rate / length_samples);
}
static int get_vgmstream_file_bitrate_from_streamfile(STREAMFILE* streamfile, int sample_rate, int length_samples) {
if (streamfile == NULL) return 0;
return get_vgmstream_file_bitrate_from_size(get_streamfile_size(streamfile), sample_rate, length_samples);
static int get_vgmstream_file_bitrate_from_streamfile(STREAMFILE* sf, int sample_rate, int32_t length_samples) {
if (sf == NULL) return 0;
return get_vgmstream_file_bitrate_from_size(get_streamfile_size(sf), sample_rate, length_samples);
}
static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, STREAMFILE** streamfile_pointers, int *pointers_count, int pointers_max) {
int sub, ch;
static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, bitrate_info_t* br) {
int i, ch;
int bitrate = 0;
/* Recursively get bitrate and fill the list of streamfiles if needed (to filter),
@ -1387,58 +1416,65 @@ static int get_vgmstream_file_bitrate_main(VGMSTREAM* vgmstream, STREAMFILE** st
*
* Because of how data, layers and segments can be combined it's possible to
* fool this in various ways; metas should report stream_size in complex cases
* to get accurate bitrates (particularly for subsongs). */
* to get accurate bitrates (particularly for subsongs). An edge case is when
* segments use only a few samples from a full file (like Wwise transitions), bitrates
* become a bit high since its hard to detect only part of the file is needed. */
if (vgmstream->stream_size) {
bitrate = get_vgmstream_file_bitrate_from_size(vgmstream->stream_size, vgmstream->sample_rate, vgmstream->num_samples);
}
else if (vgmstream->layout_type == layout_segmented) {
if (vgmstream->layout_type == layout_segmented) {
segmented_layout_data *data = (segmented_layout_data *) vgmstream->layout_data;
for (sub = 0; sub < data->segment_count; sub++) {
bitrate += get_vgmstream_file_bitrate_main(data->segments[sub], streamfile_pointers, pointers_count, pointers_max);
for (i = 0; i < data->segment_count; i++) {
bitrate += get_vgmstream_file_bitrate_main(data->segments[i], br);
}
bitrate = bitrate / data->segment_count;
}
else if (vgmstream->layout_type == layout_layered) {
layered_layout_data *data = vgmstream->layout_data;
for (sub = 0; sub < data->layer_count; sub++) {
bitrate += get_vgmstream_file_bitrate_main(data->layers[sub], streamfile_pointers, pointers_count, pointers_max);
for (i = 0; i < data->layer_count; i++) {
bitrate += get_vgmstream_file_bitrate_main(data->layers[i], br);
}
bitrate = bitrate / data->layer_count;
}
else {
/* Add channel bitrate if streamfile hasn't been used before (comparing files
* by absolute paths), so bitrate doesn't multiply when the same STREAMFILE is
* reopened per channel, also skipping repeated pointers. */
char path_current[PATH_LIMIT];
char path_compare[PATH_LIMIT];
int is_unique = 1;
/* Add channel bitrate if streamfile hasn't been used before, so bitrate doesn't count repeats
* (like same STREAMFILE reopened per channel, also considering SFs may be wrapped). */
for (ch = 0; ch < vgmstream->channels; ch++) {
STREAMFILE* sf_cur = get_vgmstream_average_bitrate_channel_streamfile(vgmstream, ch);
if (!sf_cur) continue;
get_streamfile_name(sf_cur, path_current, sizeof(path_current));
uint32_t hash_cur;
int subsong_cur;
STREAMFILE* sf_cur;
int is_unique = 1; /* default to "no other SFs exist" */
for (sub = 0; sub < *pointers_count; sub++) {
STREAMFILE* sf_cmp = streamfile_pointers[sub];
if (!sf_cmp) continue;
if (sf_cur == sf_cmp) {
is_unique = 0;
break;
}
get_streamfile_name(sf_cmp, path_compare, sizeof(path_compare));
if (strcmp(path_current, path_compare) == 0) {
/* compares paths (hashes for faster compares) + subsongs (same file + different subsong = "different" file) */
sf_cur = get_vgmstream_average_bitrate_channel_streamfile(vgmstream, ch);
if (!sf_cur) continue;
hash_cur = hash_sf(sf_cur);
subsong_cur = vgmstream->stream_index;
for (i = 0; i < br->count; i++) {
uint32_t hash_cmp = br->hash[i];
int subsong_cmp = br->subsong[i];
if (hash_cur == hash_cmp && subsong_cur == subsong_cmp) {
is_unique = 0;
break;
}
}
if (is_unique) {
if (*pointers_count >= pointers_max) goto fail;
streamfile_pointers[*pointers_count] = sf_cur;
(*pointers_count)++;
if (br->count >= br->count_max) goto fail;
bitrate += get_vgmstream_file_bitrate_from_streamfile(sf_cur, vgmstream->sample_rate, vgmstream->num_samples);
br->hash[br->count] = hash_cur;
br->subsong[br->count] = subsong_cur;
br->count++;
if (vgmstream->stream_size) {
/* stream_size applies to both channels but should add once and detect repeats (for current subsong) */
bitrate += get_vgmstream_file_bitrate_from_size(vgmstream->stream_size, vgmstream->sample_rate, vgmstream->num_samples);
}
else {
bitrate += get_vgmstream_file_bitrate_from_streamfile(sf_cur, vgmstream->sample_rate, vgmstream->num_samples);
}
break;
}
}
}
@ -1453,11 +1489,10 @@ fail:
* it counts extra data like block headers and padding. While this can be surprising
* sometimes (as it's often higher than common codec bitrates) it isn't wrong per se. */
int get_vgmstream_average_bitrate(VGMSTREAM* vgmstream) {
const size_t pointers_max = 128; /* arbitrary max, but +100 segments have been observed */
STREAMFILE* streamfile_pointers[128]; /* list already used streamfiles */
int pointers_count = 0;
bitrate_info_t br = {0};
br.count_max = BITRATE_FILES_MAX;
return get_vgmstream_file_bitrate_main(vgmstream, streamfile_pointers, &pointers_count, pointers_max);
return get_vgmstream_file_bitrate_main(vgmstream, &br);
}

View File

@ -366,7 +366,7 @@ typedef enum {
meta_NPS,
meta_PS2_RXWS, /* Sony games (Genji, Okage Shadow King, Arc The Lad Twilight of Spirits) */
meta_RAW_INT,
meta_PS2_EXST, /* Shadow of Colossus EXST */
meta_EXST,
meta_SVAG_KCET,
meta_PS_HEADERLESS, /* headerless PS-ADPCM */
meta_MIB_MIH,
@ -520,7 +520,7 @@ typedef enum {
meta_SD9, /* beatmaniaIIDX16 - EMPRESS (Arcade) */
meta_2DX9, /* beatmaniaIIDX16 - EMPRESS (Arcade) */
meta_PS2_VGV, /* Rune: Viking Warlord */
meta_NGC_GCUB, /* Sega Soccer Slam */
meta_GCUB,
meta_MAXIS_XA, /* Sim City 3000 (PC) */
meta_NGC_SCK_DSP, /* Scorpion King (NGC) */
meta_CAFF, /* iPhone .caf */
@ -764,6 +764,7 @@ typedef enum {
meta_TAC,
meta_IDSP_TOSE,
meta_DSP_KWA,
meta_OGV_3RDEYE,
} meta_t;
/* standard WAVEFORMATEXTENSIBLE speaker positions */