Updated VGMStream to r1050-2696-g0a04a738

CQTexperiment
Christopher Snowhill 2019-12-05 18:43:12 -08:00
parent 8e9f8237e3
commit 90ac083705
52 changed files with 20061 additions and 19641 deletions

View File

@ -89,6 +89,8 @@
8323894B1D22419B00482226 /* clHCA.h in Headers */ = {isa = PBXBuildFile; fileRef = 832389491D22419B00482226 /* clHCA.h */; settings = {ATTRIBUTES = (Public, ); }; };
832389501D2246C300482226 /* hca.c in Sources */ = {isa = PBXBuildFile; fileRef = 8323894F1D2246C300482226 /* hca.c */; };
832389521D224C0800482226 /* hca_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 832389511D224C0800482226 /* hca_decoder.c */; };
83269DD22399F5DE00F49FE3 /* nus3bank_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83269DD02399F5DD00F49FE3 /* nus3bank_streamfile.h */; };
83269DD32399F5DE00F49FE3 /* ivag.c in Sources */ = {isa = PBXBuildFile; fileRef = 83269DD12399F5DE00F49FE3 /* ivag.c */; };
83299FD01E7660C7003A3242 /* bik.c in Sources */ = {isa = PBXBuildFile; fileRef = 83299FCE1E7660C7003A3242 /* bik.c */; };
83299FD11E7660C7003A3242 /* dsp_adx.c in Sources */ = {isa = PBXBuildFile; fileRef = 83299FCF1E7660C7003A3242 /* dsp_adx.c */; };
832BF7FF21E050B7006F50F1 /* circus_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF7FC21E050B6006F50F1 /* circus_decoder.c */; };
@ -378,7 +380,6 @@
836F700E18BDC2190095E648 /* ps2_xa2.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED218BDC2190095E648 /* ps2_xa2.c */; };
836F700F18BDC2190095E648 /* ps2_xa30.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED318BDC2190095E648 /* ps2_xa30.c */; };
836F701118BDC2190095E648 /* ps3_cps.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED518BDC2190095E648 /* ps3_cps.c */; };
836F701218BDC2190095E648 /* ps3_ivag.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED618BDC2190095E648 /* ps3_ivag.c */; };
836F701518BDC2190095E648 /* ps3_past.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED918BDC2190095E648 /* ps3_past.c */; };
836F701E18BDC2190095E648 /* redspark.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EE218BDC2190095E648 /* redspark.c */; };
836F701F18BDC2190095E648 /* riff.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EE318BDC2190095E648 /* riff.c */; };
@ -776,6 +777,8 @@
832389491D22419B00482226 /* clHCA.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = clHCA.h; sourceTree = "<group>"; };
8323894F1D2246C300482226 /* hca.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hca.c; sourceTree = "<group>"; };
832389511D224C0800482226 /* hca_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hca_decoder.c; sourceTree = "<group>"; };
83269DD02399F5DD00F49FE3 /* nus3bank_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nus3bank_streamfile.h; sourceTree = "<group>"; };
83269DD12399F5DE00F49FE3 /* ivag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ivag.c; sourceTree = "<group>"; };
83299FCE1E7660C7003A3242 /* bik.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bik.c; sourceTree = "<group>"; };
83299FCF1E7660C7003A3242 /* dsp_adx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dsp_adx.c; sourceTree = "<group>"; };
832BF7FC21E050B6006F50F1 /* circus_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = circus_decoder.c; sourceTree = "<group>"; };
@ -1065,7 +1068,6 @@
836F6ED218BDC2190095E648 /* ps2_xa2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_xa2.c; sourceTree = "<group>"; };
836F6ED318BDC2190095E648 /* ps2_xa30.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_xa30.c; sourceTree = "<group>"; };
836F6ED518BDC2190095E648 /* ps3_cps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_cps.c; sourceTree = "<group>"; };
836F6ED618BDC2190095E648 /* ps3_ivag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_ivag.c; sourceTree = "<group>"; };
836F6ED918BDC2190095E648 /* ps3_past.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_past.c; sourceTree = "<group>"; };
836F6EE218BDC2190095E648 /* redspark.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = redspark.c; sourceTree = "<group>"; };
836F6EE318BDC2190095E648 /* riff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = riff.c; sourceTree = "<group>"; };
@ -1647,6 +1649,7 @@
836F6E5518BDC2180095E648 /* ios_psnd.c */,
83AFABBB23795202002F3947 /* isb.c */,
836F6E5618BDC2180095E648 /* ish_isd.c */,
83269DD12399F5DE00F49FE3 /* ivag.c */,
836F6E5718BDC2180095E648 /* ivaud.c */,
836F6E5818BDC2180095E648 /* ivb.c */,
837CEAE923487F2B00E62A4A /* jstm_streamfile.h */,
@ -1715,6 +1718,7 @@
83C727FC22BC893900678B4A /* nps.c */,
837CEAE223487F2A00E62A4A /* nub.c */,
832BF81B21E0514B006F50F1 /* nus3audio.c */,
83269DD02399F5DD00F49FE3 /* nus3bank_streamfile.h */,
834FE0D1215C79E9000A5D3D /* nus3bank.c */,
836F6E8118BDC2180095E648 /* nwa.c */,
832BF81421E0514A006F50F1 /* nwav.c */,
@ -1800,7 +1804,6 @@
836F6ED218BDC2190095E648 /* ps2_xa2.c */,
836F6ED318BDC2190095E648 /* ps2_xa30.c */,
836F6ED518BDC2190095E648 /* ps3_cps.c */,
836F6ED618BDC2190095E648 /* ps3_ivag.c */,
836F6ED918BDC2190095E648 /* ps3_past.c */,
837CEAE823487F2B00E62A4A /* psf.c */,
83997F5722D9569E00633184 /* rad.c */,
@ -2033,6 +2036,7 @@
837CEAF323487F2C00E62A4A /* mzrt_streamfile.h in Headers */,
8349A91B1FE6258200E26435 /* adx_keys.h in Headers */,
836F6F4D18BDC2190095E648 /* layout.h in Headers */,
83269DD22399F5DE00F49FE3 /* nus3bank_streamfile.h in Headers */,
83AA5D251F6E2F9C0020821C /* hca_keys.h in Headers */,
836F6F2318BDC2190095E648 /* coding.h in Headers */,
);
@ -2217,6 +2221,7 @@
8301659C1F256BD000CA0941 /* nds_strm_ffta2.c in Sources */,
837CEA7923487E2500E62A4A /* ubi_adpcm_decoder.c in Sources */,
834FE0EB215C79ED000A5D3D /* str_wav.c in Sources */,
83269DD32399F5DE00F49FE3 /* ivag.c in Sources */,
8349A8DF1FE6251F00E26435 /* vorbis_custom_utils_vid1.c in Sources */,
83A21F8D201D8982000F04B9 /* sqex_sead.c in Sources */,
83EED5D3203A8BC7008BEB45 /* ea_swvr.c in Sources */,
@ -2537,7 +2542,6 @@
83A21F8A201D8982000F04B9 /* fsb_encrypted.c in Sources */,
8306B0B120984552000302D4 /* blocked_halpst.c in Sources */,
836F6FD018BDC2190095E648 /* ps2_b1s.c in Sources */,
836F701218BDC2190095E648 /* ps3_ivag.c in Sources */,
83AA5D181F6E2F600020821C /* mpeg_custom_utils_awc.c in Sources */,
834FE0FE215C79ED000A5D3D /* ps_headerless.c in Sources */,
8306B0BB20984552000302D4 /* blocked_gsb.c in Sources */,

View File

