Updated VGMStream to r1702-53-g00441228
Signed-off-by: Christopher Snowhill <kode54@gmail.com>CQTexperiment
parent
08da31f96c
commit
418d03ae23
|
@ -669,6 +669,7 @@
|
||||||
83F1EE30245D4FC10076E182 /* imuse.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F1EE2F245D4FC10076E182 /* imuse.c */; };
|
83F1EE30245D4FC10076E182 /* imuse.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F1EE2F245D4FC10076E182 /* imuse.c */; };
|
||||||
83F2CCE525A5B41600F46FA8 /* acx.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F2CCE125A5B41600F46FA8 /* acx.c */; };
|
83F2CCE525A5B41600F46FA8 /* acx.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F2CCE125A5B41600F46FA8 /* acx.c */; };
|
||||||
83F5F8831908D0A400C8E65F /* fsb5.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F5F8821908D0A400C8E65F /* fsb5.c */; };
|
83F5F8831908D0A400C8E65F /* fsb5.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F5F8821908D0A400C8E65F /* fsb5.c */; };
|
||||||
|
83FB239127B14696003F3062 /* mpeg.c in Sources */ = {isa = PBXBuildFile; fileRef = 83FB238D27B14696003F3062 /* mpeg.c */; };
|
||||||
83FBD506235D31F800D35BCD /* riff_ogg_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83FBD502235D31F700D35BCD /* riff_ogg_streamfile.h */; };
|
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 */; };
|
83FC176D23AC58D100E1025F /* xma_ue3.c in Sources */ = {isa = PBXBuildFile; fileRef = 83FC176A23AC58D100E1025F /* xma_ue3.c */; };
|
||||||
83FC176E23AC58D100E1025F /* csb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83FC176B23AC58D100E1025F /* csb.c */; };
|
83FC176E23AC58D100E1025F /* csb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83FC176B23AC58D100E1025F /* csb.c */; };
|
||||||
|
@ -1488,6 +1489,7 @@
|
||||||
83F2CCE125A5B41600F46FA8 /* acx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = acx.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>"; };
|
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>"; };
|
83F5F8821908D0A400C8E65F /* fsb5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fsb5.c; sourceTree = "<group>"; };
|
||||||
|
83FB238D27B14696003F3062 /* mpeg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mpeg.c; sourceTree = "<group>"; };
|
||||||
83FBD502235D31F700D35BCD /* riff_ogg_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = riff_ogg_streamfile.h; sourceTree = "<group>"; };
|
83FBD502235D31F700D35BCD /* riff_ogg_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = riff_ogg_streamfile.h; sourceTree = "<group>"; };
|
||||||
83FC176A23AC58D100E1025F /* xma_ue3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xma_ue3.c; sourceTree = "<group>"; };
|
83FC176A23AC58D100E1025F /* xma_ue3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xma_ue3.c; sourceTree = "<group>"; };
|
||||||
83FC176B23AC58D100E1025F /* csb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = csb.c; sourceTree = "<group>"; };
|
83FC176B23AC58D100E1025F /* csb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = csb.c; sourceTree = "<group>"; };
|
||||||
|
@ -1998,6 +2000,7 @@
|
||||||
8349A9031FE6258100E26435 /* mogg.c */,
|
8349A9031FE6258100E26435 /* mogg.c */,
|
||||||
839FBFF926C354E70016A78A /* mp4_faac.c */,
|
839FBFF926C354E70016A78A /* mp4_faac.c */,
|
||||||
836F6E6018BDC2180095E648 /* mp4.c */,
|
836F6E6018BDC2180095E648 /* mp4.c */,
|
||||||
|
83FB238D27B14696003F3062 /* mpeg.c */,
|
||||||
8306B0CB2098458E000302D4 /* msb_msh.c */,
|
8306B0CB2098458E000302D4 /* msb_msh.c */,
|
||||||
832BF81721E0514A006F50F1 /* msf_banpresto.c */,
|
832BF81721E0514A006F50F1 /* msf_banpresto.c */,
|
||||||
83C7280D22BC893D00678B4A /* msf_konami.c */,
|
83C7280D22BC893D00678B4A /* msf_konami.c */,
|
||||||
|
@ -3135,6 +3138,7 @@
|
||||||
83AA7F7F2519C042004C5298 /* bsf.c in Sources */,
|
83AA7F7F2519C042004C5298 /* bsf.c in Sources */,
|
||||||
836F6F4118BDC2190095E648 /* blocked.c in Sources */,
|
836F6F4118BDC2190095E648 /* blocked.c in Sources */,
|
||||||
836F6F3B18BDC2190095E648 /* ws_decoder.c in Sources */,
|
836F6F3B18BDC2190095E648 /* ws_decoder.c in Sources */,
|
||||||
|
83FB239127B14696003F3062 /* mpeg.c in Sources */,
|
||||||
839933612591E8C1001855AF /* sbk.c in Sources */,
|
839933612591E8C1001855AF /* sbk.c in Sources */,
|
||||||
835B9B932730BF2D00F87EE3 /* lpcm_shade.c in Sources */,
|
835B9B932730BF2D00F87EE3 /* lpcm_shade.c in Sources */,
|
||||||
838BDB6E1D3B043C0022CA6F /* ffmpeg.c in Sources */,
|
838BDB6E1D3B043C0022CA6F /* ffmpeg.c in Sources */,
|
||||||
|
|
|
@ -481,6 +481,18 @@ void free_mpeg(mpeg_codec_data* data);
|
||||||
|
|
||||||
int mpeg_get_sample_rate(mpeg_codec_data* data);
|
int mpeg_get_sample_rate(mpeg_codec_data* data);
|
||||||
long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data* data);
|
long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data* data);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int version;
|
||||||
|
int layer;
|
||||||
|
int bit_rate;
|
||||||
|
int sample_rate;
|
||||||
|
int frame_samples;
|
||||||
|
int frame_size; /* bytes */
|
||||||
|
int channels;
|
||||||
|
} mpeg_frame_info;
|
||||||
|
|
||||||
|
int mpeg_get_frame_info(STREAMFILE* sf, off_t offset, mpeg_frame_info* info);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ int test_key_g7221(g7221_codec_data* data, off_t start, STREAMFILE* sf) {
|
||||||
/* assumes key was set before this call */
|
/* assumes key was set before this call */
|
||||||
|
|
||||||
while (test_frames < S14_KEY_MAX_TEST_FRAMES && current_frame < max_frames) {
|
while (test_frames < S14_KEY_MAX_TEST_FRAMES && current_frame < max_frames) {
|
||||||
int score, ok;
|
int score, res;
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
uint8_t buf[G7221_MAX_FRAME_SIZE];
|
uint8_t buf[G7221_MAX_FRAME_SIZE];
|
||||||
|
|
||||||
|
@ -127,8 +127,8 @@ int test_key_g7221(g7221_codec_data* data, off_t start, STREAMFILE* sf) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = g7221_decode_frame(data->ch[cur_ch].handle, buf, data->ch[cur_ch].buffer);
|
res = g7221_decode_frame(data->ch[cur_ch].handle, buf, data->ch[cur_ch].buffer);
|
||||||
if (!ok) {
|
if (res < 0) {
|
||||||
total_score = -1;
|
total_score = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1072,12 +1072,13 @@ static int unpack_frame(int bit_rate, const uint8_t* data, int frame_size, /*int
|
||||||
|
|
||||||
/* test for errors (in refdec but not Namco's, useful to detect decryption) */
|
/* test for errors (in refdec but not Namco's, useful to detect decryption) */
|
||||||
if (test_errors) {
|
if (test_errors) {
|
||||||
|
int max_pad_bytes = 0x8; /* usually 0x04 and rarely ~0x08 */
|
||||||
int bits_left = 8 * expected_frame_size - bitpos;
|
int bits_left = 8 * expected_frame_size - bitpos;
|
||||||
int i, endpos, test_bits;
|
int i, endpos, test_bits;
|
||||||
|
|
||||||
if (bits_left > 0) {
|
if (bits_left > 0) {
|
||||||
|
|
||||||
/* frame must be padded with 1s */
|
/* frame must be padded with 1s after regular data */
|
||||||
endpos = bitpos;
|
endpos = bitpos;
|
||||||
for (i = 0; i < bits_left; i++) {
|
for (i = 0; i < bits_left; i++) {
|
||||||
int bit = (data_u32[endpos >> 5] >> (31 - (endpos & 0x1F))) & 1;
|
int bit = (data_u32[endpos >> 5] >> (31 - (endpos & 0x1F))) & 1;
|
||||||
|
@ -1087,19 +1088,21 @@ static int unpack_frame(int bit_rate, const uint8_t* data, int frame_size, /*int
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* extra: test we aren't in the middle of padding (happens with bad keys) */
|
/* extra: test we aren't in the middle of padding (happens with bad keys, this test catches most)
|
||||||
|
* After reading the whole frame, last bit position should land near last useful
|
||||||
|
* data, a few bytes into padding, so check there aren't too many padding bits. */
|
||||||
endpos = bitpos;
|
endpos = bitpos;
|
||||||
test_bits = 8 * 0x04;
|
test_bits = 8 * max_pad_bytes;
|
||||||
if (test_bits > bitpos)
|
if (test_bits > bitpos)
|
||||||
test_bits = bitpos;
|
test_bits = bitpos;
|
||||||
for (i = 0; i < test_bits; i++) {
|
for (i = 0; i < test_bits; i++) {
|
||||||
int bit = (data_u32[endpos >> 5] >> (31 - (endpos & 0x1F))) & 1;
|
int bit = (data_u32[endpos >> 5] >> (31 - (endpos & 0x1F))) & 1;
|
||||||
endpos--;
|
endpos--; /* from last position towards valid data */
|
||||||
|
|
||||||
if (bit != 1)
|
if (bit != 1)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* so many 1s isn't very normal */
|
|
||||||
if (i == test_bits)
|
if (i == test_bits)
|
||||||
return -8;
|
return -8;
|
||||||
|
|
||||||
|
@ -1186,10 +1189,9 @@ int g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples
|
||||||
/* Namco also sets number of codes/samples done from unpack_frame/rmlt (ptr arg),
|
/* Namco also sets number of codes/samples done from unpack_frame/rmlt (ptr arg),
|
||||||
* but they seem unused */
|
* but they seem unused */
|
||||||
|
|
||||||
return 1;
|
|
||||||
fail:
|
|
||||||
//;printf("S14: fail %i\n", res);
|
|
||||||
return 0;
|
return 0;
|
||||||
|
fail:
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -1271,7 +1273,7 @@ int g7221_set_key(g7221_handle* handle, const uint8_t* key) {
|
||||||
/* reset new key */
|
/* reset new key */
|
||||||
s14aes_set_key(handle->aes, temp_key);
|
s14aes_set_key(handle->aes, temp_key);
|
||||||
|
|
||||||
return 1;
|
|
||||||
fail:
|
|
||||||
return 0;
|
return 0;
|
||||||
|
fail:
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ typedef struct g7221_handle g7221_handle;
|
||||||
/* return a handle for decoding on successful init, NULL on failure */
|
/* return a handle for decoding on successful init, NULL on failure */
|
||||||
g7221_handle* g7221_init(int bytes_per_frame);
|
g7221_handle* g7221_init(int bytes_per_frame);
|
||||||
|
|
||||||
/* decode a frame, at code_words, into 16-bit PCM in sample_buffer */
|
/* decode a frame, at code_words, into 16-bit PCM in sample_buffer. returns <0 on error */
|
||||||
int g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples);
|
int g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -26,7 +26,7 @@ void g7221_reset(g7221_handle* handle);
|
||||||
/* free resources */
|
/* free resources */
|
||||||
void g7221_free(g7221_handle* handle);
|
void g7221_free(g7221_handle* handle);
|
||||||
|
|
||||||
/* set new key (ignores key on failure) */
|
/* set new key (ignores key on failure). returns <0 on error */
|
||||||
int g7221_set_key(g7221_handle* handle, const uint8_t* key);
|
int g7221_set_key(g7221_handle* handle, const uint8_t* key);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -75,16 +75,4 @@ int mpeg_custom_parse_frame_eamp3(VGMSTREAMCHANNEL* stream, mpeg_codec_data* dat
|
||||||
#endif/* VGM_USE_MPEG */
|
#endif/* VGM_USE_MPEG */
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int version;
|
|
||||||
int layer;
|
|
||||||
int bit_rate;
|
|
||||||
int sample_rate;
|
|
||||||
int frame_samples;
|
|
||||||
int frame_size; /* bytes */
|
|
||||||
int channels;
|
|
||||||
} mpeg_frame_info;
|
|
||||||
|
|
||||||
int mpeg_get_frame_info(STREAMFILE* sf, off_t offset, mpeg_frame_info* info);
|
|
||||||
|
|
||||||
#endif/*_MPEG_DECODER_H_ */
|
#endif/*_MPEG_DECODER_H_ */
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
static const char* extension_list[] = {
|
static const char* extension_list[] = {
|
||||||
//"", /* vgmstream can play extensionless files too, but plugins must accept them manually */
|
//"", /* vgmstream can play extensionless files too, but plugins must accept them manually */
|
||||||
|
|
||||||
"04sw",
|
|
||||||
"208",
|
"208",
|
||||||
"2dx9",
|
"2dx9",
|
||||||
"2pfs",
|
"2pfs",
|
||||||
|
@ -625,6 +624,7 @@ static const char* extension_list[] = {
|
||||||
"xma",
|
"xma",
|
||||||
"xma2",
|
"xma2",
|
||||||
"xmu",
|
"xmu",
|
||||||
|
"xmv",
|
||||||
"xnb",
|
"xnb",
|
||||||
"xsh",
|
"xsh",
|
||||||
"xsf",
|
"xsf",
|
||||||
|
@ -1382,6 +1382,7 @@ static const meta_info meta_info_list[] = {
|
||||||
{meta_WBK, "Treyarch WBK header"},
|
{meta_WBK, "Treyarch WBK header"},
|
||||||
{meta_WBK_NSLB, "Treyarch NSLB header"},
|
{meta_WBK_NSLB, "Treyarch NSLB header"},
|
||||||
{meta_DSP_APEX, "Koei Tecmo APEX header"},
|
{meta_DSP_APEX, "Koei Tecmo APEX header"},
|
||||||
|
{meta_MPEG, "MPEG header"},
|
||||||
};
|
};
|
||||||
|
|
||||||
void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {
|
void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {
|
||||||
|
|
|
@ -3,11 +3,31 @@
|
||||||
#include "../util/endianness.h"
|
#include "../util/endianness.h"
|
||||||
|
|
||||||
|
|
||||||
/* FWAV and CWAV are basically identical except always LE */
|
/* RWAV is a bit simpler, while FWAV and CWAV are basically identical except for endianness.
|
||||||
typedef enum { FWAV, CWAV } bxwav_type_t;
|
* From SDK info, typically .xxxx is the original NintendoWare format (usually a .xml) and .bxxxx is a
|
||||||
|
* binary/external form (like .rseq=xml then .brseq=binary, or .wav > brwav). */
|
||||||
|
typedef enum { RWAV, FWAV, CWAV } bxwav_type_t;
|
||||||
|
|
||||||
static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type);
|
static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type);
|
||||||
|
|
||||||
|
|
||||||
|
/* RWAV - NintendoWare binary Revolution wave (Wii games) */
|
||||||
|
VGMSTREAM* init_vgmstream_brwav(STREAMFILE* sf) {
|
||||||
|
|
||||||
|
/* checks */
|
||||||
|
if (!is_id32be(0x00, sf, "RWAV"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* .brwav: from tools (no games known)
|
||||||
|
* .rwav: header id */
|
||||||
|
if (!check_extensions(sf, "brwav,rwav"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
return init_vgmstream_bxwav(sf, RWAV);
|
||||||
|
fail:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* FWAV - NintendoWare binary caFe wave (WiiU and Switch games) */
|
/* FWAV - NintendoWare binary caFe wave (WiiU and Switch games) */
|
||||||
VGMSTREAM* init_vgmstream_bfwav(STREAMFILE* sf) {
|
VGMSTREAM* init_vgmstream_bfwav(STREAMFILE* sf) {
|
||||||
|
|
||||||
|
@ -21,7 +41,6 @@ VGMSTREAM* init_vgmstream_bfwav(STREAMFILE* sf) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
return init_vgmstream_bxwav(sf, FWAV);
|
return init_vgmstream_bxwav(sf, FWAV);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +62,6 @@ VGMSTREAM* init_vgmstream_bcwav(STREAMFILE* sf) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
return init_vgmstream_bxwav(sf, CWAV);
|
return init_vgmstream_bxwav(sf, CWAV);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -52,7 +70,7 @@ fail:
|
||||||
static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) {
|
static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) {
|
||||||
VGMSTREAM* vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
|
|
||||||
uint32_t info_offset, data_offset, chtb_offset;
|
uint32_t info_offset, data_offset, chtb_offset, file_size;
|
||||||
int channels, loop_flag, codec, sample_rate;
|
int channels, loop_flag, codec, sample_rate;
|
||||||
int big_endian;
|
int big_endian;
|
||||||
int32_t num_samples, loop_start;
|
int32_t num_samples, loop_start;
|
||||||
|
@ -63,7 +81,7 @@ static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) {
|
||||||
read_s16_t read_s16;
|
read_s16_t read_s16;
|
||||||
|
|
||||||
/* BOM check */
|
/* BOM check */
|
||||||
if (read_u16be(0x04, sf) == 0xFEFF) { /* WiiU */
|
if (read_u16be(0x04, sf) == 0xFEFF) { /* Wii, WiiU */
|
||||||
big_endian = 1;
|
big_endian = 1;
|
||||||
read_u32 = read_u32be;
|
read_u32 = read_u32be;
|
||||||
read_s32 = read_s32be;
|
read_s32 = read_s32be;
|
||||||
|
@ -82,41 +100,95 @@ static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* header */
|
/* header */
|
||||||
/* 0x06(2): header size (0x40) */
|
switch(type) {
|
||||||
/* 0x08: version */
|
case RWAV:
|
||||||
/* - FWAV: 0x00010200 */
|
/* 0x06(2): version (usually 0102, 0103=Let's Tap, no diffs) */
|
||||||
/* - CWAV: 0x00000002 (Kirby's Adventure), 0x00000102 (common), 0x00010102 (FE Fates, Hyrule Warriors Legends) */
|
file_size = read_u32(0x08, sf);
|
||||||
/* 0x0c: file size */
|
/* 0x0c(2): header size (0x20) */
|
||||||
/* 0x10(2): sections (2) */
|
/* 0x0e(2): sections (2) */
|
||||||
|
|
||||||
/* 0x14(2): info mark (0x7000) */
|
info_offset = read_u32(0x10, sf);
|
||||||
info_offset = read_u32(0x18, sf);
|
/* 0x14: info size */
|
||||||
/* 0x1c: info size */
|
|
||||||
|
|
||||||
/* 0x20(2): data mark (0x7001) */
|
data_offset = read_u32(0x18, sf);
|
||||||
data_offset = read_u32(0x24, sf);
|
/* 0x1c: data size */
|
||||||
/* 0x28: data size */
|
|
||||||
/* rest: padding */
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FWAV:
|
||||||
|
case CWAV:
|
||||||
|
/* 0x06(2): header size (0x40) */
|
||||||
|
/* 0x08: version */
|
||||||
|
/* - FWAV: 0x00010200 */
|
||||||
|
/* - CWAV: 0x00000002 (Kirby's Adventure), 0x00000102 (common), 0x00010102 (FE Fates, Hyrule Warriors Legends) */
|
||||||
|
file_size = read_u32(0x0c, sf);
|
||||||
|
/* 0x10(2): sections (2) */
|
||||||
|
|
||||||
|
/* 0x14(2): info mark (0x7000) */
|
||||||
|
info_offset = read_u32(0x18, sf);
|
||||||
|
/* 0x1c: info size */
|
||||||
|
|
||||||
|
/* 0x20(2): data mark (0x7001) */
|
||||||
|
data_offset = read_u32(0x24, sf);
|
||||||
|
/* 0x28: data size */
|
||||||
|
/* rest: padding */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_size != get_streamfile_size(sf)) {
|
||||||
|
vgm_logi("BXWAV: wrong size %x vs %x\n", file_size, (uint32_t)get_streamfile_size(sf));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/* INFO section */
|
/* INFO section */
|
||||||
if (!is_id32be(info_offset + 0x00, sf, "INFO"))
|
if (!is_id32be(info_offset + 0x00, sf, "INFO"))
|
||||||
goto fail;
|
goto fail;
|
||||||
/* 0x04: size */
|
/* 0x04: size */
|
||||||
codec = read_u8(info_offset + 0x08, sf);
|
|
||||||
loop_flag = read_u8(info_offset + 0x09, sf);
|
switch(type) {
|
||||||
/* 0x0a: padding */
|
case RWAV:
|
||||||
sample_rate = read_u32(info_offset + 0x0C, sf);
|
codec = read_u8(info_offset + 0x08, sf);
|
||||||
loop_start = read_s32(info_offset + 0x10, sf);
|
loop_flag = read_u8(info_offset + 0x09, sf);
|
||||||
num_samples = read_s32(info_offset + 0x14, sf);
|
channels = read_u8(info_offset + 0x0a, sf);
|
||||||
/* 0x18: original loop start? (slightly lower) */
|
/* 0x0b: part of rate? */
|
||||||
chtb_offset = info_offset + 0x1C;
|
sample_rate = read_u16(info_offset + 0x0c, sf);
|
||||||
channels = read_u32(chtb_offset + 0x00, sf);
|
/* 0x0e(2): padding */
|
||||||
|
loop_start = read_s32(info_offset + 0x10, sf);
|
||||||
|
num_samples = read_s32(info_offset + 0x14, sf);
|
||||||
|
chtb_offset = read_u32(info_offset + 0x18, sf) + info_offset + 0x08;
|
||||||
|
/* 0x1c: channel table size */
|
||||||
|
|
||||||
|
loop_start = dsp_nibbles_to_samples(loop_start);
|
||||||
|
num_samples = dsp_nibbles_to_samples(num_samples);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FWAV:
|
||||||
|
case CWAV:
|
||||||
|
codec = read_u8(info_offset + 0x08, sf);
|
||||||
|
loop_flag = read_u8(info_offset + 0x09, sf);
|
||||||
|
/* 0x0a: padding */
|
||||||
|
sample_rate = read_u32(info_offset + 0x0C, sf);
|
||||||
|
loop_start = read_s32(info_offset + 0x10, sf);
|
||||||
|
num_samples = read_s32(info_offset + 0x14, sf);
|
||||||
|
/* 0x18: original loop start? (slightly lower) */
|
||||||
|
chtb_offset = info_offset + 0x1C;
|
||||||
|
channels = read_u32(chtb_offset + 0x00, sf);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/* channel table is parsed at the end */
|
/* channel table is parsed at the end */
|
||||||
|
|
||||||
/* DATA section */
|
/* DATA section */
|
||||||
if (!is_id32be(data_offset + 0x00, sf, "DATA"))
|
if (!is_id32be(data_offset + 0x00, sf, "DATA"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
/* 0x04: size */
|
||||||
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
|
@ -124,6 +196,7 @@ static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) {
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
|
case RWAV: vgmstream->meta_type = meta_RWAV; break;
|
||||||
case FWAV: vgmstream->meta_type = meta_FWAV; break;
|
case FWAV: vgmstream->meta_type = meta_FWAV; break;
|
||||||
case CWAV: vgmstream->meta_type = meta_CWAV; break;
|
case CWAV: vgmstream->meta_type = meta_CWAV; break;
|
||||||
default: goto fail;
|
default: goto fail;
|
||||||
|
@ -138,7 +211,7 @@ static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) {
|
||||||
|
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
/* only 0x02 is known, other codecs are probably from bxstm that do use them */
|
/* only 0x02 is known, others can be made with SDK tools */
|
||||||
switch (codec) {
|
switch (codec) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
vgmstream->coding_type = coding_PCM8;
|
vgmstream->coding_type = coding_PCM8;
|
||||||
|
@ -171,25 +244,51 @@ static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) {
|
||||||
{
|
{
|
||||||
int ch, i;
|
int ch, i;
|
||||||
for (ch = 0; ch < channels; ch++) {
|
for (ch = 0; ch < channels; ch++) {
|
||||||
uint32_t chnf_offset, chdt_offset;
|
uint32_t chnf_offset, chdt_offset, coef_offset;
|
||||||
/* channel entry: */
|
switch(type) {
|
||||||
/* - 0x00: mark (0x7100) */
|
case RWAV:
|
||||||
/* - 0x02: padding */
|
/* channel entry: */
|
||||||
/* - 0x04: channel info offset (from channel table offset) */
|
/* - 0x04: channel info offset (from INFO offset after size) */
|
||||||
chnf_offset = read_u32(chtb_offset + 0x04 + ch * 0x08 + 0x04, sf) + chtb_offset;
|
|
||||||
|
|
||||||
/* channel info: */
|
chnf_offset = read_u32(chtb_offset + ch * 0x04 + 0x00, sf) + info_offset + 0x08;
|
||||||
/* 0x00: mark (0x1F00) */
|
|
||||||
/* 0x02: padding */
|
|
||||||
/* 0x04: offset to channel data (from DATA offset after size ) */
|
|
||||||
/* 0x08: ADPCM mark (0x0300=DSP, 0x0301=IMA, 0x0000=none) */
|
|
||||||
/* 0x0a: padding */
|
|
||||||
/* 0x0c: ADPCM offset (from channel info offset), 0xFFFFFFFF otherwise */
|
|
||||||
/* 0x10: null? */
|
|
||||||
|
|
||||||
if (read_u16(chnf_offset + 0x00, sf) != 0x1F00)
|
/* channel info: */
|
||||||
goto fail;
|
/* 0x00: offset to channel data (from DATA offset after size) */
|
||||||
chdt_offset = read_u32(chnf_offset + 0x04, sf) + data_offset + 0x08;
|
/* 0x04: ADPCM offset (from INFO offset after size), 0xFFFFFFFF otherwise? */
|
||||||
|
/* 0x08: volumes x4? */
|
||||||
|
/* 0x18: padding */
|
||||||
|
|
||||||
|
chdt_offset = read_u32(chnf_offset + 0x00, sf) + data_offset + 0x08;
|
||||||
|
coef_offset = read_u32(chnf_offset + 0x04, sf) + info_offset + 0x08;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FWAV:
|
||||||
|
case CWAV:
|
||||||
|
/* channel entry: */
|
||||||
|
/* - 0x00: mark (0x7100) */
|
||||||
|
/* - 0x02: padding */
|
||||||
|
/* - 0x04: channel info offset (from channel table offset) */
|
||||||
|
|
||||||
|
chnf_offset = read_u32(chtb_offset + 0x04 + ch * 0x08 + 0x04, sf) + chtb_offset;
|
||||||
|
|
||||||
|
/* channel info: */
|
||||||
|
/* 0x00: mark (0x1F00) */
|
||||||
|
/* 0x02: padding */
|
||||||
|
/* 0x04: offset to channel data (from DATA offset after size) */
|
||||||
|
/* 0x08: ADPCM mark (0x0300=DSP, 0x0301=IMA, 0x0000=none) */
|
||||||
|
/* 0x0a: padding */
|
||||||
|
/* 0x0c: ADPCM offset (from channel info offset), 0xFFFFFFFF otherwise */
|
||||||
|
/* 0x10: padding */
|
||||||
|
|
||||||
|
if (read_u16(chnf_offset + 0x00, sf) != 0x1F00)
|
||||||
|
goto fail;
|
||||||
|
chdt_offset = read_u32(chnf_offset + 0x04, sf) + data_offset + 0x08;
|
||||||
|
coef_offset = read_u32(chnf_offset + 0x0c, sf) + chnf_offset;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
vgmstream->ch[ch].channel_start_offset = chdt_offset;
|
vgmstream->ch[ch].channel_start_offset = chdt_offset;
|
||||||
vgmstream->ch[ch].offset = chdt_offset;
|
vgmstream->ch[ch].offset = chdt_offset;
|
||||||
|
@ -197,20 +296,16 @@ static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) {
|
||||||
switch(codec) {
|
switch(codec) {
|
||||||
case 0x02: {
|
case 0x02: {
|
||||||
/* standard DSP coef + predictor + hists + loop predictor + loop hists */
|
/* standard DSP coef + predictor + hists + loop predictor + loop hists */
|
||||||
uint32_t coef_offset = read_u32(chnf_offset + 0x0c, sf) + chnf_offset;
|
|
||||||
|
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++) {
|
||||||
vgmstream->ch[ch].adpcm_coef[i] = read_s16(coef_offset + 0x00 + i*0x02, sf);
|
vgmstream->ch[ch].adpcm_coef[i] = read_s16(coef_offset + 0x00 + i*0x02, sf);
|
||||||
}
|
}
|
||||||
vgmstream->ch[ch].adpcm_history1_16 = read_s16(coef_offset + 0x22, sf);
|
//vgmstream->ch[ch].adpcm_history1_16 = read_s16(coef_offset + 0x22, sf);
|
||||||
vgmstream->ch[ch].adpcm_history2_16 = read_s16(coef_offset + 0x24, sf);
|
//vgmstream->ch[ch].adpcm_history2_16 = read_s16(coef_offset + 0x24, sf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x03: {
|
case 0x03: {
|
||||||
/* hist + step */
|
/* hist + step */
|
||||||
uint32_t coef_offset = read_u32(chnf_offset + 0x0c, sf) + chnf_offset;
|
|
||||||
|
|
||||||
vgmstream->ch[ch].adpcm_history1_16 = read_s16(coef_offset + 0x00, sf);
|
vgmstream->ch[ch].adpcm_history1_16 = read_s16(coef_offset + 0x00, sf);
|
||||||
vgmstream->ch[ch].adpcm_step_index = read_s16(coef_offset + 0x02, sf);
|
vgmstream->ch[ch].adpcm_step_index = read_s16(coef_offset + 0x02, sf);
|
||||||
break;
|
break;
|
||||||
|
@ -228,3 +323,73 @@ fail:
|
||||||
close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
|
||||||
|
/* RWAR - NintendoWare container [BIT.TRIP BEAT (Wii), Dance Dance Revolution Hottest Party 2 (Wii)] */
|
||||||
|
VGMSTREAM* init_vgmstream_brwar(STREAMFILE* sf) {
|
||||||
|
VGMSTREAM* vgmstream = NULL;
|
||||||
|
STREAMFILE* temp_sf = NULL;
|
||||||
|
uint32_t tabl_offset, data_offset;
|
||||||
|
uint32_t subfile_offset, subfile_size;
|
||||||
|
int total_subsongs, target_subsong = sf->stream_index;
|
||||||
|
|
||||||
|
|
||||||
|
/* checks */
|
||||||
|
if (!is_id32be(0x00, sf, "RWAR"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (!check_extensions(sf,"rwar"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* simple container of .rwavs (inside .brsar), rarely used with single siles (DDR) */
|
||||||
|
|
||||||
|
/* abridged, see RWAV (same header) */
|
||||||
|
/* 0x04(2): BOM */
|
||||||
|
/* 0x06(2): version (usually 0100) */
|
||||||
|
/* 0x08: file size */
|
||||||
|
/* 0x0c(2): header size (0x20) */
|
||||||
|
/* 0x0e(2): sections (2) */
|
||||||
|
|
||||||
|
tabl_offset = read_u32be(0x10, sf);
|
||||||
|
/* 0x14: tabl size */
|
||||||
|
|
||||||
|
data_offset = read_u32be(0x18, sf);
|
||||||
|
/* 0x1c: data size */
|
||||||
|
|
||||||
|
/* TABL section */
|
||||||
|
if (!is_id32be(tabl_offset + 0x00, sf, "TABL"))
|
||||||
|
goto fail;
|
||||||
|
/* 0x04: size */
|
||||||
|
|
||||||
|
total_subsongs = read_u32be(tabl_offset + 0x08,sf);
|
||||||
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
|
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||||
|
|
||||||
|
/* 0x00: always 0x01000000? */
|
||||||
|
subfile_offset = read_u32be(tabl_offset + 0x0c + (target_subsong-1) * 0x0c + 0x04,sf) + data_offset;
|
||||||
|
subfile_size = read_u32be(tabl_offset + 0x0c + (target_subsong-1) * 0x0c + 0x08,sf);
|
||||||
|
|
||||||
|
|
||||||
|
/* DATA section */
|
||||||
|
if (!is_id32be(data_offset + 0x00, sf, "DATA"))
|
||||||
|
goto fail;
|
||||||
|
/* 0x04: size */
|
||||||
|
|
||||||
|
//VGM_LOG("BRWAR: of=%x, sz=%x\n", subfile_offset, subfile_size);
|
||||||
|
|
||||||
|
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "rwav");
|
||||||
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
|
vgmstream = init_vgmstream_brwav(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;
|
||||||
|
}
|
||||||
|
|
|
@ -12,14 +12,15 @@ VGMSTREAM* init_vgmstream_bik(STREAMFILE* sf) {
|
||||||
size_t stream_size;
|
size_t stream_size;
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
/* .bik/bik2/bk2: standard
|
/* bink1/2 header, followed by version-char (audio is the same) */
|
||||||
* .bika: fake extension for demuxed audio */
|
if ((read_u32be(0x00,sf) & 0xffffff00) != get_id32be("BIK\0") &&
|
||||||
if (!check_extensions(sf,"bik,bik2,bk2,bika"))
|
(read_u32be(0x00,sf) & 0xffffff00) != get_id32be("KB2\0"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* check bink1/2 header, followed by version-char (audio is the same) */
|
/* .bik/bik2/bk2: standard
|
||||||
if ((read_32bitBE(0x00,sf) & 0xffffff00) != get_id32be("BIK\0") &&
|
* .xmv: Reflections games [Driver: Parallel Lines (Wii), Emergency Heroes (Wii)]
|
||||||
(read_32bitBE(0x00,sf) & 0xffffff00) != get_id32be("KB2\0"))
|
* .bika: fake extension for demuxed audio */
|
||||||
|
if (!check_extensions(sf,"bik,bik2,bk2,xmv,bika"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* find target stream info and samples */
|
/* find target stream info and samples */
|
||||||
|
|
|
@ -234,7 +234,7 @@ static void bruteforce_bnsf_key(STREAMFILE* sf, off_t start, g7221_codec_data* d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//done:
|
done:
|
||||||
VGM_ASSERT(best_score > 0, "BNSF: best key=%.24s (score=%i)\n", best_key, best_score);
|
VGM_ASSERT(best_score > 0, "BNSF: best key=%.24s (score=%i)\n", best_key, best_score);
|
||||||
VGM_ASSERT(best_score < 0, "BNSF: key not found\n");
|
VGM_ASSERT(best_score < 0, "BNSF: key not found\n");
|
||||||
|
|
||||||
|
|
|
@ -1050,7 +1050,7 @@ typedef struct {
|
||||||
off_t prefetch_offset;
|
off_t prefetch_offset;
|
||||||
} eaac_header;
|
} eaac_header;
|
||||||
|
|
||||||
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf_data, eaac_header *eaac);
|
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE* sf_head, STREAMFILE* sf_data, eaac_header* eaac);
|
||||||
static layered_layout_data* build_layered_eaaudiocore(STREAMFILE* sf, eaac_header *eaac, off_t start_offset);
|
static layered_layout_data* build_layered_eaaudiocore(STREAMFILE* sf, eaac_header *eaac, off_t start_offset);
|
||||||
static STREAMFILE *setup_eaac_streamfile(eaac_header *ea, STREAMFILE* sf_head, STREAMFILE* sf_data);
|
static STREAMFILE *setup_eaac_streamfile(eaac_header *ea, STREAMFILE* sf_head, STREAMFILE* sf_data);
|
||||||
static size_t calculate_eaac_size(STREAMFILE* sf, eaac_header *ea, uint32_t num_samples, off_t start_offset, int is_ram);
|
static size_t calculate_eaac_size(STREAMFILE* sf, eaac_header *ea, uint32_t num_samples, off_t start_offset, int is_ram);
|
||||||
|
@ -1137,8 +1137,9 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||||
eaac.codec == EAAC_CODEC_EALAYER3_V2_PCM ||
|
eaac.codec == EAAC_CODEC_EALAYER3_V2_PCM ||
|
||||||
eaac.codec == EAAC_CODEC_EALAYER3_V2_SPIKE ||
|
eaac.codec == EAAC_CODEC_EALAYER3_V2_SPIKE ||
|
||||||
eaac.codec == EAAC_CODEC_EAXMA ||
|
eaac.codec == EAAC_CODEC_EAXMA ||
|
||||||
eaac.codec == EAAC_CODEC_XAS1)) {
|
eaac.codec == EAAC_CODEC_XAS1 ||
|
||||||
VGM_LOG("EA EAAC: unknown actual looping for codec %x\n", eaac.codec);
|
eaac.codec == EAAC_CODEC_EATRAX)) {
|
||||||
|
VGM_LOG("EA EAAC: unknown actual looping %i for codec %x\n", eaac.loop_start, eaac.codec);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1220,7 +1221,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||||
if (eaac.version == EAAC_VERSION_V0 && eaac.streamed) {
|
if (eaac.version == EAAC_VERSION_V0 && eaac.streamed) {
|
||||||
/* open SNS file if needed */
|
/* open SNS file if needed */
|
||||||
if (standalone) {
|
if (standalone) {
|
||||||
snsFile = open_streamfile_by_ext(sf_head, "sns");
|
snsFile = open_streamfile_by_ext(sf_head, "sns"); //todo clean
|
||||||
sf_data = snsFile;
|
sf_data = snsFile;
|
||||||
}
|
}
|
||||||
if (!sf_data) goto fail;
|
if (!sf_data) goto fail;
|
||||||
|
@ -1255,7 +1256,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||||
|
|
||||||
/* special (if hacky) loop handling, see comments */
|
/* special (if hacky) loop handling, see comments */
|
||||||
if (eaac.loop_start > 0) {
|
if (eaac.loop_start > 0) {
|
||||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf, &eaac);
|
segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf, sf, &eaac);
|
||||||
if (!data) goto fail;
|
if (!data) goto fail;
|
||||||
vgmstream->layout_data = data;
|
vgmstream->layout_data = data;
|
||||||
vgmstream->coding_type = data->segments[0]->coding_type;
|
vgmstream->coding_type = data->segments[0]->coding_type;
|
||||||
|
@ -1276,7 +1277,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||||
|
|
||||||
/* special (if hacky) loop handling, see comments */
|
/* special (if hacky) loop handling, see comments */
|
||||||
if (eaac.loop_start > 0) {
|
if (eaac.loop_start > 0) {
|
||||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf, &eaac);
|
segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf, sf, &eaac);
|
||||||
if (!data) goto fail;
|
if (!data) goto fail;
|
||||||
vgmstream->layout_data = data;
|
vgmstream->layout_data = data;
|
||||||
vgmstream->coding_type = data->segments[0]->coding_type;
|
vgmstream->coding_type = data->segments[0]->coding_type;
|
||||||
|
@ -1301,14 +1302,14 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||||
|
|
||||||
/* special (if hacky) loop handling, see comments */
|
/* special (if hacky) loop handling, see comments */
|
||||||
if (eaac.loop_start > 0) {
|
if (eaac.loop_start > 0) {
|
||||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf, &eaac);
|
segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf, sf, &eaac);
|
||||||
if (!data) goto fail;
|
if (!data) goto fail;
|
||||||
vgmstream->layout_data = data;
|
vgmstream->layout_data = data;
|
||||||
vgmstream->coding_type = data->segments[0]->coding_type;
|
vgmstream->coding_type = data->segments[0]->coding_type;
|
||||||
vgmstream->layout_type = layout_segmented;
|
vgmstream->layout_type = layout_segmented;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
|
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00, 0);
|
||||||
if (!temp_sf) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
vgmstream->codec_data = init_mpeg_custom(temp_sf, 0x00, &vgmstream->coding_type, vgmstream->channels, type, &cfg);
|
vgmstream->codec_data = init_mpeg_custom(temp_sf, 0x00, &vgmstream->coding_type, vgmstream->channels, type, &cfg);
|
||||||
|
@ -1336,7 +1337,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||||
vgmstream->coding_type = coding_SPEEX;
|
vgmstream->coding_type = coding_SPEEX;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
|
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00, 0);
|
||||||
if (!temp_sf) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1349,9 +1350,21 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||||
|
|
||||||
/* EATrax is "buffered" ATRAC9, uses custom IO since it's kind of complex to add to the decoder */
|
/* EATrax is "buffered" ATRAC9, uses custom IO since it's kind of complex to add to the decoder */
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* For looped EATRAX, since we are using a deblocker SF no need to make segmented looping, though it works [Madden NFL 13 Demo (Vita)]
|
||||||
|
* An issue with segmented is that AT9 state is probably not reset between loops, which segmented can't simulate */
|
||||||
|
if (eaac.loop_start > 0) {
|
||||||
|
segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf_head, sf, &eaac);
|
||||||
|
if (!data) goto fail;
|
||||||
|
vgmstream->layout_data = data;
|
||||||
|
vgmstream->coding_type = data->segments[0]->coding_type;
|
||||||
|
vgmstream->layout_type = layout_segmented;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
cfg.channels = eaac.channels;
|
cfg.channels = eaac.channels;
|
||||||
/* sub-header after normal header */
|
/* sub-header after normal header */
|
||||||
cfg.config_data = read_32bitBE(header_offset + header_size + 0x00,sf_head);
|
cfg.config_data = read_u32be(header_offset + header_size + 0x00,sf_head);
|
||||||
/* 0x04: data size without blocks, LE b/c why make sense (but don't use it in case of truncated files) */
|
/* 0x04: data size without blocks, LE b/c why make sense (but don't use it in case of truncated files) */
|
||||||
/* 0x08: 16b frame size (same as config data) */
|
/* 0x08: 16b frame size (same as config data) */
|
||||||
|
|
||||||
|
@ -1360,7 +1373,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||||
vgmstream->coding_type = coding_ATRAC9;
|
vgmstream->coding_type = coding_ATRAC9;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
|
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00, 0);
|
||||||
if (!temp_sf) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1372,7 +1385,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||||
case EAAC_CODEC_EAMP3: { /* "EM30": EA-MP3 [Need for Speed 2015 (PS4), FIFA 2021 (PC)] */
|
case EAAC_CODEC_EAMP3: { /* "EM30": EA-MP3 [Need for Speed 2015 (PS4), FIFA 2021 (PC)] */
|
||||||
mpeg_custom_config cfg = {0};
|
mpeg_custom_config cfg = {0};
|
||||||
|
|
||||||
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
|
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00, 0);
|
||||||
if (!temp_sf) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
vgmstream->codec_data = init_mpeg_custom(temp_sf, 0x00, &vgmstream->coding_type, vgmstream->channels, MPEG_EAMP3, &cfg);
|
vgmstream->codec_data = init_mpeg_custom(temp_sf, 0x00, &vgmstream->coding_type, vgmstream->channels, MPEG_EAMP3, &cfg);
|
||||||
|
@ -1420,7 +1433,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||||
case 4: cfg.coupled_count = 2; break; /* 2ch+2ch, 2 streams */
|
case 4: cfg.coupled_count = 2; break; /* 2ch+2ch, 2 streams */
|
||||||
//case 3: /* 2ch+1ch, 2 streams */
|
//case 3: /* 2ch+1ch, 2 streams */
|
||||||
case 2: cfg.coupled_count = 1; break; /* 2ch, 1 stream */
|
case 2: cfg.coupled_count = 1; break; /* 2ch, 1 stream */
|
||||||
//case 1: cfg.coupled_count = 0; break; /* 1ch, 1 stream */
|
case 1: cfg.coupled_count = 0; break; /* 1ch, 1 stream [Madden 22 (PC)] */
|
||||||
default: goto fail;
|
default: goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1431,7 +1444,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||||
/* We *don't* remove EA blocks b/c in Multi Opus 1 block = 1 Opus packet
|
/* We *don't* remove EA blocks b/c in Multi Opus 1 block = 1 Opus packet
|
||||||
* Regular EAOPUS uses layers to fake multichannel, this is normal multichannel Opus.
|
* Regular EAOPUS uses layers to fake multichannel, this is normal multichannel Opus.
|
||||||
* This can be used for stereo too, so probably replaces EAOPUS. */
|
* This can be used for stereo too, so probably replaces EAOPUS. */
|
||||||
//temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,0,0, 0x00);
|
//temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,0,0, 0x00, 0);
|
||||||
//if (!temp_sf) goto fail;
|
//if (!temp_sf) goto fail;
|
||||||
|
|
||||||
vgmstream->codec_data = init_ffmpeg_ea_opusm(sf, offset, data_size, &cfg);
|
vgmstream->codec_data = init_ffmpeg_ea_opusm(sf, offset, data_size, &cfg);
|
||||||
|
@ -1613,10 +1626,12 @@ fail:
|
||||||
* We use the segmented layout, since the eaac_streamfile doesn't handle padding,
|
* We use the segmented layout, since the eaac_streamfile doesn't handle padding,
|
||||||
* and the segments seem fully separate (so even skipping would probably decode wrong). */
|
* and the segments seem fully separate (so even skipping would probably decode wrong). */
|
||||||
// todo reorganize code for more standard init
|
// todo reorganize code for more standard init
|
||||||
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf_data, eaac_header *eaac) {
|
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf_head, STREAMFILE *sf_data, eaac_header *eaac) {
|
||||||
segmented_layout_data *data = NULL;
|
segmented_layout_data *data = NULL;
|
||||||
STREAMFILE* temp_sf = NULL;
|
STREAMFILE* temp_sf = NULL;
|
||||||
|
uint32_t data_size = get_streamfile_size(sf_data);
|
||||||
off_t offsets[2] = { 0x00, eaac->loop_offset };
|
off_t offsets[2] = { 0x00, eaac->loop_offset };
|
||||||
|
uint32_t sizes[2] = { eaac->loop_offset, data_size - eaac->loop_offset };
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
int num_samples[2] = { eaac->loop_start, eaac->num_samples - eaac->loop_start};
|
int num_samples[2] = { eaac->loop_start, eaac->num_samples - eaac->loop_start};
|
||||||
int segment_count = 2; /* intro/loop */
|
int segment_count = 2; /* intro/loop */
|
||||||
|
@ -1628,8 +1643,11 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf
|
||||||
if (!data) goto fail;
|
if (!data) goto fail;
|
||||||
|
|
||||||
for (i = 0; i < segment_count; i++) {
|
for (i = 0; i < segment_count; i++) {
|
||||||
data->segments[i] = allocate_vgmstream(eaac->channels, 0);
|
VGMSTREAM* vgmstream = allocate_vgmstream(eaac->channels, 0);
|
||||||
if (!data->segments[i]) goto fail;
|
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
data->segments[i] = vgmstream;
|
||||||
|
|
||||||
data->segments[i]->sample_rate = eaac->sample_rate;
|
data->segments[i]->sample_rate = eaac->sample_rate;
|
||||||
data->segments[i]->num_samples = num_samples[i];
|
data->segments[i]->num_samples = num_samples[i];
|
||||||
//data->segments[i]->meta_type = eaac->meta_type; /* bleh */
|
//data->segments[i]->meta_type = eaac->meta_type; /* bleh */
|
||||||
|
@ -1669,7 +1687,7 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf
|
||||||
|
|
||||||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||||
|
|
||||||
temp_sf = setup_eaac_audio_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], sizes[i]);
|
||||||
if (!temp_sf) goto fail;
|
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);
|
data->segments[i]->codec_data = init_mpeg_custom(temp_sf, 0x00, &data->segments[i]->coding_type, eaac->channels, type, &cfg);
|
||||||
|
@ -1678,11 +1696,37 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef VGM_USE_ATRAC9
|
||||||
|
case EAAC_CODEC_EATRAX: { /* EATrax (unknown FourCC) [Need for Speed: Most Wanted (Vita)] */
|
||||||
|
atrac9_config cfg = {0};
|
||||||
|
|
||||||
|
/* EATrax is "buffered" ATRAC9, uses custom IO since it's kind of complex to add to the decoder */
|
||||||
|
|
||||||
|
cfg.channels = eaac->channels;
|
||||||
|
/* sub-header after normal header */
|
||||||
|
cfg.config_data = read_u32be(0x14 + 0x00, sf_head); //todo pass header offset
|
||||||
|
/* 0x04: data size without blocks, LE b/c why make sense (but don't use it in case of truncated files) */
|
||||||
|
/* 0x08: 16b frame size (same as config data) */
|
||||||
|
|
||||||
|
vgmstream->codec_data = init_atrac9(&cfg);
|
||||||
|
if (!vgmstream->codec_data) goto fail;
|
||||||
|
vgmstream->coding_type = coding_ATRAC9;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
|
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||||
|
|
||||||
|
//todo should make sizes
|
||||||
|
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,0,0, offsets[i], sizes[i]);
|
||||||
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vgmstream_open_stream(data->segments[i],temp_sf == NULL ? sf_data : temp_sf, start_offset))
|
if (!vgmstream_open_stream(data->segments[i], temp_sf == NULL ? sf_data : temp_sf, start_offset))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
close_streamfile(temp_sf);
|
close_streamfile(temp_sf);
|
||||||
|
@ -1732,7 +1776,7 @@ static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_
|
||||||
size_t stream_size;
|
size_t stream_size;
|
||||||
int is_xma1;
|
int is_xma1;
|
||||||
|
|
||||||
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, start_offset);
|
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, start_offset, 0);
|
||||||
if (!temp_sf) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
stream_size = get_streamfile_size(temp_sf);
|
stream_size = get_streamfile_size(temp_sf);
|
||||||
|
@ -1764,7 +1808,7 @@ static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_
|
||||||
size_t data_size;
|
size_t data_size;
|
||||||
|
|
||||||
/* We'll remove EA blocks and pass raw data to FFmpeg Opus decoder */
|
/* We'll remove EA blocks and pass raw data to FFmpeg Opus decoder */
|
||||||
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, start_offset);
|
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, start_offset, 0);
|
||||||
if (!temp_sf) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
skip = ea_opus_get_encoder_delay(0x00, temp_sf);
|
skip = ea_opus_get_encoder_delay(0x00, temp_sf);
|
||||||
|
|
|
@ -13,6 +13,7 @@ typedef struct {
|
||||||
int stream_number;
|
int stream_number;
|
||||||
int stream_count;
|
int stream_count;
|
||||||
off_t stream_offset;
|
off_t stream_offset;
|
||||||
|
uint32_t stream_size;
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
off_t logical_offset; /* offset that corresponds to physical_offset */
|
off_t logical_offset; /* offset that corresponds to physical_offset */
|
||||||
|
@ -30,7 +31,7 @@ typedef struct {
|
||||||
|
|
||||||
/* Reads skipping EA's block headers, so the resulting data is smaller or larger than physical data.
|
/* Reads skipping EA's block headers, so the resulting data is smaller or larger than physical data.
|
||||||
* physical/logical_offset will be at the start of a block and only advance when a block is done */
|
* physical/logical_offset will be at the start of a block and only advance when a block is done */
|
||||||
static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, eaac_io_data* data) {
|
static size_t eaac_io_read(STREAMFILE* sf, uint8_t *dest, off_t offset, size_t length, eaac_io_data* data) {
|
||||||
size_t total_read = 0;
|
size_t total_read = 0;
|
||||||
|
|
||||||
/* ignore bad reads */
|
/* ignore bad reads */
|
||||||
|
@ -58,8 +59,8 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
|
||||||
|
|
||||||
/* process new block */
|
/* process new block */
|
||||||
if (data->data_size == 0) {
|
if (data->data_size == 0) {
|
||||||
data->block_flag = (uint8_t)read_8bit(data->physical_offset+0x00,streamfile);
|
data->block_flag = (uint8_t)read_8bit(data->physical_offset+0x00,sf);
|
||||||
data->block_size = read_32bitBE(data->physical_offset+0x00,streamfile) & 0x00FFFFFF;
|
data->block_size = read_32bitBE(data->physical_offset+0x00,sf) & 0x00FFFFFF;
|
||||||
|
|
||||||
/* ignore header block */
|
/* ignore header block */
|
||||||
if (data->version == 1 && data->block_flag == 0x48) {
|
if (data->version == 1 && data->block_flag == 0x48) {
|
||||||
|
@ -74,9 +75,9 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
|
||||||
|
|
||||||
data->skip_size = 0x04 + 0x04;
|
data->skip_size = 0x04 + 0x04;
|
||||||
for (i = 0; i < data->stream_number; i++) {
|
for (i = 0; i < data->stream_number; i++) {
|
||||||
data->skip_size += read_32bitBE(data->physical_offset+data->skip_size, streamfile) / 4;
|
data->skip_size += read_32bitBE(data->physical_offset+data->skip_size, sf) / 4;
|
||||||
}
|
}
|
||||||
data->data_size = read_32bitBE(data->physical_offset+data->skip_size, streamfile) / 4; /* why size*4...? */
|
data->data_size = read_32bitBE(data->physical_offset+data->skip_size, sf) / 4; /* why size*4...? */
|
||||||
data->skip_size += 0x04; /* skip mini header */
|
data->skip_size += 0x04; /* skip mini header */
|
||||||
data->data_size -= 0x04; /* remove mini header */
|
data->data_size -= 0x04; /* remove mini header */
|
||||||
if (data->data_size % XMA_FRAME_SIZE)
|
if (data->data_size % XMA_FRAME_SIZE)
|
||||||
|
@ -96,7 +97,7 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
|
||||||
|
|
||||||
case 0x0a: /* EATrax */
|
case 0x0a: /* EATrax */
|
||||||
data->skip_size = 0x08;
|
data->skip_size = 0x08;
|
||||||
data->data_size = read_32bitBE(data->physical_offset+0x04,streamfile); /* also block_size - 0x08 */
|
data->data_size = read_32bitBE(data->physical_offset+0x04,sf); /* also block_size - 0x08 */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -125,7 +126,7 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
|
||||||
to_read = data->data_size - bytes_consumed;
|
to_read = data->data_size - bytes_consumed;
|
||||||
if (to_read > length)
|
if (to_read > length)
|
||||||
to_read = length;
|
to_read = length;
|
||||||
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
|
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, sf);
|
||||||
}
|
}
|
||||||
else { /* offset falls within logical padded data */
|
else { /* offset falls within logical padded data */
|
||||||
to_read = data->data_size + data->extra_size - bytes_consumed;
|
to_read = data->data_size + data->extra_size - bytes_consumed;
|
||||||
|
@ -141,7 +142,7 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
|
||||||
to_read = data->data_size - bytes_consumed;
|
to_read = data->data_size - bytes_consumed;
|
||||||
if (to_read > length)
|
if (to_read > length)
|
||||||
to_read = length;
|
to_read = length;
|
||||||
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
|
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, sf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +169,7 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
|
||||||
return data->logical_size;
|
return data->logical_size;
|
||||||
|
|
||||||
physical_offset = data->stream_offset;
|
physical_offset = data->stream_offset;
|
||||||
max_physical_offset = get_streamfile_size(streamfile);
|
max_physical_offset = physical_offset + data->stream_size;
|
||||||
|
|
||||||
/* get size of the logical stream */
|
/* get size of the logical stream */
|
||||||
while (physical_offset < max_physical_offset) {
|
while (physical_offset < max_physical_offset) {
|
||||||
|
@ -231,7 +232,7 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* logical size can be bigger in EA-XMA though */
|
/* logical size can be bigger in EA-XMA though */
|
||||||
if (physical_offset > get_streamfile_size(streamfile)) {
|
if (physical_offset > max_physical_offset) {
|
||||||
VGM_LOG("EA EAAC: wrong size\n");
|
VGM_LOG("EA EAAC: wrong size\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -247,10 +248,13 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
|
||||||
* - EATrax: ATRAC9 frames can be split between blooks
|
* - EATrax: ATRAC9 frames can be split between blooks
|
||||||
* - EAOpus: multiple Opus packets of frame size + Opus data per block
|
* - EAOpus: multiple Opus packets of frame size + Opus data per block
|
||||||
*/
|
*/
|
||||||
static STREAMFILE* setup_eaac_audio_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, uint32_t stream_offset, uint32_t stream_size) {
|
||||||
STREAMFILE *new_sf = NULL;
|
STREAMFILE *new_sf = NULL;
|
||||||
eaac_io_data io_data = {0};
|
eaac_io_data io_data = {0};
|
||||||
|
|
||||||
|
if (!stream_size)
|
||||||
|
stream_size = get_streamfile_size(sf) - stream_offset;
|
||||||
|
|
||||||
io_data.version = version;
|
io_data.version = version;
|
||||||
io_data.codec = codec;
|
io_data.codec = codec;
|
||||||
io_data.streamed = streamed;
|
io_data.streamed = streamed;
|
||||||
|
@ -258,6 +262,7 @@ static STREAMFILE* setup_eaac_audio_streamfile(STREAMFILE *sf, int version, int
|
||||||
io_data.stream_count = stream_count;
|
io_data.stream_count = stream_count;
|
||||||
io_data.stream_offset = stream_offset;
|
io_data.stream_offset = stream_offset;
|
||||||
io_data.physical_offset = stream_offset;
|
io_data.physical_offset = stream_offset;
|
||||||
|
io_data.stream_size = stream_size;
|
||||||
io_data.logical_size = eaac_io_size(sf, &io_data); /* force init */
|
io_data.logical_size = eaac_io_size(sf, &io_data); /* force init */
|
||||||
|
|
||||||
/* setup subfile */
|
/* setup subfile */
|
||||||
|
|
|
@ -564,8 +564,10 @@ VGMSTREAM * init_vgmstream_bcstm(STREAMFILE* streamFile);
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_bfstm(STREAMFILE* streamFile);
|
VGMSTREAM * init_vgmstream_bfstm(STREAMFILE* streamFile);
|
||||||
|
|
||||||
|
VGMSTREAM* init_vgmstream_brwav(STREAMFILE* sf);
|
||||||
VGMSTREAM* init_vgmstream_bfwav(STREAMFILE* sf);
|
VGMSTREAM* init_vgmstream_bfwav(STREAMFILE* sf);
|
||||||
VGMSTREAM* init_vgmstream_bcwav(STREAMFILE* sf);
|
VGMSTREAM* init_vgmstream_bcwav(STREAMFILE* sf);
|
||||||
|
VGMSTREAM* init_vgmstream_brwar(STREAMFILE* sf);
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_kt_g1l(STREAMFILE* streamFile);
|
VGMSTREAM * init_vgmstream_kt_g1l(STREAMFILE* streamFile);
|
||||||
VGMSTREAM * init_vgmstream_kt_wiibgm(STREAMFILE* streamFile);
|
VGMSTREAM * init_vgmstream_kt_wiibgm(STREAMFILE* streamFile);
|
||||||
|
@ -972,4 +974,6 @@ VGMSTREAM* init_vgmstream_wbk_nslb(STREAMFILE* sf);
|
||||||
|
|
||||||
VGMSTREAM* init_vgmstream_ubi_ckd_cwav(STREAMFILE* sf);
|
VGMSTREAM* init_vgmstream_ubi_ckd_cwav(STREAMFILE* sf);
|
||||||
|
|
||||||
|
VGMSTREAM* init_vgmstream_mpeg(STREAMFILE* sf);
|
||||||
|
|
||||||
#endif /*_META_H*/
|
#endif /*_META_H*/
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
#include "meta.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* MPEG - standard MP1/2/3 audio MP3 */
|
||||||
|
VGMSTREAM* init_vgmstream_mpeg(STREAMFILE* sf) {
|
||||||
|
#ifdef VGM_USE_MPEG
|
||||||
|
VGMSTREAM* vgmstream = NULL;
|
||||||
|
int loop_flag = 0;
|
||||||
|
mpeg_frame_info info = {0};
|
||||||
|
|
||||||
|
|
||||||
|
/* checks */
|
||||||
|
if (!mpeg_get_frame_info(sf, 0x00, &info))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* .mp3/mp2: standard (is .mp1 ever used in games?)
|
||||||
|
* .lmp1/2/3: for plugins
|
||||||
|
* .mus: Marc Ecko's Getting Up (PC) */
|
||||||
|
if (!check_extensions(sf, "mp3,mp2,mp1,mus,lmp3,lmp2,lmp1"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
loop_flag = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/* build VGMSTREAM */
|
||||||
|
vgmstream = allocate_vgmstream(info.channels, loop_flag);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
|
vgmstream->meta_type = meta_MPEG;
|
||||||
|
vgmstream->sample_rate = info.sample_rate;
|
||||||
|
|
||||||
|
/* more strict, use? */
|
||||||
|
//mpeg_custom_config cfg = {0};
|
||||||
|
//cfg.skip_samples = ...
|
||||||
|
//vgmstream->codec_data = init_mpeg_custom(sf, start_offset, &vgmstream->coding_type, fmt.channels, MPEG_STANDARD, &cfg);
|
||||||
|
|
||||||
|
vgmstream->codec_data = init_mpeg(sf, 0x00, &vgmstream->coding_type, info.channels);
|
||||||
|
if (!vgmstream->codec_data) goto fail;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
|
//vgmstream->num_samples = mpeg_bytes_to_samples(data_size, vgmstream->codec_data);
|
||||||
|
vgmstream->num_samples = mpeg_get_samples(sf, 0x00, get_streamfile_size(sf));
|
||||||
|
|
||||||
|
|
||||||
|
if (!vgmstream_open_stream(vgmstream, sf, 0x00))
|
||||||
|
goto fail;
|
||||||
|
return vgmstream;
|
||||||
|
fail:
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -608,56 +608,80 @@ static int parse_musx(STREAMFILE* sf, musx_header* musx) {
|
||||||
|
|
||||||
case SBNK: {
|
case SBNK: {
|
||||||
off_t target_offset, head_offset, data_offset;
|
off_t target_offset, head_offset, data_offset;
|
||||||
uint8_t codec;
|
uint8_t codec = 0;
|
||||||
|
uint32_t version;
|
||||||
|
|
||||||
/* 0x00: id */
|
if (!is_id32be(0x800 + 0x00, sf, "SBNK"))
|
||||||
/* 0x04: always 0x12? */
|
|
||||||
/* 0x08: file ID (same as base file) */
|
|
||||||
/* 0x0c: some ID? */
|
|
||||||
|
|
||||||
/* 0x10: table1 count */
|
|
||||||
/* 0x14: table1 offset (from here) */
|
|
||||||
/* 0x18: table2 count */
|
|
||||||
/* 0x1c: table2 offset (from here) */
|
|
||||||
|
|
||||||
/* 0x20: table3 count */
|
|
||||||
/* 0x24: table3 offset (from here) */
|
|
||||||
/* 0x28: table4 count */
|
|
||||||
/* 0x2c: table4 offset (from here) */
|
|
||||||
|
|
||||||
/* 0x30: table5 count (waves) */
|
|
||||||
/* 0x34: table5 offset (from here) */
|
|
||||||
/* 0x38: table6 count */
|
|
||||||
/* 0x3c: table6 offset (from here) */
|
|
||||||
|
|
||||||
/* 0x40: table7 count */
|
|
||||||
/* 0x44: table7 offset (from here) */
|
|
||||||
/* 0x48: data size */
|
|
||||||
/* 0x4c: data offset (absolute) */
|
|
||||||
|
|
||||||
musx->tables_offset = 0x800;
|
|
||||||
if (!is_id32be(musx->tables_offset+0x00, sf, "SBNK"))
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
musx->total_subsongs = read_u32(musx->tables_offset+0x30, sf);
|
version = read_u32(0x800 + 0x04, sf);
|
||||||
|
if (version == 0x2A) {
|
||||||
|
/* - Goldeneye 007 (X360) */
|
||||||
|
/* 0x08: "COM " */
|
||||||
|
/* 0x0c: file ID (same as base file) */
|
||||||
|
/* 0x10: some ID? */
|
||||||
|
musx->tables_offset = 0x814;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* - v0x12 (all others) */
|
||||||
|
/* 0x08: file ID (same as base file) */
|
||||||
|
/* 0x0c: some ID? */
|
||||||
|
musx->tables_offset = 0x810;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 0x00: table1 count */
|
||||||
|
/* 0x04: table1 offset (from here) */
|
||||||
|
/* 0x08: table2 count */
|
||||||
|
/* 0x0c: table2 offset (from here) */
|
||||||
|
|
||||||
|
/* 0x10: table3 count */
|
||||||
|
/* 0x14: table3 offset (from here) */
|
||||||
|
/* 0x18: table4 count */
|
||||||
|
/* 0x1c: table4 offset (from here) */
|
||||||
|
|
||||||
|
/* 0x20: table5 count (waves) */
|
||||||
|
/* 0x24: table5 offset (from here) */
|
||||||
|
/* 0x28: table6 count */
|
||||||
|
/* 0x2c: table6 offset (from here) */
|
||||||
|
|
||||||
|
/* 0x30: table7 count */
|
||||||
|
/* 0x34: table7 offset (from here) */
|
||||||
|
/* 0x38: data size */
|
||||||
|
/* 0x3c: data offset (absolute in older versions) */
|
||||||
|
|
||||||
|
musx->total_subsongs = read_u32(musx->tables_offset+0x20, sf);
|
||||||
if (target_subsong == 0) target_subsong = 1;
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
if (target_subsong > musx->total_subsongs || musx->total_subsongs <= 0) goto fail;
|
if (target_subsong > musx->total_subsongs || musx->total_subsongs <= 0) goto fail;
|
||||||
|
|
||||||
head_offset = read_u32(musx->tables_offset+0x34, sf) + musx->tables_offset + 0x34;
|
if (version == 0x2A) {
|
||||||
data_offset = read_u32(musx->tables_offset+0x4c, sf);
|
;VGM_LOG("MUSX: unknown version format\n");
|
||||||
|
goto fail;
|
||||||
|
/* subheader is 0x10 but variable?, offset table may be table 7?
|
||||||
|
- 0x00: ID?
|
||||||
|
- 0x04: samples?
|
||||||
|
- 0x08: sample rate
|
||||||
|
- 0x0a: codec?
|
||||||
|
- 0x0b: channels
|
||||||
|
- 0x0c: size?
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
head_offset = read_u32(musx->tables_offset+0x24, sf) + musx->tables_offset + 0x24;
|
||||||
|
data_offset = read_u32(musx->tables_offset+0x3c, sf);
|
||||||
|
|
||||||
target_offset = head_offset + (target_subsong - 1)*0x1c;
|
target_offset = head_offset + (target_subsong - 1) * 0x1c;
|
||||||
;VGM_LOG("MUSX: ho=%lx, do=%lx, to=%lx\n", head_offset, data_offset, target_offset);
|
;VGM_LOG("MUSX: ho=%lx, do=%lx, to=%lx\n", head_offset, data_offset, target_offset);
|
||||||
|
|
||||||
/* 0x00: subfile ID */
|
/* 0x00: subfile ID */
|
||||||
musx->num_samples = read_s32(target_offset + 0x04, sf);
|
musx->num_samples = read_s32(target_offset + 0x04, sf);
|
||||||
musx->loop_start_sample = read_s32(target_offset + 0x08, sf); /* -1 if no loop */
|
musx->loop_start_sample = read_s32(target_offset + 0x08, sf); /* -1 if no loop */
|
||||||
musx->sample_rate = read_u16(target_offset + 0x0c, sf);
|
musx->sample_rate = read_u16(target_offset + 0x0c, sf);
|
||||||
codec = read_u8 (target_offset + 0x0e, sf);
|
codec = read_u8 (target_offset + 0x0e, sf);
|
||||||
musx->channels = read_u8 (target_offset + 0x0f, sf);
|
musx->channels = read_u8 (target_offset + 0x0f, sf);
|
||||||
musx->stream_offset = read_u32(target_offset + 0x10, sf) + data_offset;
|
musx->stream_offset = read_u32(target_offset + 0x10, sf) + data_offset;
|
||||||
musx->stream_size = read_u32(target_offset + 0x14, sf);
|
musx->stream_size = read_u32(target_offset + 0x14, sf);
|
||||||
musx->loop_start = read_s32(target_offset + 0x18, sf);
|
musx->loop_start = read_s32(target_offset + 0x18, sf);
|
||||||
|
}
|
||||||
|
|
||||||
musx->loop_end_sample = musx->num_samples;
|
musx->loop_end_sample = musx->num_samples;
|
||||||
musx->loop_flag = (musx->loop_start_sample >= 0);
|
musx->loop_flag = (musx->loop_start_sample >= 0);
|
||||||
|
|
|
@ -1393,10 +1393,8 @@ VGMSTREAM* init_vgmstream_dsp_wiiadpcm(STREAMFILE* sf) {
|
||||||
|
|
||||||
dspm.header_spacing = dspm.interleave;
|
dspm.header_spacing = dspm.interleave;
|
||||||
dspm.start_offset = dspm.header_offset + 0x60;
|
dspm.start_offset = dspm.header_offset + 0x60;
|
||||||
//
|
|
||||||
|
|
||||||
VGM_LOG("%lx, %x\n", dspm.header_offset, dspm.interleave);
|
|
||||||
VGM_LOG("%x, %x\n", dspm.interleave_first_skip, dspm.interleave_first);
|
|
||||||
dspm.meta_type = meta_DSP_WIIADPCM;
|
dspm.meta_type = meta_DSP_WIIADPCM;
|
||||||
return init_vgmstream_dsp_common(sf, &dspm);
|
return init_vgmstream_dsp_common(sf, &dspm);
|
||||||
fail:
|
fail:
|
||||||
|
|
|
@ -150,6 +150,9 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
fmt->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
|
fmt->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
|
||||||
|
/* broken block size [Rayman 2 (DC)] */
|
||||||
|
if (fmt->block_size == 0x02 && fmt->channels > 1)
|
||||||
|
fmt->block_size = 0x02 * fmt->channels;
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
fmt->coding_type = coding_PCM8_U;
|
fmt->coding_type = coding_PCM8_U;
|
||||||
|
@ -234,7 +237,7 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk
|
||||||
//case 0x6750: /* Ogg Vorbis (mode 2) */
|
//case 0x6750: /* Ogg Vorbis (mode 2) */
|
||||||
//case 0x6751: /* Ogg Vorbis (mode 3) */
|
//case 0x6751: /* Ogg Vorbis (mode 3) */
|
||||||
case 0x676f: /* Ogg Vorbis (mode 1+) [Only One 2 (PC)] */
|
case 0x676f: /* Ogg Vorbis (mode 1+) [Only One 2 (PC)] */
|
||||||
//case 0x6770: /* Ogg Vorbis (mode 2+) */
|
case 0x6770: /* Ogg Vorbis (mode 2+) [Only One (PC)]*/
|
||||||
case 0x6771: /* Ogg Vorbis (mode 3+) [Liar-soft games] */
|
case 0x6771: /* Ogg Vorbis (mode 3+) [Liar-soft games] */
|
||||||
/* vorbis.acm codecs (official-ish, "+" = CBR-style modes?) */
|
/* vorbis.acm codecs (official-ish, "+" = CBR-style modes?) */
|
||||||
fmt->coding_type = coding_OGG_VORBIS;
|
fmt->coding_type = coding_OGG_VORBIS;
|
||||||
|
|
|
@ -2,177 +2,64 @@
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
#include "../util.h"
|
#include "../util.h"
|
||||||
|
|
||||||
/* Wii RWAV */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
// in
|
|
||||||
off_t offset;
|
|
||||||
STREAMFILE *sf;
|
|
||||||
int32_t (*read_32bit)(off_t,STREAMFILE*);
|
|
||||||
|
|
||||||
// out
|
|
||||||
int version;
|
|
||||||
off_t start_offset;
|
|
||||||
off_t info_chunk;
|
|
||||||
off_t wave_offset;
|
|
||||||
} rwav_data_t;
|
|
||||||
|
|
||||||
static void read_rwav(rwav_data_t* rd) {
|
|
||||||
off_t chunk_table_offset;
|
|
||||||
off_t chunk_table_step;
|
|
||||||
off_t info_chunk;
|
|
||||||
off_t data_chunk;
|
|
||||||
|
|
||||||
if (!is_id32be(rd->offset, rd->sf, "RWAV"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* big endian, version 2 */
|
|
||||||
if (read_u32be(rd->offset+4,rd->sf) != 0xFEFF0102)
|
|
||||||
return;
|
|
||||||
|
|
||||||
chunk_table_offset = rd->offset + 0x10;
|
|
||||||
chunk_table_step = 0x08;
|
|
||||||
|
|
||||||
info_chunk = rd->offset + rd->read_32bit(chunk_table_offset, rd->sf);
|
|
||||||
if (!is_id32be(info_chunk, rd->sf, "INFO"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
data_chunk = rd->offset + rd->read_32bit(chunk_table_offset + chunk_table_step, rd->sf);
|
|
||||||
if (!is_id32be(data_chunk, rd->sf, "DATA"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
rd->start_offset = data_chunk + 0x08;
|
|
||||||
rd->info_chunk = info_chunk + 0x08;
|
|
||||||
rd->version = 2;
|
|
||||||
rd->wave_offset = info_chunk - 0x08; /* pretend to have a WAVE */
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void read_rwar(rwav_data_t* rd) {
|
|
||||||
if (!is_id32be(rd->offset, rd->sf, "RWAR"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (read_u32be(rd->offset + 0x04, rd->sf) != 0xFEFF0100) /* version 0 */
|
|
||||||
return;
|
|
||||||
|
|
||||||
rd->offset += 0x60;
|
|
||||||
read_rwav(rd);
|
|
||||||
rd->version = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RWSD is quite similar to BRSTM, but can contain several streams.
|
/* RWSD is quite similar to BRSTM, but can contain several streams.
|
||||||
* Still, some games use it for single streams. We only support the
|
* Still, some games use it for single streams. We only support the single stream form here */
|
||||||
* single stream form here */
|
//TODO this meta is a hack as WSD is just note info, and data offsets are elsewhere,
|
||||||
|
// while this assumes whatever data follows RWSD must belong to it; rework for Wii Sports
|
||||||
VGMSTREAM* init_vgmstream_rwsd(STREAMFILE* sf) {
|
VGMSTREAM* init_vgmstream_rwsd(STREAMFILE* sf) {
|
||||||
VGMSTREAM* vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
char filename[PATH_LIMIT];
|
|
||||||
|
|
||||||
size_t wave_length;
|
size_t wave_length;
|
||||||
int codec;
|
int codec, channels, loop_flag;
|
||||||
int channels;
|
|
||||||
int loop_flag;
|
|
||||||
int rwar = 0;
|
|
||||||
int rwav = 0;
|
|
||||||
rwav_data_t rwav_data;
|
|
||||||
|
|
||||||
size_t stream_size;
|
size_t stream_size;
|
||||||
|
off_t start_offset, wave_offset = 0;
|
||||||
|
|
||||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
|
||||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
|
||||||
|
|
||||||
rwav_data.version = -1;
|
if (!is_id32be(0x00, sf, "RWSD"))
|
||||||
rwav_data.start_offset = 0;
|
|
||||||
rwav_data.info_chunk = -1;
|
|
||||||
rwav_data.wave_offset = -1;
|
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
|
||||||
sf->get_name(sf,filename,sizeof(filename));
|
|
||||||
|
|
||||||
if (check_extensions(sf, "rwsd")) {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
else if (check_extensions(sf, "rwar")) {
|
|
||||||
rwar = 1;
|
|
||||||
}
|
|
||||||
else if (check_extensions(sf, "rwav")) {
|
|
||||||
rwav = 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
|
||||||
|
|
||||||
read_16bit = read_16bitBE;
|
|
||||||
read_32bit = read_32bitBE;
|
|
||||||
|
|
||||||
|
if (!check_extensions(sf, "rwsd"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* check header */
|
/* check header */
|
||||||
if (rwar || rwav) {
|
switch (read_u32be(0x04, sf)) {
|
||||||
rwav_data.offset = 0;
|
case 0xFEFF0102:
|
||||||
rwav_data.sf = sf;
|
/* ideally we would look through the chunk list for a WAVE chunk,
|
||||||
rwav_data.read_32bit = read_32bit;
|
* but it's always in the same order */
|
||||||
|
|
||||||
if (rwar) read_rwar(&rwav_data);
|
/* get WAVE offset, check */
|
||||||
if (rwav) read_rwav(&rwav_data);
|
wave_offset = read_32bitBE(0x18,sf);
|
||||||
if (rwav_data.wave_offset < 0) goto fail;
|
if (!is_id32be(wave_offset + 0x00, sf, "WAVE"))
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!is_id32be(0x00, sf, "RWSD"))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
switch (read_u32be(0x04, sf)) {
|
|
||||||
case 0xFEFF0102:
|
|
||||||
/* ideally we would look through the chunk list for a WAVE chunk,
|
|
||||||
* but it's always in the same order */
|
|
||||||
|
|
||||||
/* get WAVE offset, check */
|
|
||||||
rwav_data.wave_offset = read_32bit(0x18,sf);
|
|
||||||
if (!is_id32be(rwav_data.wave_offset + 0x00, sf, "WAVE"))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* get WAVE size, check */
|
|
||||||
wave_length = read_32bit(0x1c,sf);
|
|
||||||
if (read_32bit(rwav_data.wave_offset + 0x04,sf) != wave_length)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* check wave count */
|
|
||||||
if (read_32bit(rwav_data.wave_offset + 0x08,sf) != 1)
|
|
||||||
goto fail; /* only support 1 */
|
|
||||||
|
|
||||||
rwav_data.version = 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xFEFF0103:
|
|
||||||
rwav_data.offset = 0xe0;
|
|
||||||
rwav_data.sf = sf;
|
|
||||||
rwav_data.read_32bit = read_32bit;
|
|
||||||
|
|
||||||
read_rwar(&rwav_data);
|
|
||||||
if (rwav_data.wave_offset < 0) goto fail;
|
|
||||||
|
|
||||||
rwar = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
|
||||||
|
|
||||||
|
/* get WAVE size, check */
|
||||||
|
wave_length = read_32bitBE(0x1c,sf);
|
||||||
|
if (read_32bitBE(wave_offset + 0x04,sf) != wave_length)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* check wave count */
|
||||||
|
if (read_32bitBE(wave_offset + 0x08,sf) != 1)
|
||||||
|
goto fail; /* only support 1 */
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xFEFF0103: /* followed by RWAR, extract that or use .txth subfile */
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get type details */
|
/* get type details */
|
||||||
codec = read_u8(rwav_data.wave_offset+0x10,sf);
|
codec = read_u8(wave_offset+0x10,sf);
|
||||||
loop_flag = read_u8(rwav_data.wave_offset+0x11,sf);
|
loop_flag = read_u8(wave_offset+0x11,sf);
|
||||||
channels = read_u8(rwav_data.wave_offset+0x12,sf);
|
channels = read_u8(wave_offset+0x12,sf);
|
||||||
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
vgmstream->num_samples = dsp_nibbles_to_samples(read_32bit(rwav_data.wave_offset+0x1c,sf));
|
vgmstream->num_samples = dsp_nibbles_to_samples(read_32bitBE(wave_offset+0x1c,sf));
|
||||||
vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bit(rwav_data.wave_offset+0x18,sf));
|
vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bitBE(wave_offset+0x18,sf));
|
||||||
|
|
||||||
vgmstream->sample_rate = (uint16_t)read_16bit(rwav_data.wave_offset + 0x14,sf);
|
vgmstream->sample_rate = (uint16_t)read_16bitBE(wave_offset + 0x14,sf);
|
||||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||||
|
|
||||||
switch (codec) {
|
switch (codec) {
|
||||||
|
@ -190,84 +77,48 @@ VGMSTREAM* init_vgmstream_rwsd(STREAMFILE* sf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
vgmstream->meta_type = meta_RWSD;
|
||||||
if (rwar) {
|
|
||||||
vgmstream->meta_type = meta_RWAR;
|
|
||||||
}
|
|
||||||
else if (rwav) {
|
|
||||||
vgmstream->meta_type = meta_RWAV;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
vgmstream->meta_type = meta_RWSD;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
off_t data_start_offset;
|
|
||||||
off_t codec_info_offset;
|
off_t codec_info_offset;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
for (j = 0 ; j < vgmstream->channels; j++) {
|
for (j = 0 ; j < vgmstream->channels; j++) {
|
||||||
if (rwar || rwav) {
|
// dummy for RWSD, must be a proper way to work this out
|
||||||
/* This is pretty nasty, so an explaination is in order.
|
codec_info_offset = wave_offset + 0x6c + j*0x30;
|
||||||
* At 0x10 in the info_chunk is the offset of a table with
|
|
||||||
* one entry per channel. Each entry in this table is itself
|
|
||||||
* an offset to a set of information for the channel. The
|
|
||||||
* first element in the set is the offset into DATA of the channel.
|
|
||||||
* The second element is the offset of the codec-specific setup for the channel. */
|
|
||||||
|
|
||||||
off_t channel_info_offset = rwav_data.info_chunk +
|
|
||||||
read_32bit(rwav_data.info_chunk +
|
|
||||||
read_32bit(rwav_data.info_chunk + 0x10,sf) + j*0x04, sf);
|
|
||||||
|
|
||||||
data_start_offset = rwav_data.start_offset +
|
|
||||||
read_32bit(channel_info_offset + 0x00, sf);
|
|
||||||
codec_info_offset = rwav_data.info_chunk +
|
|
||||||
read_32bit(channel_info_offset + 0x04, sf);
|
|
||||||
|
|
||||||
vgmstream->ch[j].channel_start_offset =
|
|
||||||
vgmstream->ch[j].offset = data_start_offset;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// dummy for RWSD, must be a proper way to work this out
|
|
||||||
codec_info_offset = rwav_data.wave_offset + 0x6c + j*0x30;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vgmstream->coding_type == coding_NGC_DSP) {
|
if (vgmstream->coding_type == coding_NGC_DSP) {
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++) {
|
||||||
vgmstream->ch[j].adpcm_coef[i] = read_16bit(codec_info_offset + i*0x2, sf);
|
vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(codec_info_offset + i*0x2, sf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rwar || rwav) {
|
|
||||||
/* */
|
/* this is just data size and following data may or may not be from this RWSD */
|
||||||
}
|
start_offset = read_32bitBE(0x08, sf);
|
||||||
else {
|
|
||||||
if (rwav_data.version == 2)
|
|
||||||
rwav_data.start_offset = read_32bit(0x08, sf);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream_size = read_32bit(rwav_data.wave_offset + 0x50,sf);
|
stream_size = read_32bitBE(wave_offset + 0x50,sf);
|
||||||
|
|
||||||
/* open the file for reading by each channel */
|
/* open the file for reading by each channel */
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i=0;i<channels;i++) {
|
char filename[PATH_LIMIT];
|
||||||
|
|
||||||
|
sf->get_name(sf,filename,sizeof(filename));
|
||||||
|
|
||||||
|
for (i = 0; i < channels; i++) {
|
||||||
vgmstream->ch[i].streamfile = sf->open(sf,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
vgmstream->ch[i].streamfile = sf->open(sf,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||||
|
|
||||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||||
|
|
||||||
if (!(rwar || rwav)) {
|
vgmstream->ch[i].channel_start_offset = vgmstream->ch[i].offset =
|
||||||
vgmstream->ch[i].channel_start_offset=
|
start_offset + i*stream_size;
|
||||||
vgmstream->ch[i].offset=
|
|
||||||
rwav_data.start_offset + i*stream_size;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -1062,6 +1062,7 @@ static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, cha
|
||||||
/* apply */
|
/* apply */
|
||||||
if (!txth->data_size_set) {
|
if (!txth->data_size_set) {
|
||||||
|
|
||||||
|
//TODO: this doesn't work when using name_table + subsongs, since values are pre-read
|
||||||
/* with subsongs we want to clamp data_size from this subsong start to next subsong start */
|
/* with subsongs we want to clamp data_size from this subsong start to next subsong start */
|
||||||
txth->next_offset = txth->data_size;
|
txth->next_offset = txth->data_size;
|
||||||
if (txth->subsong_count > 1 && txth->target_subsong < txth->subsong_count) {
|
if (txth->subsong_count > 1 && txth->target_subsong < txth->subsong_count) {
|
||||||
|
@ -1205,12 +1206,9 @@ static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, cha
|
||||||
else if (is_string(key,"coef_offset")) {
|
else if (is_string(key,"coef_offset")) {
|
||||||
if (!parse_num(txth->sf_head,txth,val, &txth->coef_offset)) goto fail;
|
if (!parse_num(txth->sf_head,txth,val, &txth->coef_offset)) goto fail;
|
||||||
/* special adjustments */
|
/* special adjustments */
|
||||||
VGM_LOG("coef norm=%x\n",txth->coef_offset );
|
|
||||||
txth->coef_offset += txth->base_offset;
|
txth->coef_offset += txth->base_offset;
|
||||||
VGM_LOG("coef+base=%x\n",txth->coef_offset );
|
|
||||||
if (txth->subsong_spacing && !txth->is_offset_absolute)
|
if (txth->subsong_spacing && !txth->is_offset_absolute)
|
||||||
txth->coef_offset += txth->subsong_spacing * (txth->target_subsong - 1);
|
txth->coef_offset += txth->subsong_spacing * (txth->target_subsong - 1);
|
||||||
VGM_LOG("coef+spac=%x\n",txth->coef_offset );
|
|
||||||
}
|
}
|
||||||
else if (is_string(key,"coef_spacing")) {
|
else if (is_string(key,"coef_spacing")) {
|
||||||
if (!parse_num(txth->sf_head,txth,val, &txth->coef_spacing)) goto fail;
|
if (!parse_num(txth->sf_head,txth,val, &txth->coef_spacing)) goto fail;
|
||||||
|
@ -1922,6 +1920,7 @@ static int parse_num(STREAMFILE* sf, txth_header* txth, const char* val, uint32_
|
||||||
else if ((n = is_string_field(val,"sample_rate"))) value = txth->sample_rate;
|
else if ((n = is_string_field(val,"sample_rate"))) value = txth->sample_rate;
|
||||||
else if ((n = is_string_field(val,"start_offset"))) value = txth->start_offset;
|
else if ((n = is_string_field(val,"start_offset"))) value = txth->start_offset;
|
||||||
else if ((n = is_string_field(val,"data_size"))) value = txth->data_size;
|
else if ((n = is_string_field(val,"data_size"))) value = txth->data_size;
|
||||||
|
else if ((n = is_string_field(val,"padding_size"))) value = txth->padding_size;
|
||||||
else if ((n = is_string_field(val,"num_samples"))) value = txth->num_samples;
|
else if ((n = is_string_field(val,"num_samples"))) value = txth->num_samples;
|
||||||
else if ((n = is_string_field(val,"loop_start_sample"))) value = txth->loop_start_sample;
|
else if ((n = is_string_field(val,"loop_start_sample"))) value = txth->loop_start_sample;
|
||||||
else if ((n = is_string_field(val,"loop_start"))) value = txth->loop_start_sample;
|
else if ((n = is_string_field(val,"loop_start"))) value = txth->loop_start_sample;
|
||||||
|
@ -1935,7 +1934,16 @@ static int parse_num(STREAMFILE* sf, txth_header* txth, const char* val, uint32_
|
||||||
else if ((n = is_string_field(val,"subfile_size"))) value = txth->subfile_size;
|
else if ((n = is_string_field(val,"subfile_size"))) value = txth->subfile_size;
|
||||||
else if ((n = is_string_field(val,"base_offset"))) value = txth->base_offset;
|
else if ((n = is_string_field(val,"base_offset"))) value = txth->base_offset;
|
||||||
else if ((n = is_string_field(val,"coef_offset"))) value = txth->coef_offset;
|
else if ((n = is_string_field(val,"coef_offset"))) value = txth->coef_offset;
|
||||||
|
else if ((n = is_string_field(val,"coef_spacing"))) value = txth->coef_spacing;
|
||||||
else if ((n = is_string_field(val,"hist_offset"))) value = txth->hist_offset;
|
else if ((n = is_string_field(val,"hist_offset"))) value = txth->hist_offset;
|
||||||
|
else if ((n = is_string_field(val,"hist_spacing"))) value = txth->hist_spacing;
|
||||||
|
else if ((n = is_string_field(val,"chunk_count"))) value = txth->chunk_count;
|
||||||
|
else if ((n = is_string_field(val,"chunk_start"))) value = txth->chunk_start;
|
||||||
|
else if ((n = is_string_field(val,"chunk_size"))) value = txth->chunk_size;
|
||||||
|
else if ((n = is_string_field(val,"chunk_size_offset"))) value = txth->chunk_size_offset;
|
||||||
|
else if ((n = is_string_field(val,"chunk_number"))) value = txth->chunk_number;
|
||||||
|
else if ((n = is_string_field(val,"chunk_data_size"))) value = txth->chunk_data_size;
|
||||||
|
else if ((n = is_string_field(val,"chunk_header_size"))) value = txth->chunk_header_size;
|
||||||
//todo whatever, improve
|
//todo whatever, improve
|
||||||
else if ((n = is_string_field(val,"name_value"))) value = txth->name_values[0];
|
else if ((n = is_string_field(val,"name_value"))) value = txth->name_values[0];
|
||||||
else if ((n = is_string_field(val,"name_value1"))) value = txth->name_values[0];
|
else if ((n = is_string_field(val,"name_value1"))) value = txth->name_values[0];
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
#include "ubi_bao_streamfile.h"
|
#include "ubi_bao_streamfile.h"
|
||||||
|
|
||||||
|
#define BAO_MIN_VERSION 0x1B
|
||||||
|
#define BAO_MAX_VERSION 0x2A
|
||||||
|
|
||||||
#define BAO_MAX_LAYER_COUNT 16 /* arbitrary max */
|
#define BAO_MAX_LAYER_COUNT 16 /* arbitrary max */
|
||||||
#define BAO_MAX_CHAIN_COUNT 128 /* POP:TFS goes up to ~100 */
|
#define BAO_MAX_CHAIN_COUNT 128 /* POP:TFS goes up to ~100 */
|
||||||
|
@ -145,6 +147,11 @@ VGMSTREAM* init_vgmstream_ubi_bao_pk(STREAMFILE* sf) {
|
||||||
ubi_bao_header bao = { 0 };
|
ubi_bao_header bao = { 0 };
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
|
if (read_u8(0x00, sf) != 0x01)
|
||||||
|
goto fail;
|
||||||
|
if (read_u8(0x01, sf) < BAO_MIN_VERSION || read_u8(0x01, sf) > BAO_MAX_VERSION)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
if (!check_extensions(sf, "pk,lpk,cpk"))
|
if (!check_extensions(sf, "pk,lpk,cpk"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
@ -161,12 +168,17 @@ fail:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* .BAO - single BAO files from Ubisoft's sound engine ("DARE") games in 2008+ */
|
/* .BAO - single BAO files from Ubisoft's sound engine ("DARE") games in 2007+ */
|
||||||
VGMSTREAM* init_vgmstream_ubi_bao_atomic(STREAMFILE* sf) {
|
VGMSTREAM* init_vgmstream_ubi_bao_atomic(STREAMFILE* sf) {
|
||||||
ubi_bao_header bao = { 0 };
|
ubi_bao_header bao = { 0 };
|
||||||
STREAMFILE* streamData = NULL;
|
STREAMFILE* streamData = NULL;
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
|
if (read_u8(0x00, sf) != 0x01 && read_u8(0x00, sf) != 0x02) /* 0x01=AC1, 0x02=POP2008 */
|
||||||
|
goto fail;
|
||||||
|
if (read_u8(0x01, sf) < BAO_MIN_VERSION || read_u8(0x01, sf) > BAO_MAX_VERSION)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
if (!check_extensions(sf, "bao,"))
|
if (!check_extensions(sf, "bao,"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
@ -174,13 +186,9 @@ VGMSTREAM* init_vgmstream_ubi_bao_atomic(STREAMFILE* sf) {
|
||||||
* since BAOs reference each other by id and are named by it (though the internal BAO id may
|
* since BAOs reference each other by id and are named by it (though the internal BAO id may
|
||||||
* be other) we can simulate it. Extension is .bao/sbao or extensionaless in some games. */
|
* be other) we can simulate it. Extension is .bao/sbao or extensionaless in some games. */
|
||||||
|
|
||||||
/* format: 0x01=AC1, 0x02=POP2008 */
|
|
||||||
if (read_8bit(0x00, sf) != 0x01 && read_8bit(0x00, sf) != 0x02)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
bao.is_atomic = 1;
|
bao.is_atomic = 1;
|
||||||
|
|
||||||
bao.version = read_32bitBE(0x00, sf) & 0x00FFFFFF;
|
bao.version = read_u32be(0x00, sf) & 0x00FFFFFF;
|
||||||
if (!config_bao_version(&bao, sf))
|
if (!config_bao_version(&bao, sf))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
@ -644,7 +652,7 @@ static VGMSTREAM* init_vgmstream_ubi_bao_header(ubi_bao_header* bao, STREAMFILE*
|
||||||
(uint32_t)bao->header_offset, bao->header_id, bao->stream_id, bao->prefetch_id);
|
(uint32_t)bao->header_offset, bao->header_id, bao->stream_id, bao->prefetch_id);
|
||||||
;VGM_LOG("UBI BAO: stream=%x, size=%x, res=%s\n",
|
;VGM_LOG("UBI BAO: stream=%x, size=%x, res=%s\n",
|
||||||
(uint32_t)bao->stream_offset, bao->stream_size, (bao->is_external ? bao->resource_name : "internal"));
|
(uint32_t)bao->stream_offset, bao->stream_size, (bao->is_external ? bao->resource_name : "internal"));
|
||||||
;VGM_LOG("UBI BAO: type=%i, header=%x, extra=%x, prefetch=%x, size=%x\n",
|
;VGM_LOG("UBI BAO: type=%i, header=%x, extra=%x, pre.of=%x, pre.sz=%x\n",
|
||||||
bao->header_type, bao->header_size, bao->extra_size, (uint32_t)bao->prefetch_offset, bao->prefetch_size);
|
bao->header_type, bao->header_size, bao->extra_size, (uint32_t)bao->prefetch_offset, bao->prefetch_size);
|
||||||
|
|
||||||
|
|
||||||
|
@ -703,8 +711,8 @@ static int parse_pk(ubi_bao_header* bao, STREAMFILE* sf) {
|
||||||
|
|
||||||
if (target_subsong <= 0) target_subsong = 1;
|
if (target_subsong <= 0) target_subsong = 1;
|
||||||
|
|
||||||
bao->version = read_32bitBE(0x00, sf) & 0x00FFFFFF;
|
bao->version = read_u32be(0x00, sf) & 0x00FFFFFF;
|
||||||
index_size = read_32bitLE(0x04, sf); /* can be 0, not including */
|
index_size = read_u32le(0x04, sf); /* can be 0, not including */
|
||||||
/* 0x08: resource table offset, always found even if not used */
|
/* 0x08: resource table offset, always found even if not used */
|
||||||
/* 0x0c: always 0? */
|
/* 0x0c: always 0? */
|
||||||
/* 0x10: unknown, null if no entries */
|
/* 0x10: unknown, null if no entries */
|
||||||
|
@ -1125,11 +1133,12 @@ static int parse_offsets(ubi_bao_header* bao, STREAMFILE* sf) {
|
||||||
read_string(bao->resource_name,255, resources_offset + 0x04+0x04 + name_offset, sf);
|
read_string(bao->resource_name,255, resources_offset + 0x04+0x04 + name_offset, sf);
|
||||||
|
|
||||||
if (bao->stream_size != resource_size - bao->stream_skip + bao->prefetch_size) {
|
if (bao->stream_size != resource_size - bao->stream_skip + bao->prefetch_size) {
|
||||||
VGM_LOG("UBI BAO: stream vs resource size mismatch at %lx (%x vs %x, %x, %x)\n", offset+0x10*i, bao->stream_size, resource_size, bao->stream_skip, bao->prefetch_size);
|
VGM_LOG("UBI BAO: stream vs resource size mismatch at %lx (res %x vs str=%x, skip=%x, pre=%x)\n", offset+0x10*i, resource_size, bao->stream_size, bao->stream_skip, bao->prefetch_size);
|
||||||
|
|
||||||
/* rarely resource has more data than stream (sometimes a few bytes, others +0x100000)
|
/* rarely resource has more data than stream (sometimes a few bytes, others +0x100000)
|
||||||
* sometimes short song versions, but not accessed? no samples/sizes/cues/etc in header seem to refer to that [Just Dance (Wii)] */
|
* sometimes short song versions, but not accessed? no samples/sizes/cues/etc in header seem to refer to that [Just Dance (Wii)]
|
||||||
if (!bao->cfg.audio_ignore_resource_size || bao->prefetch_size)
|
* Michael Jackson The Experience also uses prefetch size + bad size (ignored) */
|
||||||
|
if (!bao->cfg.audio_ignore_resource_size && bao->prefetch_size)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1350,6 +1359,22 @@ static STREAMFILE* open_atomic_bao(ubi_bao_file file_type, uint32_t file_id, int
|
||||||
if (sf_bao) return sf_bao;
|
if (sf_bao) return sf_bao;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If all else fails, try %08x.bao/%08x.sbao nomenclature.
|
||||||
|
* (id).bao is for mimicking engine loading files by internal ID,
|
||||||
|
* original names (like Common_BAO_0x5NNNNNNN, French_BAO_0x5NNNNNNN and the like) are OK too. */
|
||||||
|
if (file_type != UBI_FORGE_b) {
|
||||||
|
/* %08x.bao nomenclature present in Assassin's Creed (Windows Vista) exe. */
|
||||||
|
snprintf(buf,buf_size, "%08x.bao", file_id);
|
||||||
|
sf_bao = open_streamfile_by_filename(sf, buf);
|
||||||
|
if (sf_bao) return sf_bao;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* %08x.sbao nomenclature (in addition to %08x.bao) present in Shaun White Snowboarding (Windows Vista) exe. */
|
||||||
|
snprintf(buf,buf_size, "%08x.sbao", file_id);
|
||||||
|
sf_bao = open_streamfile_by_filename(sf, buf);
|
||||||
|
if (sf_bao) return sf_bao;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
snprintf(buf,buf_size, "BAO_0x%08x", file_id);
|
snprintf(buf,buf_size, "BAO_0x%08x", file_id);
|
||||||
|
@ -1359,6 +1384,11 @@ static STREAMFILE* open_atomic_bao(ubi_bao_file file_type, uint32_t file_id, int
|
||||||
strcat(buf,".bao");
|
strcat(buf,".bao");
|
||||||
sf_bao = open_streamfile_by_filename(sf, buf);
|
sf_bao = open_streamfile_by_filename(sf, buf);
|
||||||
if (sf_bao) return sf_bao;
|
if (sf_bao) return sf_bao;
|
||||||
|
|
||||||
|
/* Ditto. */
|
||||||
|
snprintf(buf,buf_size, "%08x.bao", file_id);
|
||||||
|
sf_bao = open_streamfile_by_filename(sf, buf);
|
||||||
|
if (sf_bao) return sf_bao;
|
||||||
}
|
}
|
||||||
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -1853,6 +1883,23 @@ static int config_bao_version(ubi_bao_header* bao, STREAMFILE* sf) {
|
||||||
bao->cfg.codec_map[0x06] = RAW_AT3_105;
|
bao->cfg.codec_map[0x06] = RAW_AT3_105;
|
||||||
|
|
||||||
bao->cfg.file_type = UBI_FORGE_b;
|
bao->cfg.file_type = UBI_FORGE_b;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case 0x00260000: /* Michael Jackson: The Experience (X360)-package */
|
||||||
|
config_bao_entry(bao, 0xB8, 0x28);
|
||||||
|
|
||||||
|
config_bao_audio_b(bao, 0x08, 0x28, 0x30, 0x3c, 1, 1); //loop?
|
||||||
|
config_bao_audio_m(bao, 0x4c, 0x54, 0x5c, 0x64, 0x6c, 0x7c);
|
||||||
|
|
||||||
|
config_bao_layer_m(bao, 0x00, 0x2c, 0x34, 0x4c, 0x54, 0x58, 0x00, 0x00, 1);
|
||||||
|
config_bao_layer_e(bao, 0x34, 0x00, 0x04, 0x08, 0x1c);
|
||||||
|
|
||||||
|
bao->cfg.codec_map[0x03] = FMT_OGG;
|
||||||
|
bao->cfg.codec_map[0x04] = RAW_XMA2_NEW;
|
||||||
|
|
||||||
|
bao->cfg.audio_ignore_resource_size = 1; /* leave_me_alone.pk */
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case 0x00270102: /* Drawsome (Wii)-package */
|
case 0x00270102: /* Drawsome (Wii)-package */
|
||||||
|
|
|
@ -170,7 +170,7 @@ VGMSTREAM* init_vgmstream_wbk_nslb(STREAMFILE* sf) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* always little endian, even on PS3/X360 */
|
/* always little endian, even on PS3/X360 */
|
||||||
if (read_u32le(0x04, sf) != 0x01)
|
if (read_u16le(0x04, sf) != 0x01)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
total_subsongs = read_u32le(0x10, sf);
|
total_subsongs = read_u32le(0x10, sf);
|
||||||
|
|
|
@ -410,10 +410,21 @@ VGMSTREAM* init_vgmstream_wwise_bnk(STREAMFILE* sf, int* p_prefetch) {
|
||||||
vgmstream->coding_type = coding_FFmpeg;
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
|
//if (ww.prefetch) {
|
||||||
|
// ww.data_size = ww.file_size - ww.data_offset;
|
||||||
|
//}
|
||||||
|
|
||||||
/* seek table seems BE dpds */
|
/* seek table seems BE dpds */
|
||||||
vgmstream->num_samples = xwma_dpds_get_samples(sf, ww.seek_offset, ww.seek_size, ww.channels, ww.big_endian);
|
vgmstream->num_samples = xwma_dpds_get_samples(sf, ww.seek_offset, ww.seek_size, ww.channels, ww.big_endian);
|
||||||
if (!vgmstream->num_samples)
|
if (!vgmstream->num_samples)
|
||||||
vgmstream->num_samples = xwma_get_samples(sf, ww.data_offset, ww.data_size, ww.format, ww.channels, ww.sample_rate, ww.block_size);
|
vgmstream->num_samples = xwma_get_samples(sf, ww.data_offset, ww.data_size, ww.format, ww.channels, ww.sample_rate, ww.block_size);
|
||||||
|
|
||||||
|
/* XWMA is VBR so this is very approximate percent, meh */
|
||||||
|
if (ww.prefetch) { /* Guardians of Middle Earth (X360) */
|
||||||
|
vgmstream->num_samples = (int32_t)(vgmstream->num_samples *
|
||||||
|
(double)(ww.file_size - start_offset) / (double)ww.data_size);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -921,7 +932,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ww->codec == PCM || ww->codec == IMA || ww->codec == VORBIS || ww->codec == DSP || ww->codec == XMA2 ||
|
if (ww->codec == PCM || ww->codec == IMA || ww->codec == VORBIS || ww->codec == DSP || ww->codec == XMA2 ||
|
||||||
ww->codec == OPUSNX || ww->codec == OPUS || ww->codec == OPUSWW || ww->codec == PTADPCM) {
|
ww->codec == OPUSNX || ww->codec == OPUS || ww->codec == OPUSWW || ww->codec == PTADPCM || ww->codec == XWMA) {
|
||||||
ww->prefetch = 1; /* only seen those, probably all exist (XWMA, AAC, HEVAG, ATRAC9?) */
|
ww->prefetch = 1; /* only seen those, probably all exist (XWMA, AAC, HEVAG, ATRAC9?) */
|
||||||
} else {
|
} else {
|
||||||
vgm_logi("WWISE: wrong expected size, maybe prefetch (report)\n");
|
vgm_logi("WWISE: wrong expected size, maybe prefetch (report)\n");
|
||||||
|
|
|
@ -1,58 +1,64 @@
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
/* 04SW - found in Driver: Parallel Lines (Wii) */
|
/* 04SW - Reflections games [Driver: Parallel Lines (Wii), Emergency Heroes (Wii)] */
|
||||||
VGMSTREAM * init_vgmstream_xa_04sw(STREAMFILE *streamFile) {
|
VGMSTREAM* init_vgmstream_xa_04sw(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
int loop_flag, channel_count;
|
int loop_flag, channels, sample_rate;
|
||||||
size_t file_size, data_size;
|
int32_t num_samples;
|
||||||
|
uint32_t data_size;
|
||||||
|
|
||||||
/* checks */
|
|
||||||
/* ".04sw" is just the ID, the real filename inside the file uses .XA */
|
/* checks */
|
||||||
if (!check_extensions(streamFile,"xa,04sw"))
|
if (!is_id32be(0x00,sf, "04SW"))
|
||||||
goto fail;
|
goto fail;
|
||||||
if (read_32bitBE(0x00,streamFile) != 0x30345357) /* "04SW" */
|
|
||||||
goto fail;
|
if (!check_extensions(sf,"xa"))
|
||||||
|
goto fail;
|
||||||
/* after the ID goes a semi-standard DSP header */
|
|
||||||
if (read_32bitBE(0x10,streamFile) != 0) goto fail; /* should be non looping */
|
/* after the ID goes a modified DSP header x2 */
|
||||||
loop_flag = 0;
|
if (read_u32be(0x04 + 0x0c,sf) != 0) /* should be non looping */
|
||||||
/* not in header it seems so just dual header check */
|
goto fail;
|
||||||
channel_count = (read_32bitBE(0x04,streamFile) == read_32bitBE(0x64,streamFile)) ? 2 : 1;
|
loop_flag = 0;
|
||||||
|
/* not in header it seems, so just dual header check */
|
||||||
start_offset = read_32bitBE(0x04 + 0x60*channel_count,streamFile);
|
|
||||||
|
num_samples = read_s32be(0x04 + 0x00,sf);
|
||||||
file_size = get_streamfile_size(streamFile);
|
data_size = read_u32be(0x04 + 0x04,sf);
|
||||||
data_size = read_32bitBE(0x04 + 0x60*channel_count + 0x04,streamFile);
|
sample_rate = read_u32be(0x0c,sf);
|
||||||
if (data_size+start_offset != file_size) goto fail;
|
|
||||||
|
channels = (read_u32be(0x04 + 0x00,sf) == read_u32be(0x04 + 0x60,sf)) ? 2 : 1; /* some voice .xa */
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* After DSP header goes a base header with mostly unknown values (several repeats) and the filename.
|
||||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
* Emergency Heroes has extra 0x10 at 0x10. */
|
||||||
if (!vgmstream) goto fail;
|
start_offset = read_u32be(0x04 + 0x60 * 2 + 0x00, sf);
|
||||||
|
/* 0x04: data size (includes padding after DSP data in Driver, doesn't in Emergency Heroes */
|
||||||
vgmstream->sample_rate = read_32bitBE(0x0c,streamFile);
|
/* 0x1c/2c: channels LE? */
|
||||||
vgmstream->num_samples = read_32bitBE(0x04,streamFile);
|
/* 0x74/84: utf-16 path+filename */
|
||||||
|
|
||||||
vgmstream->coding_type = coding_NGC_DSP;
|
|
||||||
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
|
/* build the VGMSTREAM */
|
||||||
vgmstream->interleave_block_size = 0x8000;
|
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||||
vgmstream->interleave_last_block_size = (read_32bitBE(0x08,streamFile) / 2 % vgmstream->interleave_block_size + 7) / 8 * 8;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
dsp_read_coefs_be(vgmstream,streamFile,0x20, 0x60);
|
vgmstream->sample_rate = sample_rate;
|
||||||
/* the initial history offset seems different thatn standard DSP and possibly always zero */
|
vgmstream->num_samples = num_samples;
|
||||||
|
|
||||||
vgmstream->meta_type = meta_XA_04SW;
|
vgmstream->coding_type = coding_NGC_DSP;
|
||||||
/* the rest of the header has unknown values (several repeats) and the filename */
|
vgmstream->layout_type = channels == 1 ? layout_none : layout_interleave;
|
||||||
|
vgmstream->interleave_block_size = 0x8000;
|
||||||
|
vgmstream->interleave_last_block_size = (data_size / 2 % vgmstream->interleave_block_size + 7) / 8 * 8;
|
||||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
|
||||||
goto fail;
|
dsp_read_coefs_be(vgmstream, sf, 0x04 + 0x1c, 0x60);
|
||||||
return vgmstream;
|
/* initial history offset seems different than standard DSP and possibly fixed/invalid */
|
||||||
|
|
||||||
fail:
|
vgmstream->meta_type = meta_XA_04SW;
|
||||||
close_vgmstream(vgmstream);
|
|
||||||
return NULL;
|
|
||||||
}
|
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||||
|
goto fail;
|
||||||
|
return vgmstream;
|
||||||
|
fail:
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
|
@ -20,8 +20,10 @@ static void try_dual_file_stereo(VGMSTREAM* opened_vgmstream, STREAMFILE* sf, VG
|
||||||
VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||||
init_vgmstream_adx,
|
init_vgmstream_adx,
|
||||||
init_vgmstream_brstm,
|
init_vgmstream_brstm,
|
||||||
|
init_vgmstream_brwav,
|
||||||
init_vgmstream_bfwav,
|
init_vgmstream_bfwav,
|
||||||
init_vgmstream_bcwav,
|
init_vgmstream_bcwav,
|
||||||
|
init_vgmstream_brwar,
|
||||||
init_vgmstream_nds_strm,
|
init_vgmstream_nds_strm,
|
||||||
init_vgmstream_afc,
|
init_vgmstream_afc,
|
||||||
init_vgmstream_ast,
|
init_vgmstream_ast,
|
||||||
|
@ -519,6 +521,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||||
init_vgmstream_ubi_ckd_cwav,
|
init_vgmstream_ubi_ckd_cwav,
|
||||||
|
|
||||||
/* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */
|
/* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */
|
||||||
|
init_vgmstream_mpeg,
|
||||||
init_vgmstream_agsc,
|
init_vgmstream_agsc,
|
||||||
init_vgmstream_dtk,
|
init_vgmstream_dtk,
|
||||||
init_vgmstream_rsf,
|
init_vgmstream_rsf,
|
||||||
|
|
|
@ -762,6 +762,7 @@ typedef enum {
|
||||||
meta_WBK,
|
meta_WBK,
|
||||||
meta_WBK_NSLB,
|
meta_WBK_NSLB,
|
||||||
meta_DSP_APEX,
|
meta_DSP_APEX,
|
||||||
|
meta_MPEG,
|
||||||
|
|
||||||
} meta_t;
|
} meta_t;
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,6 @@
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleTypeExtensions</key>
|
<key>CFBundleTypeExtensions</key>
|
||||||
<array>
|
<array>
|
||||||
<string>04sw</string>
|
|
||||||
<string>208</string>
|
<string>208</string>
|
||||||
<string>2dx9</string>
|
<string>2dx9</string>
|
||||||
<string>2pfs</string>
|
<string>2pfs</string>
|
||||||
|
@ -645,6 +644,7 @@
|
||||||
<string>xma</string>
|
<string>xma</string>
|
||||||
<string>xma2</string>
|
<string>xma2</string>
|
||||||
<string>xmu</string>
|
<string>xmu</string>
|
||||||
|
<string>xmv</string>
|
||||||
<string>xnb</string>
|
<string>xnb</string>
|
||||||
<string>xsh</string>
|
<string>xsh</string>
|
||||||
<string>xsf</string>
|
<string>xsf</string>
|
||||||
|
|
Loading…
Reference in New Issue