Updated VGMStream to r1050-3548-g64ffe5ea
parent
d070dffdbe
commit
2a52dd831a
|
@ -622,6 +622,7 @@
|
|||
83F1EE2D245D4FB20076E182 /* imuse_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F1EE28245D4FB10076E182 /* imuse_decoder.c */; };
|
||||
83F1EE2E245D4FB20076E182 /* vadpcm_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F1EE2C245D4FB20076E182 /* vadpcm_decoder.c */; };
|
||||
83F1EE30245D4FC10076E182 /* imuse.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F1EE2F245D4FC10076E182 /* imuse.c */; };
|
||||
83F2CCE525A5B41600F46FA8 /* acx.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F2CCE125A5B41600F46FA8 /* acx.c */; };
|
||||
83F5F8831908D0A400C8E65F /* fsb5.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F5F8821908D0A400C8E65F /* fsb5.c */; };
|
||||
83FBD506235D31F800D35BCD /* riff_ogg_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83FBD502235D31F700D35BCD /* riff_ogg_streamfile.h */; };
|
||||
83FC176D23AC58D100E1025F /* xma_ue3.c in Sources */ = {isa = PBXBuildFile; fileRef = 83FC176A23AC58D100E1025F /* xma_ue3.c */; };
|
||||
|
@ -1363,6 +1364,7 @@
|
|||
83F1EE28245D4FB10076E182 /* imuse_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = imuse_decoder.c; sourceTree = "<group>"; };
|
||||
83F1EE2C245D4FB20076E182 /* vadpcm_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vadpcm_decoder.c; sourceTree = "<group>"; };
|
||||
83F1EE2F245D4FC10076E182 /* imuse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = imuse.c; sourceTree = "<group>"; };
|
||||
83F2CCE125A5B41600F46FA8 /* acx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = acx.c; sourceTree = "<group>"; };
|
||||
83F412871E932F9A002E37D0 /* Vorbis.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Vorbis.xcodeproj; path = ../Vorbis/macosx/Vorbis.xcodeproj; sourceTree = "<group>"; };
|
||||
83F5F8821908D0A400C8E65F /* fsb5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fsb5.c; sourceTree = "<group>"; };
|
||||
83FBD502235D31F700D35BCD /* riff_ogg_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = riff_ogg_streamfile.h; sourceTree = "<group>"; };
|
||||
|
@ -1685,6 +1687,7 @@
|
|||
836F6E2A18BDC2180095E648 /* aax.c */,
|
||||
837CEAD623487E8300E62A4A /* acb.c */,
|
||||
836F6E2B18BDC2180095E648 /* acm.c */,
|
||||
83F2CCE125A5B41600F46FA8 /* acx.c */,
|
||||
83AA7F7A2519C042004C5298 /* adp_konami.c */,
|
||||
834FE0CF215C79E8000A5D3D /* adpcm_capcom.c */,
|
||||
836F6E2C18BDC2180095E648 /* ads.c */,
|
||||
|
@ -2674,6 +2677,7 @@
|
|||
836F6F9918BDC2190095E648 /* maxis_xa.c in Sources */,
|
||||
836F702118BDC2190095E648 /* rs03.c in Sources */,
|
||||
836F6F8818BDC2190095E648 /* fsb.c in Sources */,
|
||||
83F2CCE525A5B41600F46FA8 /* acx.c in Sources */,
|
||||
83FC176D23AC58D100E1025F /* xma_ue3.c in Sources */,
|
||||
836F6FE518BDC2190095E648 /* ps2_lpcm.c in Sources */,
|
||||
8375737321F9507D00F01AF5 /* oki_decoder.c in Sources */,
|
||||
|
|
|
@ -39,6 +39,7 @@ static const char* extension_list[] = {
|
|||
//"ac3", //common, FFmpeg/not parsed (AC3)
|
||||
"acb",
|
||||
"acm",
|
||||
"acx",
|
||||
"ad", //txth/reserved [Xenosaga Freaks (PS2)]
|
||||
"adc", //txth/reserved [Tomb Raider The Last Revelation (DC), Tomb Raider Chronicles (DC)]
|
||||
"adm",
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .acx - CRI container [Baroque (SAT), Persona 3 (PS2), THE iDOLM@STER: Live For You (X360)] */
|
||||
VGMSTREAM* init_vgmstream_acx(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
off_t subfile_offset;
|
||||
size_t subfile_size;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf,"acx"))
|
||||
goto fail;
|
||||
if (read_u32be(0x00,sf) != 0x00000000)
|
||||
goto fail;
|
||||
|
||||
/* simple container for sfx and rarely music [Burning Rangers (SAT)],
|
||||
* mainly used until .csb was introduced */
|
||||
|
||||
total_subsongs = read_u32be(0x04,sf);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
subfile_offset = read_u32be(0x08 + (target_subsong-1) * 0x08 + 0x00,sf);
|
||||
subfile_size = read_u32be(0x08 + (target_subsong-1) * 0x08 + 0x04,sf);
|
||||
|
||||
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "adx");
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_adx(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_sf);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -20,7 +20,7 @@ static const adxkey_info adxkey8_list[] = {
|
|||
{0x49e1,0x4a57,0x553d, "karaage",0},
|
||||
|
||||
/* Blood+ (PS2) [Grasshopper Manufacture] */
|
||||
{0x5f5d,0x58bd,0x55ed, NULL,0}, // keystring not in ELF?
|
||||
{0x5f5d,0x58bd,0x55ed, "LOVELOVE",0}, // obfuscated keystring is "KNUDKNUD", adds +1 to chars to get final key
|
||||
|
||||
/* Killer7 (PS2) [Grasshopper Manufacture] */
|
||||
{0x50fb,0x5803,0x5701, "GHM",0},
|
||||
|
@ -34,14 +34,14 @@ static const adxkey_info adxkey8_list[] = {
|
|||
/* Phantasy Star Universe (PC), Phantasy Star Universe: Ambition of the Illuminus (PS2) [Sonic Team] */
|
||||
{0x5deb,0x5f27,0x673f, "3x5k62bg9ptbwy",0},
|
||||
|
||||
/* Senko no Ronde [G.rev] */
|
||||
/* Senko no Ronde Rev.X (X360) [G.rev] */
|
||||
{0x46d3,0x5ced,0x474d, "ranatus",0},
|
||||
|
||||
/* NiGHTS: Journey of Dreams (Wii) [Sonic Team] */
|
||||
{0x440b,0x6539,0x5723, "sakakit4649",0},
|
||||
|
||||
/* unknown source */
|
||||
{0x586d,0x5d65,0x63eb, NULL,0}, // from guessadx (unique?)
|
||||
/* The iDOLM@STER: Live For You (X360) [Bandai Namco] (.aix) */
|
||||
{0x586d,0x5d65,0x63eb, "75_501NO_003B",0},
|
||||
|
||||
/* Shuffle! On the Stage (PS2) [Navel] */
|
||||
{0x4969,0x5deb,0x467f, "SHUF",0},
|
||||
|
@ -64,8 +64,8 @@ static const adxkey_info adxkey8_list[] = {
|
|||
/* Soulcalibur IV (PS3) [Namco] */
|
||||
{0x59ed,0x4679,0x46c9, "SC4Test",0},
|
||||
|
||||
/* Senko no Ronde DUO (X360) [G.rev] */
|
||||
{0x6157,0x6809,0x4045, NULL,0}, // from guessadx
|
||||
/* Senko no Ronde DUO (X360/AC) [G.rev] */
|
||||
{0x6157,0x6809,0x4045, "yomesokushitsu",0},
|
||||
|
||||
/* Nogizaka Haruka no Himitsu: Cosplay Hajimemashita (PS2) [Vridge] */
|
||||
{0x45af,0x5f27,0x52b1, "SKFHSIA",0},
|
||||
|
@ -100,16 +100,16 @@ static const adxkey_info adxkey8_list[] = {
|
|||
/* Soshite Kono Uchuu ni Kirameku Kimi no Shi XXX (PS2) [Datam Polystar] */
|
||||
{0x5f5d,0x552b,0x5507, "DATAM-KK2",0},
|
||||
|
||||
/* Sakura Taisen: Atsuki Chishio Ni (PS2) [Sega] */
|
||||
{0x645d,0x6011,0x5c29, NULL,0}, // confirmed unique with guessadx
|
||||
/* Sakura Taisen: Atsuki Chishio ni (PS2) [Sega] */
|
||||
{0x645d,0x6011,0x5c29, NULL,0}, // possible key: "[Seq][ADX] illegal cri or libsd status."
|
||||
|
||||
/* Sakura Taisen 3 ~Paris wa Moeteiru ka~ (PS2) [Sega] */
|
||||
{0x62ad,0x4b13,0x5957, NULL,0}, // confirmed unique with guessadx
|
||||
/* Sakura Taisen Monogatari: Mysterious Paris (PS2) [Sega] */
|
||||
{0x62ad,0x4b13,0x5957, "inoue4126",0},
|
||||
|
||||
/* Sotsugyou 2nd Generation (PS2) [Jinx] */
|
||||
{0x6305,0x509f,0x4c01, NULL,0}, // First guess from guessadx, other was {0x6307,0x509f,0x2ac5}
|
||||
|
||||
/* La Corda d'Oro (PSP) [Koei] */
|
||||
/* Kin'iro no Corda -La Corda d'Oro- (PSP) [Koei] */
|
||||
{0x55b7,0x67e5,0x5387, NULL,0}, // keystring not in ELF?
|
||||
|
||||
/* Nanatsuiro * Drops Pure!! (PS2) [Media Works] */
|
||||
|
@ -127,7 +127,7 @@ static const adxkey_info adxkey8_list[] = {
|
|||
/* Sora no Otoshimono: DokiDoki Summer Vacation (PSP) [Kadokawa Shoten] */
|
||||
{0x5e75,0x4a89,0x4c61, "funen-gomi",0},
|
||||
|
||||
/* Boku wa Koukuu Kanseikan: Airport Hero Naha (PSP) [Sonic Powered] */
|
||||
/* Boku wa Koukuu Kanseikan: Airport Hero Naha/Narita/Shinchitose/Haneda/Kankuu (PSP) [Sonic Powered] */
|
||||
{0x64ab,0x5297,0x632f, "sonic",0},
|
||||
|
||||
/* Lucky Star: Net Idol Meister (PSP) [Vridge, Kadokawa Shoten] */
|
||||
|
|
|
@ -162,7 +162,7 @@ VGMSTREAM* init_vgmstream_awc(STREAMFILE* sf) {
|
|||
vgmstream->layout_data = build_layered_awc(sf, &awc);
|
||||
if (!vgmstream->layout_data) goto fail;
|
||||
vgmstream->layout_type = layout_layered;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->coding_type = coding_VORBIS_custom;
|
||||
}
|
||||
else {
|
||||
vorbis_custom_config cfg = {0};
|
||||
|
|
|
@ -4,22 +4,22 @@
|
|||
|
||||
|
||||
/* CSB (Cue Sheet Binary?) - CRI container of memory audio, often together with a .cpk wave bank */
|
||||
VGMSTREAM * init_vgmstream_csb(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
STREAMFILE *temp_sf = NULL;
|
||||
VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
off_t subfile_offset;
|
||||
size_t subfile_size;
|
||||
utf_context *utf = NULL;
|
||||
utf_context *utf_sdl = NULL;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
uint8_t fmt = 0;
|
||||
const char *stream_name;
|
||||
const char* stream_name;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "csb"))
|
||||
if (!check_extensions(sf, "csb"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x40555446) /* "@UTF" */
|
||||
if (!is_id32be(0x00,sf, "@UTF"))
|
||||
goto fail;
|
||||
|
||||
/* .csb is an early, simpler version of .acb+awk (see acb.c) used until ~2013?
|
||||
|
@ -35,32 +35,41 @@ VGMSTREAM * init_vgmstream_csb(STREAMFILE *streamFile) {
|
|||
int found = 0;
|
||||
|
||||
|
||||
utf = utf_open(streamFile, table_offset, &rows, &name);
|
||||
utf = utf_open(sf, table_offset, &rows, &name);
|
||||
if (!utf) goto fail;
|
||||
|
||||
if (strcmp(name, "TBLCSB") != 0)
|
||||
goto fail;
|
||||
|
||||
/* each TBLCSB row has a name and subtable with actual things:
|
||||
* - INFO (TBL_INFO): table type/version
|
||||
* - INFO (TBL_INFO): table type/version, rarely ommited [Nights: Journey of Dreams (Wii)-some csb]
|
||||
* - CUE (TBLCUE): base cues
|
||||
* - SYNTH (TBLSYN): cue configs
|
||||
* - SOUND_ELEMENT (TBLSDL): audio info/data (usually AAX)
|
||||
* - ISAAC (TBLISC): 3D config
|
||||
* - VOICE_LIMIT_GROUP (TBLVLG): system info?
|
||||
* Subtable can be empty but must still appear (0 rows).
|
||||
* Subtable can be empty but still appear (0 rows).
|
||||
*/
|
||||
sdl_row = 3; /* should use fixed order */
|
||||
|
||||
/* get SOUND_ELEMENT and table */
|
||||
if (!utf_query_string(utf, sdl_row, "name", &row_name) || strcmp(row_name, "SOUND_ELEMENT") != 0)
|
||||
sdl_row = -1;
|
||||
for (i = 0; i < rows; i++) {
|
||||
if (!utf_query_string(utf, i, "name", &row_name))
|
||||
goto fail;
|
||||
if (strcmp(row_name, "SOUND_ELEMENT") == 0) {
|
||||
sdl_row = i; /* usually 2 or 3 */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sdl_row < 0)
|
||||
goto fail;
|
||||
|
||||
|
||||
/* read SOUND_ELEMENT table */
|
||||
if (!utf_query_u8(utf, sdl_row, "ttype", &ttype) || ttype != 4)
|
||||
goto fail;
|
||||
if (!utf_query_data(utf, sdl_row, "utf", &sdl_offset, &sdl_size))
|
||||
goto fail;
|
||||
|
||||
utf_sdl = utf_open(streamFile, sdl_offset, &sdl_rows, &sdl_name);
|
||||
utf_sdl = utf_open(sf, sdl_offset, &sdl_rows, &sdl_name);
|
||||
if (!utf_sdl) goto fail;
|
||||
|
||||
if (strcmp(sdl_name, "TBLSDL") != 0)
|
||||
|
@ -109,7 +118,7 @@ VGMSTREAM * init_vgmstream_csb(STREAMFILE *streamFile) {
|
|||
//;VGM_LOG("CSB: subfile offset=%lx + %x\n", subfile_offset, subfile_size);
|
||||
|
||||
|
||||
temp_sf = setup_subfile_streamfile(streamFile, subfile_offset, subfile_size, "aax");
|
||||
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "aax");
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
switch(fmt) {
|
||||
|
|
|
@ -80,6 +80,9 @@ static const uint8_t key_ghm[] = { 0x8C,0xFA,0xF3,0x14,0xB1,0x53,0xDA,0xAB,0x2B,
|
|||
/* Worms Rumble Beta (PC) */ //"FXnTffGJ9LS855Gc"
|
||||
static const uint8_t key_wrb[] = { 0x46,0x58,0x6E,0x54,0x66,0x66,0x47,0x4A,0x39,0x4C,0x53,0x38,0x35,0x35,0x47,0x63 };
|
||||
|
||||
/* Bubble Fighter (PC) */ //"qjvkeoqkrdhkdckd"
|
||||
static const uint8_t key_bbf[] = { 0x71,0x6A,0x76,0x6B,0x65,0x6F,0x71,0x6B,0x72,0x64,0x68,0x6B,0x64,0x63,0x6B,0x64 };
|
||||
|
||||
// Unknown:
|
||||
// - Battle: Los Angeles
|
||||
// - Guitar Hero: Warriors of Rock, DJ hero FSB
|
||||
|
@ -90,7 +93,7 @@ typedef struct {
|
|||
int is_fsb5; /* FSB5 or FSB4/3*/
|
||||
int is_alt; /* alt XOR mode (seemingly not tied to FSB version or anything) */
|
||||
size_t fsbkey_size;
|
||||
const uint8_t *fsbkey;
|
||||
const uint8_t* fsbkey;
|
||||
} fsbkey_info;
|
||||
|
||||
static const fsbkey_info fsbkey_list[] = {
|
||||
|
@ -153,6 +156,7 @@ static const fsbkey_info fsbkey_list[] = {
|
|||
{ 1,0, sizeof(key_scp),key_scp },// FSB5
|
||||
{ 0,1, sizeof(key_ghm),key_ghm },// FSB4
|
||||
{ 1,0, sizeof(key_wrb),key_wrb },// FSB5
|
||||
{ 0,0, sizeof(key_bbf),key_bbf },// FSB4
|
||||
};
|
||||
static const int fsbkey_list_count = sizeof(fsbkey_list) / sizeof(fsbkey_list[0]);
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ typedef struct {
|
|||
int big_endian;
|
||||
int total_subsongs;
|
||||
int target_subsong;
|
||||
int found;
|
||||
kwb_codec codec;
|
||||
|
||||
int channels;
|
||||
|
@ -26,6 +27,7 @@ typedef struct {
|
|||
|
||||
static int parse_kwb(kwb_header* kwb, STREAMFILE* sf_h, STREAMFILE* sf_b);
|
||||
static int parse_xws(kwb_header* kwb, STREAMFILE* sf);
|
||||
static VGMSTREAM* init_vgmstream_koei_wavebank(kwb_header* kwb, STREAMFILE* sf_h, STREAMFILE* sf_b);
|
||||
|
||||
|
||||
/* KWB - WaveBank from Koei games */
|
||||
|
@ -33,7 +35,6 @@ VGMSTREAM* init_vgmstream_kwb(STREAMFILE* sf) {
|
|||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE *sf_h = NULL, *sf_b = NULL;
|
||||
kwb_header kwb = {0};
|
||||
int32_t (*read_s32)(off_t,STREAMFILE*) = NULL;
|
||||
int target_subsong = sf->stream_index;
|
||||
|
||||
|
||||
|
@ -70,89 +71,11 @@ VGMSTREAM* init_vgmstream_kwb(STREAMFILE* sf) {
|
|||
|
||||
if (!parse_kwb(&kwb, sf_h, sf_b))
|
||||
goto fail;
|
||||
read_s32 = kwb.big_endian ? read_s32be : read_s32le;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(kwb.channels, kwb.loop_flag);
|
||||
vgmstream = init_vgmstream_koei_wavebank(&kwb, sf_h, sf_b);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_KWB;
|
||||
vgmstream->sample_rate = kwb.sample_rate;
|
||||
vgmstream->num_samples = kwb.num_samples;
|
||||
vgmstream->stream_size = kwb.stream_size;
|
||||
vgmstream->num_streams = kwb.total_subsongs;
|
||||
|
||||
switch(kwb.codec) {
|
||||
case PCM16: /* PCM */
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
break;
|
||||
|
||||
case MSADPCM:
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->frame_size = kwb.block_size;
|
||||
break;
|
||||
|
||||
case DSP_HEAD:
|
||||
case DSP_BODY:
|
||||
if (kwb.channels > 1) goto fail;
|
||||
vgmstream->coding_type = coding_NGC_DSP; /* subinterleave? */
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x08;
|
||||
if (kwb.codec == DSP_HEAD) {
|
||||
dsp_read_coefs(vgmstream, sf_h, kwb.dsp_offset + 0x1c, 0x60, kwb.big_endian);
|
||||
dsp_read_hist (vgmstream, sf_h, kwb.dsp_offset + 0x40, 0x60, kwb.big_endian);
|
||||
}
|
||||
else {
|
||||
/* typical DSP header + data */
|
||||
vgmstream->num_samples = read_s32(kwb.stream_offset + 0x00, sf_b);
|
||||
dsp_read_coefs(vgmstream, sf_b, kwb.stream_offset + 0x1c, 0x60, kwb.big_endian);
|
||||
dsp_read_hist (vgmstream, sf_b, kwb.stream_offset + 0x40, 0x60, kwb.big_endian);
|
||||
kwb.stream_offset += 0x60;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_ATRAC9
|
||||
case AT9: {
|
||||
atrac9_config cfg = {0};
|
||||
|
||||
{
|
||||
size_t extra_size = read_u32le(kwb.stream_offset + 0x00, sf_b);
|
||||
uint32_t config_data = read_u32be(kwb.stream_offset + 0x04, sf_b);
|
||||
/* 0x0c: encoder delay? */
|
||||
/* 0x0e: encoder padding? */
|
||||
/* 0x10: samples per frame */
|
||||
/* 0x12: frame size */
|
||||
|
||||
cfg.channels = vgmstream->channels;
|
||||
cfg.config_data = config_data;
|
||||
|
||||
kwb.stream_offset += extra_size;
|
||||
kwb.stream_size -= extra_size;
|
||||
}
|
||||
|
||||
vgmstream->codec_data = init_atrac9(&cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_ATRAC9;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
//TODO: check encoder delay
|
||||
vgmstream->num_samples = atrac9_bytes_to_samples_cfg(kwb.stream_size, cfg.config_data);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (sf_h != sf) close_streamfile(sf_h);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf_b, kwb.stream_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
|
@ -164,7 +87,6 @@ fail:
|
|||
/* XWS - WaveStream? from Koei games */
|
||||
VGMSTREAM* init_vgmstream_xws(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
kwb_header kwb = {0};
|
||||
int target_subsong = sf->stream_index;
|
||||
|
||||
|
@ -179,37 +101,138 @@ VGMSTREAM* init_vgmstream_xws(STREAMFILE* sf) {
|
|||
if (!parse_xws(&kwb, sf))
|
||||
goto fail;
|
||||
|
||||
if (kwb.codec == MSF) {
|
||||
if (kwb.stream_offset == 0) {
|
||||
vgmstream = init_vgmstream_silence(0,0,0); /* dummy, whatevs */
|
||||
if (!vgmstream) goto fail;
|
||||
}
|
||||
else {
|
||||
kwb.stream_size = read_u32be(kwb.stream_offset + 0x0c, sf) + 0x40;
|
||||
vgmstream = init_vgmstream_koei_wavebank(&kwb, sf, sf);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
temp_sf = setup_subfile_streamfile(sf, kwb.stream_offset, kwb.stream_size, "msf");
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_msf(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
}
|
||||
|
||||
vgmstream->num_streams = kwb.total_subsongs;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
fail:
|
||||
close_streamfile(temp_sf);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static VGMSTREAM* init_vgmstream_koei_wavebank(kwb_header* kwb, STREAMFILE* sf_h, STREAMFILE* sf_b) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL;
|
||||
int32_t (*read_s32)(off_t,STREAMFILE*) = NULL;
|
||||
|
||||
static int parse_type_kwb2(kwb_header* kwb, off_t offset, STREAMFILE* sf_h) {
|
||||
|
||||
read_u32 = kwb->big_endian ? read_u32be : read_u32le;
|
||||
read_s32 = kwb->big_endian ? read_s32be : read_s32le;
|
||||
|
||||
/* container */
|
||||
if (kwb->codec == MSF) {
|
||||
if (kwb->stream_offset == 0) {
|
||||
vgmstream = init_vgmstream_silence(0,0,0); /* dummy, whatevs */
|
||||
if (!vgmstream) goto fail;
|
||||
}
|
||||
else {
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
|
||||
kwb->stream_size = read_u32(kwb->stream_offset + 0x0c, sf_h) + 0x40;
|
||||
|
||||
temp_sf = setup_subfile_streamfile(sf_h, kwb->stream_offset, kwb->stream_size, "msf");
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_msf(temp_sf);
|
||||
close_streamfile(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
}
|
||||
|
||||
vgmstream->num_streams = kwb->total_subsongs;
|
||||
return vgmstream;
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(kwb->channels, kwb->loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_KWB;
|
||||
vgmstream->sample_rate = kwb->sample_rate;
|
||||
vgmstream->num_samples = kwb->num_samples;
|
||||
vgmstream->stream_size = kwb->stream_size;
|
||||
vgmstream->num_streams = kwb->total_subsongs;
|
||||
|
||||
switch(kwb->codec) {
|
||||
case PCM16: /* PCM */
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
break;
|
||||
|
||||
case MSADPCM:
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->frame_size = kwb->block_size;
|
||||
break;
|
||||
|
||||
case DSP_HEAD:
|
||||
case DSP_BODY:
|
||||
if (kwb->channels > 1) goto fail;
|
||||
vgmstream->coding_type = coding_NGC_DSP; /* subinterleave? */
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x08;
|
||||
if (kwb->codec == DSP_HEAD) {
|
||||
dsp_read_coefs(vgmstream, sf_h, kwb->dsp_offset + 0x1c, 0x60, kwb->big_endian);
|
||||
dsp_read_hist (vgmstream, sf_h, kwb->dsp_offset + 0x40, 0x60, kwb->big_endian);
|
||||
}
|
||||
else {
|
||||
/* typical DSP header + data */
|
||||
vgmstream->num_samples = read_s32(kwb->stream_offset + 0x00, sf_b);
|
||||
dsp_read_coefs(vgmstream, sf_b, kwb->stream_offset + 0x1c, 0x60, kwb->big_endian);
|
||||
dsp_read_hist (vgmstream, sf_b, kwb->stream_offset + 0x40, 0x60, kwb->big_endian);
|
||||
kwb->stream_offset += 0x60;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_ATRAC9
|
||||
case AT9: {
|
||||
atrac9_config cfg = {0};
|
||||
|
||||
{
|
||||
size_t extra_size = read_u32le(kwb->stream_offset + 0x00, sf_b);
|
||||
uint32_t config_data = read_u32be(kwb->stream_offset + 0x04, sf_b);
|
||||
/* 0x0c: encoder delay? */
|
||||
/* 0x0e: encoder padding? */
|
||||
/* 0x10: samples per frame */
|
||||
/* 0x12: frame size */
|
||||
|
||||
cfg.channels = vgmstream->channels;
|
||||
cfg.config_data = config_data;
|
||||
|
||||
kwb->stream_offset += extra_size;
|
||||
kwb->stream_size -= extra_size;
|
||||
}
|
||||
|
||||
vgmstream->codec_data = init_atrac9(&cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_ATRAC9;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
//TODO: check encoder delay
|
||||
vgmstream->num_samples = atrac9_bytes_to_samples_cfg(kwb->stream_size, cfg.config_data);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf_b, kwb->stream_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
static int parse_type_kwb2(kwb_header* kwb, off_t offset, off_t body_offset, STREAMFILE* sf_h) {
|
||||
int i, j, sounds;
|
||||
|
||||
/* 00: KWB2/KWBN id */
|
||||
|
@ -220,12 +243,15 @@ static int parse_type_kwb2(kwb_header* kwb, off_t offset, STREAMFILE* sf_h) {
|
|||
/* 10: null or 1 */
|
||||
/* 14: offset to HDDB table (from type), can be null */
|
||||
|
||||
//;VGM_LOG("KWB2: sounds %i, o=%lx\n", sounds, offset);
|
||||
|
||||
/* offset table to entries */
|
||||
for (i = 0; i < sounds; i++) {
|
||||
off_t sound_offset = read_u32le(offset + 0x18 + i*0x04, sf_h);
|
||||
int subsounds, subsound_start, subsound_size;
|
||||
uint16_t version;
|
||||
|
||||
//;VGM_LOG("KWB2: entry %i, o=%lx, so=%lx\n", i, offset + 0x18 + i*0x04, sound_offset);
|
||||
|
||||
if (sound_offset == 0) /* common... */
|
||||
continue;
|
||||
|
@ -258,6 +284,8 @@ static int parse_type_kwb2(kwb_header* kwb, off_t offset, STREAMFILE* sf_h) {
|
|||
kwb->total_subsongs++;
|
||||
if (kwb->total_subsongs != kwb->target_subsong)
|
||||
continue;
|
||||
kwb->found = 1;
|
||||
|
||||
subsound_offset = subsound_start + j*subsound_size;
|
||||
|
||||
kwb->sample_rate = read_u16le(subsound_offset + 0x00, sf_h);
|
||||
|
@ -272,6 +300,8 @@ static int parse_type_kwb2(kwb_header* kwb, off_t offset, STREAMFILE* sf_h) {
|
|||
/* when size > 0x48 */
|
||||
/* 0x48: subsound entry size */
|
||||
/* rest: reserved per codec? (usually null) */
|
||||
|
||||
kwb->stream_offset += body_offset;
|
||||
|
||||
switch(codec) {
|
||||
case 0x00:
|
||||
|
@ -304,16 +334,14 @@ static int parse_type_kwb2(kwb_header* kwb, off_t offset, STREAMFILE* sf_h) {
|
|||
then name table (null terminated and one after other)
|
||||
*/
|
||||
|
||||
if (kwb->target_subsong < 0 || kwb->target_subsong > kwb->total_subsongs || kwb->total_subsongs < 1) goto fail;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_type_k4hd(kwb_header* kwb, off_t offset, STREAMFILE* sf_h) {
|
||||
static int parse_type_k4hd(kwb_header* kwb, off_t offset, off_t body_offset, STREAMFILE* sf_h) {
|
||||
off_t ppva_offset, header_offset;
|
||||
int entries;
|
||||
int entries, current_subsongs, relative_subsong;
|
||||
size_t entry_size;
|
||||
|
||||
|
||||
|
@ -344,10 +372,14 @@ static int parse_type_k4hd(kwb_header* kwb, off_t offset, STREAMFILE* sf_h) {
|
|||
goto fail;
|
||||
}
|
||||
|
||||
kwb->total_subsongs = entries;
|
||||
if (kwb->target_subsong < 0 || kwb->target_subsong > kwb->total_subsongs || kwb->total_subsongs < 1) goto fail;
|
||||
current_subsongs = kwb->total_subsongs;
|
||||
kwb->total_subsongs += entries;
|
||||
if (kwb->target_subsong - 1 < current_subsongs || kwb->target_subsong > kwb->total_subsongs)
|
||||
return 1;
|
||||
kwb->found = 1;
|
||||
|
||||
header_offset = ppva_offset + 0x20 + (kwb->target_subsong-1) * entry_size;
|
||||
relative_subsong = kwb->target_subsong - current_subsongs;
|
||||
header_offset = ppva_offset + 0x20 + (relative_subsong-1) * entry_size;
|
||||
|
||||
kwb->stream_offset = read_u32le(header_offset + 0x00, sf_h);
|
||||
kwb->sample_rate = read_u32le(header_offset + 0x04, sf_h);
|
||||
|
@ -363,21 +395,22 @@ static int parse_type_k4hd(kwb_header* kwb, off_t offset, STREAMFILE* sf_h) {
|
|||
kwb->codec = AT9;
|
||||
kwb->channels = 1; /* always, devs use dual subsongs to fake stereo (like as hd3+bd3) */
|
||||
|
||||
kwb->stream_offset += body_offset;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_type_sdsd(kwb_header* kwb, off_t offset, STREAMFILE* sf_h) {
|
||||
static int parse_type_sdsd(kwb_header* kwb, off_t offset, off_t body_offset, STREAMFILE* sf_h) {
|
||||
/* has Vers, Head, Prog, Smpl sections (like Sony VABs)
|
||||
unknown codec, blocked with some common start, variable sized */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_type_sdwi(kwb_header* kwb, off_t offset, STREAMFILE* sf_h) {
|
||||
static int parse_type_sdwi(kwb_header* kwb, off_t offset, off_t body_offset, STREAMFILE* sf_h) {
|
||||
off_t smpl_offset, header_offset;
|
||||
int entries;
|
||||
int entries, current_subsongs, relative_subsong;
|
||||
size_t entry_size;
|
||||
|
||||
|
||||
|
@ -404,10 +437,14 @@ static int parse_type_sdwi(kwb_header* kwb, off_t offset, STREAMFILE* sf_h) {
|
|||
entries = read_u32le(smpl_offset + 0x0c, sf_h); /* LE! */
|
||||
entry_size = 0x40;
|
||||
|
||||
kwb->total_subsongs = entries;
|
||||
if (kwb->target_subsong < 0 || kwb->target_subsong > kwb->total_subsongs || kwb->total_subsongs < 1) goto fail;
|
||||
current_subsongs = kwb->total_subsongs;
|
||||
kwb->total_subsongs += entries;
|
||||
if (kwb->target_subsong - 1 < current_subsongs || kwb->target_subsong > kwb->total_subsongs)
|
||||
return 1;
|
||||
kwb->found = 1;
|
||||
|
||||
header_offset = smpl_offset + 0x10 + (kwb->target_subsong-1) * entry_size;
|
||||
relative_subsong = kwb->target_subsong - current_subsongs;
|
||||
header_offset = smpl_offset + 0x10 + (relative_subsong-1) * entry_size;
|
||||
|
||||
/* 00: "SS" + ID (0..N) */
|
||||
kwb->stream_offset = read_u32be(header_offset + 0x04, sf_h);
|
||||
|
@ -427,11 +464,14 @@ static int parse_type_sdwi(kwb_header* kwb, off_t offset, STREAMFILE* sf_h) {
|
|||
kwb->codec = DSP_BODY;
|
||||
kwb->channels = 1;
|
||||
|
||||
kwb->stream_offset += body_offset;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int parse_kwb(kwb_header* kwb, STREAMFILE* sf_h, STREAMFILE* sf_b) {
|
||||
off_t head_offset, body_offset, start;
|
||||
uint32_t type;
|
||||
|
@ -485,22 +525,22 @@ static int parse_kwb(kwb_header* kwb, STREAMFILE* sf_h, STREAMFILE* sf_b) {
|
|||
switch(type) {
|
||||
case 0x4B574232: /* "KWB2" [Bladestorm Nightmare (PC), Dissidia NT (PC)] */
|
||||
case 0x4B57424E: /* "KWBN" [Fire Emblem Warriors (Switch)] */
|
||||
if (!parse_type_kwb2(kwb, head_offset, sf_h))
|
||||
if (!parse_type_kwb2(kwb, head_offset, body_offset, sf_h))
|
||||
goto fail;
|
||||
break;
|
||||
|
||||
case 0x4B344844: /* "K4HD" [Dissidia NT (PS4), (Vita) */
|
||||
if (!parse_type_k4hd(kwb, head_offset, sf_h))
|
||||
if (!parse_type_k4hd(kwb, head_offset, body_offset, sf_h))
|
||||
goto fail;
|
||||
break;
|
||||
|
||||
case 0x53447364: /* "SDsd" (PS3? leftover files) */
|
||||
if (!parse_type_sdsd(kwb, head_offset, sf_h))
|
||||
if (!parse_type_sdsd(kwb, head_offset, body_offset, sf_h))
|
||||
goto fail;
|
||||
break;
|
||||
|
||||
case 0x53445769: /* "SDWi" [Fatal Frame 5 (WiiU)] */
|
||||
if (!parse_type_sdwi(kwb, head_offset, sf_h))
|
||||
if (!parse_type_sdwi(kwb, head_offset, body_offset, sf_h))
|
||||
goto fail;
|
||||
break;
|
||||
|
||||
|
@ -508,7 +548,8 @@ static int parse_kwb(kwb_header* kwb, STREAMFILE* sf_h, STREAMFILE* sf_b) {
|
|||
goto fail;
|
||||
}
|
||||
|
||||
kwb->stream_offset += body_offset;
|
||||
if (!kwb->found)
|
||||
goto fail;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
|
@ -517,17 +558,112 @@ fail:
|
|||
|
||||
static int parse_type_msfbank(kwb_header* kwb, off_t offset, STREAMFILE* sf) {
|
||||
/* this is just like XWSF, abridged: */
|
||||
int entries, current_subsongs, relative_subsong;
|
||||
off_t header_offset;
|
||||
|
||||
entries = read_u32be(offset + 0x14, sf);
|
||||
|
||||
kwb->total_subsongs = read_u32be(offset + 0x14, sf);
|
||||
if (kwb->target_subsong < 0 || kwb->target_subsong > kwb->total_subsongs || kwb->total_subsongs < 1) goto fail;
|
||||
current_subsongs = kwb->total_subsongs;
|
||||
kwb->total_subsongs += entries;
|
||||
if (kwb->target_subsong - 1 < current_subsongs || kwb->target_subsong > kwb->total_subsongs)
|
||||
return 1;
|
||||
kwb->found = 1;
|
||||
|
||||
header_offset = offset + 0x30 + (kwb->target_subsong-1) * 0x04;
|
||||
relative_subsong = kwb->target_subsong - current_subsongs;
|
||||
header_offset = offset + 0x30 + (relative_subsong-1) * 0x04;
|
||||
|
||||
/* just a dumb table pointing to MSF, entries can be dummy */
|
||||
kwb->stream_offset = read_u32be(header_offset, sf);
|
||||
kwb->stream_offset = read_u32be(header_offset, sf);
|
||||
kwb->codec = MSF;
|
||||
|
||||
kwb->stream_offset += offset;
|
||||
|
||||
return 1;
|
||||
//fail:
|
||||
// return 0;
|
||||
}
|
||||
|
||||
static int parse_type_xwsfile(kwb_header* kwb, off_t offset, STREAMFILE* sf) {
|
||||
off_t table1_offset, table2_offset;
|
||||
int i, chunks, chunks2;
|
||||
uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL;
|
||||
|
||||
|
||||
if (!(is_id32be(offset + 0x00, sf, "XWSF") && is_id32be(offset + 0x04, sf, "ILE\0")) &&
|
||||
!(is_id32be(offset + 0x00, sf, "tdpa") && is_id32be(offset + 0x04, sf, "ck\0\0")))
|
||||
goto fail;
|
||||
|
||||
kwb->big_endian = read_u8(offset + 0x08, sf) == 0xFF;
|
||||
/* 0x0a: version? (0100: NG2/NG3 PS3, 0101: DoA LR PC) */
|
||||
|
||||
read_u32 = kwb->big_endian ? read_u32be : read_u32le;
|
||||
|
||||
/* 0x0c: tables start */
|
||||
/* 0x10: file size */
|
||||
chunks = read_u32(offset + 0x14, sf);
|
||||
chunks2 = read_u32(offset + 0x18, sf);
|
||||
/* 0x1c: null */
|
||||
if (chunks != chunks2)
|
||||
goto fail;
|
||||
|
||||
table1_offset = read_u32(offset + 0x20, sf); /* offsets */
|
||||
table2_offset = read_u32(offset + 0x24, sf); /* sizes */
|
||||
/* 0x28: null */
|
||||
/* 0x2c: null */
|
||||
|
||||
|
||||
i = 0;
|
||||
while (i < chunks) {
|
||||
uint32_t entry_type, head_offset, body_offset, head_size;
|
||||
//;VGM_LOG("XWS: entry %i/%i\n", i, chunks);
|
||||
|
||||
/* NG2/NG3 PS3 have table1+2, DoA LR PC removes table2 and includes body offset in entries */
|
||||
if (table2_offset) {
|
||||
head_offset = read_u32(offset + table1_offset + i * 0x04 + 0x00, sf);
|
||||
head_size = read_u32(offset + table2_offset + i * 0x04 + 0x00, sf);
|
||||
body_offset = head_offset;
|
||||
i += 1;
|
||||
|
||||
/* sometimes has file end offset as entry with no size*/
|
||||
if (!head_size)
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
head_offset = read_u32(offset + table1_offset + i * 0x04 + 0x00, sf);
|
||||
body_offset = read_u32(offset + table1_offset + i * 0x04 + 0x04, sf);
|
||||
i += 2;
|
||||
}
|
||||
|
||||
if (!head_offset) /* just in case */
|
||||
continue;
|
||||
|
||||
|
||||
head_offset += offset;
|
||||
body_offset += offset;
|
||||
entry_type = read_u32be(head_offset + 0x00, sf);
|
||||
//;VGM_LOG("XWS: head=%x, body=%x\n", head_offset, body_offset);
|
||||
|
||||
if (entry_type == get_id32be("XWSF")) { /* + "ILE\0" */
|
||||
if (!parse_type_xwsfile(kwb, head_offset, sf))
|
||||
goto fail;
|
||||
}
|
||||
else if (entry_type == get_id32be("CUEB") || entry_type < 0x100) {
|
||||
; /* CUE-like info (may start with 0 or a low number instead) */
|
||||
}
|
||||
else if (entry_type == get_id32be("MSFB")) { /* + "ANK\0" */
|
||||
if (!parse_type_msfbank(kwb, head_offset, sf))
|
||||
goto fail;
|
||||
}
|
||||
else if (entry_type == get_id32be("KWB2")) {
|
||||
if (!parse_type_kwb2(kwb, head_offset, body_offset, sf))
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
VGM_LOG("XWS: unknown type %x at head=%x, body=%x\n", entry_type, head_offset, body_offset);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
|
@ -535,59 +671,23 @@ fail:
|
|||
|
||||
|
||||
static int parse_xws(kwb_header* kwb, STREAMFILE* sf) {
|
||||
off_t head_offset, body_offset, start;
|
||||
uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL;
|
||||
int chunks, chunks2;
|
||||
off_t msfb_offset;
|
||||
|
||||
/* format is similar to WHD1 with some annoyances of its own
|
||||
* variations:
|
||||
* - tdpack: points to N XWSFILE
|
||||
* - XWSFILE w/ 4 chunks: CUEBANK offset, ? offset, MSFBANK offset, end offset (PS3)
|
||||
/* Format is similar to WHD1 with some annoyances of its own. Variations:
|
||||
* - XWSFILE w/ N chunks: CUE offsets + 1 MSFBANK offset
|
||||
* [Ninja Gaiden Sigma 2 (PS3), Ninja Gaiden 3 Razor's Edge (PS3)]
|
||||
* - XWSFILE w/ 2*N chunks: KWB2 offset + data offset * N (ex. 3 pairs = 6 chunks)
|
||||
* [Dead or Alive 5 Last Round (PC)]
|
||||
* - tdpack: same but points to N XWSFILE
|
||||
* [Ninja Gaiden 3 Razor's Edge (PS3)]
|
||||
*
|
||||
* for now basic support for the second case, others we'd have to map subsong N to internal bank M
|
||||
* Needs to call sub-parts multiple times to fill total subsongs when parsing xwsfile.
|
||||
*/
|
||||
|
||||
if (read_u32be(0x00, sf) != 0x58575346 || /* "XWSF" */
|
||||
read_u32be(0x04, sf) != 0x494C4500) /* "ILE\0" */
|
||||
if (!parse_type_xwsfile(kwb, 0x00, sf))
|
||||
goto fail;
|
||||
|
||||
kwb->big_endian = read_u8(0x08, sf) == 0xFF;
|
||||
/* 0x0a: version? */
|
||||
|
||||
read_u32 = kwb->big_endian ? read_u32be : read_u32le;
|
||||
|
||||
start = read_u32(0x0c, sf);
|
||||
/* 0x10: file size */
|
||||
chunks = read_u32(0x14, sf);
|
||||
chunks2 = read_u32(0x18, sf);
|
||||
/* 0x1c: null */
|
||||
/* 0x20: some size? */
|
||||
/* 0x24: some size? */
|
||||
if (chunks != chunks2)
|
||||
if (!kwb->found)
|
||||
goto fail;
|
||||
|
||||
if (chunks != 4)
|
||||
goto fail;
|
||||
|
||||
msfb_offset = read_u32(start + 0x08, sf);
|
||||
if (read_u32be(msfb_offset, sf) == 0x4D534642) { /* "MSFB" + "ANK\0" */
|
||||
head_offset = msfb_offset;
|
||||
body_offset = msfb_offset; /* relative to start */
|
||||
|
||||
if (!parse_type_msfbank(kwb, head_offset, sf))
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
kwb->stream_offset += body_offset;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
|
|
|
@ -934,4 +934,6 @@ VGMSTREAM *init_vgmstream_sbk(STREAMFILE *sf);
|
|||
|
||||
VGMSTREAM* init_vgmstream_ifs(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_acx(STREAMFILE* sf);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
|
|
@ -660,6 +660,8 @@ VGMSTREAM* init_vgmstream_sadb(STREAMFILE* sf) {
|
|||
dspm.start_offset = read_32bitBE(0x48,sf);
|
||||
dspm.interleave = 0x10;
|
||||
|
||||
dspm.ignore_loop_ps = 1; /* does something strange with offsets/etc, ignore */
|
||||
|
||||
dspm.meta_type = meta_DSP_SADB;
|
||||
return init_vgmstream_dsp_common(sf, &dspm);
|
||||
fail:
|
||||
|
|
|
@ -3,66 +3,71 @@
|
|||
|
||||
|
||||
/* EXST - from Sony games [Shadow of the Colossus (PS2), Gacha Mecha Stadium Saru Battle (PS2)] */
|
||||
VGMSTREAM * init_vgmstream_ps2_exst(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamBody = NULL;
|
||||
VGMSTREAM* init_vgmstream_ps2_exst(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* sf_body = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
int loop_flag, channels, sample_rate;
|
||||
size_t block_size, num_blocks, loop_start_block;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .sts+int: main [Shadow of the Colossus (PS2)] (some .sts have manually joined header+body)
|
||||
/* .sts+int: standard [Shadow of the Colossus (PS2)] (some fake .sts have manually joined header+body)
|
||||
* .x: header+body [Ape Escape 3 (PS2)] */
|
||||
if (!check_extensions(streamFile, "sts,x"))
|
||||
if (!check_extensions(sf, "sts,x"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x45585354) /* "EXST" */
|
||||
if (!is_id32be(0x00,sf, "EXST"))
|
||||
goto fail;
|
||||
|
||||
streamBody = open_streamfile_by_ext(streamFile,"int");
|
||||
if (!streamBody) {
|
||||
/* data+body joined */
|
||||
start_offset = 0x78;
|
||||
if (get_streamfile_size(streamFile) < start_offset)
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
/* body is separate */
|
||||
sf_body = open_streamfile_by_ext(sf,"int");
|
||||
if (sf_body) {
|
||||
/* separate header+body (header is 0x78) */
|
||||
start_offset = 0x00;
|
||||
}
|
||||
else {
|
||||
/* joint header+body */
|
||||
start_offset = 0x78;
|
||||
/* Gacharoku 2 has header+data but padded header (ELF has pointers + size to SOUND.PCK, and
|
||||
* treats them as single files, no extension but there are Sg2ExStAdpcm* calls in the ELF) */
|
||||
if ((get_streamfile_size(sf) % 0x10) == 0)
|
||||
start_offset = 0x80;
|
||||
|
||||
if (get_streamfile_size(sf) < start_offset)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
channel_count = read_16bitLE(0x06,streamFile);
|
||||
loop_flag = read_32bitLE(0x0C,streamFile) == 1;
|
||||
loop_start_block = read_32bitLE(0x10,streamFile);
|
||||
num_blocks = read_32bitLE(0x14,streamFile);
|
||||
channels = read_u16le(0x06,sf);
|
||||
sample_rate = read_u32le(0x08,sf);
|
||||
loop_flag = read_u32le(0x0C,sf) == 1;
|
||||
loop_start_block = read_u32le(0x10,sf);
|
||||
num_blocks = read_u32le(0x14,sf);
|
||||
/* 0x18: 0x24 config per channel? (volume+panning+etc?) */
|
||||
/* rest is padding up to 0x78 */
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
|
||||
vgmstream->meta_type = meta_PS2_EXST;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x400;
|
||||
|
||||
block_size = vgmstream->interleave_block_size * vgmstream->channels;
|
||||
vgmstream->num_samples = ps_bytes_to_samples(num_blocks*block_size, channel_count);
|
||||
if (vgmstream->loop_flag) {
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start_block*block_size, channel_count);;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
vgmstream->num_samples = ps_bytes_to_samples(num_blocks * block_size, channels);
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start_block * block_size, channels);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamBody ? streamBody : streamFile,start_offset))
|
||||
if (!vgmstream_open_stream(vgmstream, sf_body ? sf_body : sf, start_offset))
|
||||
goto fail;
|
||||
close_streamfile(streamBody);
|
||||
close_streamfile(sf_body);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(streamBody);
|
||||
close_streamfile(sf_body);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
typedef enum { CODEC_NONE = 0, UBI_IMA, RAW_PCM, RAW_PSX, RAW_XMA1, RAW_XMA2_OLD, RAW_XMA2_NEW, RAW_AT3, RAW_AT3_105, FMT_AT3, RAW_DSP, FMT_OGG } ubi_bao_codec;
|
||||
typedef enum { TYPE_NONE = 0, UBI_AUDIO, UBI_LAYER, UBI_SEQUENCE, UBI_SILENCE } ubi_bao_type;
|
||||
typedef enum { FILE_NONE = 0, UBI_FORGE, UBI_FORGE_b } ubi_bao_file;
|
||||
typedef enum { FILE_NONE = 0, UBI_FORGE, UBI_FORGE_b, UBI_FAT } ubi_bao_file;
|
||||
|
||||
typedef struct {
|
||||
size_t bao_class;
|
||||
|
@ -1403,6 +1403,13 @@ static STREAMFILE* open_atomic_bao(ubi_bao_file file_type, uint32_t file_id, int
|
|||
|
||||
goto fail;
|
||||
|
||||
case UBI_FAT:
|
||||
snprintf(buf,buf_size, "%08x.bao", file_id);
|
||||
sf_bao = open_streamfile_by_filename(sf, buf);
|
||||
if (sf_bao) return sf_bao;
|
||||
|
||||
goto fail;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
@ -1747,6 +1754,30 @@ static int config_bao_version(ubi_bao_header* bao, STREAMFILE* sf) {
|
|||
bao->cfg.file_type = UBI_FORGE;
|
||||
return 1;
|
||||
|
||||
case 0x001B0200: /* Beowulf (PS3/X360)-atomic-bin+fat */
|
||||
config_bao_entry(bao, 0xA0, 0x24);
|
||||
|
||||
config_bao_audio_b(bao, 0x08, 0x1c, 0x28, 0x34, 1, 1); /* 0x2c: prefetch flag? */
|
||||
config_bao_audio_m(bao, 0x44, 0x48, 0x50, 0x58, 0x64, 0x74);
|
||||
bao->cfg.audio_interleave = 0x10;
|
||||
bao->cfg.audio_fix_psx_samples = 1;
|
||||
|
||||
config_bao_sequence(bao, 0x2c, 0x20, 0x1c, 0x14);
|
||||
|
||||
config_bao_layer_m(bao, 0x4c, 0x20, 0x2c, 0x44, 0x00, 0x50, 0x00, 0x00, 1); /* stream size: 0x48? */
|
||||
config_bao_layer_e(bao, 0x30, 0x00, 0x04, 0x08, 0x10);
|
||||
|
||||
config_bao_silence_f(bao, 0x1c);
|
||||
|
||||
bao->cfg.codec_map[0x00] = RAW_XMA1;
|
||||
bao->cfg.codec_map[0x02] = RAW_PSX;
|
||||
bao->cfg.codec_map[0x03] = UBI_IMA;
|
||||
bao->cfg.codec_map[0x04] = FMT_OGG;
|
||||
bao->cfg.codec_map[0x07] = RAW_AT3_105;
|
||||
|
||||
bao->cfg.file_type = UBI_FAT;
|
||||
return 1;
|
||||
|
||||
case 0x001F0008: /* Rayman Raving Rabbids: TV Party (Wii)-package */
|
||||
case 0x001F0010: /* Prince of Persia 2008 (PC/PS3/X360)-atomic-forge, Far Cry 2 (PS3)-atomic-dunia? */
|
||||
case 0x001F0011: /* Naruto: The Broken Bond (X360)-package */
|
||||
|
@ -1879,9 +1910,6 @@ static int config_bao_version(ubi_bao_header* bao, STREAMFILE* sf) {
|
|||
bao->cfg.file_type = UBI_FORGE_b;
|
||||
return 1;
|
||||
|
||||
case 0x001B0200: /* Beowulf (PS3)-atomic-bin+fat */
|
||||
/* same as 0x001B0100 except:
|
||||
* - base 0xA0, skip 0x24, name style %08x (.bao/sbao?) */
|
||||
case 0x001C0000: /* Lost: Via Domus (PS3)-atomic-gear */
|
||||
/* same as 0x001B0100 except:
|
||||
* - base 0xA0, skip 0x24, name style %08x.bao (not .sbao?) */
|
||||
|
|
|
@ -3988,9 +3988,11 @@ static int config_sb_version(ubi_sb_header* sb, STREAMFILE* sf) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Naruto: Rise of a Ninja (2007)(X360)-bank */
|
||||
/* Rainbow Six Vegas 2 (2008)(PS3)-bank */
|
||||
/* Rainbow Six Vegas 2 (2008)(X360)-bank */
|
||||
if ((sb->version == 0x001C0000 && sb->platform == UBI_PS3) ||
|
||||
if ((sb->version == 0x001B0001 && sb->platform == UBI_X360) ||
|
||||
(sb->version == 0x001C0000 && sb->platform == UBI_PS3) ||
|
||||
(sb->version == 0x001C0000 && sb->platform == UBI_X360)) {
|
||||
config_sb_entry(sb, 0x64, 0x7c);
|
||||
|
||||
|
|
|
@ -96,7 +96,8 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
|||
switch(ww.codec) {
|
||||
case PCM: /* common */
|
||||
/* normally riff.c has priority but it's needed when .wem is used */
|
||||
if (ww.fmt_size != 0x10 && ww.fmt_size != 0x18 && ww.fmt_size != 0x28) goto fail; /* old, new/Limbo (PC) */
|
||||
/* old=0x10, 0x12=Army of Two: the 40th Day (PS3), new/Limbo (PC) */
|
||||
if (ww.fmt_size != 0x10 && ww.fmt_size != 0x12 && ww.fmt_size != 0x18 && ww.fmt_size != 0x28) goto fail;
|
||||
if (ww.bits_per_sample != 16) goto fail;
|
||||
|
||||
vgmstream->coding_type = (ww.big_endian ? coding_PCM16BE : coding_PCM16LE);
|
||||
|
|
|
@ -12,13 +12,14 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
|||
int big_endian, flags, codec, sample_rate, block_align, bps;
|
||||
size_t data_size;
|
||||
char platform;
|
||||
int is_ogg = 0, is_at9 = 0;
|
||||
int is_sound = 0, is_ogg = 0, is_at9 = 0, is_song = 0;
|
||||
char song_name[255+1];
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf,"xnb"))
|
||||
goto fail;
|
||||
if ((read_32bitBE(0x00, sf) & 0xFFFFFF00) != 0x584E4200) /* "XNB" */
|
||||
if ((read_u32be(0x00, sf) & 0xFFFFFF00) != get_id32be("XNB\0"))
|
||||
goto fail;
|
||||
|
||||
/* XNA Studio platforms: 'w' = Windows, 'm' = Windows Phone 7, 'x' = X360
|
||||
|
@ -32,9 +33,9 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
|||
|
||||
flags = read_u8(0x05, sf);
|
||||
//if (flags & 0x01) goto fail; /* "HiDef profile" content (no actual difference) */
|
||||
|
||||
|
||||
/* full size */
|
||||
if (read_32bitLE(0x06, sf) != get_streamfile_size(sf)) {
|
||||
if (read_u32le(0x06, sf) != get_streamfile_size(sf)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -59,49 +60,73 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
|||
/* XNB contains "type reader" class references to parse "shared resource" data (can be any implemented filetype) */
|
||||
{
|
||||
char reader_name[255+1];
|
||||
size_t reader_string_len;
|
||||
uint32_t fmt_chunk_size;
|
||||
const char* type_sound = "Microsoft.Xna.Framework.Content.SoundEffectReader"; /* partial "fmt" chunk or XMA */
|
||||
const char* type_ogg = "SoundEffectFromOggReader"; /* has extra text info after base part */
|
||||
//const char* type_song = "Microsoft.Xna.Framework.Content.SongReader"; /* references a companion .wma */
|
||||
size_t string_len;
|
||||
uint8_t type_count;
|
||||
const static char* type_sound = "Microsoft.Xna.Framework.Content.SoundEffectReader"; /* partial "fmt" chunk or XMA */
|
||||
const static char* type_ogg = "SoundEffectFromOggReader"; /* has extra text info after base part */
|
||||
const static char* type_song = "Microsoft.Xna.Framework.Content.SongReader"; /* references a companion .wma */
|
||||
const static char* type_int32 = "Microsoft.Xna.Framework.Content.Int32Reader"; /* extra crap */
|
||||
|
||||
/* type reader count, accept only one for now */
|
||||
if (read_u8(offset++, sf_h) != 1)
|
||||
type_count = read_u8(offset++, sf_h);
|
||||
|
||||
/* check type reader string */
|
||||
string_len = read_u8(offset++, sf_h); /* doesn't count null */
|
||||
if (read_string(reader_name, string_len+1, offset, sf_h) != string_len)
|
||||
goto fail;
|
||||
|
||||
reader_string_len = read_u8(offset++, sf_h); /* doesn't count null */
|
||||
if (reader_string_len > 255) goto fail;
|
||||
|
||||
/* check SoundEffect type string */
|
||||
if (read_string(reader_name, reader_string_len+1, offset, sf_h) != reader_string_len)
|
||||
if (strcmp(reader_name, type_sound) == 0) {
|
||||
if (type_count != 1) goto fail;
|
||||
is_sound = 1;
|
||||
}
|
||||
else if (strncmp(reader_name, type_ogg, strlen(type_ogg)) == 0) { /* has extra info after base string */
|
||||
if (type_count != 1) goto fail;
|
||||
is_ogg = 1;
|
||||
}
|
||||
else if (strcmp(reader_name, type_song) == 0) {
|
||||
if (type_count != 2) goto fail;
|
||||
is_song = 1;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
if (strcmp(reader_name, type_sound) != 0) {
|
||||
is_ogg = strncmp(reader_name, type_ogg, strlen(type_ogg)) == 0;
|
||||
if (!is_ogg)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
offset += reader_string_len + 1;
|
||||
offset += string_len + 1;
|
||||
|
||||
if (is_song) {
|
||||
offset += 3;
|
||||
|
||||
string_len = read_u8(offset++, sf_h);
|
||||
if (read_string(reader_name, string_len+1, offset, sf_h) != string_len)
|
||||
goto fail;
|
||||
|
||||
if (strcmp(reader_name, type_int32) != 0)
|
||||
goto fail;
|
||||
|
||||
offset += string_len + 1;
|
||||
}
|
||||
|
||||
offset += 0x04; /* reader version, 0 */
|
||||
|
||||
/* shared resource count */
|
||||
/* shared resource number 1 */
|
||||
if (read_u8(offset++, sf_h) != 1)
|
||||
goto fail;
|
||||
|
||||
/* shared resource: partial "fmt" chunk */
|
||||
fmt_chunk_size = read_32bitLE(offset, sf_h);
|
||||
offset += 0x04;
|
||||
/* read shared resource */
|
||||
if (is_sound || is_ogg) {
|
||||
/* partial "fmt" chunk */
|
||||
uint32_t (*read_u32)(off_t,STREAMFILE*) = big_endian ? read_u32be : read_u32le;
|
||||
uint16_t (*read_u16)(off_t,STREAMFILE*) = big_endian ? read_u16be : read_u16le;
|
||||
uint32_t fmt_chunk_size;
|
||||
|
||||
{
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE;
|
||||
fmt_chunk_size = read_u32le(offset, sf_h);
|
||||
offset += 0x04;
|
||||
|
||||
codec = (uint16_t)read_16bit(offset+0x00, sf_h);
|
||||
channel_count = read_16bit(offset+0x02, sf_h);
|
||||
sample_rate = read_32bit(offset+0x04, sf_h);
|
||||
codec = read_u16(offset+0x00, sf_h);
|
||||
channel_count = read_u16(offset+0x02, sf_h);
|
||||
sample_rate = read_u32(offset+0x04, sf_h);
|
||||
/* 0x08: byte rate */
|
||||
block_align = read_16bit(offset+0x0c, sf_h);
|
||||
bps = read_16bit(offset+0x0e, sf_h);
|
||||
block_align = read_u16(offset+0x0c, sf_h);
|
||||
bps = read_u16(offset+0x0e, sf_h);
|
||||
|
||||
if (codec == 0x0002) {
|
||||
if (!msadpcm_check_coefs(sf_h, offset + 0x14))
|
||||
|
@ -115,30 +140,44 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
|||
|
||||
if (codec == 0xFFFF) {
|
||||
if (platform != 'S') goto fail;
|
||||
sample_rate = read_32bit(offset+fmt_chunk_size+0x04+0x08, sf_h);
|
||||
sample_rate = read_u32(offset+fmt_chunk_size+0x04+0x08, sf_h);
|
||||
}
|
||||
|
||||
/* mini-fmt has AT9 stuff then a regular RIFF [Square Heroes (PS4)] */
|
||||
if (codec == 0xFFFE) {
|
||||
is_at9 = 1;
|
||||
}
|
||||
|
||||
/* regular (with loop tags) Ogg poses as PCM [Little Savior (PC)] */
|
||||
|
||||
/* Ogg (with loop tags) poses as PCM [Little Savior (PC)] */
|
||||
|
||||
offset += fmt_chunk_size;
|
||||
|
||||
data_size = read_u32le(offset, sf_h);
|
||||
offset += 0x04;
|
||||
|
||||
start_offset = offset;
|
||||
}
|
||||
else if (is_song) {
|
||||
/* filename (typically same as .xnb but .wma) */
|
||||
string_len = read_u8(offset++, sf_h);
|
||||
|
||||
offset += fmt_chunk_size;
|
||||
if (read_string(song_name, string_len+1, offset, sf_h) != string_len + 1)
|
||||
goto fail;
|
||||
|
||||
data_size = read_32bitLE(offset, sf_h);
|
||||
offset += 0x04;
|
||||
|
||||
start_offset = offset;
|
||||
start_offset = 0;
|
||||
data_size = 0;
|
||||
/* after name is shared resource number 1 + 32b int (durationMs?) */
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* container handling */
|
||||
if (is_ogg || is_at9) {
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
const char* fake_ext = is_ogg ? "ogg" : "at9";
|
||||
|
||||
|
||||
/* after data_size is loop start + loop length and offset? (same as loop tags), 0 if not enabled */
|
||||
|
||||
temp_sf = setup_subfile_streamfile(sf_h, start_offset, data_size, fake_ext);
|
||||
|
@ -158,6 +197,31 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
|||
if (sf_h != sf) close_streamfile(sf_h);
|
||||
return vgmstream;
|
||||
}
|
||||
else if (is_song) {
|
||||
STREAMFILE* sf_body = open_streamfile_by_filename(sf, song_name);
|
||||
if (!sf_body) goto fail;
|
||||
|
||||
if (read_u32be(0x00, sf_body) == 0x01000080) {
|
||||
STREAMFILE* temp_sf = setup_subfile_streamfile(sf_body, 0x00, get_streamfile_size(sf_body), "opus");
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
/* MonoGame with NXOpus [Clan N (Switch)] */
|
||||
vgmstream = init_vgmstream_opus_std(temp_sf);
|
||||
close_streamfile(temp_sf);
|
||||
}
|
||||
else {
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
/* XNA with WMA [Guncraft: Blocked and Loaded (X360)] */
|
||||
vgmstream = init_vgmstream_ffmpeg(sf_body);
|
||||
#endif
|
||||
}
|
||||
close_streamfile(sf_body);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_XNB;
|
||||
if (sf_h != sf) close_streamfile(sf_h);
|
||||
return vgmstream;
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
@ -221,7 +285,7 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
|||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = data_size / channel_count;
|
||||
vgmstream->num_samples = read_32bitLE(start_offset + 0x00, sf_h);
|
||||
vgmstream->num_samples = read_s32le(start_offset + 0x00, sf_h);
|
||||
//vgmstream->num_samples = dsp_bytes_to_samples(data_size - 0x60*channel_count, channel_count);
|
||||
|
||||
dsp_read_coefs(vgmstream, sf_h, start_offset + 0x1c, vgmstream->interleave_block_size, big_endian);
|
||||
|
|
|
@ -861,15 +861,15 @@ STREAMFILE* open_multifile_streamfile_f(STREAMFILE **streamfiles, size_t streamf
|
|||
|
||||
/* **************************************************** */
|
||||
|
||||
STREAMFILE* open_streamfile(STREAMFILE *streamfile, const char *pathname) {
|
||||
return streamfile->open(streamfile, pathname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
STREAMFILE* open_streamfile(STREAMFILE* sf, const char* pathname) {
|
||||
return sf->open(sf, pathname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
STREAMFILE* open_streamfile_by_ext(STREAMFILE *streamfile, const char *ext) {
|
||||
STREAMFILE* open_streamfile_by_ext(STREAMFILE* sf, const char* ext) {
|
||||
char filename[PATH_LIMIT];
|
||||
int filename_len, fileext_len;
|
||||
|
||||
streamfile->get_name(streamfile, filename, sizeof(filename));
|
||||
sf->get_name(sf, filename, sizeof(filename));
|
||||
|
||||
filename_len = strlen(filename);
|
||||
fileext_len = strlen(filename_extension(filename));
|
||||
|
@ -882,17 +882,17 @@ STREAMFILE* open_streamfile_by_ext(STREAMFILE *streamfile, const char *ext) {
|
|||
strcpy(filename + filename_len - fileext_len, ext);
|
||||
}
|
||||
|
||||
return streamfile->open(streamfile, filename, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
return sf->open(sf, filename, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
STREAMFILE* open_streamfile_by_filename(STREAMFILE *streamfile, const char * filename) {
|
||||
STREAMFILE* open_streamfile_by_filename(STREAMFILE* sf, const char* filename) {
|
||||
char fullname[PATH_LIMIT];
|
||||
char partname[PATH_LIMIT];
|
||||
char *path, *name;
|
||||
|
||||
if (!streamfile || !filename || !filename[0]) return NULL;
|
||||
if (!sf || !filename || !filename[0]) return NULL;
|
||||
|
||||
streamfile->get_name(streamfile, fullname, sizeof(fullname));
|
||||
sf->get_name(sf, fullname, sizeof(fullname));
|
||||
|
||||
//todo normalize separators in a better way, safeops, improve copying
|
||||
path = strrchr(fullname,DIR_SEPARATOR);
|
||||
|
@ -903,10 +903,10 @@ STREAMFILE* open_streamfile_by_filename(STREAMFILE *streamfile, const char * fil
|
|||
fix_dir_separators(partname);
|
||||
|
||||
/* normalize relative paths as don't work ok in some plugins */
|
||||
if (partname[0]=='.' && partname[1] == DIR_SEPARATOR) { /* './name' */
|
||||
if (partname[0] == '.' && partname[1] == DIR_SEPARATOR) { /* './name' */
|
||||
name = partname + 2; /* ignore './' */
|
||||
}
|
||||
else if (partname[0]=='.' && partname[1]=='.' && partname[2] == DIR_SEPARATOR) { /* '../name' */
|
||||
else if (partname[0] == '.' && partname[1] == '.' && partname[2] == DIR_SEPARATOR) { /* '../name' */
|
||||
char *pathprev;
|
||||
|
||||
path[0] = '\0'; /* remove last separator so next call works */
|
||||
|
@ -931,23 +931,23 @@ STREAMFILE* open_streamfile_by_filename(STREAMFILE *streamfile, const char * fil
|
|||
strcpy(fullname, filename);
|
||||
}
|
||||
|
||||
return streamfile->open(streamfile, fullname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
return sf->open(sf, fullname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
STREAMFILE* reopen_streamfile(STREAMFILE *streamfile, size_t buffer_size) {
|
||||
STREAMFILE* reopen_streamfile(STREAMFILE* sf, size_t buffer_size) {
|
||||
char pathname[PATH_LIMIT];
|
||||
|
||||
if (!streamfile) return NULL;
|
||||
if (!sf) return NULL;
|
||||
|
||||
if (buffer_size == 0)
|
||||
buffer_size = STREAMFILE_DEFAULT_BUFFER_SIZE;
|
||||
streamfile->get_name(streamfile,pathname,sizeof(pathname));
|
||||
return streamfile->open(streamfile,pathname,buffer_size);
|
||||
sf->get_name(sf, pathname,sizeof(pathname));
|
||||
return sf->open(sf, pathname, buffer_size);
|
||||
}
|
||||
|
||||
/* **************************************************** */
|
||||
|
||||
size_t read_line(char *buf, int buf_size, off_t offset, STREAMFILE *sf, int *p_line_ok) {
|
||||
size_t read_line(char* buf, int buf_size, off_t offset, STREAMFILE* sf, int* p_line_ok) {
|
||||
int i;
|
||||
off_t file_size = get_streamfile_size(sf);
|
||||
int extra_bytes = 0; /* how many bytes over those put in the buffer were read */
|
||||
|
@ -996,7 +996,7 @@ size_t read_line(char *buf, int buf_size, off_t offset, STREAMFILE *sf, int *p_l
|
|||
return i + extra_bytes;
|
||||
}
|
||||
|
||||
size_t read_string(char *buf, size_t buf_size, off_t offset, STREAMFILE *sf) {
|
||||
size_t read_string(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf) {
|
||||
size_t pos;
|
||||
|
||||
for (pos = 0; pos < buf_size; pos++) {
|
||||
|
@ -1019,7 +1019,7 @@ fail:
|
|||
return 0;
|
||||
}
|
||||
|
||||
size_t read_string_utf16(char *buf, size_t buf_size, off_t offset, STREAMFILE *sf, int big_endian) {
|
||||
size_t read_string_utf16(char* buf, size_t buf_size, off_t offset, STREAMFILE* sf, int big_endian) {
|
||||
size_t pos, offpos;
|
||||
uint16_t (*read_u16)(off_t,STREAMFILE*) = big_endian ? read_u16be : read_u16le;
|
||||
|
||||
|
@ -1049,16 +1049,16 @@ size_t read_string_utf16be(char* buf, size_t buf_size, off_t offset, STREAMFILE*
|
|||
return read_string_utf16(buf, buf_size, offset, sf, 1);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
|
||||
size_t read_key_file(uint8_t *buf, size_t buf_size, STREAMFILE *sf) {
|
||||
size_t read_key_file(uint8_t* buf, size_t buf_size, STREAMFILE* sf) {
|
||||
char keyname[PATH_LIMIT];
|
||||
char filename[PATH_LIMIT];
|
||||
const char *path, *ext;
|
||||
STREAMFILE * streamFileKey = NULL;
|
||||
STREAMFILE* sf_key = NULL;
|
||||
size_t keysize;
|
||||
|
||||
sf->get_name(sf,filename,sizeof(filename));
|
||||
get_streamfile_name(sf, filename, sizeof(filename));
|
||||
|
||||
if (strlen(filename)+4 > sizeof(keyname)) goto fail;
|
||||
|
||||
|
@ -1067,20 +1067,20 @@ size_t read_key_file(uint8_t *buf, size_t buf_size, STREAMFILE *sf) {
|
|||
ext = strrchr(filename,'.');
|
||||
if (ext!=NULL) ext = ext+1;
|
||||
|
||||
path = strrchr(filename,DIR_SEPARATOR);
|
||||
path = strrchr(filename, DIR_SEPARATOR);
|
||||
if (path!=NULL) path = path+1;
|
||||
|
||||
/* "(name.ext)key" */
|
||||
strcpy(keyname, filename);
|
||||
strcat(keyname, "key");
|
||||
streamFileKey = sf->open(sf,keyname,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (streamFileKey) goto found;
|
||||
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (sf_key) goto found;
|
||||
|
||||
/* "(name.ext)KEY" */
|
||||
/*
|
||||
strcpy(keyname+strlen(keyname)-3,"KEY");
|
||||
streamFileKey = streamFile->open(streamFile,keyname,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (streamFileKey) goto found;
|
||||
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (sf_key) goto found;
|
||||
*/
|
||||
|
||||
|
||||
|
@ -1094,38 +1094,38 @@ size_t read_key_file(uint8_t *buf, size_t buf_size, STREAMFILE *sf) {
|
|||
}
|
||||
if (ext) strcat(keyname, ext);
|
||||
strcat(keyname, "key");
|
||||
streamFileKey = sf->open(sf,keyname,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (streamFileKey) goto found;
|
||||
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (sf_key) goto found;
|
||||
|
||||
/* "(.ext)KEY" */
|
||||
/*
|
||||
strcpy(keyname+strlen(keyname)-3,"KEY");
|
||||
streamFileKey = streamFile->open(streamFile,keyname,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (streamFileKey) goto found;
|
||||
sf_key = sf->open(sf, keyname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (sf_key) goto found;
|
||||
*/
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
found:
|
||||
keysize = get_streamfile_size(streamFileKey);
|
||||
keysize = get_streamfile_size(sf_key);
|
||||
if (keysize > buf_size) goto fail;
|
||||
|
||||
if (read_streamfile(buf, 0, keysize, streamFileKey) != keysize)
|
||||
if (read_streamfile(buf, 0, keysize, sf_key) != keysize)
|
||||
goto fail;
|
||||
|
||||
close_streamfile(streamFileKey);
|
||||
close_streamfile(sf_key);
|
||||
return keysize;
|
||||
|
||||
fail:
|
||||
close_streamfile(streamFileKey);
|
||||
close_streamfile(sf_key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
STREAMFILE *read_filemap_file(STREAMFILE *sf, int file_num) {
|
||||
STREAMFILE* read_filemap_file(STREAMFILE* sf, int file_num) {
|
||||
char filename[PATH_LIMIT];
|
||||
off_t txt_offset, file_size;
|
||||
STREAMFILE *sf_map = NULL;
|
||||
STREAMFILE* sf_map = NULL;
|
||||
|
||||
sf_map = open_streamfile_by_filename(sf, ".txtm");
|
||||
if (!sf_map) goto fail;
|
||||
|
@ -1163,7 +1163,7 @@ STREAMFILE *read_filemap_file(STREAMFILE *sf, int file_num) {
|
|||
if (strcmp(key, filename) == 0) {
|
||||
int n;
|
||||
char subval[PATH_LIMIT];
|
||||
const char *current = val;
|
||||
const char* current = val;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= file_num; i++) {
|
||||
|
@ -1192,7 +1192,7 @@ fail:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void fix_dir_separators(char * filename) {
|
||||
void fix_dir_separators(char* filename) {
|
||||
char c;
|
||||
int i = 0;
|
||||
while ((c = filename[i]) != '\0') {
|
||||
|
@ -1202,11 +1202,13 @@ void fix_dir_separators(char * filename) {
|
|||
}
|
||||
}
|
||||
|
||||
int check_extensions(STREAMFILE *sf, const char * cmp_exts) {
|
||||
/* ************************************************************************* */
|
||||
|
||||
int check_extensions(STREAMFILE* sf, const char* cmp_exts) {
|
||||
char filename[PATH_LIMIT];
|
||||
const char * ext = NULL;
|
||||
const char * cmp_ext = NULL;
|
||||
const char * ststr_res = NULL;
|
||||
const char* ext = NULL;
|
||||
const char* cmp_ext = NULL;
|
||||
const char* ststr_res = NULL;
|
||||
size_t ext_len, cmp_len;
|
||||
|
||||
sf->get_name(sf,filename,sizeof(filename));
|
||||
|
@ -1232,6 +1234,7 @@ int check_extensions(STREAMFILE *sf, const char * cmp_exts) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
/**
|
||||
* Find a chunk starting from an offset, and save its offset/size (if not NULL), with offset after id/size.
|
||||
|
@ -1241,11 +1244,11 @@ int check_extensions(STREAMFILE *sf, const char * cmp_exts) {
|
|||
*
|
||||
* returns 0 on failure
|
||||
*/
|
||||
static int find_chunk_internal(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, size_t max_size, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian_type, int big_endian_size, int zero_size_end) {
|
||||
static int find_chunk_internal(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian_type, int big_endian_size, int zero_size_end) {
|
||||
int32_t (*read_32bit_type)(off_t,STREAMFILE*) = big_endian_type ? read_32bitBE : read_32bitLE;
|
||||
int32_t (*read_32bit_size)(off_t,STREAMFILE*) = big_endian_size ? read_32bitBE : read_32bitLE;
|
||||
off_t offset, max_offset;
|
||||
size_t file_size = get_streamfile_size(streamFile);
|
||||
size_t file_size = get_streamfile_size(sf);
|
||||
|
||||
if (max_size == 0)
|
||||
max_size = file_size;
|
||||
|
@ -1258,8 +1261,8 @@ static int find_chunk_internal(STREAMFILE *streamFile, uint32_t chunk_id, off_t
|
|||
|
||||
/* read chunks */
|
||||
while (offset < max_offset) {
|
||||
uint32_t chunk_type = read_32bit_type(offset + 0x00,streamFile);
|
||||
uint32_t chunk_size = read_32bit_size(offset + 0x04,streamFile);
|
||||
uint32_t chunk_type = read_32bit_type(offset + 0x00,sf);
|
||||
uint32_t chunk_size = read_32bit_size(offset + 0x04,sf);
|
||||
//;VGM_LOG("CHUNK: type=%x, size=%x at %lx\n", chunk_type, chunk_size, offset);
|
||||
|
||||
if (chunk_type == 0xFFFFFFFF || chunk_size == 0xFFFFFFFF)
|
||||
|
@ -1280,36 +1283,39 @@ static int find_chunk_internal(STREAMFILE *streamFile, uint32_t chunk_id, off_t
|
|||
|
||||
return 0;
|
||||
}
|
||||
int find_chunk_be(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk(streamFile, chunk_id, start_offset, full_chunk_size, out_chunk_offset, out_chunk_size, 1, 0);
|
||||
int find_chunk_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk(sf, chunk_id, start_offset, full_chunk_size, out_chunk_offset, out_chunk_size, 1, 0);
|
||||
}
|
||||
int find_chunk_le(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk(streamFile, chunk_id, start_offset, full_chunk_size, out_chunk_offset, out_chunk_size, 0, 0);
|
||||
int find_chunk_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk(sf, chunk_id, start_offset, full_chunk_size, out_chunk_offset, out_chunk_size, 0, 0);
|
||||
}
|
||||
int find_chunk(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian_size, int zero_size_end) {
|
||||
return find_chunk_internal(streamFile, chunk_id, start_offset, 0, full_chunk_size, out_chunk_offset, out_chunk_size, 1, big_endian_size, zero_size_end);
|
||||
int find_chunk(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian_size, int zero_size_end) {
|
||||
return find_chunk_internal(sf, chunk_id, start_offset, 0, full_chunk_size, out_chunk_offset, out_chunk_size, 1, big_endian_size, zero_size_end);
|
||||
}
|
||||
int find_chunk_riff_le(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk_internal(streamFile, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, 1, 0, 0);
|
||||
int find_chunk_riff_le(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk_internal(sf, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, 1, 0, 0);
|
||||
}
|
||||
int find_chunk_riff_be(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk_internal(streamFile, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, 1, 1, 0);
|
||||
int find_chunk_riff_be(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size) {
|
||||
return find_chunk_internal(sf, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, 1, 1, 0);
|
||||
}
|
||||
int find_chunk_riff_ve(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian) {
|
||||
return find_chunk_internal(streamFile, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, big_endian, big_endian, 0);
|
||||
int find_chunk_riff_ve(STREAMFILE* sf, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian) {
|
||||
return find_chunk_internal(sf, chunk_id, start_offset, max_size, 0, out_chunk_offset, out_chunk_size, big_endian, big_endian, 0);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
/* copies name as-is (may include full path included) */
|
||||
void get_streamfile_name(STREAMFILE *streamFile, char * buffer, size_t size) {
|
||||
streamFile->get_name(streamFile,buffer,size);
|
||||
void get_streamfile_name(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
sf->get_name(sf, buffer, size);
|
||||
}
|
||||
|
||||
/* copies the filename without path */
|
||||
void get_streamfile_filename(STREAMFILE *streamFile, char * buffer, size_t size) {
|
||||
void get_streamfile_filename(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
char foldername[PATH_LIMIT];
|
||||
const char *path;
|
||||
const char* path;
|
||||
|
||||
|
||||
streamFile->get_name(streamFile,foldername,sizeof(foldername));
|
||||
get_streamfile_name(sf, foldername, sizeof(foldername));
|
||||
|
||||
//todo Windows CMD accepts both \\ and /, better way to handle this?
|
||||
path = strrchr(foldername,'\\');
|
||||
|
@ -1325,22 +1331,24 @@ void get_streamfile_filename(STREAMFILE *streamFile, char * buffer, size_t size)
|
|||
strcpy(buffer, foldername);
|
||||
}
|
||||
}
|
||||
/* copies the filename without path or extension */
|
||||
void get_streamfile_basename(STREAMFILE *streamFile, char * buffer, size_t size) {
|
||||
char *ext;
|
||||
|
||||
get_streamfile_filename(streamFile,buffer,size);
|
||||
/* copies the filename without path or extension */
|
||||
void get_streamfile_basename(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
char* ext;
|
||||
|
||||
get_streamfile_filename(sf, buffer, size);
|
||||
|
||||
ext = strrchr(buffer,'.');
|
||||
if (ext) {
|
||||
ext[0] = '\0'; /* remove .ext from buffer */
|
||||
}
|
||||
}
|
||||
/* copies path removing name (NULL when if filename has no path) */
|
||||
void get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size) {
|
||||
const char *path;
|
||||
|
||||
streamFile->get_name(streamFile,buffer,size);
|
||||
/* copies path removing name (NULL when if filename has no path) */
|
||||
void get_streamfile_path(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
const char* path;
|
||||
|
||||
get_streamfile_name(sf, buffer, size);
|
||||
|
||||
path = strrchr(buffer,DIR_SEPARATOR);
|
||||
if (path!=NULL) path = path+1; /* includes "/" */
|
||||
|
@ -1351,34 +1359,47 @@ void get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size) {
|
|||
buffer[0] = '\0';
|
||||
}
|
||||
}
|
||||
void get_streamfile_ext(STREAMFILE *streamFile, char * filename, size_t size) {
|
||||
streamFile->get_name(streamFile,filename,size);
|
||||
strcpy(filename, filename_extension(filename));
|
||||
|
||||
/* copies extension only */
|
||||
void get_streamfile_ext(STREAMFILE* sf, char* buffer, size_t size) {
|
||||
char filename[PATH_LIMIT];
|
||||
const char* extension = NULL;
|
||||
|
||||
get_streamfile_name(sf, filename, sizeof(filename));
|
||||
extension = filename_extension(filename);
|
||||
if (!extension) {
|
||||
buffer[0] = '\n';
|
||||
}
|
||||
else {
|
||||
strncpy(buffer, extension, size); //todo use something better
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
/* debug util, mainly for custom IO testing */
|
||||
void dump_streamfile(STREAMFILE *streamFile, int num) {
|
||||
void dump_streamfile(STREAMFILE* sf, int num) {
|
||||
#ifdef VGM_DEBUG_OUTPUT
|
||||
off_t offset = 0;
|
||||
FILE *f = NULL;
|
||||
FILE* f = NULL;
|
||||
|
||||
if (num >= 0) {
|
||||
char filename[PATH_LIMIT];
|
||||
char dumpname[PATH_LIMIT];
|
||||
|
||||
get_streamfile_filename(streamFile, filename, PATH_LIMIT);
|
||||
get_streamfile_filename(sf, filename, PATH_LIMIT);
|
||||
snprintf(dumpname,PATH_LIMIT, "%s_%02i.dump", filename, num);
|
||||
|
||||
f = fopen(dumpname,"wb");
|
||||
if (!f) return;
|
||||
}
|
||||
|
||||
VGM_LOG("dump streamfile: size %x\n", get_streamfile_size(streamFile));
|
||||
while (offset < get_streamfile_size(streamFile)) {
|
||||
VGM_LOG("dump streamfile: size %x\n", get_streamfile_size(sf));
|
||||
while (offset < get_streamfile_size(sf)) {
|
||||
uint8_t buffer[0x8000];
|
||||
size_t read;
|
||||
|
||||
read = read_streamfile(buffer,offset,0x8000,streamFile);
|
||||
read = read_streamfile(buffer,offset,0x8000,sf);
|
||||
if(!read) {
|
||||
VGM_LOG("dump streamfile: can't read at %lx\n", offset);
|
||||
break;
|
||||
|
|
|
@ -516,6 +516,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
|||
init_vgmstream_dsp_wiiadpcm,
|
||||
init_vgmstream_dsp_cwac,
|
||||
init_vgmstream_ifs,
|
||||
init_vgmstream_acx,
|
||||
|
||||
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
|
||||
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
|
||||
|
|
Loading…
Reference in New Issue