@ -7,6 +7,7 @@
#include "libatrac9.h"
#endif
/* opaque struct */
struct atrac9_codec_data {
uint8_t *data_buffer;

View File

@ -239,7 +239,7 @@ static int ps_find_loop_offsets_internal(STREAMFILE *streamFile, off_t start_off
int detect_full_loops = config & 1;
if (data_size == 0 || channels == 0 || (channels > 0 && interleave == 0))
if (data_size == 0 || channels == 0 || (channels > 1 && interleave == 0))
return 0;
while (offset < max_offset) {

View File

@ -32,6 +32,7 @@ static const char* extension_list[] = {
//"aac", //common
"aa3", //FFmpeg/not parsed (ATRAC3/ATRAC3PLUS/MP3/LPCM/WMA)
"aax",
"abc", //txth/reserved [Find My Own Way (PS2) tech demo]
"abk",
//"ac3", //common, FFmpeg/not parsed (AC3)
"acb",
@ -326,6 +327,7 @@ static const char* extension_list[] = {
"nps",
"npsf", //fake extension/header id for .nps (in bigfiles)
"nub",
"nub2",
"nus3audio",
"nus3bank",
"nwa",
@ -798,7 +800,7 @@ static const layout_info layout_info_list[] = {
{layout_blocked_vs, "blocked (Melbourne House VS)"},
{layout_blocked_mul, "blocked (MUL)"},
{layout_blocked_gsb, "blocked (GSB)"},
{layout_blocked_thp, "blocked (THP Movie Audio)"},
{layout_blocked_thp, "blocked (THP)"},
{layout_blocked_filp, "blocked (FILP)"},
{layout_blocked_ea_swvr, "blocked (EA SWVR)"},
{layout_blocked_adm, "blocked (ADM)"},
@ -987,7 +989,7 @@ static const meta_info meta_info_list[] = {
{meta_DCS_WAV, "In Utero DCS+WAV header"},
{meta_SMP, "Infernal Engine .smp header"},
{meta_MUL, "Crystal Dynamics .MUL header"},
{meta_THP, "THP Movie File Format Header"},
{meta_THP, "Nintendo THP header"},
{meta_STS_WII, "Shikigami no Shiro (WII) Header"},
{meta_PS2_P2BT, "Pop'n'Music 7 Header"},
{meta_PS2_GBTS, "Pop'n'Music 9 Header"},
@ -1098,7 +1100,7 @@ static const meta_info meta_info_list[] = {
{meta_MN_STR, "Mini Ninjas 'STR' header"},
{meta_MSS, "Guerilla MCSS header"},
{meta_PS2_HSF, "Lowrider 'HSF' header"},
{meta_PS3_IVAG, "PS3 'IVAG' Header"},
{meta_IVAG, "Namco IVAG header"},
{meta_PS2_2PFS, "Konami 2PFS header"},
{meta_UBI_CKD, "Ubisoft CKD RIFF header"},
{meta_PS2_VBK, "PS2 VBK Header"},
@ -1107,7 +1109,7 @@ static const meta_info meta_info_list[] = {
{meta_FSTM, "Nintendo FSTM Header"},
{meta_KT_WIIBGM, "Koei Tecmo WiiBGM Header"},
{meta_KTSS, "Koei Tecmo Nintendo Stream KTSS Header"},
{meta_IDSP_NUS3, "Namco NUS3 IDSP header"},
{meta_IDSP_NAMCO, "Namco IDSP header"},
{meta_WIIU_BTSND, "Nintendo Wii U Menu Boot Sound"},
{meta_MCA, "Capcom MCA header"},
{meta_XB3D_ADX, "Xenoblade 3D ADX header"},

View File

@ -24,7 +24,7 @@ void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream) {
/* At 0x00(1): block flag
* - in SNS: 0x00=normal block, 0x80=last block (not mandatory)
* - in SPS: 0x48=header, 0x44=normal block, 0x45=last block (empty) */
block_id = (block_size & 0x00FFFFFF) >> 24;
block_id = (block_size & 0xFF000000) >> 24;
block_size &= 0x00FFFFFF;
if (block_id == 0x00 || block_id == 0x80 || block_id == 0x44) {

View File

@ -5,27 +5,37 @@
void block_update_thp(off_t block_offset, VGMSTREAM *vgmstream) {
int i, j;
STREAMFILE *streamFile = vgmstream->ch[0].streamfile;
off_t start_offset;
int32_t nextFrameSize;
off_t audio_offset;
size_t next_block_size, video_size;
next_block_size = read_32bitBE(block_offset + 0x00, streamFile);
/* 0x04: frame size previous */
video_size = read_32bitBE(block_offset + 0x08,streamFile);
/* 0x0c: audio size */
audio_offset = block_offset + 0x10 + video_size;
vgmstream->current_block_offset = block_offset;
nextFrameSize=read_32bitBE(vgmstream->current_block_offset,streamFile);
vgmstream->next_block_offset = block_offset + vgmstream->full_block_size;
vgmstream->full_block_size = next_block_size;
vgmstream->next_block_offset = vgmstream->current_block_offset
+ vgmstream->full_block_size;
vgmstream->full_block_size = nextFrameSize;
/* block samples can be smaller than block size, normally in the last block,
* but num_samples already takes that into account, so there is no real difference */
vgmstream->current_block_size = read_32bitBE(audio_offset + 0x00, streamFile);
vgmstream->current_block_samples = read_32bitBE(audio_offset + 0x04, streamFile);
start_offset=vgmstream->current_block_offset
+ read_32bitBE(vgmstream->current_block_offset+0x08,streamFile)+0x10;
vgmstream->current_block_size=read_32bitBE(start_offset,streamFile);
start_offset+=8;
audio_offset += 0x08;
for (i = 0; i < vgmstream->channels; i++) {
off_t coef_offset = audio_offset + i*0x20;
off_t hist_offset = audio_offset + vgmstream->channels*0x20 + i*0x04;
off_t data_offset = audio_offset + vgmstream->channels*0x24 + i*vgmstream->current_block_size;
for (j = 0; j < 16; j++) {
vgmstream->ch[i].adpcm_coef[j]=read_16bitBE(start_offset+(i*0x20)+(j*2),streamFile);
vgmstream->ch[i].adpcm_coef[j] = read_16bitBE(coef_offset + (j*0x02),streamFile);
}
vgmstream->ch[i].adpcm_history1_16=read_16bitBE(start_offset + (0x20*vgmstream->channels) + (i*4),streamFile);
vgmstream->ch[i].adpcm_history2_16=read_16bitBE(start_offset + (0x20*vgmstream->channels) + (i*4) + 2,streamFile);
vgmstream->ch[i].offset = start_offset + (0x24*vgmstream->channels)+(i*vgmstream->current_block_size);
vgmstream->ch[i].adpcm_history1_16 = read_16bitBE(hist_offset + 0x00,streamFile);
vgmstream->ch[i].adpcm_history2_16 = read_16bitBE(hist_offset + 0x02,streamFile);
vgmstream->ch[i].offset = data_offset;
}
}

View File

@ -184,6 +184,9 @@ static const adxkey_info adxkey8_list[] = {
/* Gintama Gin-san to Issho! Boku no Kabukichou Nikki (PS2) [Bandai Namco?] */
{0x67CD,0x5CA7,0x655F, "gt25809",0},
/* Lucky Star: RAvish Romance (PS2) [Vridge] */
{0x5347,0x4FB7,0x6415, "LUCKYSRARPS2",0},
};
static const adxkey_info adxkey9_list[] = {
@ -219,6 +222,9 @@ static const adxkey_info adxkey9_list[] = {
/* Mashiro Witch (Android) */
{0x2669,0x1495,0x2407, NULL,0x55D11D3349495204}, // 55D11D3349495204
/* Nogizaka46 Rhythm Festival (Android) */
{0x2378,0x5511,0x0201, NULL,5613126134333697}, // 0013F11BC5510101
};
static const int adxkey8_list_count = sizeof(adxkey8_list) / sizeof(adxkey8_list[0]);

View File

@ -25,8 +25,7 @@
#define EAAC_TYPE_RAM 0x00
#define EAAC_TYPE_STREAM 0x01
#define EAAC_LOOP_SET 0x01
#define EAAC_TYPE_GIGASAMPLE 0x02
#define EAAC_BLOCKID0_DATA 0x00
#define EAAC_BLOCKID0_END 0x80 /* maybe meant to be a bitflag? */
@ -35,64 +34,32 @@
#define EAAC_BLOCKID1_DATA 0x44 /* 'D' */
#define EAAC_BLOCKID1_END 0x45 /* 'E' */
static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, STREAMFILE * streamData, off_t header_offset, off_t start_offset, meta_t meta_type);
static size_t get_snr_size(STREAMFILE *streamFile, off_t offset);
static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, STREAMFILE * streamData, off_t header_offset, off_t start_offset, meta_t meta_type, int standalone);
static VGMSTREAM *parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint16_t target_index, off_t ast_offset);
VGMSTREAM * init_vgmstream_gin_header(STREAMFILE *streamFile, off_t offset);
/* .SNR+SNS - from EA latest games (~2008-2013), v0 header */
VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE * streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * streamData = NULL;
/* check extension, case insensitive */
if (!check_extensions(streamFile,"snr"))
goto fail;
/* SNR headers normally need an external SNS file, but some have data [Burnout Paradise, NFL2013 (iOS)] */
if (get_streamfile_size(streamFile) > 0x10) {
off_t start_offset = get_snr_size(streamFile, 0x00);
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, 0x00, start_offset, meta_EA_SNR_SNS);
if (!vgmstream) goto fail;
}
else {
streamData = open_streamfile_by_ext(streamFile,"sns");
if (!streamData) goto fail;
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamData, 0x00, 0x00, meta_EA_SNR_SNS);
if (!vgmstream) goto fail;
}
close_streamfile(streamData);
return vgmstream;
return init_vgmstream_eaaudiocore_header(streamFile, NULL, 0x00, 0x00, meta_EA_SNR_SNS, 1);
fail:
close_streamfile(streamData);
return NULL;
}
/* .SPS - from EA latest games (~2014), v1 header */
VGMSTREAM * init_vgmstream_ea_sps(STREAMFILE * streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
/* check extension, case insensitive */
if (!check_extensions(streamFile,"sps"))
goto fail;
/* SPS block start: 0x00(1): block flag (header=0x48); 0x01(3): block size (usually 0x0c-0x14) */
if (read_8bit(0x00, streamFile) != EAAC_BLOCKID1_HEADER)
goto fail;
start_offset = read_32bitBE(0x00, streamFile) & 0x00FFFFFF;
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, 0x04, start_offset, meta_EA_SPS);
if (!vgmstream) goto fail;
return vgmstream;
return init_vgmstream_eaaudiocore_header(streamFile, NULL, 0x00, 0x00, meta_EA_SPS, 1);
fail:
close_vgmstream(vgmstream);
return NULL;
}
@ -125,7 +92,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) {
header_offset = 0x10; /* SNR header */
start_offset = read_32bit(0x08,streamFile); /* SNS blocks */
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, header_offset, start_offset, meta_EA_SNU);
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, header_offset, start_offset, meta_EA_SNU, 0);
if (!vgmstream) goto fail;
return vgmstream;
@ -259,9 +226,9 @@ fail:
}
/* EA S10A header - seen inside new ABK files. Putting it here in case it's encountered stand-alone. */
static VGMSTREAM * parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint16_t target_index, off_t ast_offset) {
static VGMSTREAM * parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint16_t target_index, off_t sns_offset) {
uint32_t num_sounds;
off_t snr_offset, sns_offset;
off_t snr_offset;
STREAMFILE *astFile = NULL;
VGMSTREAM *vgmstream;
@ -279,11 +246,10 @@ static VGMSTREAM * parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint1
snr_offset = offset + read_32bitBE(offset + 0x0C + 0x04 * target_index, streamFile);
if (ast_offset == 0xFFFFFFFF) {
if (sns_offset == 0xFFFFFFFF) {
/* RAM asset */
sns_offset = snr_offset + get_snr_size(streamFile, snr_offset);
//;VGM_LOG("EA S10A: RAM at sns=%lx, sns=%lx\n", snr_offset, sns_offset);
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
//;VGM_LOG("EA S10A: RAM at snr=%lx", snr_offset);
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, NULL, snr_offset, 0x00, meta_EA_SNR_SNS, 0);
if (!vgmstream)
goto fail;
} else {
@ -295,9 +261,8 @@ static VGMSTREAM * parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint1
if (read_32bitBE(0x00, astFile) != 0x53313053) /* "S10S" */
goto fail;
sns_offset = ast_offset;
//;VGM_LOG("EA S10A: stream at sns=%lx, sns=%lx\n", snr_offset, sns_offset);
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, astFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
//;VGM_LOG("EA S10A: stream at snr=%lx, sns=%lx\n", snr_offset, sns_offset);
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, astFile, snr_offset, sns_offset, meta_EA_SNR_SNS, 0);
if (!vgmstream)
goto fail;
@ -373,16 +338,12 @@ VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE *streamFile) {
if (read_32bitBE(0x00, sbsFile) != 0x53424B53) /* "SBKS" */
goto fail;
snr_offset = sns_offset;
sns_offset = snr_offset + (read_32bitBE(snr_offset, sbsFile) & 0x00FFFFFF);
snr_offset += 0x04;
vgmstream = init_vgmstream_eaaudiocore_header(sbsFile, sbsFile, snr_offset, sns_offset, meta_EA_SPS);
vgmstream = init_vgmstream_eaaudiocore_header(sbsFile, NULL, sns_offset, 0x00, meta_EA_SPS, 0);
if (!vgmstream)
goto fail;
} else if (sns_offset == 0) {
/* RAM asset */
sns_offset = snr_offset + get_snr_size(streamFile, snr_offset);
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, NULL, snr_offset, 0x00, meta_EA_SNR_SNS, 0);
if (!vgmstream)
goto fail;
} else {
@ -394,7 +355,7 @@ VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE *streamFile) {
if (read_32bitBE(0x00, sbsFile) != 0x53424B53) /* "SBKS" */
goto fail;
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, sbsFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, sbsFile, snr_offset, sns_offset, meta_EA_SNR_SNS, 0);
if (!vgmstream)
goto fail;
}
@ -428,6 +389,9 @@ VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) {
/* 0x0C: zero */
/* 0x10: table start */
if (!check_extensions(streamFile, "hdr"))
goto fail;
if (read_8bit(0x09, streamFile) != 0)
goto fail;
@ -520,7 +484,7 @@ VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) {
if (block_id != EAAC_BLOCKID0_DATA && block_id != EAAC_BLOCKID0_END)
goto fail;
vgmstream = init_vgmstream_eaaudiocore_header(sthFile, datFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
vgmstream = init_vgmstream_eaaudiocore_header(sthFile, datFile, snr_offset, sns_offset, meta_EA_SNR_SNS, 0);
if (!vgmstream)
goto fail;
@ -594,7 +558,7 @@ static STREAMFILE *open_mapfile_pair(STREAMFILE *streamFile, int track, int num_
continue;
}
strncpy(buf, mus_name, PATH_LIMIT);
strncpy(buf, mus_name, PATH_LIMIT - 1);
pch = strtok(buf, ","); //TODO: not thread safe in std C
for (j = 0; j < track && pch; j++) {
pch = strtok(NULL, ",");
@ -603,9 +567,9 @@ static STREAMFILE *open_mapfile_pair(STREAMFILE *streamFile, int track, int num_
if (use_mask) {
file_name[file_len - map_len] = '\0';
strncat(file_name, pch + 1, PATH_LIMIT);
strncat(file_name, pch + 1, PATH_LIMIT - 1);
} else {
strncpy(file_name, pch, PATH_LIMIT);
strncpy(file_name, pch, PATH_LIMIT - 1);
}
musFile = open_streamfile_by_filename(streamFile, file_name);
@ -632,7 +596,7 @@ static STREAMFILE *open_mapfile_pair(STREAMFILE *streamFile, int track, int num_
/* EA MPF/MUS combo - used in older 7th gen games for storing interactive music */
VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) {
uint32_t num_tracks, track_start, track_hash, mus_sounds, mus_stream = 0;
uint8_t version, sub_version, block_id;
uint8_t version, sub_version;
off_t tracks_table, samples_table, eof_offset, table_offset, entry_offset, snr_offset, sns_offset;
int32_t(*read_32bit)(off_t, STREAMFILE*);
STREAMFILE *musFile = NULL;
@ -716,12 +680,7 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) {
table_offset = 0x08;
entry_offset = table_offset + mus_stream * 0x0c;
snr_offset = read_32bit(entry_offset + 0x04, musFile);
if (is_ram) {
sns_offset = snr_offset + get_snr_size(musFile, snr_offset);
} else {
sns_offset = read_32bit(entry_offset + 0x08, musFile);
}
} else if (sub_version == 3) {
/* number of files is always little endian */
mus_sounds = read_32bitLE(0x04, musFile);
@ -752,11 +711,7 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) {
goto fail;
}
block_id = read_8bit(sns_offset, musFile);
if (block_id != EAAC_BLOCKID0_DATA && block_id != EAAC_BLOCKID0_END)
goto fail;
vgmstream = init_vgmstream_eaaudiocore_header(musFile, musFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
vgmstream = init_vgmstream_eaaudiocore_header(musFile, musFile, snr_offset, sns_offset, meta_EA_SNR_SNS, 0);
if (!vgmstream)
goto fail;
@ -773,7 +728,7 @@ fail:
/* EA TMX - used for engine sounds in NFS games (2007-present) */
VGMSTREAM * init_vgmstream_ea_tmx(STREAMFILE *streamFile) {
uint32_t num_sounds, sound_type;
off_t table_offset, data_offset, entry_offset, sound_offset, sns_offset;
off_t table_offset, data_offset, entry_offset, sound_offset;
VGMSTREAM *vgmstream = NULL;
int target_stream = streamFile->stream_index;
@ -798,13 +753,11 @@ VGMSTREAM * init_vgmstream_ea_tmx(STREAMFILE *streamFile) {
switch (sound_type) {
case 0x47494E20: /* "GIN " */
/* FIXME: need to get GIN size somehow */
vgmstream = init_vgmstream_gin_header(streamFile, sound_offset);
if (!vgmstream) goto fail;
break;
case 0x534E5220: /* "SNR " */
sns_offset = sound_offset + get_snr_size(streamFile, sound_offset);
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, sound_offset, sns_offset, meta_EA_SNR_SNS);
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, NULL, sound_offset, 0x00, meta_EA_SNR_SNS, 0);
if (!vgmstream) goto fail;
break;
default:
@ -823,7 +776,7 @@ VGMSTREAM * init_vgmstream_ea_sbr_harmony(STREAMFILE *streamFile) {
uint32_t num_dsets, set_sounds, chunk_id;
uint32_t i;
uint8_t set_type, flag, offset_size;
off_t data_offset, table_offset, dset_offset, base_offset, sound_table_offset, sound_offset, header_offset, start_offset;
off_t data_offset, table_offset, dset_offset, base_offset, sound_table_offset, sound_offset;
STREAMFILE *sbsFile = NULL, *streamData = NULL;
VGMSTREAM *vgmstream = NULL;
int target_stream = streamFile->stream_index, total_sounds, local_target, is_streamed = 0;
@ -973,12 +926,7 @@ VGMSTREAM * init_vgmstream_ea_sbr_harmony(STREAMFILE *streamFile) {
}
}
if (read_8bit(sound_offset, streamData) != EAAC_BLOCKID1_HEADER)
goto fail;
header_offset = sound_offset + 0x04;
start_offset = sound_offset + (read_32bitBE(sound_offset, streamData) & 0x00FFFFFF);
vgmstream = init_vgmstream_eaaudiocore_header(streamData, streamData, header_offset, start_offset, meta_EA_SNR_SNS);
vgmstream = init_vgmstream_eaaudiocore_header(streamData, NULL, sound_offset, 0x00, meta_EA_SPS, 0);
if (!vgmstream)
goto fail;
@ -999,7 +947,6 @@ typedef struct {
int channel_config;
int sample_rate;
int type;
int loop;
int streamed;
int channels;
@ -1008,25 +955,37 @@ typedef struct {
int loop_start;
int loop_end;
int loop_flag;
int prefetch_samples;
off_t stream_offset;
off_t loop_offset;
off_t prefetch_offset;
} eaac_header;
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf_data, eaac_header *eaac);
static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *streamFile, eaac_header *eaac);
static size_t calculate_eaac_size(VGMSTREAM *vgmstream, STREAMFILE *streamFile, eaac_header *eaac, off_t start_offset);
static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *streamFile, eaac_header *eaac, off_t start_offset);
static STREAMFILE *setup_eaac_streamfile(eaac_header *ea, STREAMFILE *streamHead, STREAMFILE *streamData);
static size_t calculate_eaac_size(STREAMFILE *streamFile, eaac_header *ea, uint32_t num_samples, off_t start_offset);
/* EA newest header from RwAudioCore (RenderWare?) / EAAudioCore library (still generated by sx.exe).
* Audio "assets" come in separate RAM headers (.SNR/SPH) and raw blocked streams (.SNS/SPS),
* or together in pseudoformats (.SNU, .SBR+.SBS banks, .AEMS, .MUS, etc).
* Some .SNR include stream data, while .SPS have headers so .SPH is optional. */
static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, STREAMFILE * streamData, off_t header_offset, off_t start_offset, meta_t meta_type) {
static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, STREAMFILE * streamData, off_t header_offset, off_t start_offset, meta_t meta_type, int standalone) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE* temp_streamFile = NULL;
uint32_t header1, header2;
STREAMFILE* temp_streamFile = NULL, *streamFile = NULL, *snsFile = NULL;
uint32_t header1, header2, header_block_size = 0, header_size;
uint8_t header_block_id;
eaac_header eaac = {0};
if (meta_type == meta_EA_SPS) {
header_block_id = read_8bit(header_offset, streamHead);
header_block_size = read_32bitBE(header_offset, streamHead) & 0x00FFFFFF;
if (header_block_id != EAAC_BLOCKID1_HEADER)
goto fail;
header_offset += 0x04;
}
/* EA SNR/SPH header */
header1 = (uint32_t)read_32bitBE(header_offset + 0x00, streamHead);
@ -1036,14 +995,15 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
eaac.channel_config = (header1 >> 18) & 0x3F; /* 6 bits */
eaac.sample_rate = (header1 >> 0) & 0x03FFFF; /* 18 bits */
eaac.type = (header2 >> 30) & 0x03; /* 2 bits */
eaac.loop = (header2 >> 29) & 0x01; /* 1 bits */
eaac.loop_flag = (header2 >> 29) & 0x01; /* 1 bits */
eaac.num_samples = (header2 >> 0) & 0x1FFFFFFF; /* 29 bits */
/* rest is optional, depends on used flags and codec (handled below) */
eaac.stream_offset = start_offset;
/* common channel configs are mono/stereo/quad/5.1/7.1 (from debug strings), while others are quite rare
* [Battlefield 4 (X360)-EAXMA: 3/5/7ch, Army of Two: The Devil's Cartel (PS3)-EALayer3v2P: 11ch] */
eaac.channels = eaac.channel_config + 1;
/* EA 6ch channel mapping is L C R BL BR LFE, but may use stereo layers for dynamic music
* instead, so we can't re-map automatically (use TXTP) */
/* V0: SNR+SNS, V1: SPR+SPS (no apparent differences, other than block flags) */
if (eaac.version != EAAC_VERSION_V0 && eaac.version != EAAC_VERSION_V1) {
@ -1057,53 +1017,33 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
goto fail;
}
/* catch unknown values (0x02: "gigasample"? some kind of memory+stream thing?) */
if (eaac.type != EAAC_TYPE_RAM && eaac.type != EAAC_TYPE_STREAM) {
/* catch unknown values */
if (eaac.type != EAAC_TYPE_RAM && eaac.type != EAAC_TYPE_STREAM && eaac.type != EAAC_TYPE_GIGASAMPLE) {
VGM_LOG("EA EAAC: unknown type 0x%02x\n", eaac.type);
goto fail;
}
/* Non-streamed sounds are stored as a single block (may not set block end flags) */
eaac.streamed = (eaac.type == EAAC_TYPE_STREAM);
eaac.streamed = (eaac.type != EAAC_TYPE_RAM);
/* get loops (fairly involved due to the multiple layouts and mutant streamfiles)
* full loops aren't too uncommon [Dead Space (PC) stream sfx/ambiance, FIFA 98 (PS3) RAM sfx],
* full loops aren't too uncommon [Dead Space (PC) stream sfx/ambiance, FIFA 08 (PS3) RAM sfx],
* while actual looping is very rare [Need for Speed: World (PC)-EAL3, The Simpsons Game (X360)-EAXMA] */
if (eaac.loop == EAAC_LOOP_SET) {
eaac.loop_flag = 1;
/* get optional header values */
header_size = 0x08;
if (eaac.loop_flag) {
header_size += 0x04;
eaac.loop_start = read_32bitBE(header_offset + 0x08, streamHead);
eaac.loop_end = eaac.num_samples;
if (eaac.streamed) {
eaac.loop_offset = read_32bitBE(header_offset+0x0c, streamHead);
if (eaac.version == EAAC_VERSION_V0) {
/* SNR+SNS are separate so offsets are relative to the data start
* (first .SNS block, or extra data before the .SNS block in case of .SNU) */
eaac.loop_offset = eaac.stream_offset + eaac.loop_offset;
} else {
/* SPS have headers+data together so offsets are relative to the file start [ex. FIFA 18 (PC)] */
eaac.loop_offset = header_offset - 0x04 + eaac.loop_offset;
}
}
else if (eaac.loop_start > 0) {
/* RAM assets have two blocks in case of actual loops */
/* find the second block by getting the first block size */
eaac.loop_offset = read_32bitBE(eaac.stream_offset, streamData) & 0x00FFFFF;
eaac.loop_offset = eaac.stream_offset + eaac.loop_offset;
}
else {
/* RAM assets have only one block in case of full loops */
eaac.loop_offset = eaac.stream_offset; /* implicit */
}
//todo EATrax has extra values in header, which would coexist with loop values
/* TODO: EATrax has extra values in header, which would coexist with loop values */
if (eaac.codec == EAAC_CODEC_EATRAX) {
VGM_LOG("EA EAAC: unknown loop header for EATrax\n");
goto fail;
}
//todo need more cases to test how layout/streamfiles react
/* TODO: need more cases to test how layout/streamfiles react */
if (eaac.loop_start > 0 && !(
eaac.codec == EAAC_CODEC_EALAYER3_V1 ||
eaac.codec == EAAC_CODEC_EALAYER3_V2_PCM ||
@ -1115,9 +1055,74 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
}
}
/* if type is gigasample there seems to be a field with number of "gigasamples in ram",
* that goes after loop_start but before streamed/gigasamples' eaac.loop_offset) */
switch (eaac.type) {
case EAAC_TYPE_RAM:
break;
case EAAC_TYPE_STREAM:
if (eaac.loop_flag) {
header_size += 0x04;
eaac.loop_offset = read_32bitBE(header_offset + 0x0c, streamHead);
}
break;
case EAAC_TYPE_GIGASAMPLE: /* rarely seen [Def Jam Icon (X360)] */
if (eaac.loop_flag) {
VGM_LOG("EAAC: Looped gigasample found.\n");
goto fail;
}
header_size += 0x04;
eaac.prefetch_samples = read_32bitBE(header_offset + 0x08, streamHead);
break;
}
/* get data offsets */
if (eaac.version == EAAC_VERSION_V0) {
switch (eaac.type) {
case EAAC_TYPE_RAM:
eaac.stream_offset = header_offset + header_size;
break;
case EAAC_TYPE_STREAM:
eaac.stream_offset = start_offset;
break;
case EAAC_TYPE_GIGASAMPLE:
eaac.prefetch_offset = header_offset + header_size;
eaac.stream_offset = start_offset;
break;
}
} else {
eaac.stream_offset = header_offset - 0x04 + header_block_size;
}
/* correct loop offsets */
if (eaac.loop_flag) {
if (eaac.streamed) {
/* SNR+SNS are separate so offsets are relative to the data start
* (first .SNS block, or extra data before the .SNS block in case of .SNU)
* SPS have headers+data together so offsets are relative to the file start [ex. FIFA 18 (PC)] */
if (eaac.version == EAAC_VERSION_V1) {
eaac.loop_offset -= header_block_size;
}
} else if (eaac.loop_start > 0) {
/* RAM assets have two blocks in case of actual loops */
/* find the second block by getting the first block size */
eaac.loop_offset = read_32bitBE(eaac.stream_offset, streamHead) & 0x00FFFFFF;
} else {
/* RAM assets have only one block in case of full loops */
eaac.loop_offset = 0x00; /* implicit */
}
}
if (eaac.version == EAAC_VERSION_V0 && eaac.streamed) {
/* open SNS file if needed */
if (standalone) {
snsFile = open_streamfile_by_ext(streamHead, "sns");
streamData = snsFile;
}
if (!streamData) goto fail;
}
/* build streamfile with audio data */
streamFile = setup_eaac_streamfile(&eaac, streamHead, streamData);
if (!streamFile) goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(eaac.channels,eaac.loop_flag);
@ -1128,6 +1133,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
vgmstream->loop_start_sample = eaac.loop_start;
vgmstream->loop_end_sample = eaac.loop_end;
vgmstream->meta_type = meta_type;
vgmstream->stream_size = get_streamfile_size(streamFile);
/* EA decoder list and known internal FourCCs */
switch(eaac.codec) {
@ -1143,14 +1149,14 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
/* special (if hacky) loop handling, see comments */
if (eaac.loop_start > 0) {
segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamData, &eaac);
segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamFile, &eaac);
if (!data) goto fail;
vgmstream->layout_data = data;
vgmstream->coding_type = data->segments[0]->coding_type;
vgmstream->layout_type = layout_segmented;
}
else {
vgmstream->layout_data = build_layered_eaaudiocore(streamData, &eaac);
vgmstream->layout_data = build_layered_eaaudiocore(streamFile, &eaac, 0x00);
if (!vgmstream->layout_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_layered;
@ -1164,7 +1170,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
/* special (if hacky) loop handling, see comments */
if (eaac.loop_start > 0) {
segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamData, &eaac);
segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamFile, &eaac);
if (!data) goto fail;
vgmstream->layout_data = data;
vgmstream->coding_type = data->segments[0]->coding_type;
@ -1187,21 +1193,19 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
* and to properly apply discard modes (see ealayer3 decoder)
* (otherwise, and after removing discard code, it'd work with layout_blocked_ea_sns) */
start_offset = 0x00; /* must point to the custom streamfile's beginning */
/* special (if hacky) loop handling, see comments */
if (eaac.loop_start > 0) {
segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamData, &eaac);
segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamFile, &eaac);
if (!data) goto fail;
vgmstream->layout_data = data;
vgmstream->coding_type = data->segments[0]->coding_type;
vgmstream->layout_type = layout_segmented;
}
else {
temp_streamFile = setup_eaac_streamfile(streamData, eaac.version, eaac.codec, eaac.streamed,0,0, eaac.stream_offset);
temp_streamFile = setup_eaac_audio_streamfile(streamFile, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
if (!temp_streamFile) goto fail;
vgmstream->codec_data = init_mpeg_custom(temp_streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, type, &cfg);
vgmstream->codec_data = init_mpeg_custom(temp_streamFile, 0x00, &vgmstream->coding_type, vgmstream->channels, type, &cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
}
@ -1222,8 +1226,6 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
/* EATrax is "buffered" ATRAC9, uses custom IO since it's kind of complex to add to the decoder */
start_offset = 0x00; /* must point to the custom streamfile's beginning */
cfg.channels = eaac.channels;
cfg.config_data = read_32bitBE(header_offset + 0x08,streamHead);
/* 0x10: frame size? (same as config data?) */
@ -1235,7 +1237,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
vgmstream->coding_type = coding_ATRAC9;
vgmstream->layout_type = layout_none;
temp_streamFile = setup_eaac_streamfile(streamData, eaac.version, eaac.codec, eaac.streamed,0,0, eaac.stream_offset);
temp_streamFile = setup_eaac_audio_streamfile(streamFile, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
if (!temp_streamFile) goto fail;
break;
@ -1247,12 +1249,10 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
case EAAC_CODEC_EAMP3: { /* "EM30"?: EAMP3 [Need for Speed 2015 (PS4)] */
mpeg_custom_config cfg = {0};
start_offset = 0x00; /* must point to the custom streamfile's beginning */
temp_streamFile = setup_eaac_streamfile(streamData, eaac.version, eaac.codec, eaac.streamed,0,0, eaac.stream_offset);
temp_streamFile = setup_eaac_audio_streamfile(streamFile, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
if (!temp_streamFile) goto fail;
vgmstream->codec_data = init_mpeg_custom(temp_streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_EAMP3, &cfg);
vgmstream->codec_data = init_mpeg_custom(temp_streamFile, 0x00, &vgmstream->coding_type, vgmstream->channels, MPEG_EAMP3, &cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
@ -1263,7 +1263,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
#ifdef VGM_USE_FFMPEG
case EAAC_CODEC_EAOPUS: { /* EAOpus (unknown FourCC) [FIFA 17 (PC), FIFA 19 (Switch)]*/
vgmstream->layout_data = build_layered_eaaudiocore(streamData, &eaac);
vgmstream->layout_data = build_layered_eaaudiocore(streamFile, &eaac, 0x00);
if (!vgmstream->layout_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_layered;
@ -1277,73 +1277,162 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
goto fail;
}
if (!vgmstream_open_stream(vgmstream, temp_streamFile ? temp_streamFile : streamData, start_offset))
if (!vgmstream_open_stream(vgmstream, temp_streamFile ? temp_streamFile : streamFile, 0x00))
goto fail;
if (eaac.loop_start == 0) {
vgmstream->stream_size = calculate_eaac_size(vgmstream, temp_streamFile ? temp_streamFile : streamData, &eaac, start_offset);
}
close_streamfile(streamFile);
close_streamfile(snsFile);
close_streamfile(temp_streamFile);
return vgmstream;
fail:
close_streamfile(streamFile);
close_streamfile(snsFile);
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}
static size_t get_snr_size(STREAMFILE *streamFile, off_t offset) {
//const int EAAC_FLAG_LOOPED = 0x02;
//const int EAAC_FLAG_STREAMED = 0x04;
switch (read_8bit(offset + 0x04, streamFile) >> 4 & 0x0F) { /* flags */ //todo improve
case 0x02 | 0x04: return 0x10;
case 0x02: return 0x0C;
default: return 0x08;
}
}
static size_t calculate_eaac_size(VGMSTREAM *vgmstream, STREAMFILE *streamFile, eaac_header *eaac, off_t start_offset) {
uint32_t total_samples;
static size_t calculate_eaac_size(STREAMFILE *streamFile, eaac_header *ea, uint32_t num_samples, off_t start_offset) {
uint32_t samples_parsed, block_size, block_samples;
uint8_t block_id;
size_t stream_size, file_size;
off_t block_offset;
if (streamFile == NULL)
return 0;
switch (eaac->codec) {
case EAAC_CODEC_EAXMA:
case EAAC_CODEC_EALAYER3_V1:
case EAAC_CODEC_EALAYER3_V2_PCM:
case EAAC_CODEC_EALAYER3_V2_SPIKE:
case EAAC_CODEC_EATRAX:
case EAAC_CODEC_EAMP3:
case EAAC_CODEC_EAOPUS:
stream_size = get_streamfile_size(streamFile);
break;
default:
stream_size = 0;
total_samples = 0;
file_size = get_streamfile_size(streamFile);
vgmstream->next_block_offset = start_offset;
block_offset = start_offset;
stream_size = 0, samples_parsed = 0;
while (vgmstream->next_block_offset < file_size && total_samples != vgmstream->num_samples) {
block_update_ea_sns(vgmstream->next_block_offset, vgmstream);
if (vgmstream->current_block_samples == 0)
continue;
/* stream size is almost never provided in bank files so we have to calc it manually */
stream_size += vgmstream->next_block_offset - vgmstream->ch[0].offset;
total_samples += vgmstream->current_block_samples;
}
/* reset once we're done */
block_update(start_offset, vgmstream);
break;
}
while (block_offset < file_size && samples_parsed < num_samples) {
block_id = read_8bit(block_offset, streamFile);
block_size = read_32bitBE(block_offset, streamFile) & 0x00FFFFFF;
if (ea->version == EAAC_VERSION_V0) {
if (block_id != EAAC_BLOCKID0_DATA && block_id != EAAC_BLOCKID0_END)
goto fail;
} else {
if (block_id != EAAC_BLOCKID1_DATA) {
if (block_id == EAAC_BLOCKID1_END && ea->codec == EAAC_CODEC_EATRAX) {
/* number of samples in block header is wrong for EATrax so stop when we reach end marker */
return stream_size;
}
goto fail;
}
}
block_samples = read_32bitBE(block_offset + 0x04, streamFile);
stream_size += block_size;
samples_parsed += block_samples;
block_offset += block_size;
}
if (samples_parsed != num_samples)
goto fail;
return stream_size;
fail:
return 0;
}
static STREAMFILE *setup_eaac_streamfile(eaac_header *ea, STREAMFILE *streamHead, STREAMFILE *streamData) {
size_t data_size;
STREAMFILE *new_streamFile = NULL;
STREAMFILE *temp_streamFile = NULL;
STREAMFILE *stream_segments[2] = { 0 };
if (ea->version == EAAC_VERSION_V0) {
switch (ea->type) {
case EAAC_TYPE_RAM:
/* both header and data in SNR */
data_size = calculate_eaac_size(streamHead, ea, ea->num_samples, ea->stream_offset);
if (data_size == 0) goto fail;
new_streamFile = open_wrap_streamfile(streamHead);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_clamp_streamfile(temp_streamFile, ea->stream_offset, data_size);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
break;
case EAAC_TYPE_STREAM:
/* header in SNR, data in SNS */
data_size = calculate_eaac_size(streamData, ea, ea->num_samples, ea->stream_offset);
if (data_size == 0) goto fail;
new_streamFile = open_wrap_streamfile(streamData);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_clamp_streamfile(temp_streamFile, ea->stream_offset, data_size);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
break;
case EAAC_TYPE_GIGASAMPLE:
/* header and prefetched data in SNR, rest of data in SNS */
/* open prefetched data */
data_size = calculate_eaac_size(streamHead, ea, ea->prefetch_samples, ea->prefetch_offset);
if (data_size == 0) goto fail;
new_streamFile = open_wrap_streamfile(streamHead);
if (!new_streamFile) goto fail;
stream_segments[0] = new_streamFile;
new_streamFile = open_clamp_streamfile(stream_segments[0], ea->prefetch_offset, data_size);
if (!new_streamFile) goto fail;
stream_segments[0] = new_streamFile;
/* open main data */
data_size = calculate_eaac_size(streamData, ea, ea->num_samples - ea->prefetch_samples, ea->stream_offset);
if (data_size == 0) goto fail;
new_streamFile = open_wrap_streamfile(streamData);
if (!new_streamFile) goto fail;
stream_segments[1] = new_streamFile;
new_streamFile = open_clamp_streamfile(stream_segments[1], ea->stream_offset, data_size);
if (!new_streamFile) goto fail;
stream_segments[1] = new_streamFile;
new_streamFile = open_multifile_streamfile(stream_segments, 2);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
stream_segments[0] = NULL;
stream_segments[1] = NULL;
break;
}
} else {
if (ea->type == EAAC_TYPE_GIGASAMPLE) {
/* not seen so far, need samples */
VGM_LOG("EAAC: Found SPS gigasample\n");
goto fail;
}
data_size = calculate_eaac_size(streamHead, ea, ea->num_samples, ea->stream_offset);
if (data_size == 0) goto fail;
new_streamFile = open_wrap_streamfile(streamHead);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
new_streamFile = open_clamp_streamfile(temp_streamFile, ea->stream_offset, data_size);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
}
return temp_streamFile;
fail:
close_streamfile(stream_segments[0]);
close_streamfile(stream_segments[1]);
close_streamfile(temp_streamFile);
return NULL;
}
/* Actual looping uses 2 block sections, separated by a block end flag *and* padded.
*
@ -1353,7 +1442,7 @@ static size_t calculate_eaac_size(VGMSTREAM *vgmstream, STREAMFILE *streamFile,
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf_data, eaac_header *eaac) {
segmented_layout_data *data = NULL;
STREAMFILE* temp_sf = NULL;
off_t offsets[2] = { eaac->stream_offset, eaac->loop_offset };
off_t offsets[2] = { 0x00, eaac->loop_offset };
off_t start_offset;
int num_samples[2] = { eaac->loop_start, eaac->num_samples - eaac->loop_start};
int segment_count = 2; /* intro/loop */
@ -1377,12 +1466,11 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf
eaac_header temp_eaac = *eaac; /* equivalent to memcpy... I think */
temp_eaac.loop_flag = 0;
temp_eaac.num_samples = num_samples[i];
temp_eaac.stream_offset = offsets[i];
start_offset = 0x00; /* must point to the custom streamfile's beginning */
/* layers inside segments, how trippy */
data->segments[i]->layout_data = build_layered_eaaudiocore(sf_data, &temp_eaac);
data->segments[i]->layout_data = build_layered_eaaudiocore(sf_data, &temp_eaac, offsets[i]);
if (!data->segments[i]->layout_data) goto fail;
data->segments[i]->coding_type = coding_FFmpeg;
data->segments[i]->layout_type = layout_layered;
@ -1407,7 +1495,7 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf
start_offset = 0x00; /* must point to the custom streamfile's beginning */
temp_sf = setup_eaac_streamfile(sf_data, eaac->version,eaac->codec,eaac->streamed,0,0, offsets[i]);
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version,eaac->codec,eaac->streamed,0,0, offsets[i]);
if (!temp_sf) goto fail;
data->segments[i]->codec_data = init_mpeg_custom(temp_sf, 0x00, &data->segments[i]->coding_type, eaac->channels, type, &cfg);
@ -1425,9 +1513,6 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf
close_streamfile(temp_sf);
temp_sf = NULL;
//todo temp_streamFile doesn't contain EAXMA's streamfile
data->segments[i]->stream_size = calculate_eaac_size(data->segments[i], temp_sf, eaac, start_offset);
}
if (!setup_layout_segmented(data))
@ -1440,7 +1525,7 @@ fail:
return NULL;
}
static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_header *eaac) {
static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_header *eaac, off_t start_offset) {
layered_layout_data* data = NULL;
STREAMFILE* temp_sf = NULL;
int i, layers = (eaac->channels+1) / 2;
@ -1472,7 +1557,7 @@ static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_
int bytes, block_size, block_count;
size_t stream_size;
temp_sf = setup_eaac_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, eaac->stream_offset);
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, start_offset);
if (!temp_sf) goto fail;
stream_size = get_streamfile_size(temp_sf);
@ -1497,7 +1582,7 @@ static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_
size_t data_size;
/* We'll remove EA blocks and pass raw data to FFmpeg Opus decoder */
temp_sf = setup_eaac_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, eaac->stream_offset);
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, start_offset);
if (!temp_sf) goto fail;
skip = ea_opus_get_encoder_delay(0x00, temp_sf);
@ -1507,8 +1592,6 @@ static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_
if (!data->layers[i]->codec_data) goto fail;
data->layers[i]->coding_type = coding_FFmpeg;
data->layers[i]->layout_type = layout_none;
//TODO: 6ch channel layout seems L C R BL BR LFE, not sure about other EAAC
break;
}

View File

@ -245,7 +245,7 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
* - EATrax: ATRAC9 frames can be split between blooks
* - EAOpus: multiple Opus packets of frame size + Opus data per block
*/
static STREAMFILE* setup_eaac_streamfile(STREAMFILE *sf, int version, int codec, int streamed, int stream_number, int stream_count, off_t stream_offset) {
static STREAMFILE* setup_eaac_audio_streamfile(STREAMFILE *sf, int version, int codec, int streamed, int stream_number, int stream_count, off_t stream_offset) {
STREAMFILE *new_sf = NULL;
eaac_io_data io_data = {0};

View File

@ -690,7 +690,7 @@ static STREAMFILE* open_mapfile_pair(STREAMFILE *streamFile, int track, int num_
continue;
}
strncpy(buf, mus_name, PATH_LIMIT);
strncpy(buf, mus_name, PATH_LIMIT - 1);
pch = strtok(buf, ","); //TODO: not thread safe in std C
for (j = 0; j < track && pch; j++) {
pch = strtok(NULL, ",");
@ -699,9 +699,9 @@ static STREAMFILE* open_mapfile_pair(STREAMFILE *streamFile, int track, int num_
if (use_mask) {
file_name[file_len - map_len] = '\0';
strncat(file_name, pch + 1, PATH_LIMIT);
strncat(file_name, pch + 1, PATH_LIMIT - 1);
} else {
strncpy(file_name, pch, PATH_LIMIT);
strncpy(file_name, pch, PATH_LIMIT - 1);
}
musFile = open_streamfile_by_filename(streamFile, file_name);

View File

@ -5,16 +5,10 @@ VGMSTREAM * init_vgmstream_gin_header(STREAMFILE *streamFile, off_t offset);
/* .gin - EA engine sounds [Need for Speed: Most Wanted (multi)] */
VGMSTREAM * init_vgmstream_gin(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
if (!check_extensions(streamFile, "gin"))
goto fail;
vgmstream = init_vgmstream_gin_header(streamFile, 0x00);
if (!vgmstream)
goto fail;
return vgmstream;
return init_vgmstream_gin_header(streamFile, 0x00);
fail:
return NULL;

View File

@ -15,7 +15,7 @@ typedef struct {
* CRI's tools expect an unsigned 64 bit number string, but keys are commonly found online in hex form.
* Keys only use 56 bits though, so the upper 8 bits can be ignored.
*
* ACB+AWB after mid 2018 use a user seed key + a scramble subkey in the AWB (normally 16b LE at 0x0e)
* Some ACB+AWB after mid 2018 use a user seed key + a scramble subkey in the AWB (normally 16b LE at 0x0e)
* to create the final HCA key, which means there is one key per AWB (so most HCA have a unique key).
* vgmstream derives the key if subkey table is provided.
*/
@ -303,7 +303,19 @@ static const hcakey_info hcakey_list[] = {
/* BLACKSTAR -Theater Starless- (Android) */
{121837007188}, // 0000001C5E0D3154
/* Dragalia Lost (Cygames) [iOS/Android] */
/* Nogizaka46 Rhythm Festival (Android) */
{5613126134333697}, // 0013F11BC5510101
/* IDOLiSH7 (Android) */
{8548758374946935437}, // 76A34A72E15B928D
/* Phantom of the Kill (Android) */
{33624594140214547}, // 00777563E571B513
/* Dankira!!! Boys, be DANCING! (Android) */
{3957325206121219506}, // 36EB3E4EE38E05B2
/* Dragalia Lost (iOS/Android) */
{2967411924141, subkeys_dgl, sizeof(subkeys_dgl) / sizeof(subkeys_dgl[0]) }, // 000002B2E7889CAD
};

View File

@ -0,0 +1,50 @@
#include "meta.h"
/* IVAG - Namco header (from NUS3) [THE iDOLM@STER 2 (PS3), THE iDOLM@STER: Gravure For You! (PS3)] */
VGMSTREAM * init_vgmstream_ivag(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag = 0;
int channel_count;
/* checks */
/* .ivag: header id (since format can't be found outside NUS3) */
if (!check_extensions(streamFile, "ivag"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x49564147) /* "IVAG" */
goto fail;
/* 0x04: null */
channel_count = read_32bitBE(0x08, streamFile);
loop_flag = (read_32bitBE(0x18, streamFile) != 0);
/* skip VAGp headers per channel (size 0x40) */
start_offset = 0x40 + (0x40 * channel_count);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_IVAG;
vgmstream->sample_rate = read_32bitBE(0x0C,streamFile);
vgmstream->num_samples = read_32bitBE(0x10,streamFile);
vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile);
vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile);
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitBE(0x1C,streamFile);
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -28,7 +28,7 @@ VGMSTREAM * init_vgmstream_ngc_mdsp_std(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ngc_dsp_stm(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ngc_mpdsp(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_idsp_nus3(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_idsp_namco(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sadb(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sadf(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile);
@ -542,7 +542,7 @@ VGMSTREAM * init_vgmstream_mss(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_hsf(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps3_ivag(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ivag(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_2pfs(STREAMFILE* streamFile);
@ -746,6 +746,7 @@ VGMSTREAM * init_vgmstream_hd3_bd3(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_nus3bank(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_nus3bank_encrypted(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_scd_sscf(STREAMFILE *streamFile);

View File

@ -228,6 +228,12 @@ static int parse_musx_stream(STREAMFILE *streamFile, musx_header *musx) {
musx->codec = DAT;
break;
case 0x50435F5F: /* "PC__" */
default_channels = 2;
default_sample_rate = 44100;
musx->codec = DAT;
break;
default:
VGM_LOG("MUSX: unknown platform %x\n", musx->platform);
goto fail;
@ -294,18 +300,26 @@ static int parse_musx_stream(STREAMFILE *streamFile, musx_header *musx) {
musx->loop_flag = (musx->loop_start_sample >= 0);
}
/* fix some v10 sizes */
/* fix some v10 platform (like PSP) sizes */
if (musx->stream_size == 0) {
off_t offset;
musx->stream_size = musx->file_size - musx->stream_offset;
/* remove padding */
offset = musx->stream_offset + musx->stream_size - 0x04;
while (offset > 0) {
if (read_32bit(offset, streamFile) != 0xABABABAB)
/* always padded to nearest 0x800 sector */
if (musx->stream_size > 0x800) {
uint8_t buf[0x800];
int pos;
off_t offset = musx->stream_offset + musx->stream_size - 0x800;
if (read_streamfile(buf, offset, sizeof(buf), streamFile) != 0x800)
goto fail;
pos = 0x800 - 0x04;
while (pos > 0) {
if (get_u32be(buf + pos) != 0xABABABAB)
break;
musx->stream_size -= 0x04;
offset -= 0x04;
pos -= 0x04;
}
}
}
@ -334,9 +348,9 @@ static int parse_musx(STREAMFILE *streamFile, musx_header *musx) {
musx->is_old = 1;
break;
case 4: /* Spyro: A Hero's Tail (PS2/Xbox/GC) */
case 4: /* Spyro: A Hero's Tail (PS2/Xbox/GC), Athens 2004 (PC) */
case 5: /* Predator: Concrete Jungle (PS2/Xbox), Robots (GC) */
case 6: /* Batman Begins (GC), Ice Age 2 (PS2) */
case 6: /* Batman Begins (GC), Ice Age 2 (PS2/PC) */
musx->platform = read_32bitBE(0x10,streamFile);
/* 0x14: some id/hash? */
/* 0x18: platform number? */
@ -352,7 +366,10 @@ static int parse_musx(STREAMFILE *streamFile, musx_header *musx) {
/* 0x1c: null */
/* 0x20: hash */
musx->tables_offset = 0; /* no tables */
musx->big_endian = (musx->platform == 0x5749495F || musx->platform == 0x5053335F); /* "GC__" / "PS3_" (only after header) */
musx->big_endian = (musx->platform == 0x47435F5F || /* "GC__" */
musx->platform == 0x58455F5F || /* "XE__" */
musx->platform == 0x5053335F || /* "PS3_" */
musx->platform == 0x5749495F); /* "WII_" */
break;
default:
@ -438,6 +455,7 @@ static int parse_musx(STREAMFILE *streamFile, musx_header *musx) {
uint32_t miniheader = read_32bitBE(0x40, streamFile);
switch(miniheader) {
case 0x44415434: /* "DAT4" */
case 0x44415435: /* "DAT5" */
case 0x44415438: /* "DAT8" */
/* found on PS3/Wii (but not always?) */
musx->stream_size = read_32bitLE(0x44, streamFile);
@ -446,7 +464,14 @@ static int parse_musx(STREAMFILE *streamFile, musx_header *musx) {
musx->loops_offset = 0x50;
break;
default:
if (read_32bitBE(0x30, streamFile) == 0x00 &&
read_32bitBE(0x34, streamFile) == 0x00) {
/* no subheader [Spider-Man 4 (Wii)] */
musx->loops_offset = 0x00;
} else {
/* loop info only [G-Force (PS3)] */
musx->loops_offset = 0x30;
}
break;
}
}
@ -529,9 +554,6 @@ static int parse_musx(STREAMFILE *streamFile, musx_header *musx) {
musx->channels = 1;
}
VGM_LOG("to=%lx, %lx, %x\n", target_offset, musx->stream_offset, musx->stream_size);
if (coef_size == 0)
musx->coefs_offset = 0; /* disable for later detection */

View File

@ -597,8 +597,8 @@ fail:
return NULL;
}
/* IDSP - Namco header (from NUS3) + interleaved dsp [SSB4 (3DS), Tekken Tag Tournament 2 (WiiU)] */
VGMSTREAM * init_vgmstream_idsp_nus3(STREAMFILE *streamFile) {
/* IDSP - Namco header (from NUB/NUS3) + interleaved dsp [SSB4 (3DS), Tekken Tag Tournament 2 (WiiU)] */
VGMSTREAM * init_vgmstream_idsp_namco(STREAMFILE *streamFile) {
dsp_meta dspm = {0};
/* checks */
@ -606,21 +606,26 @@ VGMSTREAM * init_vgmstream_idsp_nus3(STREAMFILE *streamFile) {
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x49445350) /* "IDSP" */
goto fail;
/* 0x0c: sample rate, 0x10: num_samples, 0x14: loop_start_sample, 0x18: loop_start_sample */
dspm.channel_count = read_32bitBE(0x08, streamFile);
dspm.max_channels = 8;
/* games do adjust loop_end if bigger than num_samples (only happens in user-created IDSPs) */
dspm.fix_looping = 1;
/* 0x04: null */
dspm.channel_count = read_32bitBE(0x08, streamFile);
/* 0x0c: sample rate */
/* 0x10: num_samples */
/* 0x14: loop start */
/* 0x18: loop end */
dspm.interleave = read_32bitBE(0x1c,streamFile); /* usually 0x10 */
dspm.header_offset = read_32bitBE(0x20,streamFile);
dspm.header_spacing = read_32bitBE(0x24,streamFile);
dspm.start_offset = read_32bitBE(0x28,streamFile);
dspm.interleave = read_32bitBE(0x1c,streamFile); /* usually 0x10 */
if (dspm.interleave == 0) /* Taiko no Tatsujin: Atsumete Tomodachi Daisakusen (WiiU) */
dspm.interleave = read_32bitBE(0x2c,streamFile); /* half interleave, use channel size */
/* Soul Calibur: Broken destiny (PSP), Taiko no Tatsujin: Atsumete Tomodachi Daisakusen (WiiU) */
if (dspm.interleave == 0) /* half interleave (happens sometimes), use channel size */
dspm.interleave = read_32bitBE(0x2c,streamFile);
dspm.meta_type = meta_IDSP_NUS3;
dspm.meta_type = meta_IDSP_NAMCO;
return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
return NULL;

View File

@ -2,14 +2,14 @@
#include "../coding/coding.h"
static void load_name(char *name, size_t name_size, STREAMFILE *sf, int big_endian, int total_subsongs, int target_subsong);
static STREAMFILE* setup_nub_streamfile(STREAMFILE *sf, off_t header_offset, size_t header_size, off_t stream_offset, size_t stream_size, const char *fake_ext);
/* .nub - Namco's nu Sound v2 audio container */
/* .nub - Namco's nuSound2 audio container */
VGMSTREAM * init_vgmstream_nub(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_sf = NULL;
off_t name_offset = 0;
size_t name_size = 0;
int big_endian;
int total_subsongs, target_subsong = streamFile->stream_index;
uint32_t version, codec;
const char* fake_ext;
@ -25,13 +25,14 @@ VGMSTREAM * init_vgmstream_nub(STREAMFILE *streamFile) {
version = read_32bitBE(0x00,streamFile);
if (version != 0x00020000 && /* v2.0 (rare, ex. Ridge Race 6 (X360)) */
version != 0x00020100 && /* v2.1 (common) */
version != 0x01020100) /* same but LE? (seen in PSP games, not PS4) */
version != 0x01020100) /* same but LE (seen in PSP/PC games, except PS4) */
goto fail;
if (read_32bitBE(0x04,streamFile) != 0x00000000) /* null */
goto fail;
/* sometimes LE [Soul Calibur: Broken Destiny (PSP), Tales of Vesperia (PS4) */
if (guess_endianness32bit(0x10, streamFile)) {
big_endian = guess_endianness32bit(0x10, streamFile);
if (big_endian) {
read_32bit = read_32bitBE;
} else{
read_32bit = read_32bitLE;
@ -44,8 +45,8 @@ VGMSTREAM * init_vgmstream_nub(STREAMFILE *streamFile) {
size_t header_size, subheader_size, stream_size;
/* - base header */
/* 0x08: file id/number (can be 0 = first) */
total_subsongs = read_32bit(0x0c, streamFile); /* .nub with 0 files do exist */
/* 0x08: file id (0 = first) */
total_subsongs = read_32bit(0x0c, streamFile); /* .nub with 0 files do exist, and with 1 song only too */
data_start = read_32bit(0x10, streamFile); /* exists even with 0 files */
/* 0x14: data end (may have padding) */
header_start = read_32bit(0x18, streamFile);
@ -63,16 +64,17 @@ VGMSTREAM * init_vgmstream_nub(STREAMFILE *streamFile) {
/* .nus have all headers first then all data, but extractors often just paste them together,
* so we'll combine header+data on the fly to make them playable with existing parsers.
* Formats inside .nub don't exist as external files, so they could be extracted in various
* ways that we'll try to match (though BNSF can be found as header+data in some bigfiles too). */
* Formats inside .nub normally don't exist as external files, so they could be extracted in various
* ways that we'll try to match (though IDSP/BNSF can be found as header+data in some bigfiles).
* Headers seem to be called "tones" and data "streams" in debug strings. */
header_offset = offset;
/* - extension (as referenced in companion files with internal filenames, ex. "BGM_MovingDemo1.is14" > "is14") */
if (version != 0x00020000)
offset += 0x04; /* skip but not in v2.0 */
offset += 0x04; /* skip, not found in v2.0 */
/* - file header */
/* - tone header */
/* 0x00: config? */
/* 0x04: header id/number */
codec = (uint32_t)read_32bit(offset + 0x08, streamFile);
@ -80,7 +82,8 @@ VGMSTREAM * init_vgmstream_nub(STREAMFILE *streamFile) {
stream_size = read_32bit(offset + 0x10, streamFile); /* 0x10 aligned */
stream_offset = read_32bit(offset + 0x14, streamFile) + data_start;
subheader_size = read_32bit(offset + 0x18, streamFile);
/* rest looks like config/volumes/etc */
/* 0x1c: extra info, size 0x10 (meaning varies but usually loop points) */
/* rest until sub-header start looks like config/volumes/pan/etc in various floats */
if (version == 0x00020000)
subheader_start = 0xAC;
@ -137,33 +140,10 @@ VGMSTREAM * init_vgmstream_nub(STREAMFILE *streamFile) {
if (!temp_sf) goto fail;
}
/* get names */
{
/* file names are in a companion file, rarely [Noby Noby Boy (PS3)] */
STREAMFILE *nameFile = NULL;
char filename[PATH_LIMIT];
char basename[255];
get_streamfile_basename(streamFile, basename, sizeof(basename));
snprintf(filename,sizeof(filename), "nuSound2ToneStr%s.bin", basename);
/* get names from companion file, rarely [Noby Noby Boy (PS3), Wangan Midnight Maximum Tune (AC)] */
load_name(name, sizeof(name), streamFile, big_endian, total_subsongs, target_subsong);
nameFile = open_streamfile_by_filename(streamFile, filename);
if (nameFile && read_32bit(0x08, nameFile) == total_subsongs) {
off_t header_start = 0x40; /* first name is bank name */
char name1[0x20+1] = {0};
char name2[0x20+1] = {0};
name_size = 0x20;
name_offset = header_start + (target_subsong-1)*(name_size*2);
read_string(name1,name_size, name_offset + 0x00, nameFile); /* internal name */
read_string(name2,name_size, name_offset + 0x20, nameFile); /* file name */
//todo some filenames use shift-jis, not sure what to do
snprintf(name,sizeof(name), "%s/%s", name1,name2);
}
close_streamfile(nameFile);
}
/* init the VGMSTREAM */
vgmstream = init_vgmstream_function(temp_sf);
@ -185,6 +165,50 @@ fail:
/* *********************************************************** */
static void load_name(char *name, size_t name_size, STREAMFILE *sf, int big_endian, int total_subsongs, int target_subsong) {
STREAMFILE *sf_names = NULL;
char filename[PATH_LIMIT];
char basename[255];
char name1[0x40+1] = {0};
char name2[0x40+1] = {0};
int count;
off_t offset;
size_t name1_size, name2_size;
uint32_t (*read_u32)(off_t,STREAMFILE*) = big_endian ? read_u32be : read_u32le;
get_streamfile_basename(sf, basename, sizeof(basename));
snprintf(filename, sizeof(filename), "nuSound2ToneStr%s.bin", basename);
sf_names = open_streamfile_by_filename(sf, filename);
if (!sf_names) goto done;
/* 0x00: version/endianness? (0=NNB, 1=WMMT5) */
/* 0x04: version/endianness? (1=NNB, 0=WMMT5) */
count = read_u32(0x08, sf_names);
/* 0x0c: file size */
name1_size = read_u32(0x10, sf_names);
name2_size = read_u32(0x14, sf_names);
/* 0x18/1c: null */
/* 0x20: bank name (size 0x20) */
if (count != total_subsongs)
goto done;
if (name1_size >= sizeof(name1) || name2_size >= sizeof(name2))
goto done;
offset = 0x40 + (target_subsong - 1) * (name1_size + name2_size);
read_string(name1, name1_size, offset + 0x00, sf_names); /* internal name */
read_string(name2, name2_size, offset + name1_size, sf_names); /* file name */
//todo some filenames use shift-jis, not sure what to do
snprintf(name, name_size, "%s/%s", name1, name2);
done:
close_streamfile(sf_names);
}
static STREAMFILE* setup_nub_streamfile(STREAMFILE *sf, off_t header_offset, size_t header_size, off_t stream_offset, size_t stream_size, const char *fake_ext) {
STREAMFILE *new_sf = NULL;
STREAMFILE *multi_sf[2] = {0};
@ -206,7 +230,10 @@ static STREAMFILE* setup_nub_streamfile(STREAMFILE *sf, off_t header_offset, siz
VGMSTREAM * init_vgmstream_nub_wav(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
int loop_flag, channel_count, sample_rate;
size_t data_size, loop_start, loop_length;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
/* checks */
@ -215,24 +242,43 @@ VGMSTREAM * init_vgmstream_nub_wav(STREAMFILE *streamFile) {
if (read_32bitBE(0x00,streamFile) != 0x77617600) /* "wav\0" "*/
goto fail;
if (read_16bitBE(0xBC+0x00,streamFile) != 0x0001) /* mini "fmt" chunk */
goto fail;
if (guess_endianness32bit(0x1c, streamFile)) {
read_32bit = read_32bitBE;
read_16bit = read_16bitBE;
} else {
read_32bit = read_32bitLE;
read_16bit = read_16bitLE;
}
data_size = read_32bit(0x14,streamFile);
/* info header */
loop_start = read_32bit(0x20,streamFile);
loop_length = read_32bit(0x24,streamFile);
loop_flag = read_32bit(0x28,streamFile);
/* 0x2c: null */
/* format header: mini "fmt" chunk */
if (read_16bit(0xBC + 0x00, streamFile) != 0x0001)
goto fail;
channel_count = read_16bit(0xBC + 0x02,streamFile);
sample_rate = read_32bit(0xBC + 0x04,streamFile);
/* 0x08: bitrate */
/* 0x0c: block align/bps */
loop_flag = read_32bitBE(0x24,streamFile);
channel_count = read_16bitBE(0xBC+0x02,streamFile);
start_offset = 0xD0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_NUB;
vgmstream->sample_rate = read_32bitBE(0xBC+0x04,streamFile);
vgmstream->num_samples = pcm_bytes_to_samples(read_32bitBE(0x14,streamFile), channel_count, 16);
vgmstream->loop_start_sample = pcm_bytes_to_samples(read_32bitBE(0x20,streamFile), channel_count, 16);
vgmstream->loop_end_sample = pcm_bytes_to_samples(read_32bitBE(0x24,streamFile), channel_count, 16);
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, 16);
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, channel_count, 16);
vgmstream->loop_end_sample = pcm_bytes_to_samples(loop_start + loop_length, channel_count, 16);
vgmstream->coding_type = coding_PCM16BE;
vgmstream->coding_type = coding_PCM16BE; /* always BE */
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
@ -249,7 +295,9 @@ fail:
VGMSTREAM * init_vgmstream_nub_vag(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
int loop_flag, channel_count, sample_rate;
size_t data_size, loop_start, loop_length;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
/* checks */
@ -258,19 +306,35 @@ VGMSTREAM * init_vgmstream_nub_vag(STREAMFILE *streamFile) {
if (read_32bitBE(0x00,streamFile) != 0x76616700) /* "vag\0" */
goto fail;
loop_flag = read_32bitBE(0x24,streamFile);
channel_count = 1; /* dual file stereo */
if (guess_endianness32bit(0x1c, streamFile)) {
read_32bit = read_32bitBE;
} else {
read_32bit = read_32bitLE;
}
data_size = read_32bit(0x14,streamFile);
/* info header */
loop_start = read_32bit(0x20,streamFile);
loop_length = read_32bit(0x24,streamFile);
loop_flag = read_32bit(0x28,streamFile);
/* 0x2c: null */
/* format header */
sample_rate = read_32bit(0xBC + 0x00,streamFile);
channel_count = 1;
start_offset = 0xC0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_NUB;
vgmstream->sample_rate = read_32bitBE(0xBC,streamFile);
vgmstream->num_samples = ps_bytes_to_samples(read_32bitBE(0x14,streamFile), channel_count);
vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitBE(0x20,streamFile), channel_count);
vgmstream->loop_end_sample = ps_bytes_to_samples(read_32bitBE(0x24,streamFile), channel_count);
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channel_count);
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_start + loop_length, channel_count);
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_none;
@ -299,7 +363,15 @@ VGMSTREAM * init_vgmstream_nub_at3(STREAMFILE *streamFile) {
if (read_32bitBE(0x00,streamFile) != 0x61743300) /* "at3\0" */
goto fail;
/* mini fmt+fact header, we can use RIFF anyway */
/* info header */
/* 0x20: loop start (in samples) */
/* 0x24: loop length (in samples) */
/* 0x28: loop flag */
/* 0x2c: null */
/* format header: mini fmt (WAVEFORMATEX) + fact chunks LE (clone of RIFF's) */
/* we can just ignore and use RIFF at data start since it has the same info */
subfile_offset = 0x100;
subfile_size = read_32bitLE(subfile_offset + 0x04, streamFile) + 0x08; /* RIFF size */
@ -337,7 +409,12 @@ VGMSTREAM * init_vgmstream_nub_xma(STREAMFILE *streamFile) {
data_size = read_32bitBE(0x14,streamFile);
header_size = read_32bitBE(0x1c,streamFile);
chunk_offset = 0xBC;
/* info header */
/* 0x20: null */
chunk_size = read_32bitBE(0x24,streamFile);
/* 0x24: loop flag */
/* 0x20: null */
}
else if (read_32bitBE(0x08,streamFile) == 0 && read_32bitBE(0x0c,streamFile) == 0) {
/* nub v2.0 from Ridge Racer 6 */
@ -345,6 +422,7 @@ VGMSTREAM * init_vgmstream_nub_xma(STREAMFILE *streamFile) {
data_size = read_32bitBE(0x10,streamFile);
header_size = read_32bitBE(0x18,streamFile);
chunk_offset = 0xAC;
chunk_size = header_size;
}
else {
@ -435,51 +513,44 @@ fail:
/* .nub idsp - from Namco NUB archives [Soul Calibur Legends (Wii), Sky Crawlers: Innocent Aces (Wii)] */
VGMSTREAM * init_vgmstream_nub_idsp(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
STREAMFILE *temp_sf = NULL;
off_t header_offset, stream_offset;
size_t header_size, stream_size;
/* checks */
if (!check_extensions(streamFile,"idsp"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x69647370) /* "idsp" */
goto fail;
if (read_32bitBE(0xBC,streamFile) != 0x49445350) /* "IDSP" (actual header) */
goto fail;
loop_flag = read_32bitBE(0x20,streamFile);
channel_count = read_32bitBE(0xC4,streamFile);
if (channel_count > 8) goto fail;
start_offset = 0x100 + (channel_count * 0x60);
/* info header */
/* 0x20: loop start (in samples) */
/* 0x24: loop length (in samples) */
/* 0x28: loop flag */
/* 0x2c: null */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
/* paste header+data together and pass to meta, which has loop info too */
header_offset = 0xBC;
stream_size = read_32bitBE(0x14, streamFile);
header_size = read_32bitBE(0x1c, streamFile);
stream_offset = align_size_to_block(header_offset + header_size, 0x10);
temp_sf = setup_nub_streamfile(streamFile, header_offset, header_size, stream_offset, stream_size, "idsp");
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_idsp_namco(temp_sf);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_NUB;
vgmstream->sample_rate = read_32bitBE(0xC8,streamFile);
vgmstream->num_samples = dsp_bytes_to_samples(read_32bitBE(0x14,streamFile),channel_count);
vgmstream->loop_start_sample = read_32bitBE(0xD0,streamFile);
vgmstream->loop_end_sample = read_32bitBE(0xD4,streamFile);
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitBE(0xD8,streamFile);
if (vgmstream->interleave_block_size == 0)
vgmstream->interleave_block_size = read_32bitBE(0x14,streamFile) / channel_count;
dsp_read_coefs_be(vgmstream,streamFile,0x118,0x60);
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
goto fail;
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}
/* .nub is14 - from Namco NUB archives [Tales of Vesperia (PS3)] */
/* .nub is14 - from Namco NUB archives [Tales of Vesperia (PS3), Mojipittan (Wii)] */
VGMSTREAM * init_vgmstream_nub_is14(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_sf = NULL;
@ -500,6 +571,7 @@ VGMSTREAM * init_vgmstream_nub_is14(STREAMFILE *streamFile) {
read_32bit = read_32bitLE;
}
/* info header: null (even when BSNF loops) */
/* paste header+data together and pass to meta */
header_offset = 0xBC;

View File

@ -92,7 +92,7 @@ VGMSTREAM * init_vgmstream_nus3audio(STREAMFILE *streamFile) {
/* init the VGMSTREAM */
switch(codec) {
case IDSP:
vgmstream = init_vgmstream_idsp_nus3(temp_streamFile);
vgmstream = init_vgmstream_idsp_namco(temp_streamFile);
if (!vgmstream) goto fail;
break;
case OPUS:

View File

@ -1,12 +1,14 @@
#include "meta.h"
#include "../coding/coding.h"
typedef enum { /*XMA_RAW, ATRAC3,*/ IDSP, ATRAC9, OPUS, BNSF, /*PCM, XMA_RIFF*/ } nus3bank_codec;
#include "nus3bank_streamfile.h"
typedef enum { IDSP, IVAG, BNSF, RIFF, OPUS, RIFF_ENC, } nus3bank_codec;
/* .nus3bank - Namco's newest audio container [Super Smash Bros (Wii U), idolmaster (PS4))] */
VGMSTREAM * init_vgmstream_nus3bank(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
STREAMFILE *temp_sf = NULL;
off_t tone_offset = 0, pack_offset = 0, name_offset = 0, subfile_offset = 0;
size_t name_size = 0, subfile_size = 0;
nus3bank_codec codec;
@ -14,7 +16,9 @@ VGMSTREAM * init_vgmstream_nus3bank(STREAMFILE *streamFile) {
int total_subsongs, target_subsong = streamFile->stream_index;
/* checks */
if (!check_extensions(streamFile, "nus3bank"))
/* .nub2: early [THE iDOLM@STER 2 (PS3/X360)]
* .nus3bank: standard */
if (!check_extensions(streamFile, "nub2,nus3bank"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4E555333) /* "NUS3" */
goto fail;
@ -23,6 +27,8 @@ VGMSTREAM * init_vgmstream_nus3bank(STREAMFILE *streamFile) {
if (read_32bitBE(0x0c,streamFile) != 0x544F4320) /* "TOC\0" */
goto fail;
/* header is always LE, while contained files may use another endianness */
/* parse TOC with all existing chunks and sizes (offsets must be derived) */
{
int i;
@ -43,8 +49,8 @@ VGMSTREAM * init_vgmstream_nus3bank(STREAMFILE *streamFile) {
case 0x50524F50: /* "PROP": project info */
case 0x42494E46: /* "BINF": bank info (filename) */
case 0x47525020: /* "GRP ": ? */
case 0x44544F4E: /* "DTON": ? */
case 0x47525020: /* "GRP ": cues/events with names? */
case 0x44544F4E: /* "DTON": related to GRP? */
case 0x4D41524B: /* "MARK": ? */
case 0x4A554E4B: /* "JUNK": padding */
default:
@ -72,69 +78,108 @@ VGMSTREAM * init_vgmstream_nus3bank(STREAMFILE *streamFile) {
if (target_subsong == 0) target_subsong = 1;
for (i = 0; i < entries; i++) {
off_t header_offset, header_suboffset, stream_name_offset, stream_offset;
size_t stream_name_size, stream_size;
off_t tone_header_offset = read_32bitLE(tone_offset+0x04+(i*0x08)+0x00, streamFile);
size_t tone_header_size = read_32bitLE(tone_offset+0x04+(i*0x08)+0x04, streamFile);
off_t offset, tone_header_offset, stream_name_offset, stream_offset;
size_t tone_header_size, stream_name_size, stream_size;
uint8_t flags2;
tone_header_offset = read_32bitLE(tone_offset+0x04+(i*0x08)+0x00, streamFile);
tone_header_size = read_32bitLE(tone_offset+0x04+(i*0x08)+0x04, streamFile);
offset = tone_offset + tone_header_offset;
//;VGM_LOG("NUS3BANK: tone at %lx, size %x\n", tone_offset + tone_header_offset, tone_header_size);
if (tone_header_size <= 0x0c) {
//VGM_LOG("NUS3BANK: bad tone at %lx, size %x\n", tone_offset + tone_header_offset, tone_header_size);
continue; /* ignore non-sounds */
}
header_offset = tone_offset + tone_header_offset;
/* 0x00: type? normally 0x00 and rarely 0x09 */
/* 0x04: usually -1, found when tone is not a stream (most flags are off too) */
/* 0x06: flags1 */
flags2 = read_8bit(offset + 0x07, streamFile);
offset += 0x08;
stream_name_size = read_8bit(header_offset+0x0c, streamFile); /* includes null */
stream_name_offset = header_offset+0x0d;
header_suboffset = 0x0c + 0x01 + stream_name_size;
if (header_suboffset % 0x04) /* padded */
header_suboffset += (0x04 - (header_suboffset % 0x04));
if (read_32bitLE(header_offset+header_suboffset+0x04, streamFile) != 0x08) {
continue; /* ignore non-sounds, too */
/* flags3-6 (early .nub2 and some odd non-stream don't have them) */
if (flags2 & 0x80) {
offset += 0x04;
}
stream_offset = read_32bitLE(header_offset+header_suboffset+0x08, streamFile) + pack_offset;
stream_size = read_32bitLE(header_offset+header_suboffset+0x0c, streamFile);
stream_name_size = read_8bit(offset + 0x00, streamFile); /* includes null */
stream_name_offset = offset + 0x01;
offset += align_size_to_block(0x01 + stream_name_size, 0x04); /* padded if needed */
/* 0x00: subtype? should be 0 */
if (read_32bitLE(offset + 0x04, streamFile) != 0x08) { /* flag? */
//;VGM_LOG("NUS3BANK: bad tone type at %lx, size %x\n", tone_offset + tone_header_offset, tone_header_size);
continue;
}
stream_offset = read_32bitLE(offset + 0x08, streamFile) + pack_offset;
stream_size = read_32bitLE(offset + 0x0c, streamFile);
//;VGM_LOG("NUS3BANK: so=%lx, ss=%x\n", stream_offset, stream_size);
/* Beyond are a bunch of sub-chunks of unknown size with floats and stuff, that seemingly
* appear depending on flags1-6. One is a small stream header, which contains basic
* sample rate/channels/loops/etc, but it's actually optional and maybe controlled by
* flags 3-6 (ex. not found in .nub2) */
/* happens in some sfx packs (ex. Taiko no Tatsujin Switch's se_minigame) */
if (stream_size == 0) {
continue; /* happens in some sfx packs */
//;VGM_LOG("NUS3BANK: bad tone stream size at %lx, size %x\n", tone_offset + tone_header_offset, tone_header_size);
continue;
}
total_subsongs++;
if (total_subsongs == target_subsong) {
//;VGM_LOG("NUS3BANK: subsong header offset %lx\n", header_offset);
//;VGM_LOG("NUS3BANK: subsong header offset %lx\n", offset);
subfile_offset = stream_offset;
subfile_size = stream_size;
name_size = stream_name_size;
name_offset = stream_name_offset;
//todo improve, codec may be related to header values at 0x00/0x06/0x08
codec_id = read_32bitBE(subfile_offset, streamFile);
}
/* continue counting subsongs */
}
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
if (subfile_offset == 0 || codec_id == 0) {
if (subfile_offset == 0) {
VGM_LOG("NUS3BANK: subsong not found\n");
goto fail;
}
//todo improve, codec may be in one of the tone sub-chunks (or other chunk? one bank seems to use one codec)
codec_id = read_32bitBE(subfile_offset, streamFile);
switch(codec_id) {
case 0x49445350: /* "IDSP" [Super Smash Bros. for 3DS (3DS)] */
codec = IDSP;
fake_ext = "idsp";
break;
case 0x52494646: /* "RIFF" [idolm@ster: Platinum Stars (PS4)] */
//todo this can be standard PCM RIFF too, ex. Mario Kart Arcade GP DX (PC) (works but should have better detection)
codec = ATRAC9;
fake_ext = "at9";
case 0x52494646: /* "RIFF" [THE iDOLM@STER 2 (PS3), Mario Kart Arcade GP DX (PC), idolm@ster: Platinum Stars (PS4)] */
codec = RIFF;
fake_ext = "wav"; //TODO: works but should have better detection
break;
case 0x4F505553: /* "OPUS" [Taiko no Tatsujin (Switch)] */
codec = OPUS;
fake_ext = "opus";
break;
case 0x424E5346: /* "BNSF" [Naruto Shippuden Ultimate Ninja Storm 4 (PC)] */
codec = BNSF;
fake_ext = "bnsf";
break;
case 0x49564147: /* "IVAG" [THE iDOLM@STER 2 (PS3), THE iDOLM@STER: Gravure For You! (PS3)] */
codec = IVAG;
fake_ext = "ivag";
break;
case 0x552AAF17: /* "RIFF" with encrypted header (not data) [THE iDOLM@STER 2 (X360)] */
codec = RIFF_ENC;
fake_ext = "xma";
break;
default:
VGM_LOG("NUS3BANK: unknown codec %x\n", codec_id);
goto fail;
@ -143,27 +188,41 @@ VGMSTREAM * init_vgmstream_nus3bank(STREAMFILE *streamFile) {
//;VGM_LOG("NUS3BANK: subfile=%lx, size=%x\n", subfile_offset, subfile_size);
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, fake_ext);
if (!temp_streamFile) goto fail;
temp_sf = setup_subfile_streamfile(streamFile, subfile_offset, subfile_size, fake_ext);
if (!temp_sf) goto fail;
/* init the VGMSTREAM */
switch(codec) {
case IDSP:
vgmstream = init_vgmstream_idsp_nus3(temp_streamFile);
vgmstream = init_vgmstream_idsp_namco(temp_sf);
if (!vgmstream) goto fail;
break;
case OPUS:
vgmstream = init_vgmstream_opus_nus3(temp_streamFile);
vgmstream = init_vgmstream_opus_nus3(temp_sf);
if (!vgmstream) goto fail;
break;
case ATRAC9:
vgmstream = init_vgmstream_riff(temp_streamFile);
case RIFF:
vgmstream = init_vgmstream_riff(temp_sf);
if (!vgmstream) goto fail;
break;
case BNSF:
vgmstream = init_vgmstream_bnsf(temp_streamFile);
vgmstream = init_vgmstream_bnsf(temp_sf);
if (!vgmstream) goto fail;
break;
case IVAG:
vgmstream = init_vgmstream_ivag(temp_sf);
if (!vgmstream) goto fail;
break;
case RIFF_ENC:
vgmstream = init_vgmstream_nus3bank_encrypted(temp_sf);
if (!vgmstream) goto fail;
break;
default:
goto fail;
}
@ -173,11 +232,38 @@ VGMSTREAM * init_vgmstream_nus3bank(STREAMFILE *streamFile) {
read_string(vgmstream->stream_name,name_size, name_offset,streamFile);
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}
/* encrypted RIFF from the above, in case kids try to extract and play single files */
VGMSTREAM* init_vgmstream_nus3bank_encrypted(STREAMFILE *sf) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_sf = NULL;
/* checks */
if (!check_extensions(sf, "nus3bank,xma"))
goto fail;
if (read_u32be(0x00, sf) != 0x552AAF17) /* "RIFF" encrypted */
goto fail;
temp_sf = setup_nus3bank_streamfile(sf, 0x00);
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_xma(temp_sf);
if (!vgmstream) goto fail;
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -0,0 +1,126 @@
#ifndef _NUS3BANK_STREAMFILE_H_
#define _NUS3BANK_STREAMFILE_H_
#include "../streamfile.h"
static uint32_t swap_endian32(uint32_t v) {
return ((v & 0xff000000) >> 24u) |
((v & 0x00ff0000) >> 8u) |
((v & 0x0000ff00) << 8u) |
((v & 0x000000ff) << 24u);
}
#define KEY_MAX_SIZE 0x1000
typedef struct {
uint8_t key[KEY_MAX_SIZE];
int key_len;
} io_data_t;
static size_t io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_t length, io_data_t *data) {
int i;
size_t bytes = read_streamfile(dest, offset, length, sf);
/* decrypt data (xor) */
if (offset < data->key_len) {
for (i = 0; i < bytes; i++) {
if (offset + i < data->key_len)
dest[i] ^= data->key[offset + i];
}
}
return bytes;
}
/* decrypts RIFF streams in NUS3BANK */
static STREAMFILE* setup_nus3bank_streamfile(STREAMFILE *sf, off_t start) {
STREAMFILE *new_sf = NULL;
io_data_t io_data = {0};
/* setup key */
{
uint32_t base_key, chunk_key;
uint8_t buf[KEY_MAX_SIZE];
uint32_t chunk_type, chunk_size;
int pos, data_pos, bytes;
/* Header is XORed with a base key and a derived chunk type/size key, while chunk data is XORed with
* unencrypted data itself, so we need to find where "data" starts then do another pass to properly set key.
* Original code handles RIFF's "data" and also BNSF's "sdat" too, encrypted BNSF aren't known though. */
bytes = read_streamfile(buf, start, sizeof(buf), sf);
if (bytes < 0x800) goto fail; /* files of 1 XMA block do exist, but not less */
base_key = 0x0763E951;
chunk_type = get_u32be(buf + 0x00) ^ base_key;
chunk_size = get_u32be(buf + 0x04) ^ base_key;
if (chunk_type != 0x52494646) /* "RIFF" */
goto fail;
chunk_key = base_key ^ (((chunk_size >> 16u) & 0x0000FFFF) | ((chunk_size << 16u) & 0xFFFF0000)); /* ROTr 16 size */
/* find "data" */
pos = 0x0c;
while(pos < sizeof(buf)) {
chunk_type = get_u32be(buf + pos + 0x00) ^ chunk_key;
chunk_size = get_u32be(buf + pos + 0x04) ^ chunk_key;
chunk_size = swap_endian32(chunk_size);
pos += 0x08;
if (chunk_type == 0x64617461) { /* "data" */
data_pos = pos;
break;
}
if (pos + chunk_size > sizeof(buf) - 0x08) {
VGM_LOG("NUS3 SF: header too big\n");
goto fail; /* max around 0x400 */
}
pos += chunk_size;
}
/* setup key */
put_u32be(io_data.key + 0x00, base_key);
put_u32be(io_data.key + 0x04, base_key);
put_u32be(io_data.key + 0x08, chunk_key);
pos = 0x0c; /* after WAVE */
while (pos < data_pos) {
chunk_type = get_u32be(buf + pos + 0x00) ^ chunk_key;
chunk_size = get_u32be(buf + pos + 0x04) ^ chunk_key;
chunk_size = swap_endian32(chunk_size);
put_u32be(io_data.key + pos + 0x00, chunk_key);
put_u32be(io_data.key + pos + 0x04, chunk_key);
pos += 0x08;
if (pos >= data_pos)
break;
/* buf must contain data of at least chunk_size */
if (data_pos + chunk_size >= sizeof(buf)) {
VGM_LOG("NUS3 SF: chunk too big\n");
goto fail;
}
memcpy(io_data.key + pos, buf + data_pos, chunk_size);
pos += chunk_size;
}
io_data.key_len = data_pos;
}
new_sf = open_wrap_streamfile(sf);
new_sf = open_io_streamfile(new_sf, &io_data, sizeof(io_data_t), io_read, NULL);
return new_sf;
fail:
close_streamfile(sf);
return NULL;
}
#endif /* _NUS3BANK_STREAMFILE_H_ */

View File

@ -1,84 +0,0 @@
#include "meta.h"
#include "../util.h"
/* IVAG
- The Idolm@ster: Gravure For You! Vol. 3 (PS3)
Appears to be two VAGp streams interleaved.
*/
VGMSTREAM * init_vgmstream_ps3_ivag(STREAMFILE *streamFile)
{
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag = 0;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("ivag",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x49564147) // "IVAG"
goto fail;
// channel count
channel_count = read_32bitBE(0x08, streamFile);
// header size
start_offset = 0x40 + (0x40 * channel_count);
// loop flag
if ((read_32bitBE(0x14, streamFile) != 0 ||
(read_32bitBE(0x18, streamFile) != 0)))
{
loop_flag = 1;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x0C,streamFile);
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = read_32bitBE(0x10,streamFile);
if (loop_flag)
{
vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile);
vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile);
}
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitBE(0x1C,streamFile);
vgmstream->meta_type = meta_PS3_IVAG;
/* 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;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset + (vgmstream->interleave_block_size * i);
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -465,20 +465,23 @@ static void parse_sead_mab_name(sead_header *sead, STREAMFILE *sf) {
static void parse_sead_sab_name(sead_header *sead, STREAMFILE *sf) {
int32_t (*read_32bit)(off_t,STREAMFILE*) = sead->big_endian ? read_32bitBE : read_32bitLE;
int16_t (*read_16bit)(off_t,STREAMFILE*) = sead->big_endian ? read_16bitBE : read_16bitLE;
int i, entries, snd_id, wave_id, snd_found = 0;
int i, snd_entries, trk_entries, snd_id, wave_id, snd_found = 0;
size_t size;
off_t entry_offset;
//todo looks mostly correct for many subsongs but in rare cases wave_ids aren't referenced
// or maybe id needs another jump (seq?) (ex. DQB se_break_soil, FFXV aircraftzeroone)
// or maybe id needs another jump (seq?) (ex. DQB se_break_soil, FFXV aircraftzeroone, FFXV 03bt100031pc00)
snd_entries = read_16bit(sead->snd_offset + 0x04, sf);
trk_entries = read_16bit(sead->trk_offset + 0x04, sf);
/* parse "trk" (track info) */
entries = read_16bit(sead->trk_offset + 0x04, sf);
for (i = 0; i < entries; i++) {
for (i = 0; i < trk_entries; i++) {
entry_offset = sead->trk_offset + read_32bit(sead->trk_offset + 0x10 + i*0x04, sf);
/* 0x00: type/count? */
/* 0x00: type? */
/* 0x01: subtype? */
size = read_16bit(entry_offset + 0x02, sf); /* bigger if 'type=03' */
/* 0x04: trk id? */
/* 0x04: some id? */
@ -499,16 +502,21 @@ static void parse_sead_sab_name(sead_header *sead, STREAMFILE *sf) {
}
}
if (snd_found && snd_id >= snd_entries) {
VGM_LOG("SEAD: bad snd_id found\n");
snd_found = 0;
}
if (!snd_found) {
if (sead->total_subsongs == 1) {
if (sead->total_subsongs == 1 || snd_entries == 1) {
snd_id = 0; /* meh */
VGM_LOG("SEAD: snd_id not found, using first\n");
} else {
VGM_LOG("SEAD: snd_id not found, subsongs=%i, snd=%i, trk=%i\n", sead->total_subsongs, snd_entries, trk_entries);
return;
}
}
/* parse "snd " (sound info) */
{
off_t entry_offset = sead->snd_offset + read_32bit(sead->snd_offset + 0x10 + snd_id*0x04, sf);

View File

@ -1,103 +1,100 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../util.h"
/* THP (Just play audio from .thp movie file)
by fastelbja */
/* THP - Nintendo movie format found in GC/Wii games */
VGMSTREAM* init_vgmstream_thp(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
uint32_t maxAudioSize=0;
uint32_t numComponents;
off_t componentTypeOffset;
off_t componentDataOffset;
char thpVersion;
int loop_flag;
int channel_count=-1;
off_t start_offset, component_type_offset, component_data_offset;
uint32_t version, max_audio_size;
int num_components;
int loop_flag, channel_count;
int i;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("thp",filename_extension(filename)) &&
strcasecmp("dsp",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x54485000)
/* checks */
/* .thp: actual extension
* .dsp: fake extension?
* (extensionless): Fragile (Wii) */
if (!check_extensions(streamFile, "thp,dsp,"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x54485000) /* "THP\0" */
goto fail;
maxAudioSize = read_32bitBE(0x0C,streamFile);
thpVersion = read_8bit(0x06,streamFile);
version = read_32bitBE(0x04,streamFile); /* 16b+16b major/minor */
/* 0x08: max buffer size */
max_audio_size = read_32bitBE(0x0C,streamFile);
/* 0x10: fps in float */
/* 0x14: block count */
/* 0x18: first block size */
/* 0x1c: data size */
if(maxAudioSize==0) // no sound
if (version != 0x00010000 && version != 0x00011000) /* v1.0 (~2002) or v1.1 (rest) */
goto fail;
if (max_audio_size == 0) /* no sound */
goto fail;
loop_flag = 0; // allways unloop
/* fill in the vital statistics */
if(thpVersion==0x10) {
start_offset = read_32bitBE(0x24,streamFile);
/* No idea what's up with this */
if (start_offset == 0)
start_offset = read_32bitBE(0x28,streamFile);
} else
component_type_offset = read_32bitBE(0x20,streamFile);
/* 0x24: block offsets table offset (optional, for seeking) */
start_offset = read_32bitBE(0x28,streamFile);
/* 0x2c: last block offset */
// Get info from the first block
componentTypeOffset = read_32bitBE(0x20,streamFile);
numComponents = read_32bitBE(componentTypeOffset ,streamFile);
componentDataOffset=componentTypeOffset+0x14;
componentTypeOffset+=4;
/* first component "type" x16 then component headers */
num_components = read_32bitBE(component_type_offset,streamFile);
component_type_offset += 0x04;
component_data_offset = component_type_offset + 0x10;
/* parse "component" (data that goes into blocks) */
for (i = 0; i < num_components; i++) {
int type = read_8bit(component_type_offset + i,streamFile);
if (type == 0x00) { /* video */
if (version == 0x00010000)
component_data_offset += 0x08; /* width + height */
else
component_data_offset += 0x0c; /* width + height + format? */
}
else if (type == 0x01) { /* audio */
/* parse below */
#if 0
if (version == 0x00010000)
component_data_offset += 0x0c; /* channels + sample rate + samples */
else
component_data_offset += 0x10; /* channels + sample rate + samples + format? */
#endif
break;
}
else { /* 0xFF / no data (reserved as THP is meant to be extensible) */
goto fail;
}
}
/* official docs remark original's audio is adjusted to match GC's hardware rate
* (48000 > 48043 / 32000 > 32028), not sure if that means ouput sample rate should
* adjusted, but we can't detect Wii (non adjusted) .thp tho */
loop_flag = 0;
channel_count = read_32bitBE(component_data_offset + 0x00,streamFile);
for(i=0;i<numComponents;i++) {
if(read_8bit(componentTypeOffset+i,streamFile)==1) {
channel_count=read_32bitBE(componentDataOffset,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->channels=channel_count;
vgmstream->sample_rate=read_32bitBE(componentDataOffset+4,streamFile);
vgmstream->num_samples=read_32bitBE(componentDataOffset+8,streamFile);
break;
} else {
if(thpVersion==0x10)
componentDataOffset+=0x0c;
else
componentDataOffset+=0x08;
}
}
/* 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;
}
}
vgmstream->full_block_size = read_32bitBE(0x18,streamFile); /* block size of current block, changes every time */
block_update_thp(start_offset,vgmstream);
vgmstream->sample_rate = read_32bitBE(component_data_offset + 0x04,streamFile);
vgmstream->num_samples = read_32bitBE(component_data_offset + 0x08,streamFile);
vgmstream->meta_type = meta_THP;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_blocked_thp;
vgmstream->meta_type = meta_THP;
/* coefs are in every block */
vgmstream->full_block_size = read_32bitBE(0x18,streamFile); /* next block size */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -123,6 +123,7 @@ typedef struct {
uint32_t loop_start_segment;
uint32_t loop_end_segment;
int is_loop_keep;
int is_loop_auto;
txtp_entry default_entry;
int default_entry_set;
@ -188,7 +189,7 @@ VGMSTREAM * init_vgmstream_txtp(STREAMFILE *streamFile) {
txtp->vgmstream[i] = init_vgmstream_from_STREAMFILE(temp_streamFile);
close_streamfile(temp_streamFile);
if (!txtp->vgmstream[i]) {
VGM_LOG("TXTP: cannot open vgmstream for %s\n", txtp->entry[i].filename);
VGM_LOG("TXTP: cannot open vgmstream for %s#%i\n", txtp->entry[i].filename, txtp->entry[i].subsong);
goto fail;
}
@ -313,8 +314,13 @@ static int make_group_segment(txtp_header* txtp, int position, int count) {
/* loop settings only make sense if this group becomes final vgmstream */
if (position == 0 && txtp->vgmstream_count == count) {
if (txtp->loop_start_segment && !txtp->loop_end_segment)
if (txtp->loop_start_segment && !txtp->loop_end_segment) {
txtp->loop_end_segment = count;
}
else if (txtp->is_loop_auto) { /* auto set to last segment */
txtp->loop_start_segment = count;
txtp->loop_end_segment = count;
}
loop_flag = (txtp->loop_start_segment > 0 && txtp->loop_start_segment <= count);
}
@ -611,7 +617,7 @@ static int get_int(const char * config, int *value) {
int n,m;
int temp;
m = sscanf(config, " %i%n", &temp,&n);
m = sscanf(config, " %d%n", &temp,&n);
if (m != 1 || temp < 0)
return 0;
@ -645,7 +651,7 @@ static int get_time(const char * config, double *value_f, int32_t *value_i) {
char temp_c;
/* test if format is hour: N:N(.n) or N_N(.n) */
m = sscanf(config, " %i%c%i%n", &temp_i1,&temp_c,&temp_i2,&n);
m = sscanf(config, " %d%c%d%n", &temp_i1,&temp_c,&temp_i2,&n);
if (m == 3 && (temp_c == ':' || temp_c == '_')) {
m = sscanf(config, " %lf%c%lf%n", &temp_f1,&temp_c,&temp_f2,&n);
if (m != 3 || /*temp_f1 < 0.0 ||*/ temp_f1 >= 60.0 || temp_f2 < 0.0 || temp_f2 >= 60.0)
@ -656,7 +662,7 @@ static int get_time(const char * config, double *value_f, int32_t *value_i) {
}
/* test if format is seconds: N.n */
m = sscanf(config, " %i.%i%n", &temp_i1,&temp_i2,&n);
m = sscanf(config, " %d.%d%n", &temp_i1,&temp_i2,&n);
if (m == 2) {
m = sscanf(config, " %lf%n", &temp_f1,&n);
if (m != 1 /*|| temp_f1 < 0.0*/)
@ -677,7 +683,7 @@ static int get_time(const char * config, double *value_f, int32_t *value_i) {
}
/* assume format is samples: N */
m = sscanf(config, " %i%n", &temp_i1,&n);
m = sscanf(config, " %d%n", &temp_i1,&n);
if (m == 1) {
/* allow negative samples for special meanings */
//if (temp_i1 < 0)
@ -1389,6 +1395,9 @@ static int parse_keyval(txtp_header * txtp, const char * key, const char * val)
if (is_substring(val,"keep")) {
txtp->is_loop_keep = 1;
}
else if (is_substring(val,"auto")) {
txtp->is_loop_auto = 1;
}
else {
goto fail;
}

View File

@ -1525,7 +1525,7 @@ static int parse_stream_codec(ubi_sb_header * sb) {
break;
default:
VGM_LOG("Unknown stream_type %02x for version %08x\n", sb->stream_type, sb->version);
VGM_LOG("UBI SB: Unknown stream_type %02x for version %08x\n", sb->stream_type, sb->version);
goto fail;
}
} else if (sb->version < 0x000A0000) {
@ -1539,7 +1539,7 @@ static int parse_stream_codec(ubi_sb_header * sb) {
break;
default:
VGM_LOG("Unknown stream_type %02x for version %08x\n", sb->stream_type, sb->version);
VGM_LOG("UBI SB: Unknown stream_type %02x for version %08x\n", sb->stream_type, sb->version);
goto fail;
}
} else {
@ -1555,7 +1555,7 @@ static int parse_stream_codec(ubi_sb_header * sb) {
break;
case UBI_PSP:
/* TODO: IMA using Ubisoft ADPCM frame layout [Splinter Cell: Essentials (PSP)] */
VGM_LOG("Unimplemented custom IMA codec.\n");
VGM_LOG("UBI SB: Unimplemented custom IMA codec.\n");
goto fail;
default:
sb->codec = UBI_ADPCM;
@ -1581,7 +1581,7 @@ static int parse_stream_codec(ubi_sb_header * sb) {
sb->codec = FMT_AT3;
break;
default:
VGM_LOG("UBI SB: unknown codec for stream_type %x\n", sb->stream_type);
VGM_LOG("UBI SB: unknown codec for stream_type %02x\n", sb->stream_type);
goto fail;
}
break;
@ -1599,7 +1599,7 @@ static int parse_stream_codec(ubi_sb_header * sb) {
break;
default:
VGM_LOG("Unknown stream_type %02x\n", sb->stream_type);
VGM_LOG("UBI SB: Unknown stream_type %02x\n", sb->stream_type);
goto fail;
}
}
@ -2364,7 +2364,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
return 1;
}
/* Rainbow Six 3 (2003)(PC)-bank 0x0000000B */
/* Tom Clancy's Rainbow Six 3: Raven Shield + addons (2003)(PC)-bank 0x0000000B */
if (sb->version == 0x0000000B && sb->platform == UBI_PC) {
config_sb_entry(sb, 0x5c, 0x7c);
@ -2519,7 +2519,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
/* Batman: Rise of Sin Tzu (2003)(GC)-map 0x000A0002 */
/* Prince of Persia: The Sands of Time (2003)(GC)-bank 0x000A0004 / 0x000A0002 (POP1 port) */
/* Tom Clancy's Rainbow Six 3 (2003)(Xbox)-bank 0x000A0007 */
/* Tom Clancy's Rainbow Six 3 (2003)(GC)-bank 0x000A0007 */
if ((sb->version == 0x000A0002 && sb->platform == UBI_GC) ||
(sb->version == 0x000A0004 && sb->platform == UBI_GC) ||
(sb->version == 0x000A0007 && sb->platform == UBI_GC)) {

View File

@ -199,13 +199,15 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
interleave = 0x800;
loop_flag = 0;
}
else if (read_32bitBE(0x24, streamFile) == 0x56414778) { /* VAGx" */
else if (read_32bitBE(0x24, streamFile) == 0x56414778) { /* "VAGx" */
/* Need for Speed: Hot Pursuit 2 (PS2) */
start_offset = 0x30;
channel_count = read_32bitBE(0x2c, streamFile);
channel_size = channel_size / channel_count;
loop_flag = 0;
if (file_size % 0x10 != 0) goto fail;
/* detect interleave using end markers */
interleave = 0;
@ -214,7 +216,7 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
off_t end_off = 0;
uint8_t flag;
while (1) {
while (offset > start_offset) {
offset -= 0x10;
flag = read_8bit(offset + 0x01, streamFile);
if (flag == 0x01) {
@ -225,9 +227,9 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
break;
}
}
if (offset == start_offset) goto fail;
}
if (!interleave) goto fail;
}
}
else {

View File

@ -201,7 +201,9 @@ int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tags, STREAMFILE* tagfile) {
if (tags->section_found) {
/* find possible file tag */
ok = sscanf(line, "# %%%[^ \t] %[^\r\n] ", tags->key,tags->val);
ok = sscanf(line, "# %%%[^%%]%% %[^\r\n] ", tags->key,tags->val); /* key with spaces */
if (ok != 2)
ok = sscanf(line, "# %%%[^ \t] %[^\r\n] ", tags->key,tags->val); /* key without */
if (ok == 2) {
tags_clean(tags);
return 1;
@ -224,7 +226,9 @@ int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tags, STREAMFILE* tagfile) {
}
/* find possible global tag */
ok = sscanf(line, "# @%[^ \t] %[^\r\n]", tags->key,tags->val);
ok = sscanf(line, "# @%[^@]@ %[^\r\n]", tags->key,tags->val); /* key with spaces */
if (ok != 2)
ok = sscanf(line, "# @%[^ \t] %[^\r\n]", tags->key,tags->val); /* key without */
if (ok == 2) {
tags_clean(tags);
return 1;

View File

@ -59,6 +59,14 @@ void put_16bitBE(uint8_t * buf, int16_t i);
void put_32bitBE(uint8_t * buf, int32_t i);
/* alias of the above */ //TODO: improve
#define put_u8 put_8bit
#define put_u16le put_16bitLE
#define put_u32le put_32bitLE
#define put_u16be put_16bitBE
#define put_u32be put_32bitBE
/* signed nibbles come up a lot */
static int nibble_to_int[16] = {0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1};

View File

@ -285,14 +285,14 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_mn_str,
init_vgmstream_mss,
init_vgmstream_ps2_hsf,
init_vgmstream_ps3_ivag,
init_vgmstream_ivag,
init_vgmstream_ps2_2pfs,
init_vgmstream_xnb,
init_vgmstream_ubi_ckd,
init_vgmstream_ps2_vbk,
init_vgmstream_otm,
init_vgmstream_bcstm,
init_vgmstream_idsp_nus3,
init_vgmstream_idsp_namco,
init_vgmstream_kt_g1l,
init_vgmstream_kt_wiibgm,
init_vgmstream_ktss,
@ -405,6 +405,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_hd3_bd3,
init_vgmstream_bnk_sony,
init_vgmstream_nus3bank,
init_vgmstream_nus3bank_encrypted,
init_vgmstream_scd_sscf,
init_vgmstream_dsp_sps_n1,
init_vgmstream_dsp_itl_ch,
@ -513,8 +514,8 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile) {
if (!vgmstream)
continue;
/* fail if there is nothing to play (without this check vgmstream can generate empty files) */
if (vgmstream->num_samples <= 0) {
/* fail if there is nothing/too much to play (<=0 generates empty files, >N writes GBs of garbage) */
if (vgmstream->num_samples <= 0 || vgmstream->num_samples > VGMSTREAM_MAX_NUM_SAMPLES) {
VGM_LOG("VGMSTREAM: wrong num_samples %i\n", vgmstream->num_samples);
close_vgmstream(vgmstream);
continue;

View File

@ -12,6 +12,7 @@ enum { VGMSTREAM_MAX_CHANNELS = 64 };
enum { VGMSTREAM_MIN_SAMPLE_RATE = 300 }; /* 300 is Wwise min */
enum { VGMSTREAM_MAX_SAMPLE_RATE = 192000 }; /* found in some FSB5 */
enum { VGMSTREAM_MAX_SUBSONGS = 65535 };
enum { VGMSTREAM_MAX_NUM_SAMPLES = 1000000000 }; /* no ~5h vgm hopefully */
#include "streamfile.h"
@ -582,13 +583,13 @@ typedef enum {
meta_MN_STR, /* Mini Ninjas (PC/PS3/WII) */
meta_MSS, /* Guerilla: ShellShock Nam '67 (PS2/Xbox), Killzone (PS2) */
meta_PS2_HSF, /* Lowrider (PS2) */
meta_PS3_IVAG, /* Interleaved VAG files (PS3) */
meta_IVAG,
meta_PS2_2PFS, /* Konami: Mahoromatic: Moetto - KiraKira Maid-San, GANTZ (PS2) */
meta_PS2_VBK, /* Disney's Stitch - Experiment 626 */
meta_OTM, /* Otomedius (Arcade) */
meta_CSTM, /* Nintendo 3DS CSTM (Century Stream) */
meta_FSTM, /* Nintendo Wii U FSTM (caFe? Stream) */
meta_IDSP_NUS3, /* Namco 3DS/Wii U IDSP */
meta_IDSP_NAMCO,
meta_KT_WIIBGM, /* Koei Tecmo WiiBGM */
meta_KTSS, /* Koei Tecmo Nintendo Stream (KNS) */
meta_MCA, /* Capcom MCA "MADP" */