diff --git a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj index f7d556e40..333cacff7 100644 --- a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj +++ b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 83031EDB243C510500C3F3E0 /* xnb_lz4mg.h in Headers */ = {isa = PBXBuildFile; fileRef = 83031ED6243C510400C3F3E0 /* xnb_lz4mg.h */; }; 83031EDC243C510500C3F3E0 /* vid1.c in Sources */ = {isa = PBXBuildFile; fileRef = 83031ED7243C510400C3F3E0 /* vid1.c */; }; 83031EDD243C510500C3F3E0 /* xnb_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83031ED8243C510500C3F3E0 /* xnb_streamfile.h */; }; + 830595D8277EEAA500EBFAAE /* ffmpeg_decoder_custom_mp4.c in Sources */ = {isa = PBXBuildFile; fileRef = 830595D7277EEAA500EBFAAE /* ffmpeg_decoder_custom_mp4.c */; }; 8306B08420984518000302D4 /* at3plus_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B08120984517000302D4 /* at3plus_decoder.c */; }; 8306B08520984518000302D4 /* yamaha_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B08220984517000302D4 /* yamaha_decoder.c */; }; 8306B08620984518000302D4 /* fadpcm_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 8306B08320984517000302D4 /* fadpcm_decoder.c */; }; @@ -377,13 +378,12 @@ 836F6FF218BDC2190095E648 /* ps2_rnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB618BDC2180095E648 /* ps2_rnd.c */; }; 836F6FF318BDC2190095E648 /* ps2_rstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB718BDC2180095E648 /* ps2_rstm.c */; }; 836F6FF418BDC2190095E648 /* rws.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EB818BDC2180095E648 /* rws.c */; }; - 836F6FF618BDC2190095E648 /* ps2_sfs.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBA18BDC2180095E648 /* ps2_sfs.c */; }; + 836F6FF618BDC2190095E648 /* ster.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBA18BDC2180095E648 /* ster.c */; }; 836F6FF718BDC2190095E648 /* ps2_sl3.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBB18BDC2180095E648 /* ps2_sl3.c */; }; 836F6FF818BDC2190095E648 /* ps2_smpl.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBC18BDC2180095E648 /* ps2_smpl.c */; }; 836F6FF918BDC2190095E648 /* ps2_snd.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBD18BDC2180095E648 /* ps2_snd.c */; }; 836F6FFA18BDC2190095E648 /* spm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBE18BDC2190095E648 /* spm.c */; }; 836F6FFB18BDC2190095E648 /* ps2_sps.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EBF18BDC2190095E648 /* ps2_sps.c */; }; - 836F6FFC18BDC2190095E648 /* ps2_ster.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EC018BDC2190095E648 /* ps2_ster.c */; }; 836F700118BDC2190095E648 /* ps2_tec.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EC518BDC2190095E648 /* ps2_tec.c */; }; 836F700218BDC2190095E648 /* ps2_tk5.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EC618BDC2190095E648 /* ps2_tk5.c */; }; 836F700418BDC2190095E648 /* ps2_vas.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EC818BDC2190095E648 /* ps2_vas.c */; }; @@ -846,6 +846,7 @@ 83031ED6243C510400C3F3E0 /* xnb_lz4mg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xnb_lz4mg.h; sourceTree = ""; }; 83031ED7243C510400C3F3E0 /* vid1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vid1.c; sourceTree = ""; }; 83031ED8243C510500C3F3E0 /* xnb_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xnb_streamfile.h; sourceTree = ""; }; + 830595D7277EEAA500EBFAAE /* ffmpeg_decoder_custom_mp4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffmpeg_decoder_custom_mp4.c; sourceTree = ""; }; 8306B08120984517000302D4 /* at3plus_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = at3plus_decoder.c; sourceTree = ""; }; 8306B08220984517000302D4 /* yamaha_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yamaha_decoder.c; sourceTree = ""; }; 8306B08320984517000302D4 /* fadpcm_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fadpcm_decoder.c; sourceTree = ""; }; @@ -1195,13 +1196,12 @@ 836F6EB618BDC2180095E648 /* ps2_rnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rnd.c; sourceTree = ""; }; 836F6EB718BDC2180095E648 /* ps2_rstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_rstm.c; sourceTree = ""; }; 836F6EB818BDC2180095E648 /* rws.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rws.c; sourceTree = ""; }; - 836F6EBA18BDC2180095E648 /* ps2_sfs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_sfs.c; sourceTree = ""; }; + 836F6EBA18BDC2180095E648 /* ster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ster.c; sourceTree = ""; }; 836F6EBB18BDC2180095E648 /* ps2_sl3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_sl3.c; sourceTree = ""; }; 836F6EBC18BDC2180095E648 /* ps2_smpl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_smpl.c; sourceTree = ""; }; 836F6EBD18BDC2180095E648 /* ps2_snd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_snd.c; sourceTree = ""; }; 836F6EBE18BDC2190095E648 /* spm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = spm.c; sourceTree = ""; }; 836F6EBF18BDC2190095E648 /* ps2_sps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_sps.c; sourceTree = ""; }; - 836F6EC018BDC2190095E648 /* ps2_ster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_ster.c; sourceTree = ""; }; 836F6EC518BDC2190095E648 /* ps2_tec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_tec.c; sourceTree = ""; }; 836F6EC618BDC2190095E648 /* ps2_tk5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_tk5.c; sourceTree = ""; }; 836F6EC818BDC2190095E648 /* ps2_vas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_vas.c; sourceTree = ""; }; @@ -1676,6 +1676,7 @@ 83AA5D0E1F6E2F5F0020821C /* ea_xa_decoder.c */, 83AA5D151F6E2F600020821C /* ea_xas_decoder.c */, 8306B08320984517000302D4 /* fadpcm_decoder.c */, + 830595D7277EEAA500EBFAAE /* ffmpeg_decoder_custom_mp4.c */, 834FE0AB215C798A000A5D3D /* ffmpeg_decoder_custom_opus.c */, 837CEA7723487E2400E62A4A /* ffmpeg_decoder_utils.c */, 838BDB6B1D3AFAB10022CA6F /* ffmpeg_decoder.c */, @@ -2086,12 +2087,10 @@ 836F6EB318BDC2180095E648 /* ps2_pnb.c */, 836F6EB618BDC2180095E648 /* ps2_rnd.c */, 836F6EB718BDC2180095E648 /* ps2_rstm.c */, - 836F6EBA18BDC2180095E648 /* ps2_sfs.c */, 836F6EBB18BDC2180095E648 /* ps2_sl3.c */, 836F6EBC18BDC2180095E648 /* ps2_smpl.c */, 836F6EBD18BDC2180095E648 /* ps2_snd.c */, 836F6EBF18BDC2190095E648 /* ps2_sps.c */, - 836F6EC018BDC2190095E648 /* ps2_ster.c */, 836F6EC518BDC2190095E648 /* ps2_tec.c */, 836F6EC618BDC2190095E648 /* ps2_tk5.c */, 832BF80D21E05148006F50F1 /* ps2_va3.c */, @@ -2163,6 +2162,7 @@ 837CEAF023487F2C00E62A4A /* sqex_sead_streamfile.h */, 83A21F84201D8981000F04B9 /* sqex_sead.c */, 8317C24826982CC1007DD0B8 /* sspr.c */, + 836F6EBA18BDC2180095E648 /* ster.c */, 8306B0C12098458C000302D4 /* sthd.c */, 83AA5D231F6E2F9C0020821C /* stm.c */, 836F6EF718BDC2190095E648 /* str_snds.c */, @@ -2700,7 +2700,6 @@ 8322ECE7240268BB009E9429 /* raw_al.c in Sources */, 83EDE5D91A70951A005F5D84 /* btsnd.c in Sources */, 8306B0E420984590000302D4 /* wave.c in Sources */, - 836F6FFC18BDC2190095E648 /* ps2_ster.c in Sources */, 8349A9171FE6258200E26435 /* pc_adp_otns.c in Sources */, 836F701E18BDC2190095E648 /* redspark.c in Sources */, 8306B0ED20984590000302D4 /* txtp.c in Sources */, @@ -2795,6 +2794,7 @@ 835B9B912730BF2D00F87EE3 /* lopu_fb.c in Sources */, 8346D97B25BF838C00D1A8B0 /* ktac.c in Sources */, 8349A8ED1FE6253900E26435 /* blocked_ea_sns.c in Sources */, + 830595D8277EEAA500EBFAAE /* ffmpeg_decoder_custom_mp4.c in Sources */, 836F6F6F18BDC2190095E648 /* akb.c in Sources */, 83EED5D6203A8BD7008BEB45 /* blocked_ea_swvr.c in Sources */, 8349A9181FE6258200E26435 /* ea_1snh.c in Sources */, @@ -3007,7 +3007,7 @@ 836F702A18BDC2190095E648 /* sd9.c in Sources */, 836F6FB418BDC2190095E648 /* ngc_nst_dsp.c in Sources */, 836F6FDB18BDC2190095E648 /* ps2_hsf.c in Sources */, - 836F6FF618BDC2190095E648 /* ps2_sfs.c in Sources */, + 836F6FF618BDC2190095E648 /* ster.c in Sources */, 834FE10E215C79ED000A5D3D /* ahv.c in Sources */, 8306B08420984518000302D4 /* at3plus_decoder.c in Sources */, 8349A90E1FE6258200E26435 /* scd_pcm.c in Sources */, diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding.h b/Frameworks/vgmstream/vgmstream/src/coding/coding.h index 40ea9f99e..8e5453a71 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/coding.h +++ b/Frameworks/vgmstream/vgmstream/src/coding/coding.h @@ -338,7 +338,7 @@ typedef struct { } hca_keytest_t; void test_hca_key(hca_codec_data* data, hca_keytest_t* hk); -void hca_set_encryption_key(hca_codec_data* data, uint64_t keycode); +void hca_set_encryption_key(hca_codec_data* data, uint64_t keycode, uint64_t subkey); STREAMFILE* hca_get_streamfile(hca_codec_data* data); @@ -639,6 +639,26 @@ size_t switch_opus_get_encoder_delay(off_t offset, STREAMFILE* sf); size_t ue4_opus_get_encoder_delay(off_t offset, STREAMFILE* sf); size_t ea_opus_get_encoder_delay(off_t offset, STREAMFILE* sf); size_t fsb_opus_get_encoder_delay(off_t offset, STREAMFILE* sf); + +/* ffmpeg_decoder_custom_mp4.c*/ +typedef struct { + int channels; + int sample_rate; + int32_t num_samples; + + uint32_t stream_offset; + uint32_t stream_size; + uint32_t table_offset; + uint32_t table_entries; + + int encoder_delay; + int end_padding; + int frame_samples; +} mp4_custom_t; + +ffmpeg_codec_data* init_ffmpeg_mp4_custom_std(STREAMFILE* sf, mp4_custom_t* mp4); +ffmpeg_codec_data* init_ffmpeg_mp4_custom_lyn(STREAMFILE* sf, mp4_custom_t* mp4); + #endif diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_mp4.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_mp4.c new file mode 100644 index 000000000..fb8379866 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_mp4.c @@ -0,0 +1,538 @@ +#include "coding.h" +#include "../streamfile.h" +#include "../meta/deblock_streamfile.h" + +#ifdef VGM_USE_FFMPEG + +typedef enum { MP4_STD, MP4_LYN } mp4_type_t; + +/** + * Makes a MP4 header for MP4 raw data with a separate frame table, simulating a real MP4 that + * also has such table embedded in their custom chunks. + */ +//TODO: segfaults with certain audio files (ffmpeg?) + +/* *********************************************************** */ + +/* Helpers to make a M4A header, an insane soup of chunks (AKA "atoms"). + * Needs *A LOT* of atoms and fields so this is more elaborate than usual. + * - https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFPreface/qtffPreface.html + */ + +/* generic additions */ +typedef struct { + uint8_t* out; + int bytes; +} m4a_state_t; + +typedef struct { + STREAMFILE* sf; + mp4_custom_t* mp4; /* config */ + mp4_type_t type; + + uint8_t* out; /* current position */ + int bytes; /* written bytes */ + m4a_state_t chunks; /* chunks offsets are absolute, save position until we know header size */ +} m4a_header_t; + +static void add_u32b(m4a_header_t* h, uint32_t value) { + put_u32be(h->out, value); + h->out += 0x04; + h->bytes += 0x04; +} + +static void add_u24b(m4a_header_t* h, uint32_t value) { + put_u16be(h->out + 0x00, (value >> 8u) & 0xFFFF); + put_u8 (h->out + 0x02, (value >> 0u) & 0xFF); + h->out += 0x03; + h->bytes += 0x03; +} + +static void add_u16b(m4a_header_t* h, uint16_t value) { + put_u16be(h->out, value); + h->out += 0x02; + h->bytes += 0x02; +} + +static void add_u8(m4a_header_t* h, uint32_t value) { + put_u8(h->out, value); + h->out += 0x01; + h->bytes += 0x01; +} + +static void add_name(m4a_header_t* h, const char* name) { + memcpy(h->out, name, 0x4); + h->out += 0x04; + h->bytes += 0x04; +} + +static void add_atom(m4a_header_t* h, const char* name, uint32_t size) { + add_u32b(h, size); + add_name(h, name); +} + +/* register + write final size for atoms of variable/complex size */ +static void save_atom(m4a_header_t* h, m4a_state_t* s) { + s->out = h->out; + s->bytes = h->bytes; +} + +static void load_atom(m4a_header_t* h, m4a_state_t* s) { + put_u32be(s->out, h->bytes - s->bytes); +} + +/* common atoms */ + +static void add_ftyp(m4a_header_t* h) { + add_atom(h, "ftyp", 0x18); + add_name(h, "M4A "); /* major brand */ + add_u32b(h, 512); /* minor version */ + add_name(h, "isom"); /* compatible brands */ + add_name(h, "iso2"); /* compatible brands */ +} + +static void add_free(m4a_header_t* h) { + add_atom(h, "free", 0x08); +} + +static void add_mdat(m4a_header_t* h) { + add_atom(h, "mdat", 0x08 + h->mp4->stream_size); +} + +/* variable atoms */ + +static void add_stco(m4a_header_t* h) { + add_atom(h, "stco", 0x10 + 1 * 0x04); + add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ + add_u32b(h, 1); /* Number of entries */ + /* there may be an entry per frame, but only first seems needed */ + save_atom(h, &h->chunks); + add_u32b(h, 0); /* Absolute offset N */ +} + +static void add_stsz(m4a_header_t* h) { + int i; + uint32_t size; + + add_atom(h, "stsz", 0x14 + h->mp4->table_entries * 0x04); + add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ + add_u32b(h, 0); /* Sample size (CBR) */ + add_u32b(h, h->mp4->table_entries); /* Number of entries (VBR) */ + + switch(h->type) { + case MP4_LYN: { + uint32_t curr_size, next_size; + + /* LyN has a seek table with every frame, and frames are preprended by a 0x02 + * frame header with frame size, so we can reconstruct a frame table */ + for (i = 0; i < h->mp4->table_entries - 1; i++) { + curr_size = read_u32le(h->mp4->table_offset + (i + 0) * 0x04, h->sf); + next_size = read_u32le(h->mp4->table_offset + (i + 1) * 0x04, h->sf); + + size = next_size - curr_size - 0x02; + add_u32b(h, size); /* Sample N */ + //;VGM_LOG("%i: %x (%x: %x - %x - 0x02)\n", i, size, h->mp4->table_offset + (i + 1) * 0x04, next_size, curr_size); + } + curr_size = read_u32le(h->mp4->table_offset + (i + 0) * 0x04, h->sf); + next_size = h->mp4->stream_size; /* no last offset */ + + size = next_size - curr_size - 0x02; + add_u32b(h, size); /* Sample N */ + //;VGM_LOG("%i: %x\n", i, size); + break; + } + + default: { + for (i = 0; i < h->mp4->table_entries; i++) { + size = read_u32le(h->mp4->table_offset + i * 0x04, h->sf); + add_u32b(h, size); /* Sample N */ + } + break; + } + } +} + +static void add_stsc(m4a_header_t* h) { + add_atom(h, "stsc", 0x1c); + add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ + add_u32b(h, 1); /* Number of entries */ + add_u32b(h, 1); /* First chunk */ + add_u32b(h, h->mp4->table_entries); /* Samples per chunk */ + add_u32b(h, 1); /* Sample description ID */ +} + +static void add_stts(m4a_header_t* h) { + add_atom(h, "stts", 0x18); + add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ + add_u32b(h, 1); /* Number of entries */ + add_u32b(h, h->mp4->table_entries); /* Sample count */ + add_u32b(h, h->mp4->frame_samples); /* Sample duration */ +} + +/* from mpeg4audio.c (also see ff_mp4_read_dec_config_descr) */ +static const int m4a_sample_rates[16] = { + 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350 +}; +static const uint8_t m4a_channels[14] = { + 0, + 1, // mono (1/0) + 2, // stereo (2/0) + 3, // 3/0 + 4, // 3/1 + 5, // 3/2 + 6, // 3/2.1 + 8, // 5/2.1 + //0, + //0, + //0, + //7, // 3/3.1 + //8, // 3/2/2.1 + //24 // 3/3/3 - 5/2/3 - 3/0/0.2 +}; + +static void add_esds(m4a_header_t* h) { + uint16_t config = 0; + + /* ES_descriptor (TLV format see ISO 14496-1) and DecSpecificInfoTag define actual decoding + - config (channels/rate/etc), other atoms with the same stuff is just info + * - http://ecee.colorado.edu/~ecen5653/ecen5653/papers/ISO%2014496-1%202004.PDF */ + + { + uint8_t object_type = 0x02; /* 0x00=none, 0x01=AAC main, 0x02=AAC LC */ + uint8_t sr_index = 0; + uint8_t ch_index = 0; + uint8_t unknown = 0; + int i; + for (i = 0; i < 16; i++) { + if (m4a_sample_rates[i] == h->mp4->sample_rate) { + sr_index = i; + break; + } + } + for (i = 0; i < 8; i++) { + if (m4a_channels[i] == h->mp4->channels) { + ch_index = i; + break; + } + } + + config |= (object_type & 0x1F) << 11; /* 5b */ + config |= (sr_index & 0x0F) << 7; /* 4b */ + config |= (ch_index & 0x0F) << 3; /* 4b */ + config |= (unknown & 0x07) << 0; /* 3b */ + } + + add_atom(h, "esds", 0x33); + add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ + + add_u8 (h, 0x03); /* ES_DescrTag */ + add_u32b(h, 0x80808022); /* size 0x22 */ + add_u16b(h, 0x0000); /* stream Id */ + add_u8 (h, 0x00); /* flags */ + + add_u8 (h, 0x04); /* DecoderConfigDescrTag */ + add_u32b(h, 0x80808014); /* size 0x14 */ + add_u8 (h, 0x40); /* object type (0x40=audio) */ + add_u8 (h, 0x15); /* stream type (6b: 0x5=audio) + upstream (1b) + reserved (1b: const 1) */ + add_u24b(h, 0x000000); /* buffer size */ + add_u32b(h, 0); /* max bitrate (256000?)*/ + add_u32b(h, 0); /* average bitrate (256000?) */ + + add_u8 (h, 0x05); /* DecSpecificInfoTag */ + add_u32b(h, 0x80808002); /* size 0x02 */ + add_u16b(h, config); /* actual decoder info */ + + add_u8 (h, 0x06); /* SLConfigDescrTag */ + add_u32b(h, 0x80808001); /* size 0x01 */ + add_u8 (h, 0x02); /* predefined (2=default) */ +} + +static void add_mp4a(m4a_header_t* h) { + add_atom(h, "mp4a", 0x57); + add_u32b(h, 0); /* ? */ + add_u32b(h, 1); /* Data reference index */ + add_u32b(h, 0); /* Reserved */ + add_u32b(h, 0); /* Reserved 2 */ + add_u16b(h, h->mp4->channels); /* Channel count */ + add_u16b(h, 16); /* Sample size */ + add_u32b(h, 0); /* Pre-defined */ + add_u16b(h, h->mp4->sample_rate); /* Sample rate */ + add_u16b(h, 0); /* ? */ + add_esds(h); /* elementary stream descriptor */ +} + +static void add_stsd(m4a_header_t* h) { + add_atom(h, "stsd", 0x67); + add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ + add_u32b(h, 1); /* Number of entries */ + add_mp4a(h); +} + +static void add_stbl(m4a_header_t* h) { + m4a_state_t s; + + save_atom(h, &s); + add_atom(h, "stbl", 0x00); + add_stsd(h); /* Sample description */ + add_stts(h); /* Time-to-sample */ + add_stsc(h); /* Sample-to-chunk */ + add_stsz(h); /* Sample size */ + add_stco(h); /* Chunk offset */ + load_atom(h, &s); +} + +static void add_dinf(m4a_header_t* h) { + add_atom(h, "dinf", 0x24); + add_atom(h, "dref", 0x1c); + add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ + add_u32b(h, 1); /* Number of entries */ + add_atom(h, "url ", 0x0c); + add_u32b(h, 1); /* Version (1 byte) + Flags (3 byte) */ +} + +static void add_smhd(m4a_header_t* h) { + add_atom(h, "smhd", 0x10); + add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ + add_u16b(h, 0); /* Balance */ + add_u16b(h, 0); /* Reserved */ +} + +static void add_minf(m4a_header_t* h) { + m4a_state_t s; + + save_atom(h, &s); + add_atom(h, "minf", 0x00); + add_smhd(h); + add_dinf(h); + add_stbl(h); + load_atom(h, &s); +} + +static void add_hdlr(m4a_header_t* h) { + add_atom(h, "hdlr", 0x22); + add_u32b(h, 0); /* version (1 byte) + flags (3 byte) */ + add_u32b(h, 0); /* Component type */ + add_name(h, "soun"); /* Component subtype */ + add_u32b(h, 0); /* Component manufacturer */ + add_u32b(h, 0); /* Component flags */ + add_u32b(h, 0); /* Component flags mask */ + add_u16b(h, 0); /* Component name */ +} + +static void add_mdhd(m4a_header_t* h) { + add_atom(h, "mdhd", 0x20); + add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ + add_u32b(h, 0); /* Creation time */ + add_u32b(h, 0); /* Modification time */ + add_u32b(h, h->mp4->sample_rate); /* Time scale */ + add_u32b(h, h->mp4->num_samples); /* Duration */ + add_u16b(h, 0); /* Language (0xC455=eng?) */ + add_u16b(h, 0); /* Quality */ +} + +static void add_mdia(m4a_header_t* h) { + m4a_state_t s; + + save_atom(h, &s); + add_atom(h, "mdia", 0x00); + add_mdhd(h); + add_hdlr(h); + add_minf(h); + load_atom(h, &s); +} + +static void add_tkhd(m4a_header_t* h) { + add_atom(h, "tkhd", 0x5C); + add_u32b(h, 0x00000001); /* Version (1 byte) + Flags (3 byte), 1=track enabled */ + add_u32b(h, 0); /* Creation time */ + add_u32b(h, 0); /* Modification time */ + add_u32b(h, 1); /* Track ID */ + add_u32b(h, 0); /* Reserved 1 */ + add_u32b(h, h->mp4->num_samples); /* Duration */ + add_u32b(h, 0); /* Reserved 1 */ + add_u32b(h, 0); /* Reserved 2 */ + add_u16b(h, 0); /* Layer */ + add_u16b(h, 0); /* Alternate group (1?) */ + add_u16b(h, 0x0100); /* Volume */ + add_u16b(h, 0); /* Reserved */ + add_u32b(h, 0x00010000); /* matrix_A */ + add_u32b(h, 0); /* matrix_B */ + add_u32b(h, 0); /* matrix_U */ + add_u32b(h, 0); /* matrix_C */ + add_u32b(h, 0x00010000); /* matrix_D */ + add_u32b(h, 0); /* matrix_V */ + add_u32b(h, 0); /* matrix_X */ + add_u32b(h, 0); /* matrix_Y */ + add_u32b(h, 0x40000000); /* matrix_W */ + add_u32b(h, 0); /* Width */ + add_u32b(h, 0); /* Height */ +} + +static void add_trak(m4a_header_t* h) { + m4a_state_t s; + + save_atom(h, &s); + add_atom(h, "trak", 0x00); + add_tkhd(h); + add_mdia(h); + load_atom(h, &s); +} + +static void add_mvhd(m4a_header_t* h) { + add_atom(h, "mvhd", 0x6c); + add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ + add_u32b(h, 0); /* Creation time */ + add_u32b(h, 0); /* Modification time */ + add_u32b(h, h->mp4->sample_rate); /* Time scale */ + add_u32b(h, h->mp4->num_samples); /* Duration */ + add_u32b(h, 0x00010000); /* Preferred rate */ + add_u16b(h, 0x0100); /* Preferred volume */ + add_u32b(h, 0); /* Reserved 1 */ + add_u32b(h, 0); /* Reserved 2 */ + add_u16b(h, 0); /* Reserved 3 */ + add_u32b(h, 0x00010000); /* matrix_A */ + add_u32b(h, 0); /* matrix_B */ + add_u32b(h, 0); /* matrix_U */ + add_u32b(h, 0); /* matrix_C */ + add_u32b(h, 0x00010000); /* matrix_D */ + add_u32b(h, 0); /* matrix_V */ + add_u32b(h, 0); /* matrix_X */ + add_u32b(h, 0); /* matrix_Y */ + add_u32b(h, 0x40000000); /* matrix_W */ + add_u32b(h, 0); /* Preview time */ + add_u32b(h, 0); /* Preview duration */ + add_u32b(h, 0); /* Poster time */ + add_u32b(h, 0); /* Selection time */ + add_u32b(h, 0); /* Selection duration */ + add_u32b(h, 0); /* Current time */ + add_u32b(h, 2); /* Next track ID */ +} + +static void add_moov(m4a_header_t* h) { + m4a_state_t s; + + save_atom(h, &s); + add_atom(h, "moov", 0x00); + add_mvhd(h); + add_trak(h); + //add_udta(h); + load_atom(h, &s); +} + +/* *** */ + +static int make_m4a_header(uint8_t* buf, int buf_len, mp4_custom_t* mp4, STREAMFILE* sf, mp4_type_t type) { + m4a_header_t h = {0}; + + if (buf_len < 0x400 + mp4->table_entries * 0x4) /* approx */ + goto fail; + + h.sf = sf; + h.mp4 = mp4; + h.type = type; + h.out = buf; + + add_ftyp(&h); + add_free(&h); + add_moov(&h); + add_mdat(&h); + + + /* define absolute chunk offset after all calcs */ + put_u32be(h.chunks.out, h.bytes); + + return h.bytes; +fail: + return 0; +} + +/* ************************************************************************* */ + +static void block_callback(STREAMFILE* sf, deblock_io_data* data) { + data->data_size = read_u16be(data->physical_offset, sf); + data->skip_size = 0x02; + data->block_size = data->skip_size + data->data_size; +} + +static STREAMFILE* setup_mp4_streamfile(STREAMFILE* sf, mp4_custom_t* mp4, mp4_type_t type) { + STREAMFILE* new_sf = NULL; + deblock_config_t cfg = {0}; + + cfg.stream_start = mp4->stream_offset; + cfg.stream_size = mp4->stream_size; + cfg.block_callback = block_callback; + + switch(type) { + case MP4_LYN: /* each frame has a 0x02 header */ + cfg.logical_size = mp4->stream_size - (mp4->table_entries * 0x02); + break; + default: + return NULL; + } + + /* setup sf */ + new_sf = open_wrap_streamfile(sf); + new_sf = open_io_deblock_streamfile_f(new_sf, &cfg); + //new_sf = open_clamp_streamfile_f(new_sf, 0x00, clean_size); + return new_sf; +} + +/* ************************************************************************* */ + +static ffmpeg_codec_data* init_ffmpeg_mp4_custom(STREAMFILE* sf, mp4_custom_t* mp4, mp4_type_t type) { + ffmpeg_codec_data* ffmpeg_data = NULL; + STREAMFILE* temp_sf = NULL; + int bytes; + uint8_t* buf = NULL; + int buf_len = 0x800 + mp4->table_entries * 0x4; /* approx max sum of atom chunks is ~0x400 */ + + if (buf_len > 0x100000) /* ??? */ + goto fail; + + buf = malloc(buf_len); + if (!buf) goto fail; + bytes = make_m4a_header(buf, buf_len, mp4, sf, type); /* before changing stream_offset/size */ + + switch(type) { + case MP4_STD: /* regular raw data */ + temp_sf = sf; + break; + case MP4_LYN: /* frames have size before them, but also a seek table */ + temp_sf = setup_mp4_streamfile(sf, mp4, type); + mp4->stream_offset = 0; + mp4->stream_size = get_streamfile_size(temp_sf); + break; + default: + goto fail; + } + if (!temp_sf) goto fail; + + ffmpeg_data = init_ffmpeg_header_offset(temp_sf, buf, bytes, mp4->stream_offset, mp4->stream_size); + if (!ffmpeg_data) goto fail; + + /* not part of fake header since it's kinda complex to add (iTunes string comment) */ + ffmpeg_set_skip_samples(ffmpeg_data, mp4->encoder_delay); + + free(buf); + if (sf != temp_sf) close_streamfile(temp_sf); + return ffmpeg_data; +fail: + free(buf); + if (sf != temp_sf) close_streamfile(temp_sf); + free_ffmpeg(ffmpeg_data); + return NULL; +} + +ffmpeg_codec_data* init_ffmpeg_mp4_custom_std(STREAMFILE* sf, mp4_custom_t* mp4) { + return init_ffmpeg_mp4_custom(sf, mp4, MP4_STD); +} + +ffmpeg_codec_data* init_ffmpeg_mp4_custom_lyn(STREAMFILE* sf, mp4_custom_t* mp4) { + //TODO: most LyN files seem to give FFmpeg error in some frame, mono or stereo files, + // seek table correct and complete, no observed frame size/format/etc oddities. + // No audible issues though so maybe it's must some FFmpeg issue to be fixed there. + // (ex. frame 272 of 1162 in VO_ACT2_M12_FD_54_GILLI_PLS_0008479.Cafe_00000006.son) + return init_ffmpeg_mp4_custom(sf, mp4, MP4_LYN); +} + +#endif diff --git a/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c index 74c73693c..b1daf710c 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c @@ -209,7 +209,7 @@ STREAMFILE* hca_get_streamfile(hca_codec_data* data) { /* Test a number of frames if key decrypts correctly. * Returns score: <0: error/wrong, 0: unknown/silent file, >0: good (the closest to 1 the better). */ -static int test_hca_score(hca_codec_data* data, hca_keytest_t* hk, unsigned long long keycode) { +static int test_hca_score(hca_codec_data* data, hca_keytest_t* hk) { size_t test_frames = 0, current_frame = 0, blank_frames = 0; int total_score = 0; const unsigned int block_size = data->info.blockSize; @@ -222,7 +222,7 @@ static int test_hca_score(hca_codec_data* data, hca_keytest_t* hk, unsigned long * Buffered IO seems fast enough (not very different reading a large block once vs frame by frame). * clHCA_TestBlock could be optimized a bit more. */ - clHCA_SetKey(data->handle, keycode); + hca_set_encryption_key(data, hk->key, hk->subkey); /* Test up to N non-blank frames or until total frames. */ /* A final score of 0 (=silent) is only possible for short files with all blank frames */ @@ -289,35 +289,26 @@ static int test_hca_score(hca_codec_data* data, hca_keytest_t* hk, unsigned long void test_hca_key(hca_codec_data* data, hca_keytest_t* hk) { int score; - uint64_t key = hk->key; - uint16_t subkey = hk->subkey; - //;VGM_LOG("HCA: test key=%08x%08x, subkey=%04x\n", - // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey); - - if (subkey) { - key = key * ( ((uint64_t)subkey << 16u) | ((uint16_t)~subkey + 2u) ); - } - - score = test_hca_score(data, hk, (unsigned long long)key); + score = test_hca_score(data, hk); //;VGM_LOG("HCA: test key=%08x%08x, subkey=%04x, score=%i\n", - // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey, score); + // (uint32_t)((hk->key >> 32) & 0xFFFFFFFF), (uint32_t)(hk->key & 0xFFFFFFFF), hk->subkey, score); /* wrong key */ if (score < 0) return; - //;VGM_LOG("HCA: ok key=%08x%08x, subkey=%04x, score=%i\n", - // (uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), subkey, score); - /* update if something better is found */ if (hk->best_score <= 0 || (score < hk->best_score && score > 0)) { hk->best_score = score; - hk->best_key = key; + hk->best_key = hk->key; /* base */ } } -void hca_set_encryption_key(hca_codec_data* data, uint64_t keycode) { +void hca_set_encryption_key(hca_codec_data* data, uint64_t keycode, uint64_t subkey) { + if (subkey) { + keycode = keycode * ( ((uint64_t)subkey << 16u) | ((uint16_t)~subkey + 2u) ); + } clHCA_SetKey(data->handle, (unsigned long long)keycode); } diff --git a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c index f083a0ff1..d22709c2f 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c @@ -62,10 +62,10 @@ mpeg_codec_data* init_mpeg(STREAMFILE* sf, off_t start_offset, coding_t* coding_ } while (rc != MPG123_NEW_FORMAT); /* check first frame header and validate */ - rc = mpg123_getformat(main_m,&sample_rate_per_frame,&channels_per_frame,&encoding); + rc = mpg123_getformat(main_m, &sample_rate_per_frame, &channels_per_frame, &encoding); if (rc != MPG123_OK) goto fail; - mpg123_info(main_m,&mi); + mpg123_info(main_m, &mi); if (encoding != MPG123_ENC_SIGNED_16) goto fail; @@ -89,12 +89,11 @@ mpeg_codec_data* init_mpeg(STREAMFILE* sf, off_t start_offset, coding_t* coding_ samples_per_frame = 1152; else if (mi.layer == 3) samples_per_frame = 576; - else goto fail; + else + goto fail; data->channels_per_frame = channels_per_frame; data->samples_per_frame = samples_per_frame; - if (channels_per_frame != channels) - goto fail; /* copy current as open_feed may invalidate until data is fed */ memcpy(&data->mi, &mi, sizeof(struct mpg123_frameinfo)); diff --git a/Frameworks/vgmstream/vgmstream/src/formats.c b/Frameworks/vgmstream/vgmstream/src/formats.c index e604de758..e762af24e 100644 --- a/Frameworks/vgmstream/vgmstream/src/formats.c +++ b/Frameworks/vgmstream/vgmstream/src/formats.c @@ -138,7 +138,7 @@ static const char* extension_list[] = { "cps", "csa", //txth/reserved [LEGO Racers 2 (PS2)] "csmp", - "cvs", + "cvs", //txth/reserved [Aladdin in Nasira's Revenge (PS1)] "cwav", "cxs", @@ -401,7 +401,6 @@ static const char* extension_list[] = { "psf", "psh", //fake extension for .vsv (to be removed) "psnd", - "psw", //fake extension for .wam (renamed, to be removed) "r", "rac", //txth/reserved [Manhunt (Xbox)] @@ -599,7 +598,7 @@ static const char* extension_list[] = { "wic", //txth/reserved [Road Rash (SAT)-videos] "wip", //txth/reserved [Colin McRae DiRT (PC)] "wlv", //txth/reserved [ToeJam & Earl III: Mission to Earth (DC)] - "wmus", + "wmus", //fake extension (to be removed) "wp2", "wpd", "wsd", @@ -618,7 +617,7 @@ static const char* extension_list[] = { "xa", "xa2", "xa30", - "xag", + "xag", //txth/reserved [Tamsoft's PS2 games] "xau", "xav", "xb", //txth/reserved [Scooby-Doo! Unmasked (Xbox)] @@ -937,7 +936,7 @@ static const meta_info meta_info_list[] = { {meta_AGSC, "Retro Studios AGSC header"}, {meta_CSMP, "Retro Studios CSMP header"}, {meta_RFRM, "Retro Studios RFRM header"}, - {meta_NGC_ADPDTK, "Nintendo ADP raw header"}, + {meta_DTK, "Nintendo DTK raw header"}, {meta_RSF, "Retro Studios RSF raw header"}, {meta_AFC, "Nintendo .AFC header"}, {meta_AST, "Nintendo AST header"}, @@ -976,7 +975,7 @@ static const meta_info meta_info_list[] = { {meta_PS2_VAGp_AAAP, "Acclaim Austin AAAp VAG header"}, {meta_SEB, "Game Arts .SEB header"}, {meta_STR_WAV, "Blitz Games .STR+WAV header"}, - {meta_PS2_ILD, "ILD header"}, + {meta_ILD, "Tose ILD header"}, {meta_PS2_PNB, "assumed PNB (PsychoNauts Bgm File) by .pnb extension"}, {meta_RAW_WAVM, "Xbox .wavm raw header"}, {meta_DSP_STR, "assumed Conan Gamecube STR File by .str extension"}, @@ -1021,7 +1020,7 @@ static const meta_info meta_info_list[] = { {meta_LEG, "Legaia 2 - Duel Saga LEG Header"}, {meta_FILP, "Bio Hazard - Gun Survivor FILp Header"}, {meta_IKM, "MiCROViSiON IKM header"}, - {meta_SFS, "String .SFS header"}, + {meta_STER, "ALCHEMY STER header"}, {meta_SAT_DVI, "Konami KCEN DVI. header"}, {meta_DC_KCEY, "Konami KCEY KCEYCOMP header"}, {meta_BG00, "Falcom BG00 Header"}, @@ -1140,7 +1139,6 @@ static const meta_info meta_info_list[] = { {meta_PONA_PSX, "Policenauts BGM header"}, {meta_NGC_DSP_AAAP, "Acclaim Austin AAAp DSP header"}, {meta_NGC_DSP_KONAMI, "Konami DSP header"}, - {meta_PS2_STER, "STER Header"}, {meta_BNSF, "Namco Bandai BNSF header"}, {meta_PS2_WB, "Shooting Love. ~TRIZEAL~ WB header"}, {meta_S14, "Namco .S14 raw header"}, @@ -1383,6 +1381,7 @@ static const meta_info meta_info_list[] = { {meta_LOPU_FB, "French-Bread LOPU header"}, {meta_LPCM_FB, "French-Bread LPCM header"}, {meta_WBK, "Treyarch WBK header"}, + {meta_WBK_NSLB, "Treyarch NSLB header"}, {meta_DSP_APEX, "Koei Tecmo APEX header"}, }; diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c index a21263658..d23cbea0d 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_schl.c @@ -159,7 +159,7 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) { flush_ea_mt(vgmstream); break; - #ifdef VGM_USE_MPEG +#ifdef VGM_USE_MPEG /* id, size, samples, offsets, unknown (null for MP2, some size/config for EALayer3; only if not >2ch) */ case coding_MPEG_custom: case coding_MPEG_layer1: @@ -179,7 +179,7 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) { vgmstream->ch[i].offset = block_offset + 0x0C + (0x04*vgmstream->channels) + channel_start; } break; - #endif +#endif /* id, size, samples, offsets-per-channel, interleaved data (w/ optional hist per channel) */ default: for (i = 0; i < vgmstream->channels; i++) { diff --git a/Frameworks/vgmstream/vgmstream/src/meta/acm.c b/Frameworks/vgmstream/vgmstream/src/meta/acm.c index e35879c8c..e5887688a 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/acm.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/acm.c @@ -3,51 +3,53 @@ #include "../coding/acm_decoder_libacm.h" /* ACM - InterPlay infinity engine games [Planescape: Torment (PC), Baldur's Gate (PC)] */ -VGMSTREAM * init_vgmstream_acm(STREAMFILE *streamFile) { +VGMSTREAM* init_vgmstream_acm(STREAMFILE* sf) { VGMSTREAM * vgmstream = NULL; - int loop_flag = 0, channel_count, sample_rate, num_samples; + int loop_flag = 0, channels, sample_rate, num_samples; int force_channel_number = 0; acm_codec_data *data = NULL; /* checks */ /* .acm: plain ACM extension (often but not always paired with .mus, parsed elsewhere) + * .tun: Descent to Undermountain (PC) * .wavc: header id for WAVC sfx (from bigfiles, extensionless) */ - if (!check_extensions(streamFile, "acm,wavc")) + if (!check_extensions(sf, "acm,tun,wavc")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x97280301 && /* header id (music) */ - read_32bitBE(0x00,streamFile) != 0x57415643) /* "WAVC" (sfx) */ + if (read_u32be(0x00,sf) != 0x97280301 && /* header id (music) */ + !is_id32be(0x00,sf, "WAVC")) /* sfx */ goto fail; - /* Plain ACM "channels" in the header may be set to 2 for mono voices or 1 for music, + /* Plain ACM "channels" in the header (at 0x08) may be set to 2 for mono voices [FO1] or 1 for music [P:T], * but actually seem related to ACM rows/cols and have nothing to do with channels. * - * libacm will set plain ACM (not WAVC) to 2ch unless changes unless changed, but - * only Fallout (PC) seems to use plain ACM for sfx, others are WAVC (which do have channels). + * libacm will set plain ACM (not WAVC) to 2ch unless changed, but only Fallout (PC) + * and Descent to Undermountain (PC) seems to use plain ACM for sfx/voices, + * others are WAVC (which do have channels). + * DtU seems to use the field * * Doesn't look like there is any way to detect mono/stereo, so as a quick hack if * we have a plain ACM (not WAVC) named .wavc we will force 1ch. */ - if (check_extensions(streamFile, "wavc") - && read_32bitBE(0x00,streamFile) == 0x97280301) { + if (check_extensions(sf, "wavc") && read_u32be(0x00,sf) == 0x97280301) { force_channel_number = 1; } /* init decoder */ { ACMStream *handle; - data = init_acm(streamFile, force_channel_number); + data = init_acm(sf, force_channel_number); if (!data) goto fail; handle = data->handle; - channel_count = handle->info.channels; + channels = handle->info.channels; sample_rate = handle->info.rate; num_samples = handle->total_values / handle->info.channels; } /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); + vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; vgmstream->sample_rate = sample_rate; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bwav.c b/Frameworks/vgmstream/vgmstream/src/meta/bwav.c index 2d6ced0ce..a0cf1df1d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/bwav.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/bwav.c @@ -41,6 +41,7 @@ VGMSTREAM * init_vgmstream_bwav(STREAMFILE *streamFile) { vgmstream->loop_start_sample = read_32bitLE(0x50, streamFile); vgmstream->loop_end_sample = read_32bitLE(0x4C, streamFile); vgmstream->meta_type = meta_BWAV; + vgmstream->allow_dual_stereo = 1; switch(codec) { case 0x0000: diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c index 6474fc3bd..6f179e20e 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c @@ -1479,6 +1479,8 @@ static size_t calculate_eaac_size(STREAMFILE *sf, eaac_header *ea, uint32_t num_ while (block_offset < file_size) { block_id = read_8bit(block_offset, sf); block_size = read_32bitBE(block_offset, sf) & 0x00FFFFFF; + if (block_size == 0 || block_size == 0x00FFFFFF) + goto fail; /* stop when we reach the end marker */ if (ea->version == EAAC_VERSION_V0) { diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c index fe296deb5..c822e0601 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c @@ -4,96 +4,106 @@ #include "ea_schl_streamfile.h" /* header version */ -#define EA_VERSION_NONE -1 -#define EA_VERSION_V0 0x00 /* ~early PC (when codec1 was used) */ -#define EA_VERSION_V1 0x01 /* ~PC */ -#define EA_VERSION_V2 0x02 /* ~PS1 */ -#define EA_VERSION_V3 0x03 /* ~PS2 */ +#define EA_VERSION_NONE -1 +#define EA_VERSION_V0 0x00 /* ~early PC (when codec1 was used) */ +#define EA_VERSION_V1 0x01 /* ~PC */ +#define EA_VERSION_V2 0x02 /* ~PS1 */ +#define EA_VERSION_V3 0x03 /* ~PS2 */ /* platform constants (unassigned values seem internal only) */ -#define EA_PLATFORM_PC 0x00 -#define EA_PLATFORM_PSX 0x01 -#define EA_PLATFORM_N64 0x02 -#define EA_PLATFORM_MAC 0x03 -#define EA_PLATFORM_SAT 0x04 -#define EA_PLATFORM_PS2 0x05 -#define EA_PLATFORM_GC 0x06 /* also used on Wii */ -#define EA_PLATFORM_XBOX 0x07 -#define EA_PLATFORM_GENERIC 0x08 /* typically Wii/X360/PS3/videos */ -#define EA_PLATFORM_X360 0x09 -#define EA_PLATFORM_PSP 0x0A -#define EA_PLATFORM_PS3 0x0E /* very rare [Need for Speed: Carbon (PS3)] */ -#define EA_PLATFORM_WII 0x10 /* not seen so far (sx.exe samples ok) */ -#define EA_PLATFORM_3DS 0x14 +#define EA_PLATFORM_PC 0x00 +#define EA_PLATFORM_PSX 0x01 +#define EA_PLATFORM_N64 0x02 +#define EA_PLATFORM_MAC 0x03 +#define EA_PLATFORM_SAT 0x04 +#define EA_PLATFORM_PS2 0x05 +#define EA_PLATFORM_GC 0x06 /* also used on Wii */ +#define EA_PLATFORM_XBOX 0x07 +#define EA_PLATFORM_GENERIC 0x08 /* typically Wii/X360/PS3/videos */ +#define EA_PLATFORM_X360 0x09 +#define EA_PLATFORM_PSP 0x0A +//#define EA_PLATFORM_PC_EAAC 0x0B /* not used (sx.exe internal defs) */ +//#define EA_PLATFORM_X360_EAAC 0x0C /* not used (sx.exe internal defs) */ +//#define EA_PLATFORM_PSP_EAAC 0x0D /* not used (sx.exe internal defs) */ +#define EA_PLATFORM_PS3 0x0E /* very rare [Need for Speed: Carbon (PS3)] */ +//#define EA_PLATFORM_PS3_EAAC 0x0F +#define EA_PLATFORM_WII 0x10 /* not seen so far (sx.exe samples ok) */ +//#define EA_PLATFORM_WII_EAAC 0x11 /* not used (sx.exe internal defs) */ +//#define EA_PLATFORM_PC64_EAAC 0x12 /* not used (sx.exe internal defs) */ +//#define EA_PLATFORM_MOBILE_EAAC 0x13 /* not used (sx.exe internal defs) */ +#define EA_PLATFORM_3DS 0x14 /* codec constants (undefined are probably reserved, ie.- sx.exe encodes PCM24/DVI but no platform decodes them) */ /* CODEC1 values were used early, then they migrated to CODEC2 values */ -#define EA_CODEC1_NONE -1 -#define EA_CODEC1_PCM 0x00 -//#define EA_CODEC1_IMA 0x02 /* not used (sx.exe internal defs) */ -#define EA_CODEC1_N64 0x05 -#define EA_CODEC1_VAG 0x06 -#define EA_CODEC1_EAXA 0x07 -#define EA_CODEC1_MT10 0x09 +#define EA_CODEC1_NONE -1 +#define EA_CODEC1_PCM 0x00 +//#define EA_CODEC1_IMA 0x02 /* not used (sx.exe internal defs) */ +#define EA_CODEC1_N64 0x05 +#define EA_CODEC1_VAG 0x06 +#define EA_CODEC1_EAXA 0x07 +#define EA_CODEC1_MT10 0x09 -#define EA_CODEC2_NONE -1 -#define EA_CODEC2_S16LE_INT 0x00 -#define EA_CODEC2_S16BE_INT 0x01 -#define EA_CODEC2_S8_INT 0x02 -#define EA_CODEC2_EAXA_INT 0x03 -#define EA_CODEC2_MT10 0x04 -#define EA_CODEC2_VAG 0x05 -#define EA_CODEC2_N64 0x06 -#define EA_CODEC2_S16BE 0x07 -#define EA_CODEC2_S16LE 0x08 -#define EA_CODEC2_S8 0x09 -#define EA_CODEC2_EAXA 0x0A -//#define EA_CODEC2_U8_INT 0x0B /* not used (sx.exe internal defs) */ -//#define EA_CODEC2_CDXA 0x0C /* not used (sx.exe internal defs) */ -//#define EA_CODEC2_IMA 0x0D /* not used (sx.exe internal defs) */ -//#define EA_CODEC2_LAYER1 0x0E /* not used (sx.exe internal defs) */ -#define EA_CODEC2_LAYER2 0x0F -#define EA_CODEC2_LAYER3 0x10 /* not seen so far but may be used somewhere */ -#define EA_CODEC2_GCADPCM 0x12 -//#define EA_CODEC2_S24LE_INT 0x13 /* not used (sx.exe internal defs) */ -#define EA_CODEC2_XBOXADPCM 0x14 -//#define EA_CODEC2_S24BE_INT 0x15 /* not used (sx.exe internal defs) */ -#define EA_CODEC2_MT5 0x16 -#define EA_CODEC2_EALAYER3 0x17 -#define EA_CODEC2_ATRAC3 0x1A /* not seen so far (sx.exe samples ok) */ -#define EA_CODEC2_ATRAC3PLUS 0x1B +#define EA_CODEC2_NONE -1 +#define EA_CODEC2_S16LE_INT 0x00 +#define EA_CODEC2_S16BE_INT 0x01 +#define EA_CODEC2_S8_INT 0x02 +#define EA_CODEC2_EAXA_INT 0x03 +#define EA_CODEC2_MT10 0x04 +#define EA_CODEC2_VAG 0x05 +#define EA_CODEC2_N64 0x06 +#define EA_CODEC2_S16BE 0x07 +#define EA_CODEC2_S16LE 0x08 +#define EA_CODEC2_S8 0x09 +#define EA_CODEC2_EAXA 0x0A +//#define EA_CODEC2_U8_INT 0x0B /* not used (sx.exe internal defs) */ +//#define EA_CODEC2_CDXA 0x0C /* not used (sx.exe internal defs) */ +//#define EA_CODEC2_IMA_INT 0x0D /* not used (sx.exe internal defs) */ +//#define EA_CODEC2_LAYER1 0x0E /* not used (sx.exe internal defs) */ +#define EA_CODEC2_LAYER2 0x0F +#define EA_CODEC2_LAYER3 0x10 /* not seen so far but may be used somewhere */ +#define EA_CODEC2_GCADPCM 0x12 +//#define EA_CODEC2_S24LE_INT 0x13 /* not used (sx.exe internal defs) */ +#define EA_CODEC2_XBOXADPCM 0x14 +//#define EA_CODEC2_S24BE_INT 0x15 /* not used (sx.exe internal defs) */ +#define EA_CODEC2_MT5 0x16 +#define EA_CODEC2_EALAYER3 0x17 +//#define EA_CODEC2_XAS0_INT 0x18 /* not used (sx.exe internal defs) */ +//#define EA_CODEC2_EALAYER3_INT 0x19 /* not used (sx.exe internal defs) */ +#define EA_CODEC2_ATRAC3 0x1A /* not seen so far (sx.exe samples ok) */ +#define EA_CODEC2_ATRAC3PLUS 0x1B +/* EAAC (SND10) codecs begin after this point */ /* Block headers, SCxy - where x is block ID and y is endianness flag (always 'l'?) */ -#define EA_BLOCKID_HEADER 0x5343486C /* "SCHl" */ -#define EA_BLOCKID_COUNT 0x5343436C /* "SCCl" */ -#define EA_BLOCKID_DATA 0x5343446C /* "SCDl" */ -#define EA_BLOCKID_LOOP 0x53434C6C /* "SCLl */ -#define EA_BLOCKID_END 0x5343456C /* "SCEl" */ +#define EA_BLOCKID_HEADER 0x5343486C /* "SCHl" */ +#define EA_BLOCKID_COUNT 0x5343436C /* "SCCl" */ +#define EA_BLOCKID_DATA 0x5343446C /* "SCDl" */ +#define EA_BLOCKID_LOOP 0x53434C6C /* "SCLl */ +#define EA_BLOCKID_END 0x5343456C /* "SCEl" */ /* Localized block headers, Sxyy - where x is block ID and yy is lang code (e.g. "SHEN"), used in videos */ -#define EA_BLOCKID_LOC_HEADER 0x53480000 /* "SH" */ -#define EA_BLOCKID_LOC_COUNT 0x53430000 /* "SC" */ -#define EA_BLOCKID_LOC_DATA 0x53440000 /* "SD" */ -#define EA_BLOCKID_LOC_END 0x53450000 /* "SE" */ +#define EA_BLOCKID_LOC_HEADER 0x53480000 /* "SH" */ +#define EA_BLOCKID_LOC_COUNT 0x53430000 /* "SC" */ +#define EA_BLOCKID_LOC_DATA 0x53440000 /* "SD" */ +#define EA_BLOCKID_LOC_END 0x53450000 /* "SE" */ -#define EA_BLOCKID_LOC_EN 0x0000454E /* English */ -#define EA_BLOCKID_LOC_FR 0x00004652 /* French */ -#define EA_BLOCKID_LOC_GE 0x00004745 /* German, older */ -#define EA_BLOCKID_LOC_DE 0x00004445 /* German, newer */ -#define EA_BLOCKID_LOC_IT 0x00004954 /* Italian */ -#define EA_BLOCKID_LOC_SP 0x00005350 /* Castilian Spanish, older */ -#define EA_BLOCKID_LOC_ES 0x00004553 /* Castilian Spanish, newer */ -#define EA_BLOCKID_LOC_MX 0x00004D58 /* Mexican Spanish */ -#define EA_BLOCKID_LOC_RU 0x00005255 /* Russian */ -#define EA_BLOCKID_LOC_JA 0x00004A41 /* Japanese, older */ -#define EA_BLOCKID_LOC_JP 0x00004A50 /* Japanese, newer */ -#define EA_BLOCKID_LOC_PL 0x0000504C /* Polish */ -#define EA_BLOCKID_LOC_BR 0x00004252 /* Brazilian Portuguese */ +#define EA_BLOCKID_LOC_EN 0x0000454E /* English */ +#define EA_BLOCKID_LOC_FR 0x00004652 /* French */ +#define EA_BLOCKID_LOC_GE 0x00004745 /* German, older */ +#define EA_BLOCKID_LOC_DE 0x00004445 /* German, newer */ +#define EA_BLOCKID_LOC_IT 0x00004954 /* Italian */ +#define EA_BLOCKID_LOC_SP 0x00005350 /* Castilian Spanish, older */ +#define EA_BLOCKID_LOC_ES 0x00004553 /* Castilian Spanish, newer */ +#define EA_BLOCKID_LOC_MX 0x00004D58 /* Mexican Spanish */ +#define EA_BLOCKID_LOC_RU 0x00005255 /* Russian */ +#define EA_BLOCKID_LOC_JA 0x00004A41 /* Japanese, older */ +#define EA_BLOCKID_LOC_JP 0x00004A50 /* Japanese, newer */ +#define EA_BLOCKID_LOC_PL 0x0000504C /* Polish */ +#define EA_BLOCKID_LOC_BR 0x00004252 /* Brazilian Portuguese */ -#define EA_BNK_HEADER_LE 0x424E4B6C /* "BNKl" */ -#define EA_BNK_HEADER_BE 0x424E4B62 /* "BNKb" */ +#define EA_BNK_HEADER_LE 0x424E4B6C /* "BNKl" */ +#define EA_BNK_HEADER_BE 0x424E4B62 /* "BNKb" */ -#define EA_MAX_CHANNELS 6 +#define EA_MAX_CHANNELS 6 typedef struct { int32_t num_samples; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca.c b/Frameworks/vgmstream/vgmstream/src/meta/hca.c index 37e58d296..57a2060fe 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca.c @@ -49,14 +49,10 @@ VGMSTREAM* init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey) { keysize = read_key_file(keybuf, 0x08+0x04, sf); if (keysize == 0x08) { /* standard */ keycode = get_u64be(keybuf+0x00); - if (subkey) { - keycode = keycode * ( ((uint64_t)subkey << 16u) | ((uint16_t)~subkey + 2u) ); - } } else if (keysize == 0x08+0x02) { /* seed key + AWB subkey */ - uint64_t file_key = get_u64be(keybuf+0x00); - uint16_t file_sub = get_u16be(keybuf+0x08); - keycode = file_key * ( ((uint64_t)file_sub << 16u) | ((uint16_t)~file_sub + 2u) ); + keycode = get_u64be(keybuf+0x00); + subkey = get_u16be(keybuf+0x08); } #ifdef HCA_BRUTEFORCE else if (1) { @@ -69,7 +65,7 @@ VGMSTREAM* init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey) { find_hca_key(hca_data, &keycode, subkey); } - hca_set_encryption_key(hca_data, keycode); + hca_set_encryption_key(hca_data, keycode, subkey); } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h index 040798581..1022d80e8 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h @@ -418,6 +418,7 @@ static const hcakey_info hcakey_list[] = { {393410674916959300}, // 0575ACECA945A444 /* D4DJ Groovy Mix (Android) [music_* files, per-song later mixed with subkey] */ {0x59f449354d063308}, //music_0000001 + {0xf19d4cb84172f7ab}, //music_0000004 {0x52d065d9ccdb8696}, //music_0110001 {0xba26e58923a5da5d}, //music_0110002 {0x5b877af6e52af19b}, //music_0110003 @@ -454,6 +455,7 @@ static const hcakey_info hcakey_list[] = { {0xb96786621e27daf3}, //music_0120014 {0xa2c543b227b8e5e2}, //music_0120015 {0x845437ec4e367a13}, //music_0120016 + {0xadfecfaf25cfe2ce}, //music_0120017 {0x3674aba8da7bc84b}, //music_0120018 {0xfd61f2c3b89f3888}, //music_0120019 {0x4fffee4065d22bec}, //music_0210001 @@ -484,6 +486,7 @@ static const hcakey_info hcakey_list[] = { {0x4aa31e0c4f787a8}, //music_0220014 {0x94466db0d3c10f4b}, //music_0220015 {0xe6d1fd6effa46736}, //music_0220017 + {0xd23bdacd616fc4c9}, //music_0220018 {0xfceaa73248868ec5}, //music_0220019 {0x6a15a9610d10d210}, //music_0310001 {0x57111c24801b44a1}, //music_0310002 @@ -498,6 +501,7 @@ static const hcakey_info hcakey_list[] = { {0xc86f8564e0b9078c}, //music_0310011 {0xcc5610c09f472ce9}, //music_0310012 {0xd447a497c5547a1c}, //music_0310013 + {0x227b85948bb3d899}, //music_0310014 {0xb921c3992807dadd}, //music_0320001 {0x38ad99a045dc971f}, //music_0320002 {0xf616642579ba5850}, //music_0320003 @@ -512,6 +516,7 @@ static const hcakey_info hcakey_list[] = { {0x244a92885ab77b7c}, //music_0320012 {0xfc3fa77fc33460d4}, //music_0320013 {0x26ee13598091b548}, //music_0320014 + {0xf06a6bfdd00c8286}, //music_0320015 {0x2df608ef06aca41c}, //music_0320016 {0x776c4aded0bca5d1}, //music_0410001 {0xb7bff4fbf66be43f}, //music_0410002 @@ -583,6 +588,7 @@ static const hcakey_info hcakey_list[] = { {0xa01c597d1aa13358}, //music_0610010 {0x6492e7708204838}, //music_0610011 {0x957e4d3948427952}, //music_0610012 + {0x7081f083ac3d6f0a}, //music_0610013 {0x8258ddd6a1d0849b}, //music_0620001 {0x1dd21a1244ca12f1}, //music_0620002 {0xfdec74b23d8b494b}, //music_0620003 @@ -663,7 +669,10 @@ static const hcakey_info hcakey_list[] = { {0xd0471c163265ca1b}, //music_5030041 {0xd689966609595d7d}, //music_5030042 {0x172171a4ff10fdc1}, //music_5030043 + {0x53c2bddb0a15d322}, //music_5030044 {0xcb2c44d594252491}, //music_5030045 + {0xbdc220ba31087591}, //music_5030046 + {0xe2346e5f5d18228e}, //music_5030047 {0x458b73844ed5219e}, //music_5030048 {0x7d83b8da9023ef26}, //music_5030049 {0x32cb728ddab4d956}, //music_5030050 @@ -746,6 +755,7 @@ static const hcakey_info hcakey_list[] = { {0x138df0b866e902e0}, //music_5050052 {0xc076e8604740ff5f}, //music_5050053 {0x69fe38ae5970d450}, //music_5050054 + {0x414200bd8ac11b40}, //music_5050055 {0xbce9e85d31089fb2}, //music_5050056 {0x817b919679c96d7}, //music_5050057 {0x3e0e51043bd7d5e5}, //music_5050058 @@ -789,6 +799,11 @@ static const hcakey_info hcakey_list[] = { {0xba4484d824fb61af}, //music_5050099 {0xb70fe5c5e12c7a1c}, //music_5050100 {0x7f5d26ba72161054}, //music_5050101 + {0x79c1f27fa0f8c937}, //music_5050103 + {0xe1e4f9125646aa8a}, //music_5050104 + {0xd5cf3ce581c59e40}, //music_5050105 + {0x5ecb21ac94aa4b8f}, //music_5050107 + {0x3786b3940e98628a}, //music_5050108 {0x52c250eade92393b}, //music_9010001 {0xf66e6bb5b0599b07}, //music_9010002 {0xfea0d6adff136868}, //music_9050001 @@ -843,6 +858,8 @@ static const hcakey_info hcakey_list[] = { {0x0a5d0fc8cc5c4502}, // Sng018 {0x198ea1a17416050b}, // Sng019 {0x2aa3b8abad207a1e}, // Sng020 + {0x1175edbbacc1fc18}, // Sng024 + {0x0e14d06d7f7a6c8c}, // Sng025 {0x33d98a3a9f9bfdef}, // Sng026 {0x2284fd5ca82c78f4}, // Sng027 {0x178a76b6436d20f0}, // Sng028 @@ -857,6 +874,9 @@ static const hcakey_info hcakey_list[] = { // Super Robot Wars 30 (PC) {6734488621090458}, // 0017ECFB5201069A + // CHUNITHM NEW (AC) + {32931609366120192}, // 0074FF1FCE264700 + }; #endif/*_HCA_KEYS_H_*/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ktac.c b/Frameworks/vgmstream/vgmstream/src/meta/ktac.c index 54606188a..75789c7f8 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ktac.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ktac.c @@ -3,26 +3,16 @@ typedef struct { - int channels; - int sample_rate; int loop_flag; - int32_t num_samples; int32_t loop_start; int32_t loop_end; uint32_t file_size; - uint32_t stream_offset; - uint32_t stream_size; - uint32_t table_offset; - uint32_t table_entries; + + mp4_custom_t mp4; int type; - int encoder_delay; - int end_padding; - int frame_samples; } ktac_header_t; -static int make_m4a_header(uint8_t* buf, int buf_len, ktac_header_t* ktac, STREAMFILE* sf); - /* KTAC - Koei Tecmo custom AAC [Kin'iro no Corda 3 (Vita), Shingeki no Kyojin: Shichi kara no Dasshutsu (3DS), Dynasty Warriors (PS4)] */ VGMSTREAM* init_vgmstream_ktac(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; @@ -40,21 +30,21 @@ VGMSTREAM* init_vgmstream_ktac(STREAMFILE* sf) { ktac.file_size = read_u32le(0x08,sf); if (ktac.file_size != get_streamfile_size(sf)) goto fail; - ktac.stream_offset = read_u32le(0x0c,sf); - ktac.stream_size = read_u32le(0x10,sf); - ktac.type = read_u32le(0x14,sf); - ktac.sample_rate = read_u32le(0x18,sf); - ktac.num_samples = read_u32le(0x1c,sf); /* full samples */ - ktac.channels = read_u16le(0x20,sf); - ktac.frame_samples = read_u16le(0x22,sf); - ktac.encoder_delay = read_u16le(0x24,sf); - ktac.end_padding = read_u16le(0x26,sf); - ktac.loop_start = read_u32le(0x28,sf); - ktac.loop_end = read_u32le(0x2c,sf); + ktac.mp4.stream_offset = read_u32le(0x0c,sf); + ktac.mp4.stream_size = read_u32le(0x10,sf); + ktac.type = read_u32le(0x14,sf); + ktac.mp4.sample_rate = read_u32le(0x18,sf); + ktac.mp4.num_samples = read_u32le(0x1c,sf); /* full samples */ + ktac.mp4.channels = read_u16le(0x20,sf); + ktac.mp4.frame_samples = read_u16le(0x22,sf); + ktac.mp4.encoder_delay = read_u16le(0x24,sf); + ktac.mp4.end_padding = read_u16le(0x26,sf); + ktac.loop_start = read_u32le(0x28,sf); + ktac.loop_end = read_u32le(0x2c,sf); /* 0x30: ? (big, related to loops) */ /* 0x34: ? (always null) */ - ktac.table_offset = read_u32le(0x38,sf); - ktac.table_entries= read_u32le(0x3c,sf); + ktac.mp4.table_offset = read_u32le(0x38,sf); + ktac.mp4.table_entries = read_u32le(0x3c,sf); ktac.loop_flag = (ktac.loop_end > 0); @@ -65,41 +55,23 @@ VGMSTREAM* init_vgmstream_ktac(STREAMFILE* sf) { /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(ktac.channels, ktac.loop_flag); + vgmstream = allocate_vgmstream(ktac.mp4.channels, ktac.loop_flag); if (!vgmstream) goto fail; vgmstream->meta_type = meta_KTAC; - vgmstream->sample_rate = ktac.sample_rate; - vgmstream->num_samples = ktac.num_samples - ktac.encoder_delay - ktac.end_padding; - vgmstream->loop_start_sample = ktac.loop_start * ktac.frame_samples - ktac.encoder_delay; - vgmstream->loop_end_sample = ktac.loop_end * ktac.frame_samples - ktac.encoder_delay; + vgmstream->sample_rate = ktac.mp4.sample_rate; + vgmstream->num_samples = ktac.mp4.num_samples - ktac.mp4.encoder_delay - ktac.mp4.end_padding; + vgmstream->loop_start_sample = ktac.loop_start * ktac.mp4.frame_samples - ktac.mp4.encoder_delay; + vgmstream->loop_end_sample = ktac.loop_end * ktac.mp4.frame_samples - ktac.mp4.encoder_delay; /* KTAC uses AAC, but not type found in .aac (that has headered frames, like mp3) but raw - * packets + frame size table (similar to .mp4/m4a). We make a fake M4A header to feed FFmpeg */ + * packets + frame size table (similar to .mp4/m4a). We set config for FFmpeg's fake M4A header */ #ifdef VGM_USE_FFMPEG { - ffmpeg_codec_data* ffmpeg_data = NULL; - int bytes; - uint8_t* buf = NULL; - int buf_len = 0x400 + ktac.table_entries * 0x4; - - if (buf_len > 0x100000) /* ??? */ - goto fail; - - buf = malloc(buf_len); - if (!buf) goto fail; - - bytes = make_m4a_header(buf, buf_len, &ktac, sf); - ffmpeg_data = init_ffmpeg_header_offset(sf, buf, bytes, ktac.stream_offset, ktac.stream_size); - free(buf); - - if (!ffmpeg_data) goto fail; - vgmstream->codec_data = ffmpeg_data; + vgmstream->codec_data = init_ffmpeg_mp4_custom_std(sf, &ktac.mp4); + if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; - - /* not part of fake header since it's kinda complex to add (iTunes string comment) */ - ffmpeg_set_skip_samples(ffmpeg_data, ktac.encoder_delay); } #else goto fail; @@ -110,405 +82,3 @@ fail: close_vgmstream(vgmstream); return NULL; } - -/* *********************************************************** */ - -/* Helpers for M4A headers, an insane soup of chunks (AKA "atoms"). - * Needs *A LOT* of atoms and fields so this is more elaborate than usual. - * - https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFPreface/qtffPreface.html - */ - -/* generic additions */ -typedef struct { - uint8_t* out; - int bytes; -} m4a_state_t; - -typedef struct { - STREAMFILE* sf; - ktac_header_t* ktac; /* config */ - uint8_t* out; /* current position */ - int bytes; /* written bytes */ - m4a_state_t chunks; /* chunks offsets are absolute, save position until we know header size */ -} m4a_header_t; - -static void add_u32b(m4a_header_t* h, uint32_t value) { - put_u32be(h->out, value); - h->out += 0x04; - h->bytes += 0x04; -} - -static void add_u24b(m4a_header_t* h, uint32_t value) { - put_u16be(h->out + 0x00, (value >> 8u) & 0xFFFF); - put_u8 (h->out + 0x02, (value >> 0u) & 0xFF); - h->out += 0x03; - h->bytes += 0x03; -} - -static void add_u16b(m4a_header_t* h, uint16_t value) { - put_u16be(h->out, value); - h->out += 0x02; - h->bytes += 0x02; -} - -static void add_u8(m4a_header_t* h, uint32_t value) { - put_u8(h->out, value); - h->out += 0x01; - h->bytes += 0x01; -} - -static void add_name(m4a_header_t* h, const char* name) { - memcpy(h->out, name, 0x4); - h->out += 0x04; - h->bytes += 0x04; -} - -static void add_atom(m4a_header_t* h, const char* name, uint32_t size) { - add_u32b(h, size); - add_name(h, name); -} - -/* register + write final size for atoms of variable/complex size */ -static void save_atom(m4a_header_t* h, m4a_state_t* s) { - s->out = h->out; - s->bytes = h->bytes; -} - -static void load_atom(m4a_header_t* h, m4a_state_t* s) { - put_u32be(s->out, h->bytes - s->bytes); -} - -/* common atoms */ - -static void add_ftyp(m4a_header_t* h) { - add_atom(h, "ftyp", 0x18); - add_name(h, "M4A "); /* major brand */ - add_u32b(h, 512); /* minor version */ - add_name(h, "isom"); /* compatible brands */ - add_name(h, "iso2"); /* compatible brands */ -} - -static void add_free(m4a_header_t* h) { - add_atom(h, "free", 0x08); -} - -static void add_mdat(m4a_header_t* h) { - add_atom(h, "mdat", 0x08 + h->ktac->stream_size); -} - -/* variable atoms */ - - -static void add_stco(m4a_header_t* h) { - add_atom(h, "stco", 0x10 + 1 * 0x04); - add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ - add_u32b(h, 1); /* Number of entries */ - /* there may be an entry per frame, but only first seems needed */ - save_atom(h, &h->chunks); - add_u32b(h, 0); /* Absolute offset N */ -} -static void add_stsz(m4a_header_t* h) { - int i; - - add_atom(h, "stsz", 0x14 + h->ktac->table_entries * 0x04); - add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ - add_u32b(h, 0); /* Sample size (CBR) */ - add_u32b(h, h->ktac->table_entries); /* Number of entries (VBR) */ - for (i = 0; i < h->ktac->table_entries; i++) { - uint32_t size = read_u32le(h->ktac->table_offset + i*0x04, h->sf); - add_u32b(h, size); /* Sample N */ - } -} - -static void add_stsc(m4a_header_t* h) { - add_atom(h, "stsc", 0x1c); - add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ - add_u32b(h, 1); /* Number of entries */ - add_u32b(h, 1); /* First chunk */ - add_u32b(h, h->ktac->table_entries); /* Samples per chunk */ - add_u32b(h, 1); /* Sample description ID */ -} - -static void add_stts(m4a_header_t* h) { - add_atom(h, "stts", 0x18); - add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ - add_u32b(h, 1); /* Number of entries */ - add_u32b(h, h->ktac->table_entries); /* Sample count */ - add_u32b(h, h->ktac->frame_samples); /* Sample duration */ -} - -/* from mpeg4audio.c (also see ff_mp4_read_dec_config_descr) */ -static const int m4a_sample_rates[16] = { - 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350 -}; -static const uint8_t m4a_channels[14] = { - 0, - 1, // mono (1/0) - 2, // stereo (2/0) - 3, // 3/0 - 4, // 3/1 - 5, // 3/2 - 6, // 3/2.1 - 8, // 5/2.1 - //0, - //0, - //0, - //7, // 3/3.1 - //8, // 3/2/2.1 - //24 // 3/3/3 - 5/2/3 - 3/0/0.2 -}; - -static void add_esds(m4a_header_t* h) { - uint16_t config = 0; - - /* ES_descriptor (TLV format see ISO 14496-1) and DecSpecificInfoTag define actual decoding - - config (channels/rate/etc), other atoms with the same stuff is just info - * - http://ecee.colorado.edu/~ecen5653/ecen5653/papers/ISO%2014496-1%202004.PDF */ - - { - uint8_t object_type = 0x02; /* 0x00=none, 0x01=AAC main, 0x02=AAC LC */ - uint8_t sr_index = 0; - uint8_t ch_index = 0; - uint8_t unknown = 0; - int i; - for (i = 0; i < 16; i++) { - if (m4a_sample_rates[i] == h->ktac->sample_rate) { - sr_index = i; - break; - } - } - for (i = 0; i < 8; i++) { - if (m4a_channels[i] == h->ktac->channels) { - ch_index = i; - break; - } - } - - config |= (object_type & 0x1F) << 11; /* 5b */ - config |= (sr_index & 0x0F) << 7; /* 4b */ - config |= (ch_index & 0x0F) << 3; /* 4b */ - config |= (unknown & 0x07) << 0; /* 3b */ - } - - add_atom(h, "esds", 0x33); - add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ - - add_u8 (h, 0x03); /* ES_DescrTag */ - add_u32b(h, 0x80808022); /* size 0x22 */ - add_u16b(h, 0x0000); /* stream Id */ - add_u8 (h, 0x00); /* flags */ - - add_u8 (h, 0x04); /* DecoderConfigDescrTag */ - add_u32b(h, 0x80808014); /* size 0x14 */ - add_u8 (h, 0x40); /* object type (0x40=audio) */ - add_u8 (h, 0x15); /* stream type (6b: 0x5=audio) + upstream (1b) + reserved (1b: const 1) */ - add_u24b(h, 0x000000); /* buffer size */ - add_u32b(h, 0); /* max bitrate (256000?)*/ - add_u32b(h, 0); /* average bitrate (256000?) */ - - add_u8 (h, 0x05); /* DecSpecificInfoTag */ - add_u32b(h, 0x80808002); /* size 0x02 */ - add_u16b(h, config); /* actual decoder info */ - - add_u8 (h, 0x06); /* SLConfigDescrTag */ - add_u32b(h, 0x80808001); /* size 0x01 */ - add_u8 (h, 0x02); /* predefined (2=default) */ -} - -static void add_mp4a(m4a_header_t* h) { - add_atom(h, "mp4a", 0x57); - add_u32b(h, 0); /* ? */ - add_u32b(h, 1); /* Data reference index */ - add_u32b(h, 0); /* Reserved */ - add_u32b(h, 0); /* Reserved 2 */ - add_u16b(h, h->ktac->channels); /* Channel count */ - add_u16b(h, 16); /* Sample size */ - add_u32b(h, 0); /* Pre-defined */ - add_u16b(h, h->ktac->sample_rate); /* Sample rate */ - add_u16b(h, 0); /* ? */ - add_esds(h); /* elementary stream descriptor */ -} - -static void add_stsd(m4a_header_t* h) { - add_atom(h, "stsd", 0x67); - add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ - add_u32b(h, 1); /* Number of entries */ - add_mp4a(h); -} - -static void add_stbl(m4a_header_t* h) { - m4a_state_t s; - - save_atom(h, &s); - add_atom(h, "stbl", 0x00); - add_stsd(h); /* Sample description */ - add_stts(h); /* Time-to-sample */ - add_stsc(h); /* Sample-to-chunk */ - add_stsz(h); /* Sample size */ - add_stco(h); /* Chunk offset */ - load_atom(h, &s); -} - -static void add_dinf(m4a_header_t* h) { - add_atom(h, "dinf", 0x24); - add_atom(h, "dref", 0x1c); - add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ - add_u32b(h, 1); /* Number of entries */ - add_atom(h, "url ", 0x0c); - add_u32b(h, 1); /* Version (1 byte) + Flags (3 byte) */ -} - -static void add_smhd(m4a_header_t* h) { - add_atom(h, "smhd", 0x10); - add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ - add_u16b(h, 0); /* Balance */ - add_u16b(h, 0); /* Reserved */ -} - -static void add_minf(m4a_header_t* h) { - m4a_state_t s; - - save_atom(h, &s); - add_atom(h, "minf", 0x00); - add_smhd(h); - add_dinf(h); - add_stbl(h); - load_atom(h, &s); -} - -static void add_hdlr(m4a_header_t* h) { - add_atom(h, "hdlr", 0x22); - add_u32b(h, 0); /* version (1 byte) + flags (3 byte) */ - add_u32b(h, 0); /* Component type */ - add_name(h, "soun"); /* Component subtype */ - add_u32b(h, 0); /* Component manufacturer */ - add_u32b(h, 0); /* Component flags */ - add_u32b(h, 0); /* Component flags mask */ - add_u16b(h, 0); /* Component name */ -} - -static void add_mdhd(m4a_header_t* h) { - add_atom(h, "mdhd", 0x20); - add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ - add_u32b(h, 0); /* Creation time */ - add_u32b(h, 0); /* Modification time */ - add_u32b(h, h->ktac->sample_rate); /* Time scale */ - add_u32b(h, h->ktac->num_samples); /* Duration */ - add_u16b(h, 0); /* Language (0xC455=eng?) */ - add_u16b(h, 0); /* Quality */ -} - -static void add_mdia(m4a_header_t* h) { - m4a_state_t s; - - save_atom(h, &s); - add_atom(h, "mdia", 0x00); - add_mdhd(h); - add_hdlr(h); - add_minf(h); - load_atom(h, &s); -} - -static void add_tkhd(m4a_header_t* h) { - add_atom(h, "tkhd", 0x5C); - add_u32b(h, 0x00000001); /* Version (1 byte) + Flags (3 byte), 1=track enabled */ - add_u32b(h, 0); /* Creation time */ - add_u32b(h, 0); /* Modification time */ - add_u32b(h, 1); /* Track ID */ - add_u32b(h, 0); /* Reserved 1 */ - add_u32b(h, h->ktac->num_samples); /* Duration */ - add_u32b(h, 0); /* Reserved 1 */ - add_u32b(h, 0); /* Reserved 2 */ - add_u16b(h, 0); /* Layer */ - add_u16b(h, 0); /* Alternate group (1?) */ - add_u16b(h, 0x0100); /* Volume */ - add_u16b(h, 0); /* Reserved */ - add_u32b(h, 0x00010000); /* matrix_A */ - add_u32b(h, 0); /* matrix_B */ - add_u32b(h, 0); /* matrix_U */ - add_u32b(h, 0); /* matrix_C */ - add_u32b(h, 0x00010000); /* matrix_D */ - add_u32b(h, 0); /* matrix_V */ - add_u32b(h, 0); /* matrix_X */ - add_u32b(h, 0); /* matrix_Y */ - add_u32b(h, 0x40000000); /* matrix_W */ - add_u32b(h, 0); /* Width */ - add_u32b(h, 0); /* Height */ -} - -static void add_trak(m4a_header_t* h) { - m4a_state_t s; - - save_atom(h, &s); - add_atom(h, "trak", 0x00); - add_tkhd(h); - add_mdia(h); - load_atom(h, &s); -} - -static void add_mvhd(m4a_header_t* h) { - add_atom(h, "mvhd", 0x6c); - add_u32b(h, 0); /* Version (1 byte) + Flags (3 byte) */ - add_u32b(h, 0); /* Creation time */ - add_u32b(h, 0); /* Modification time */ - add_u32b(h, h->ktac->sample_rate); /* Time scale */ - add_u32b(h, h->ktac->num_samples); /* Duration */ - add_u32b(h, 0x00010000); /* Preferred rate */ - add_u16b(h, 0x0100); /* Preferred volume */ - add_u32b(h, 0); /* Reserved 1 */ - add_u32b(h, 0); /* Reserved 2 */ - add_u16b(h, 0); /* Reserved 3 */ - add_u32b(h, 0x00010000); /* matrix_A */ - add_u32b(h, 0); /* matrix_B */ - add_u32b(h, 0); /* matrix_U */ - add_u32b(h, 0); /* matrix_C */ - add_u32b(h, 0x00010000); /* matrix_D */ - add_u32b(h, 0); /* matrix_V */ - add_u32b(h, 0); /* matrix_X */ - add_u32b(h, 0); /* matrix_Y */ - add_u32b(h, 0x40000000); /* matrix_W */ - add_u32b(h, 0); /* Preview time */ - add_u32b(h, 0); /* Preview duration */ - add_u32b(h, 0); /* Poster time */ - add_u32b(h, 0); /* Selection time */ - add_u32b(h, 0); /* Selection duration */ - add_u32b(h, 0); /* Current time */ - add_u32b(h, 2); /* Next track ID */ -} - -static void add_moov(m4a_header_t* h) { - m4a_state_t s; - - save_atom(h, &s); - add_atom(h, "moov", 0x00); - add_mvhd(h); - add_trak(h); - //add_udta(h); - load_atom(h, &s); -} - -/* *** */ - -static int make_m4a_header(uint8_t* buf, int buf_len, ktac_header_t* ktac, STREAMFILE* sf) { - m4a_header_t h = {0}; - - if (buf_len < 0x300 + ktac->table_entries * 0x4) /* approx */ - goto fail; - - h.sf = sf; - h.ktac = ktac; - h.out = buf; - - add_ftyp(&h); - add_free(&h); - add_moov(&h); - add_mdat(&h); - - - /* define absolute chunk offset after all calcs */ - put_u32be(h.chunks.out, h.bytes); - - return h.bytes; -fail: - return 0; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/meta.h b/Frameworks/vgmstream/vgmstream/src/meta/meta.h index 19541b025..0b22dc921 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h @@ -28,7 +28,7 @@ VGMSTREAM * init_vgmstream_halpst(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_nds_strm(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_ngc_adpdtk(STREAMFILE *streamFile); +VGMSTREAM* init_vgmstream_dtk(STREAMFILE* sf); VGMSTREAM* init_vgmstream_ngc_dsp_std(STREAMFILE* sf); VGMSTREAM* init_vgmstream_ngc_mdsp_std(STREAMFILE* sf); @@ -77,7 +77,7 @@ VGMSTREAM * init_vgmstream_nps(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_rs03(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_rsf(STREAMFILE *streamFile); +VGMSTREAM* init_vgmstream_rsf(STREAMFILE* sf); VGMSTREAM * init_vgmstream_rwsd(STREAMFILE *streamFile); @@ -94,9 +94,9 @@ VGMSTREAM * init_vgmstream_svag_kcet(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_mib_mih(STREAMFILE *streamFile); +VGMSTREAM* init_vgmstream_mib_mih(STREAMFILE* sf); -VGMSTREAM * init_vgmstream_ps2_mic(STREAMFILE *streamFile); +VGMSTREAM* init_vgmstream_mic_koei(STREAMFILE* sf); VGMSTREAM * init_vgmstream_raw_pcm(STREAMFILE *streamFile); @@ -105,7 +105,7 @@ VGMSTREAM * init_vgmstream_vag_aaap(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_seb(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_ps2_ild(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_ild(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ps2_pnb(STREAMFILE *streamFile); @@ -225,7 +225,7 @@ VGMSTREAM * init_vgmstream_filp(STREAMFILE * streamFile); VGMSTREAM* init_vgmstream_ikm(STREAMFILE* sf); -VGMSTREAM * init_vgmstream_sfs(STREAMFILE * streamFile); +VGMSTREAM* init_vgmstream_ster(STREAMFILE* sf); VGMSTREAM * init_vgmstream_sat_dvi(STREAMFILE * streamFile); @@ -451,8 +451,6 @@ VGMSTREAM * init_vgmstream_dmsg(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_ngc_dsp_konami(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_ps2_ster(STREAMFILE* streamFile); - VGMSTREAM * init_vgmstream_bnsf(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_ps2_wb(STREAMFILE* streamFile); @@ -971,5 +969,6 @@ VGMSTREAM* init_vgmstream_lopu_fb(STREAMFILE* sf); VGMSTREAM* init_vgmstream_lpcm_fb(STREAMFILE* sf); VGMSTREAM* init_vgmstream_wbk(STREAMFILE* sf); +VGMSTREAM* init_vgmstream_wbk_nslb(STREAMFILE* sf); #endif /*_META_H*/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/msf.c b/Frameworks/vgmstream/vgmstream/src/meta/msf.c index 5e3e21cb8..f4b94d952 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/msf.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/msf.c @@ -14,8 +14,9 @@ VGMSTREAM* init_vgmstream_msf(STREAMFILE* sf) { /* .msf: standard * .msa: Sonic & Sega All-Stars Racing (PS3) * .at3: Silent Hill HD Collection (PS3), Z/X Zekkai no Crusade (PS3) - * .mp3: Darkstalkers Resurrection (PS3) */ - if (!check_extensions(sf,"msf,msa,at3,mp3")) + * .mp3: Darkstalkers Resurrection (PS3) + * .str: Pac-Man and the Ghostly Adventures (PS3) */ + if (!check_extensions(sf,"msf,msa,at3,mp3,str")) goto fail; /* check header "MSF" + version-char, usually: diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ngc_adpdtk.c b/Frameworks/vgmstream/vgmstream/src/meta/ngc_adpdtk.c index 63db64338..982cd45aa 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ngc_adpdtk.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ngc_adpdtk.c @@ -3,7 +3,7 @@ #include "../util.h" /* DTK - headerless Nintendo GC DTK file [Harvest Moon: Another Wonderful Life (GC), XGRA (GC)] */ -VGMSTREAM* init_vgmstream_ngc_adpdtk(STREAMFILE* sf) { +VGMSTREAM* init_vgmstream_dtk(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; off_t start_offset; int channels, loop_flag; @@ -22,12 +22,12 @@ VGMSTREAM* init_vgmstream_ngc_adpdtk(STREAMFILE* sf) { for (i = 0; i < 10; i++) { /* try a bunch of frames */ /* header 0x00/01 are repeated in 0x02/03 (for error correction?), * could also test header values (upper nibble should be 0..3, and lower nibble 0..C) */ - if (read_8bit(0x00 + i*0x20,sf) != read_8bit(0x02 + i*0x20,sf) || - read_8bit(0x01 + i*0x20,sf) != read_8bit(0x03 + i*0x20,sf)) + if (read_u8(0x00 + i*0x20,sf) != read_u8(0x02 + i*0x20,sf) || + read_u8(0x01 + i*0x20,sf) != read_u8(0x03 + i*0x20,sf)) goto fail; /* frame headers for silent frames are 0x0C, never null */ - if (read_8bit(0x00 + i*0x20,sf) == 0x00) + if (read_u8(0x00 + i*0x20,sf) == 0x00) goto fail; } } @@ -48,13 +48,11 @@ VGMSTREAM* init_vgmstream_ngc_adpdtk(STREAMFILE* sf) { vgmstream->sample_rate = 48000; /* due to a GC hardware defect this may be closer to 48043 */ vgmstream->coding_type = coding_NGC_DTK; vgmstream->layout_type = layout_none; - vgmstream->meta_type = meta_NGC_ADPDTK; + vgmstream->meta_type = meta_DTK; - if ( !vgmstream_open_stream(vgmstream, sf, start_offset) ) + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) goto fail; - return vgmstream; - fail: close_vgmstream(vgmstream); return NULL; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_ild.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_ild.c index 761ea4ecb..d7b1146ea 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_ild.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_ild.c @@ -1,69 +1,58 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* ILD */ - -VGMSTREAM * init_vgmstream_ps2_ild(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - int loop_flag=0; - int channel_count; +/* ILD - from Tose(?) games [Battle of Sunrise (PS2), Nightmare Before Christmas: Oogie's Revenge (PS2)] */ +VGMSTREAM* init_vgmstream_ild(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + int channels, loop_flag; + uint32_t data_size; off_t start_offset; - int i; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("ild",filename_extension(filename))) goto fail; /* check ILD Header */ - if (read_32bitBE(0x00,streamFile) != 0x494C4400) + if (!is_id32be(0x00,sf, "ILD\0")) goto fail; - /* check loop */ - loop_flag = (read_32bitLE(0x2C,streamFile)!=0); - channel_count=read_32bitLE(0x04,streamFile); - + if (!check_extensions(sf, "ild")) + goto fail; + + channels = read_u32le(0x04,sf); /* tracks (seen 2 and 4) */ + start_offset = read_u32le(0x08,sf); + data_size = read_u32le(0x0C,sf); + /* 0x10: headers size / 2? */ + /* 0x14: header per channel */ + /* - 0x00: null */ + /* - 0x04: header size? (always 0x20) */ + /* - 0x08: size (may vary a bit between channel pairs) */ + /* - 0x0c: interleave? */ + /* - 0x10: channels per track (1) */ + /* - 0x14: sample rate */ + /* - 0x18: loop start */ + /* - 0x1c: loop end (also varies) */ + + + loop_flag = (read_s32le(0x2C,sf) > 0); + + /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); + vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - vgmstream->channels = read_32bitLE(0x04,streamFile); - vgmstream->sample_rate = read_32bitLE(0x28,streamFile); + vgmstream->meta_type = meta_ILD; + + vgmstream->num_samples = ps_bytes_to_samples(data_size, channels); + vgmstream->interleave_block_size = read_u32le(0x14 + 0x0c,sf); + vgmstream->sample_rate = read_u32le(0x14 + 0x14,sf); + vgmstream->loop_start_sample = ps_bytes_to_samples(read_u32le(0x14 + 0x18,sf), 1); + vgmstream->loop_end_sample = ps_bytes_to_samples(read_u32le(0x14 + 0x1c,sf), 1); - /* Check for Compression Scheme */ vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = read_32bitLE(0x0C,streamFile)/16*28/vgmstream->channels; - - /* Get loop point values */ - if(vgmstream->loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(0x2C,streamFile)/16*28; - vgmstream->loop_end_sample = read_32bitLE(0x30,streamFile)/16*28; - } - - vgmstream->interleave_block_size = read_32bitLE(0x18,streamFile)/2; vgmstream->layout_type = layout_interleave; - vgmstream->meta_type = meta_PS2_ILD; - - start_offset = (off_t)read_32bitLE(0x08,streamFile); - - /* open the file for reading by each channel */ - { - for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - - if (!vgmstream->ch[i].streamfile) goto fail; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset= - (off_t)(start_offset+vgmstream->interleave_block_size*i); - } - } + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_mic.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_mic.c index 14850d20b..84bbfff45 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_mic.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_mic.c @@ -2,29 +2,37 @@ #include "../coding/coding.h" /* .MIC - from KOEI games [Crimson Sea 2 (PS2), Dynasty Tactics 2 (PS2)] */ -VGMSTREAM * init_vgmstream_ps2_mic(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; +VGMSTREAM* init_vgmstream_mic_koei(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; off_t start_offset; - int loop_flag, channel_count, loop_start, loop_end, sample_rate; + int loop_flag, channels, loop_start, loop_end, sample_rate; size_t interleave, block_size; /* checks */ - if (!check_extensions(streamFile, "mic")) + if (!check_extensions(sf, "mic")) goto fail; - start_offset = read_32bitLE(0x00,streamFile); + /* simple header so throws some extra in some checks */ + start_offset = read_u32le(0x00,sf); if (start_offset != 0x800) goto fail; - sample_rate = read_32bitLE(0x04,streamFile); - channel_count = read_32bitLE(0x08,streamFile); - interleave = read_32bitLE(0x0c,streamFile); - loop_end = read_32bitLE(0x10,streamFile); - loop_start = read_32bitLE(0x14,streamFile); + sample_rate = read_u32le(0x04,sf); + channels = read_u32le(0x08,sf); + if (channels > 2) goto fail; + interleave = read_u32le(0x0c,sf); + if (interleave != 0x10) goto fail; + + loop_end = read_32bitLE(0x10,sf); + loop_start = read_32bitLE(0x14,sf); + if (read_u32le(0x18,sf) != 0) goto fail; + if (read_u32le(0x1c,sf) != 0) goto fail; + loop_flag = (loop_start != 1); - block_size = interleave * channel_count; + block_size = interleave * channels; + /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count, loop_flag); + vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; vgmstream->meta_type = meta_PS2_MIC; @@ -34,11 +42,11 @@ VGMSTREAM * init_vgmstream_ps2_mic(STREAMFILE *streamFile) { vgmstream->interleave_block_size = interleave; vgmstream->layout_type = layout_interleave; - vgmstream->num_samples = ps_bytes_to_samples(loop_end * block_size, channel_count); - vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start * block_size, channel_count); + vgmstream->num_samples = ps_bytes_to_samples(loop_end * block_size, channels); + vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start * block_size, channels); vgmstream->loop_end_sample = vgmstream->num_samples; - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) goto fail; return vgmstream; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_ster.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_ster.c deleted file mode 100644 index f56e57c5c..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_ster.c +++ /dev/null @@ -1,66 +0,0 @@ -#include "meta.h" -#include "../util.h" - -/* STER (from Juuni Kokuki: Kakukaku Taru Ou Michi Beni Midori no Uka) */ -VGMSTREAM * init_vgmstream_ps2_ster(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("ster",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x53544552) /* "STER" */ - goto fail; - - - loop_flag = (read_16bitLE(0xB,streamFile)==0); - channel_count = 2; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x30; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitBE(0x10,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = read_32bitLE(0x4,streamFile)*56/32; - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(0x8,streamFile)*28/32; - vgmstream->loop_end_sample = vgmstream->num_samples; - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x10; - vgmstream->meta_type = meta_PS2_STER; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps_headerless.c b/Frameworks/vgmstream/vgmstream/src/meta/ps_headerless.c index 30dd869e1..08c11ae53 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps_headerless.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ps_headerless.c @@ -2,9 +2,9 @@ #include "../coding/coding.h" -/* headerless PS-ADPCM - from Katamary Damacy (PS2), Air (PS2), Aladdin: Nasira's Revenge (PS1) - * (guesses interleave and channels by testing data and using the file extension, and finds - * loops in PS-ADPCM flags; this is a crutch for convenience, consider using GENH/TXTH instead). */ +/* Headerless PS-ADPCM + * Guesses interleave/channels/loops by testing data and using the file extension for sample rate. + * This is an ugly crutch for older sets, use TXTH to properly play headerless data instead. */ VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset = 0x00; @@ -34,18 +34,12 @@ VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile) { /* checks * .mib: common, but many ext-less files are renamed to this. * .mi4: fake .mib to force another sample rate - * .cvs: Aladdin - Nasira's Revenge (PS1) - * .snds: The Incredibles (PS2) * .vb: Tantei Jinguuji Saburo - Mikan no Rupo (PS1) - * .xag: Hagane no Renkinjutsushi - Dream Carnival (PS2) * */ streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("cvs",filename_extension(filename)) && - strcasecmp("mib",filename_extension(filename)) && + if (strcasecmp("mib",filename_extension(filename)) && strcasecmp("mi4",filename_extension(filename)) && - strcasecmp("snds",filename_extension(filename))&& - strcasecmp("vb",filename_extension(filename)) && - strcasecmp("xag",filename_extension(filename))) + strcasecmp("vb",filename_extension(filename))) goto fail; /* test if raw PS-ADPCM */ @@ -136,9 +130,6 @@ VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile) { if(!strcasecmp("vb",filename_extension(filename))) loopStart=0; - if(!strcasecmp("xag",filename_extension(filename))) - channel_count=2; - // Calc Loop Points & Interleave ... if(loopStartPointsCount>=2) { // can't get more then 0x10 loop point ! @@ -200,8 +191,7 @@ VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile) { channel_count=newChannelCount; } - if (!strcasecmp("cvs", filename_extension(filename)) || - !strcasecmp("vb",filename_extension(filename))) + if (!strcasecmp("vb",filename_extension(filename))) channel_count=1; @@ -220,14 +210,7 @@ VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile) { if(!strcasecmp("mi4",filename_extension(filename))) vgmstream->sample_rate = 48000; - if(!strcasecmp("snds", filename_extension(filename))) - vgmstream->sample_rate = 48000; - - if(!strcasecmp("xag",filename_extension(filename))) - vgmstream->sample_rate = 44100; - - if (!strcasecmp("cvs", filename_extension(filename)) || - !strcasecmp("vb",filename_extension(filename))) + if (!strcasecmp("vb",filename_extension(filename))) vgmstream->sample_rate = 22050; vgmstream->num_samples = (int32_t)(fileLength/16/channel_count*28); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/psb.c b/Frameworks/vgmstream/vgmstream/src/meta/psb.c index ec021b4d6..db5e2230b 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/psb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/psb.c @@ -155,7 +155,7 @@ VGMSTREAM* init_vgmstream_psb(STREAMFILE* sf) { default: goto fail; } - if (psb.duration_test && psb.loop_start + psb.loop_end < vgmstream->num_samples) + if (psb.duration_test && psb.loop_start + psb.loop_end <= vgmstream->num_samples) vgmstream->loop_end_sample += psb.loop_start; break; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/riff.c b/Frameworks/vgmstream/vgmstream/src/meta/riff.c index 6ec580ae3..453c4b8fc 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/riff.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/riff.c @@ -518,10 +518,10 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) { break; case 0x66616374: /* "fact" */ - if (chunk_size == 0x04) { /* standard (usually for ADPCM, MS recommends to set for non-PCM codecs) */ + if (chunk_size == 0x04) { /* standard (usually for ADPCM, MS recommends setting for non-PCM codecs but optional) */ fact_sample_count = read_32bitLE(current_chunk+0x08, sf); } - else if (chunk_size == 0x10 && read_32bitBE(current_chunk+0x08+0x04, sf) == 0x4C794E20) { /* "LyN " */ + else if (chunk_size == 0x10 && is_id32be(current_chunk+0x08+0x04, sf, "LyN ")) { goto fail; /* parsed elsewhere */ } else if ((fmt.is_at3 || fmt.is_at3p) && chunk_size == 0x08) { /* early AT3 (mainly PSP games) */ @@ -540,6 +540,9 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) { } break; + case 0x4C795345: /* "LySE" */ + goto fail; /* parsed elsewhere */ + case 0x70666c74: /* "pflt" (.mwv extension) */ if (!mwv) break; /* ignore if not in an mwv */ mwv_pflt_offset = current_chunk; /* predictor filters */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/rsf.c b/Frameworks/vgmstream/vgmstream/src/meta/rsf.c index 864fb07a9..d6fdeedff 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/rsf.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/rsf.c @@ -4,42 +4,47 @@ /* .rsf - from Metroid Prime */ -VGMSTREAM * init_vgmstream_rsf(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; +VGMSTREAM* init_vgmstream_rsf(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + int channels, loop_flag; + uint32_t interleave, file_size; - size_t file_size; + /* checks */ + if (!check_extensions(sf,"rsf")) + goto fail; - /* check extension, case insensitive */ /* this is all we have to go on, rsf is completely headerless */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("rsf",filename_extension(filename))) goto fail; - file_size = get_streamfile_size(streamFile); + file_size = get_streamfile_size(sf); + interleave = (file_size + 1) / 2; + /* G.721 has no zero nibbles, so we look at the first few bytes + * (known files start with 0xFFFFFFFF, but probably an oddity of the codec) */ { - /* extra check: G.721 has no zero nibbles, so we look at - * the first few bytes*/ - int8_t test_byte; + uint8_t test_byte; off_t i; + /* 0x20 is arbitrary, all files are much larger */ - for (i=0;i<0x20;i++) { - test_byte = read_8bit(i,streamFile); + for (i = 0; i < 0x20; i++) { + test_byte = read_u8(i,sf); if (!(test_byte&0xf) || !(test_byte&0xf0)) goto fail; } + /* and also check start of second channel */ - for (i=(file_size+1)/2;i<(file_size+1)/2+0x20;i++) { - test_byte = read_8bit(i,streamFile); + for (i = interleave; i < interleave + 0x20; i++) { + test_byte = read_u8(i,sf); if (!(test_byte&0xf) || !(test_byte&0xf0)) goto fail; } } - /* build the VGMSTREAM */ + channels = 2; + loop_flag = 0; - vgmstream = allocate_vgmstream(2,0); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ vgmstream->num_samples = file_size; vgmstream->sample_rate = 32000; @@ -47,27 +52,20 @@ VGMSTREAM * init_vgmstream_rsf(STREAMFILE *streamFile) { vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_RSF; + if (!vgmstream_open_stream(vgmstream, sf, 0)) + goto fail; + /* open the file for reading by each channel */ { int i; - for (i=0;i<2;i++) { - vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - - if (!vgmstream->ch[i].streamfile) goto fail; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset= - (file_size+1)/2*i; - - + for (i = 0; i < channels; i++) { + vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset = interleave * i; g72x_init_state(&(vgmstream->ch[i].g72x_state)); } } return vgmstream; - - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_sfs.c b/Frameworks/vgmstream/vgmstream/src/meta/ster.c similarity index 74% rename from Frameworks/vgmstream/vgmstream/src/meta/ps2_sfs.c rename to Frameworks/vgmstream/vgmstream/src/meta/ster.c index 97de7a32b..293ea80e4 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_sfs.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ster.c @@ -1,8 +1,8 @@ #include "meta.h" #include "../coding/coding.h" -/* SFS - from Sting games [Baroque (PS2)] */ -VGMSTREAM* init_vgmstream_sfs(STREAMFILE* sf) { +/* STER - from Silicon Studios/Vicarious Visions's ALCHEMY middleware [Baroque (PS2), Star Soldier (PS2)] */ +VGMSTREAM* init_vgmstream_ster(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; off_t start_offset; int loop_flag, channels, sample_rate; @@ -10,8 +10,9 @@ VGMSTREAM* init_vgmstream_sfs(STREAMFILE* sf) { /* checks */ - /* .sfs: bigfile extension (no apparent names) */ - if (!check_extensions(sf, "sfs")) + /* .ster: header id (no apparent names/extensions) + * .sfs: generic bigfile extension (to be removed?)*/ + if (!check_extensions(sf, "ster,sfs")) goto fail; if (!is_id32be(0x00,sf, "STER")) @@ -20,9 +21,10 @@ VGMSTREAM* init_vgmstream_sfs(STREAMFILE* sf) { loop_start = read_u32le(0x08, sf); /* absolute (ex. offset 0x50 for full loops) */ /* 0x0c: data size BE */ sample_rate = read_s32be(0x10,sf); + /* 0x14~20: null */ loop_flag = loop_start != 0xFFFFFFFF; - channels = 2; + channels = 2; /* mono files are simply .VAG */ start_offset = 0x30; @@ -30,7 +32,7 @@ VGMSTREAM* init_vgmstream_sfs(STREAMFILE* sf) { vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; - vgmstream->meta_type = meta_SFS; + vgmstream->meta_type = meta_STER; vgmstream->sample_rate = sample_rate; vgmstream->num_samples = ps_bytes_to_samples(channel_size, 1); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c index 46a21ccb5..d5cbf394d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c @@ -32,6 +32,8 @@ typedef struct { off_t audio_stream_type; off_t audio_prefetch_size; size_t audio_interleave; + off_t audio_cue_count; + off_t audio_cue_size; int audio_fix_psx_samples; int audio_external_and; int audio_loop_and; @@ -79,21 +81,21 @@ typedef struct { ubi_bao_config cfg; /* header info */ - off_t header_offset; + uint32_t header_offset; uint8_t header_format; uint32_t header_version; uint32_t header_id; uint32_t header_type; - size_t header_skip; /* common sub-header size */ - size_t header_size; /* normal base size (not counting extra tables) */ - size_t extra_size; /* extra tables size */ + uint32_t header_skip; /* common sub-header size */ + uint32_t header_size; /* normal base size (not counting extra tables) */ + uint32_t extra_size; /* extra tables size */ uint32_t stream_id; - size_t stream_size; - off_t stream_offset; + uint32_t stream_size; + uint32_t stream_offset; uint32_t prefetch_id; - size_t prefetch_size; - off_t prefetch_offset; + uint32_t prefetch_size; + uint32_t prefetch_offset; size_t memory_skip; size_t stream_skip; @@ -265,10 +267,10 @@ static VGMSTREAM* init_vgmstream_ubi_bao_base(ubi_bao_header* bao, STREAMFILE* s vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = bao->stream_size / bao->channels; - +VGM_LOG("dsp=%x, %x, %x\n", bao->header_offset, bao->header_size, bao->extra_size); /* mini DSP header (first 0x10 seem to contain DSP header fields like nibbles and format) */ - dsp_read_coefs_be(vgmstream, streamHead, bao->header_offset + bao->header_size + 0x10, 0x40); - dsp_read_hist_be (vgmstream, streamHead, bao->header_offset + bao->header_size + 0x34, 0x40); /* after gain/initial ps */ + dsp_read_coefs_be(vgmstream, streamHead, bao->header_offset + bao->header_size + bao->extra_size + 0x10, 0x40); + dsp_read_hist_be (vgmstream, streamHead, bao->header_offset + bao->header_size + bao->extra_size + 0x34, 0x40); /* after gain/initial ps */ break; #ifdef VGM_USE_FFMPEG @@ -638,12 +640,12 @@ static VGMSTREAM* init_vgmstream_ubi_bao_header(ubi_bao_header* bao, STREAMFILE* goto fail; /* not uncommon */ } - //;VGM_LOG("UBI BAO: target at %x, h_id=%08x, s_id=%08x, p_id=%08x\n", - // (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", - // (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", - // bao->header_type, bao->header_size, bao->extra_size, (uint32_t)bao->prefetch_offset, bao->prefetch_size); + ;VGM_LOG("UBI BAO: target at %x, h_id=%08x, s_id=%08x, p_id=%08x\n", + (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", + (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", + bao->header_type, bao->header_size, bao->extra_size, (uint32_t)bao->prefetch_offset, bao->prefetch_size); switch(bao->type) { @@ -830,6 +832,12 @@ static int parse_type_audio(ubi_bao_header* bao, off_t offset, STREAMFILE* sf) { bao->channels = read_32bit(h_offset + bao->cfg.audio_channels, sf); bao->sample_rate = read_32bit(h_offset + bao->cfg.audio_sample_rate, sf); + /* extra cue table, rare (found with DSP) [We Dare (Wii)] */ + if (bao->cfg.audio_cue_size) { + //bao->cfg.audio_cue_count //not needed? + bao->extra_size = read_32bit(h_offset + bao->cfg.audio_cue_size, sf); + } + /* prefetch data is in another internal BAO right after the base header */ if (bao->cfg.audio_prefetch_size) { bao->prefetch_size = read_32bit(h_offset + bao->cfg.audio_prefetch_size, sf); @@ -1570,6 +1578,12 @@ static void config_bao_audio_m(ubi_bao_header* bao, off_t channels, off_t sample bao->cfg.audio_prefetch_size = prefetch_size; } +static void config_bao_audio_c(ubi_bao_header* bao, off_t cue_count, off_t cue_size) { + /* audio header extra */ + bao->cfg.audio_cue_count = cue_count; + bao->cfg.audio_cue_size = cue_size; +} + static void config_bao_sequence(ubi_bao_header* bao, off_t sequence_count, off_t sequence_single, off_t sequence_loop, off_t entry_size) { /* sequence header and chain table */ bao->cfg.sequence_sequence_count = sequence_count; @@ -1768,6 +1782,9 @@ static int config_bao_version(ubi_bao_header* bao, STREAMFILE* sf) { if (version == 0x0022000D) /* Just Dance (Wii) oddity */ bao->cfg.audio_ignore_resource_size = 1; + if (version == 0x0022000D) /* We Dare (Wii) */ + config_bao_audio_c(bao, 0x68, 0x78); + return 1; case 0x00220015: /* James Cameron's Avatar: The Game (PSP)-package */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_jade.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_jade.c index dec628671..d0936bfbb 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_jade.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_jade.c @@ -1,106 +1,116 @@ #include "meta.h" +#include "../util/chunks.h" #include "../coding/coding.h" -static int get_loop_points(STREAMFILE* sf, int* p_loop_start, int* p_loop_end); +static int get_loop_points(STREAMFILE* sf, uint32_t cue_offset, uint32_t cue_size, uint32_t list_offset, uint32_t list_size, int* p_loop_start, int* p_loop_end); /* Jade RIFF - from Ubisoft Jade engine games [Beyond Good & Evil (multi), Rayman Raving Rabbids 1/2 (multi)] */ VGMSTREAM* init_vgmstream_ubi_jade(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; - off_t start_offset, first_offset = 0xc; - off_t fmt_offset, data_offset; - size_t fmt_size, data_size; - int loop_flag, channel_count, sample_rate, codec, block_size; + uint32_t fmt_offset = 0, fmt_size = 0, data_offset = 0, data_size = 0; + uint32_t cue_offset = 0, cue_size = 0, list_offset = 0, list_size = 0; + int loop_flag = 0, channels = 0, sample_rate = 0, codec = 0, block_size = 0; int loop_start = 0, loop_end = 0; int is_jade_v2 = 0; /* checks */ - /* .waa: ambiances, .wam: music, .wac: sfx, .wad: dialogs (usually) - * .wav: Beyond Good & Evil HD (PS3) - * .psw: fake/badly extracted names [ex. Rayman Raving Rabbids (PS2)] */ - if (!check_extensions(sf,"waa,wac,wad,wam,wav,lwav,psw")) + if (!is_id32be(0x00,sf, "RIFF")) + goto fail; + if (read_u32le(0x04,sf) + 0x04 + 0x04 != get_streamfile_size(sf)) + goto fail; + if (!is_id32be(0x08,sf, "WAVE")) + goto fail; + + /* .waa: ambiances / .wam: music / .wac: sfx / .wad: dialogs (usually) + * .wav: Beyond Good & Evil HD (PS3) */ + if (!check_extensions(sf,"waa,wac,wad,wam,wav,lwav")) goto fail; /* a slightly twisted RIFF with custom codecs */ - if (!is_id32be(0x00,sf, "RIFF") || - !is_id32be(0x08,sf, "WAVE")) - goto fail; - - if (check_extensions(sf,"psw")) { /* .psw are incorrectly extracted missing 0x04 at the end */ - if (read_32bitLE(0x04,sf)+0x04 != get_streamfile_size(sf)) - goto fail; - } - else { - if (read_32bitLE(0x04,sf)+0x04+0x04 != get_streamfile_size(sf)) - goto fail; - } - - if (!find_chunk(sf, 0x666d7420,first_offset,0, &fmt_offset,&fmt_size, 0, 0)) /* "fmt " */ - goto fail; - if (!find_chunk(sf, 0x64617461,first_offset,0, &data_offset,&data_size, 0, 0)) /* "data" */ - goto fail; - - /* ignore LyN RIFF (needed as codec 0xFFFE is reused) */ + /* parse chunks (reads once linearly) */ { - off_t fact_offset; - size_t fact_size; + chunk_t rc = {0}; - if (find_chunk(sf, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) { /* "fact" */ - if (fact_size == 0x10 && read_32bitBE(fact_offset+0x04, sf) == 0x4C794E20) /* "LyN " */ - goto fail; /* parsed elsewhere */ - /* Jade doesn't use "fact", though */ - } - } + rc.current = 0x0c; + while (next_chunk(&rc, sf)) { + switch(rc.type) { + case 0x666d7420: /* "fmt " */ + fmt_offset = rc.offset; + fmt_size = rc.size; - /* parse format */ - { - if (fmt_size < 0x10) - goto fail; - codec = (uint16_t)read_16bitLE(fmt_offset+0x00,sf); - channel_count = read_16bitLE(fmt_offset+0x02,sf); - sample_rate = read_32bitLE(fmt_offset+0x04,sf); - block_size = (uint16_t)read_16bitLE(fmt_offset+0x0c,sf); - /* 0x08: average bytes, 0x0e: bps, etc */ + if (fmt_size < 0x10) /* min 0x10: MSF, 0x12: common, 0x32: MSADPCM */ + goto fail; + codec = read_u16le(fmt_offset+0x00,sf); + channels = read_u16le(fmt_offset+0x02,sf); + sample_rate = read_s32le(fmt_offset+0x04,sf); + block_size = read_u16le(fmt_offset+0x0c,sf); + /* 0x08: average bytes, 0x0e: bps, etc */ + break; - /* autodetect Jade "v2", uses a different interleave [Rayman Raving Rabbids (PS2/Wii)] */ - switch(codec) { - case 0xFFFF: { /* PS2 */ - int i; + case 0x64617461: /* "data" */ + data_offset = rc.offset; + data_size = rc.size; + break; - /* half interleave check as there is no flag (ends with the PS-ADPCM stop frame) */ - for (i = 0; i < channel_count; i++) { - off_t end_frame = data_offset + (data_size / channel_count) * (i+1) - 0x10; - if (read_32bitBE(end_frame+0x00,sf) != 0x07007777 || - read_32bitBE(end_frame+0x04,sf) != 0x77777777 || - read_32bitBE(end_frame+0x08,sf) != 0x77777777 || - read_32bitBE(end_frame+0x0c,sf) != 0x77777777) { - is_jade_v2 = 1; - break; - } - } - break; + case 0x63756520: /* "cue ": catches PC Rabbids (hopefully) */ + is_jade_v2 = 1; + cue_offset = rc.offset; + cue_size = rc.size; + break; + + case 0x66616374: /* "fact" */ + /* ignore LyN RIFF (needed as codec 0xFFFE is reused, and Jade doesn't set "fact") */ + //if (rc.size == 0x10 && !is_id32be(rc.offset + 0x04, sf, "LyN ")) + // goto fail; /* parsed elsewhere */ + goto fail; + + case 0x4C495354: /* "LIST": labels (rare) */ + list_offset = rc.offset; + list_size = rc.size; + break; + + default: + /* unknown chunk: must be another RIFF */ + goto fail; } - - case 0xFFFE: /* GC/Wii */ - is_jade_v2 = (read_16bitLE(fmt_offset+0x10,sf) == 0); /* extra data size (0x2e*channels) */ - break; - - default: - break; - } - - /* hopefully catches PC Rabbids */ - if (find_chunk(sf, 0x63756520,first_offset,0, NULL,NULL, 0, 0)) { /* "cue " */ - is_jade_v2 = 1; } } + if (!fmt_offset || !fmt_size || !data_offset || !data_size) + goto fail; + + /* autodetect Jade "v2", uses a different interleave [Rayman Raving Rabbids (PS2/Wii)] */ + switch(codec) { + case 0xFFFF: { /* PS2 */ + int i; + + /* half interleave check as there is no flag (ends with the PS-ADPCM stop frame) */ + for (i = 0; i < channels; i++) { + uint32_t end_frame = data_offset + (data_size / channels) * (i+1) - 0x10; + if (read_u32be(end_frame+0x00,sf) != 0x07007777 || + read_u32be(end_frame+0x04,sf) != 0x77777777 || + read_u32be(end_frame+0x08,sf) != 0x77777777 || + read_u32be(end_frame+0x0c,sf) != 0x77777777) { + is_jade_v2 = 1; + break; + } + } + break; + } + + case 0xFFFE: /* GC/Wii */ + is_jade_v2 = (read_u16le(fmt_offset+0x10,sf) == 0); /* extra data size (0x2e*channels) */ + break; + + default: + break; + } - /* get loop points */ if (is_jade_v2) { - loop_flag = get_loop_points(sf, &loop_start, &loop_end); /* loops in "LIST" */ + loop_flag = get_loop_points(sf, cue_offset, cue_size, list_offset, list_size, &loop_start, &loop_end); /* loops in "LIST" */ } else { /* BG&E files don't contain looping information, so the looping is done by extension. @@ -109,15 +119,13 @@ VGMSTREAM* init_vgmstream_ubi_jade(STREAMFILE* sf) { loop_flag = check_extensions(sf,"waa,wam"); } - start_offset = data_offset; - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); + vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; - vgmstream->sample_rate = sample_rate; vgmstream->meta_type = meta_UBI_JADE; + vgmstream->sample_rate = sample_rate; if (is_jade_v2) { vgmstream->loop_start_sample = loop_start; vgmstream->loop_end_sample = loop_end; @@ -128,12 +136,12 @@ VGMSTREAM* init_vgmstream_ubi_jade(STREAMFILE* sf) { case 0x0069: /* Xbox */ /* Peter Jackson's King Kong uses 0x14 (other versions don't) */ if (fmt_size != 0x12 && fmt_size != 0x14) goto fail; - if (block_size != 0x24*channel_count) goto fail; + if (block_size != 0x24*channels) goto fail; vgmstream->coding_type = coding_XBOX_IMA; vgmstream->layout_type = layout_none; - vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, channel_count); + vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, channels); if (!is_jade_v2) { vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = vgmstream->num_samples; @@ -154,10 +162,10 @@ VGMSTREAM* init_vgmstream_ubi_jade(STREAMFILE* sf) { vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels; } else { - vgmstream->interleave_block_size = data_size / channel_count; + vgmstream->interleave_block_size = data_size / channels; } - vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count); + vgmstream->num_samples = ps_bytes_to_samples(data_size, channels); if (!is_jade_v2) { vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = vgmstream->num_samples; @@ -172,7 +180,7 @@ VGMSTREAM* init_vgmstream_ubi_jade(STREAMFILE* sf) { vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_interleave; - vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count); + vgmstream->num_samples = dsp_bytes_to_samples(data_size, channels); if (!is_jade_v2) { vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = vgmstream->num_samples; @@ -191,7 +199,7 @@ VGMSTREAM* init_vgmstream_ubi_jade(STREAMFILE* sf) { }; int i, ch; - for (ch = 0; ch < channel_count; ch++) { + for (ch = 0; ch < channels; ch++) { for (i = 0; i < 16; i++) { vgmstream->ch[ch].adpcm_coef[i] = coef[i]; } @@ -200,23 +208,33 @@ VGMSTREAM* init_vgmstream_ubi_jade(STREAMFILE* sf) { } else { /* has extra 0x2e coefs before each channel, not counted in data_size */ - vgmstream->interleave_block_size = (data_size + 0x2e*channel_count) / channel_count; + vgmstream->interleave_block_size = (data_size + 0x2e*channels) / channels; - dsp_read_coefs_be(vgmstream, sf, start_offset+0x00, vgmstream->interleave_block_size); - dsp_read_hist_be (vgmstream, sf, start_offset+0x20, vgmstream->interleave_block_size); - start_offset += 0x2e; + dsp_read_coefs_be(vgmstream, sf, data_offset+0x00, vgmstream->interleave_block_size); + dsp_read_hist_be (vgmstream, sf, data_offset+0x20, vgmstream->interleave_block_size); + data_offset += 0x2e; } break; case 0x0002: /* PC */ - if (fmt_size != 0x12) goto fail; - if (block_size != 0x24*channel_count) goto fail; + if (fmt_size != 0x12 && fmt_size != 0x32) goto fail; + if (block_size != 0x24*channels) goto fail; vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; vgmstream->frame_size = block_size; - vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, vgmstream->frame_size, channel_count); + /* King Kong: Gamers Edition (PC) */ + if (fmt_size == 0x32) { + /* standard WAVEFORMATEX must write extra size here, Jade sets 0 */ + if (read_u16le(fmt_offset + 0x10, sf) != 0) + goto fail; + /* 0x12: block samples */ + if (!msadpcm_check_coefs(sf, fmt_offset + 0x14)) + goto fail; + } + + vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, vgmstream->frame_size, channels); if (!is_jade_v2) { vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = vgmstream->num_samples; @@ -225,17 +243,17 @@ VGMSTREAM* init_vgmstream_ubi_jade(STREAMFILE* sf) { break; case 0x0001: { /* PS3 */ - VGMSTREAM *temp_vgmstream = NULL; - STREAMFILE *temp_sf = NULL; + VGMSTREAM* temp_vgmstream = NULL; + STREAMFILE* temp_sf = NULL; if (fmt_size != 0x10) goto fail; - if (block_size != 0x02*channel_count) goto fail; + if (block_size != 0x02 * channels) goto fail; /* a MSF (usually ATRAC3) masquerading as PCM */ - if (read_32bitBE(start_offset, sf) != 0x4D534643) /* "MSF\43" */ + if (!is_id32be(data_offset, sf, "MSFC")) goto fail; - temp_sf = setup_subfile_streamfile(sf, start_offset, data_size, "msf"); + temp_sf = setup_subfile_streamfile(sf, data_offset, data_size, "msf"); if (!temp_sf) goto fail; temp_vgmstream = init_vgmstream_msf(temp_sf); @@ -260,7 +278,7 @@ VGMSTREAM* init_vgmstream_ubi_jade(STREAMFILE* sf) { } - if (!vgmstream_open_stream(vgmstream, sf,start_offset)) + if (!vgmstream_open_stream(vgmstream, sf, data_offset)) goto fail; return vgmstream; @@ -270,58 +288,54 @@ fail: } /* extract loops from "cue /LIST", returns if loops (info from Droolie) */ -static int get_loop_points(STREAMFILE *sf, int *out_loop_start, int *out_loop_end) { - off_t cue_offset, list_offset; - size_t cue_size, list_size; - off_t offset, first_offset = 0x0c; +static int get_loop_points(STREAMFILE* sf, uint32_t cue_offset, uint32_t cue_size, uint32_t list_offset, uint32_t list_size, int* p_loop_start, int* p_loop_end) { + //off_t offset; int i, cue_count, loop_id = 0, loop_start = 0, loop_end = 0; - + chunk_t rc = {0}; /* unlooped files may contain LIST, but also may not */ - if (!find_chunk(sf, 0x63756520,first_offset,0, &cue_offset,&cue_size, 0, 0)) /* "cue " */ - goto fail; - if (!find_chunk(sf, 0x4C495354,first_offset,0, &list_offset,&list_size, 0, 0)) /* "LIST" */ + if (!cue_offset || !cue_size || !list_offset || !list_size) goto fail; - offset = list_offset + 0x04; - while (offset < list_offset + list_size) { - uint32_t chunk_id = read_32bitBE(offset+0x00, sf); - uint32_t chunk_size = read_32bitLE(offset+0x04, sf); - offset += 0x08; - - switch(chunk_id) { + rc.current = list_offset + 0x04; /* skip "adtl" */ + rc.max = list_offset + list_size; + while (next_chunk(&rc, sf)) { + switch(rc.type) { case 0x6C61626C: /* "labl" */ - if (read_32bitBE(offset+0x04, sf) == 0x6C6F6F70) /* "loop", actually an string tho */ - loop_id = read_32bitLE(offset+0x00, sf); - chunk_size += (chunk_size % 2) ? 1 : 0; /* string is even-padded after size */ + if (is_id32be(rc.offset + 0x04, sf, "loop")) /* actually a C-string tho */ + loop_id = read_u32le(rc.offset + 0x00, sf); + + if (rc.size % 2) { /* string is even-padded after size */ + rc.size++; + rc.current++; + } break; + case 0x6C747874: /* "ltxt" */ - if (loop_id == read_32bitLE(offset+0x00, sf)) - loop_end = read_32bitLE(offset+0x04, sf); + if (loop_id == read_u32le(rc.offset + 0x00, sf)) + loop_end = read_u32le(rc.offset + 0x04, sf); break; default: - VGM_LOG("Jade: unknown LIST chunk\n"); + VGM_LOG("UBI JADE: unknown LIST chunk\n"); goto fail; } - - offset += chunk_size; } if (!loop_end) return 0; - cue_count = read_32bitLE(cue_offset+0x00, sf); + cue_count = read_u32le(cue_offset+0x00, sf); for (i = 0; i < cue_count; i++) { - if (loop_id == read_32bitLE(cue_offset+0x04 + i*0x18 + 0x00, sf)) { - loop_start = read_32bitLE(cue_offset+0x04 + i*0x18 + 0x04, sf); + if (loop_id == read_u32le(cue_offset+0x04 + i*0x18 + 0x00, sf)) { + loop_start = read_u32le(cue_offset+0x04 + i*0x18 + 0x04, sf); loop_end += loop_start; break; } } - *out_loop_start = loop_start; - *out_loop_end = loop_end; + *p_loop_start = loop_start; + *p_loop_end = loop_end; return 1; fail: @@ -340,23 +354,19 @@ VGMSTREAM* init_vgmstream_ubi_jade_container(STREAMFILE* sf) { * the RIFF + padding after. Most extractors don't remove the padding correctly, so here we add support. */ /* checks */ - /* standard Jade exts + .xma for padded XMA used in Beyond Good & Evil HD (X360) */ - if (!check_extensions(sf,"waa,wac,wad,wam,wav,lwav,xma")) - goto fail; - - if (read_32bitBE(0x04,sf) == 0x52494646 && - read_32bitLE(0x00,sf)+0x04 == get_streamfile_size(sf)) { + if (is_id32be(0x04,sf, "RIFF") && + read_u32le(0x00,sf)+0x04 == get_streamfile_size(sf)) { /* data size + RIFF + padding */ subfile_offset = 0x04; } - else if (read_32bitBE(0x00,sf) == 0x52494646 && - read_32bitLE(0x04,sf)+0x04+0x04 < get_streamfile_size(sf) && + else if (is_id32be(0x00,sf, "RIFF") && + read_u32le(0x04,sf) + 0x04 + 0x04 < get_streamfile_size(sf) && (get_streamfile_size(sf) + 0x04) % 0x800 == 0) { /* RIFF + padding with data size removed (bad extraction) */ subfile_offset = 0x00; } - else if (read_32bitBE(0x04,sf) == 0x52494646 && - read_32bitLE(0x00,sf) == get_streamfile_size(sf)) { + else if (is_id32be(0x04,sf, "RIFF") && + read_u32le(0x00,sf) == get_streamfile_size(sf)) { /* data_size + RIFF + padding - 0x04 (bad extraction) */ subfile_offset = 0x04; } @@ -364,14 +374,19 @@ VGMSTREAM* init_vgmstream_ubi_jade_container(STREAMFILE* sf) { goto fail; } - subfile_size = read_32bitLE(subfile_offset+0x04,sf) + 0x04+0x04; + /* standard Jade exts + .xma for padded XMA used in Beyond Good & Evil HD (X360) */ + if (!check_extensions(sf,"waa,wac,wad,wam,wav,lwav,xma")) + goto fail; - temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, NULL); + subfile_size = read_u32le(subfile_offset + 0x04,sf) + 0x04 + 0x04; + + temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, NULL); if (!temp_sf) goto fail; - if (check_extensions(sf,"xma")) { + if (read_u16le(0x14, sf) == 0x166) { vgmstream = init_vgmstream_xma(temp_sf); - } else { + } + else { vgmstream = init_vgmstream_ubi_jade(temp_sf); } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_lyn.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_lyn.c index f518e930f..a57574dc7 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_lyn.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_lyn.c @@ -1,70 +1,98 @@ #include "meta.h" #include "../layout/layout.h" #include "../coding/coding.h" +#include "../util/chunks.h" #include "ubi_lyn_streamfile.h" /* LyN RIFF - from Ubisoft LyN engine games [Red Steel 2 (Wii), Adventures of Tintin (Multi), From Dust (Multi), Just Dance 3/4 (multi)] */ VGMSTREAM* init_vgmstream_ubi_lyn(STREAMFILE* sf) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset, first_offset = 0xc; - off_t fmt_offset, data_offset, fact_offset; - size_t fmt_size, data_size, fact_size; - int loop_flag, channels, sample_rate, codec; - int num_samples; + VGMSTREAM* vgmstream = NULL; + off_t start_offset; + uint32_t fmt_offset = 0, fmt_size = 0, data_offset = 0, data_size = 0, fact_offset = 0, fact_size = 0; + int loop_flag = 0, channels = 0, sample_rate = 0, codec = 0; + int32_t num_samples = 0; /* checks */ + if (!is_id32be(0x00,sf, "RIFF")) + goto fail; + if (read_u32le(0x04,sf) + 0x04 + 0x04 != get_streamfile_size(sf)) + goto fail; + if (!is_id32be(0x08,sf, "WAVE")) + goto fail; + /* .sns: Red Steel 2 * .wav: Tintin, Just Dance - * .son: From Dust */ + * .son: From Dust, ZombieU */ if (!check_extensions(sf,"sns,wav,lwav,son")) goto fail; /* a slightly eccentric RIFF with custom codecs */ - if (!is_id32be(0x00,sf, "RIFF") || - !is_id32be(0x08,sf, "WAVE")) - goto fail; - if (read_32bitLE(0x04,sf) + 0x04 + 0x04 != get_streamfile_size(sf)) - goto fail; - if (!find_chunk(sf, 0x666d7420,first_offset,0, &fmt_offset,&fmt_size, 0, 0)) /* "fmt " */ - goto fail; - if (!find_chunk(sf, 0x64617461,first_offset,0, &data_offset,&data_size, 0, 0)) /* "data" */ - goto fail; - - /* always found, even with PCM (LyN subchunk seems to contain the engine version, ex. 0x0d/10) */ - if (!find_chunk(sf, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) /* "fact" */ - goto fail; - if (fact_size != 0x10 || read_32bitBE(fact_offset+0x04, sf) != 0x4C794E20) /* "LyN " */ - goto fail; - num_samples = read_32bitLE(fact_offset+0x00, sf); - /* sometimes there is a LySE chunk */ - - - /* parse format */ + /* parse chunks (reads once linearly) */ { - if (fmt_size < 0x12) - goto fail; - codec = read_u16le(fmt_offset+0x00,sf); - channels = read_u16le(fmt_offset+0x02,sf); - sample_rate = read_s32le(fmt_offset+0x04,sf); - /* 0x08: average bytes, 0x0c: block align, 0x0e: bps, etc */ + chunk_t rc = {0}; - /* fake WAVEFORMATEX, used with > 2ch */ - if (codec == 0xFFFE) { - if (fmt_size < 0x28) - goto fail; - /* fake GUID with first value doubling as codec */ - codec = read_32bitLE(fmt_offset+0x18,sf); - if (read_32bitBE(fmt_offset+0x1c,sf) != 0x00001000 && - read_32bitBE(fmt_offset+0x20,sf) != 0x800000AA && - read_32bitBE(fmt_offset+0x24,sf) != 0x00389B71) { - goto fail; + rc.current = 0x0c; + while (next_chunk(&rc, sf)) { + + switch(rc.type) { + case 0x666d7420: /* "fmt " */ + fmt_offset = rc.offset; + fmt_size = rc.size; + + if (fmt_size < 0x12) + goto fail; + codec = read_u16le(fmt_offset+0x00,sf); + channels = read_u16le(fmt_offset+0x02,sf); + sample_rate = read_s32le(fmt_offset+0x04,sf); + /* 0x08: average bytes, 0x0c: block align, 0x0e: bps, etc */ + + /* fake WAVEFORMATEX, used with > 2ch */ + if (codec == 0xFFFE) { + if (fmt_size < 0x28) + goto fail; + /* fake GUID with first value doubling as codec */ + codec = read_u32le(fmt_offset+0x18,sf); + if (read_u32be(fmt_offset+0x1c,sf) != 0x00001000 && + read_u32be(fmt_offset+0x20,sf) != 0x800000AA && + read_u32be(fmt_offset+0x24,sf) != 0x00389B71) { + goto fail; + } + } + break; + + case 0x64617461: /* "data" */ + data_offset = rc.offset; + data_size = rc.size; + break; + + case 0x66616374: /* "fact" */ + /* always found, even with PCM (LyN subchunk seems to contain the engine version, ex. 0x0d/10) */ + fact_offset = rc.offset; + fact_size = rc.size; + + if (fact_size != 0x10 || !is_id32be(fact_offset+0x04, sf, "LyN ")) + goto fail; + num_samples = read_s32le(fact_offset+0x00, sf); + break; + + case 0x4C795345: /* "LySE": optional, config? */ + case 0x63756520: /* "cue ": total size cue? (rare) */ + case 0x4C495354: /* "LIST": labels (rare) */ + break; + + default: + /* unknown chunk: must be another RIFF */ + goto fail; } } } + if (!fmt_offset || !fmt_size || !data_offset || !data_size || !fact_offset || !fact_size) + goto fail; + /* most songs simply repeat; loop if it looks long enough, * but not too long (ex. Michael Jackson The Experience songs) */ loop_flag = (num_samples > 20*sample_rate && num_samples < 60*3*sample_rate); /* in seconds */ @@ -111,15 +139,19 @@ VGMSTREAM* init_vgmstream_ubi_lyn(STREAMFILE* sf) { break; #ifdef VGM_USE_VORBIS - case 0x3157: { /* Ogg (PC), interleaved 1ch */ + case 0x3156: /* Ogg (PC), interleaved 1ch (older version) [Rabbids Go Home (PC)] */ + case 0x3157: { /* Ogg (PC), interleaved 1ch (newer version) [Adventures of Tintin (PC)] */ size_t interleave_size; layered_layout_data* data = NULL; int i; - if (read_32bitLE(start_offset+0x00,sf) != 1) /* id? */ - goto fail; + if (codec == 0x3157) { + if (read_u32le(start_offset+0x00,sf) != 1) /* id? */ + goto fail; + start_offset += 0x04; + } - interleave_size = read_32bitLE(start_offset+0x04,sf); + interleave_size = read_u32le(start_offset+0x00,sf); /* interleave is adjusted so there is no smaller last block, it seems */ vgmstream->coding_type = coding_OGG_VORBIS; @@ -133,8 +165,8 @@ VGMSTREAM* init_vgmstream_ubi_lyn(STREAMFILE* sf) { /* open each layer subfile */ for (i = 0; i < channels; i++) { STREAMFILE* temp_sf = NULL; - size_t logical_size = read_32bitLE(start_offset+0x08 + 0x04*i,sf); - off_t layer_offset = start_offset + 0x08 + 0x04*channels; //+ interleave_size*i; + size_t logical_size = read_u32le(start_offset+0x04 + 0x04*i,sf); + off_t layer_offset = start_offset + 0x04 + 0x04*channels; temp_sf = setup_ubi_lyn_streamfile(sf, layer_offset, interleave_size, i, channels, logical_size); if (!temp_sf) goto fail; @@ -208,6 +240,38 @@ VGMSTREAM* init_vgmstream_ubi_lyn(STREAMFILE* sf) { #endif #ifdef VGM_USE_FFMPEG + case 0x5052: { /* MP4 AAC (WiiU), custom */ + mp4_custom_t mp4 = {0}; + int entries; + + /* 0x00: null? */ + /* 0x04: fact samples again */ + entries = read_s32le(start_offset + 0x08, sf); + + /* has a seek/frame table then raw (non-header) AAC data */ + mp4.channels = channels; + mp4.sample_rate = sample_rate; + mp4.num_samples = num_samples; + mp4.stream_offset = data_offset + (0x0c + entries * 0x04); + mp4.stream_size = data_size - (0x0c + entries * 0x04); + mp4.table_offset = data_offset + 0x0c; + mp4.table_entries = entries; + + /* assumed (not in fmt's block size, fact, LyN, etc) */ + mp4.encoder_delay = 1024; /* observed, uses libaac */ + mp4.end_padding = 0; + mp4.frame_samples = 1024; + + vgmstream->num_samples -= mp4.encoder_delay; + vgmstream->loop_end_sample -= mp4.encoder_delay; + + vgmstream->codec_data = init_ffmpeg_mp4_custom_lyn(sf, &mp4); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; + break; + } + case 0x0166: { /* XMA (X360), standard */ uint8_t buf[0x100]; int bytes; @@ -217,8 +281,8 @@ VGMSTREAM* init_vgmstream_ubi_lyn(STREAMFILE* sf) { /* skip standard XMA header + seek table */ /* 0x00: version? no apparent differences (0x1=Just Dance 4, 0x3=others) */ chunk_offset = start_offset + 0x04 + 0x04; - chunk_size = read_32bitLE(start_offset + 0x04, sf); - seek_size = read_32bitLE(chunk_offset+chunk_size, sf); + chunk_size = read_u32le(start_offset + 0x04, sf); + seek_size = read_u32le(chunk_offset+chunk_size, sf); start_offset += (0x04 + 0x04 + chunk_size + 0x04 + seek_size); data_size -= (0x04 + 0x04 + chunk_size + 0x04 + seek_size); @@ -248,9 +312,9 @@ fail: /* LyN RIFF in containers */ -VGMSTREAM * init_vgmstream_ubi_lyn_container(STREAMFILE *sf) { - VGMSTREAM *vgmstream = NULL; - STREAMFILE *temp_sf = NULL; +VGMSTREAM* init_vgmstream_ubi_lyn_container(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + STREAMFILE* temp_sf = NULL; off_t subfile_offset; size_t subfile_size; @@ -262,29 +326,30 @@ VGMSTREAM * init_vgmstream_ubi_lyn_container(STREAMFILE *sf) { goto fail; /* find "RIFF" position */ - if (read_32bitBE(0x00,sf) == 0x4C795345 && /* "LySE" */ - read_32bitBE(0x14,sf) == 0x52494646) { /* "RIFF" */ + if (is_id32be(0x00,sf, "LySE") && + is_id32be(0x14,sf, "RIFF")) { subfile_offset = 0x14; /* Adventures of Tintin */ } - else if (read_32bitBE(0x20,sf) == 0x4C795345 && /* "LySE" */ - read_32bitBE(0x34,sf) == 0x52494646) { /* "RIFF" */ + else if (read_u32le(0x00,sf) + 0x22 == get_streamfile_size(sf) && + is_id32be(0x20,sf, "LySE") && + is_id32be(0x34,sf, "RIFF")) { subfile_offset = 0x34; /* Michael Jackson The Experience (Wii) */ } - else if (read_32bitLE(0x00,sf)+0x20 == get_streamfile_size(sf) && - read_32bitBE(0x20,sf) == 0x52494646) { /* "RIFF" */ - subfile_offset = 0x20; /* Red Steel 2, From Dust */ + else if (read_u32le(0x00,sf)+0x20 == get_streamfile_size(sf) && + is_id32be(0x20,sf, "RIFF")) { + subfile_offset = 0x20; /* Red Steel 2, From Dust, ZombieU (also has "SON\0" at 0x18) */ } else { goto fail; } - - subfile_size = read_32bitLE(subfile_offset+0x04,sf) + 0x04+0x04; + + subfile_size = read_u32le(subfile_offset+0x04,sf) + 0x04 + 0x04; temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, NULL); if (!temp_sf) goto fail; vgmstream = init_vgmstream_ubi_lyn(temp_sf); - + close_streamfile(temp_sf); return vgmstream; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wbk.c b/Frameworks/vgmstream/vgmstream/src/meta/wbk.c index d884dc11b..4b8cf0c9d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/wbk.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/wbk.c @@ -4,7 +4,7 @@ /* .WBK - seen in some Treyarch games [Spider-Man 2, Ultimate Spider-Man, Call of Duty 2: Big Red One] */ VGMSTREAM* init_vgmstream_wbk(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; - uint32_t table_offset, entry_offset, data_offset, streams_offset, strings_offset, strings_size, coefsec_offset, + uint32_t table_offset, entry_offset, data_offset, strings_offset, coefsec_offset, name_offset, codec, flags, channels, sound_offset, sound_size, num_samples, sample_rate; int target_subsong = sf->stream_index, total_subsongs, loop_flag, has_names, i; @@ -13,14 +13,13 @@ VGMSTREAM* init_vgmstream_wbk(STREAMFILE* sf) { !is_id32be(0x04, sf, "BK11")) goto fail; - /* checks */ if (!check_extensions(sf, "wbk")) goto fail; /* always little endian, even on GC */ data_offset = read_u32le(0x10, sf); //data_size = read_u32le(0x14, sf); - streams_offset = read_u32le(0x18, sf); + //streams_offset = read_u32le(0x18, sf); //streams_size = read_u32le(0x1c, sf); total_subsongs = read_u32le(0x40, sf); @@ -34,7 +33,7 @@ VGMSTREAM* init_vgmstream_wbk(STREAMFILE* sf) { //paramsec_offset = read_u32le(0x54, sf); //coefsec_size = read_u32le(0x58, sf); coefsec_offset = read_u32le(0x5c, sf); - strings_size = read_u32le(0x60, sf); + //strings_size = read_u32le(0x60, sf); strings_offset = read_u32le(0x64, sf); /* Ultimate Spider-Man has no names, only name hashes */ @@ -60,7 +59,7 @@ VGMSTREAM* init_vgmstream_wbk(STREAMFILE* sf) { * 0x1c: sound offset * 0x20: sample rate * 0x24: always 0? - * + * * struct slightly changed in Call of Duty 2 but still compatible */ entry_offset = table_offset + (target_subsong - 1) * 0x28; @@ -94,7 +93,7 @@ VGMSTREAM* init_vgmstream_wbk(STREAMFILE* sf) { switch (codec) { case 0x03: { /* DSP */ uint32_t coef_offset; - uint16_t coef_table[16] = { + static const int16_t coef_table[16] = { 0x0216,0xfc9f,0x026c,0x04b4,0x065e,0xfdec,0x0a11,0xfd1e, 0x0588,0xfc38,0x05ad,0x01da,0x083b,0xfdbc,0x08c3,0xff18 }; @@ -116,6 +115,7 @@ VGMSTREAM* init_vgmstream_wbk(STREAMFILE* sf) { } break; } + case 0x04: /* PSX */ vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_interleave; @@ -152,4 +152,182 @@ VGMSTREAM* init_vgmstream_wbk(STREAMFILE* sf) { fail: close_vgmstream(vgmstream); return NULL; -} \ No newline at end of file +} + +/* .WBK - evolution of the above Treyarch bank format [Call of Duty 3] */ +VGMSTREAM* init_vgmstream_wbk_nslb(STREAMFILE* sf) { + VGMSTREAM* vgmstream = NULL; + uint32_t table_offset, name_table_offset, strings_offset, info_offset, data_offset, streams_offset, + name_offset, entry_offset, info_entry_offset, + codec, flags, channels, sound_offset, sound_size, num_samples, sample_rate; + int target_subsong = sf->stream_index, total_subsongs, loop_flag; + + /* checks */ + if (!is_id32be(0x00, sf, "NSLB")) + goto fail; + + if (!check_extensions(sf, "wbk")) + goto fail; + + /* always little endian, even on PS3/X360 */ + if (read_u32le(0x04, sf) != 0x01) + goto fail; + + total_subsongs = read_u32le(0x10, sf); + + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) + goto fail; + + name_table_offset = read_u32le(0x18, sf); + table_offset = read_u32le(0x1c, sf); + //info_size = read_u32le(0x20, sf); + info_offset = read_u32le(0x24, sf); + //strings_size = read_u32le(0x28, sf); + strings_offset = read_u32le(0x2c, sf); + //data_size = read_u32le(0x30, sf); + data_offset = read_u32le(0x34, sf); + //streams_size = read_u32le(0x38, sf); + streams_offset = read_u32le(0x3c, sf); + + name_offset = read_u32le(name_table_offset + 0x04 * (target_subsong - 1), sf); + entry_offset = table_offset + 0x10 * (target_subsong - 1); + + info_entry_offset = read_u32le(entry_offset + 0x00, sf) + info_offset; + sound_offset = read_u32le(entry_offset + 0x04, sf); + sound_size = read_u32le(entry_offset + 0x08, sf); + num_samples = read_u32le(entry_offset + 0x0c, sf); + + sample_rate = read_u16le(info_entry_offset + 0x00, sf); + codec = read_u8(info_entry_offset + 0x04, sf); + flags = read_u8(info_entry_offset + 0x05, sf); + channels = read_u8(info_entry_offset + 0x06, sf) == 0x03 ? 2 : 1; + + if (flags & 0x01) + sound_offset += streams_offset; + else + sound_offset += data_offset; + + loop_flag = (flags & 0x02); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->meta_type = meta_WBK_NSLB; + vgmstream->sample_rate = sample_rate; + vgmstream->stream_size = sound_size; + vgmstream->num_samples = num_samples; + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = num_samples; /* full loops only */ + vgmstream->num_streams = total_subsongs; + + switch (codec) { + case 0x20: /* XBOX */ + vgmstream->coding_type = coding_XBOX_IMA; + vgmstream->layout_type = layout_none; + break; + + case 0x21: /* PSX */ + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = (flags & 0x01) ? 0x800 : sound_size / channels; + break; + + case 0x22: { /* DSP */ + int i, j; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = (flags & 0x01) ? 0x8000 : sound_size / channels; + + /* It looks like the table is re-interpreted as 8 32-bit integers and stored with little endian byte order + * like the rest of the data. Fun times. */ + for (i = 0; i < vgmstream->channels; i++) { + off_t coef_offset = info_entry_offset + 0x4c + 0x30*i; + for (j = 0; j < 8; j++) { + vgmstream->ch[i].adpcm_coef[j*2] = read_s16le(coef_offset + j*0x04 + 0x02, sf); + vgmstream->ch[i].adpcm_coef[j*2+1] = read_s16le(coef_offset + j*0x04 + 0x00, sf); + } + } + break; + } + + case 0x25: { /* FSB IMA */ + VGMSTREAM* fsb_vgmstream; + STREAMFILE* temp_sf; + + /* skip "fsb3adpc" */ + sound_offset += 0x08; + sound_size -= 0x08; + temp_sf = setup_subfile_streamfile(sf, sound_offset, sound_size, "fsb"); + if (!temp_sf) goto fail; + temp_sf->stream_index = 0; + + fsb_vgmstream = init_vgmstream_fsb(temp_sf); + close_streamfile(temp_sf); + if (!fsb_vgmstream) goto fail; + + fsb_vgmstream->meta_type = vgmstream->meta_type; + fsb_vgmstream->num_streams = vgmstream->num_streams; + vgmstream_force_loop(fsb_vgmstream, loop_flag, 0, fsb_vgmstream->num_samples); + read_string(fsb_vgmstream->stream_name, STREAM_NAME_SIZE, strings_offset + name_offset, sf); + + close_vgmstream(vgmstream); + return fsb_vgmstream; + } + +#ifdef VGM_USE_FFMPEG + case 0x30: { /* RIFF XMA */ + uint8_t buf[0x100]; + off_t riff_fmt_offset, riff_data_offset; + size_t bytes, riff_fmt_size, riff_data_size; + + /* find "fmt" chunk */ + if (!find_chunk_riff_le(sf, 0x666d7420, sound_offset + 0x0c, sound_size - 0x0c, &riff_fmt_offset, &riff_fmt_size)) + goto fail; + + /* find "data" chunk */ + if (!find_chunk_riff_le(sf, 0x64617461, sound_offset + 0x0c, sound_size - 0x0c, &riff_data_offset, &riff_data_size)) + goto fail; + + bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf, 0x100, riff_fmt_offset, riff_fmt_size, riff_data_size, sf, 0); + + vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf, bytes, riff_data_offset, riff_data_size); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; + + xma_fix_raw_samples(vgmstream, sf, riff_data_offset, riff_data_size, riff_fmt_offset, 0, 0); + break; + } +#endif + +#ifdef VGM_USE_MPEG + case 0x32: { /* MP3 */ + coding_t mpeg_coding; + + vgmstream->codec_data = init_mpeg(sf, sound_offset, &mpeg_coding, channels); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = mpeg_coding; + vgmstream->layout_type = layout_none; + break; + } +#endif + + default: + goto fail; + } + + if (codec != 0x21) /* name table is filled with garbage on PS2 for some reason */ + read_string(vgmstream->stream_name, STREAM_NAME_SIZE, strings_offset + name_offset, sf); + + if (!vgmstream_open_stream(vgmstream, sf, sound_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c index 945677fdc..0ee26df6e 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/wwise.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/wwise.c @@ -56,7 +56,7 @@ typedef struct { } wwise_header; static int parse_wwise(STREAMFILE* sf, wwise_header* ww); -static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_offset); +static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_offset, int full_detection); /* Wwise - Audiokinetic Wwise (WaveWorks Interactive Sound Engine) middleware */ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) { @@ -329,13 +329,16 @@ VGMSTREAM* init_vgmstream_wwise_bnk(STREAMFILE* sf, int* p_prefetch) { vgmstream->num_samples = dsp_bytes_to_samples(ww.data_size, ww.channels); if (ww.wiih_size != 0x2e * ww.channels) goto fail; - if (is_dsp_full_interleave(sf, &ww, ww.wiih_offset)) + if (is_dsp_full_interleave(sf, &ww, ww.wiih_offset, 1)) vgmstream->interleave_block_size = ww.data_size / 2; } else if (ww.extra_size == 0x0c + ww.channels * 0x2e) { /* newer */ vgmstream->num_samples = read_s32(ww.fmt_offset + 0x18, sf); ww.wiih_offset = ww.fmt_offset + 0x1c; ww.wiih_size = 0x2e * ww.channels; + + if (is_dsp_full_interleave(sf, &ww, ww.wiih_offset, 0)) /* less common */ + vgmstream->interleave_block_size = ww.data_size / 2; } else { goto fail; @@ -670,9 +673,9 @@ fail: return NULL; } -static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_offset) { - /* older (only?) Wwise use full interleave for memory (in .bnk) files, but - * detection from the .wem side is problematic [Punch Out!! (Wii)] +static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_offset, int full_detection) { + /* older (bank ~v48) Wwise use full interleave for memory (in .bnk) files, but + * detection from the .wem side is problematic [Punch Out!! (Wii)-old, Luigi's Mansion 2 (3DS)-new] * - prefetch point to streams = normal * - .bnk would be memory banks = full * - otherwise small-ish sizes, stereo, with initial predictors for the @@ -692,7 +695,8 @@ static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_o if (ww->data_size > 0x30000) return 0; - { + /* skip reading data if possible */ + if (full_detection) { uint16_t head_ps2 = read_u16be(coef_offset + 1 * 0x2e + 0x22, sf); /* ch2's initial predictor */ uint16_t init_ps2 = read_u8(ww->data_offset + 0x08, sf); /* at normal interleave */ uint16_t half_ps2 = read_u8(ww->data_offset + ww->data_size / 2, sf); /* at full interleave */ diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.c b/Frameworks/vgmstream/vgmstream/src/vgmstream.c index 25a5dd1e7..89965820b 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.c @@ -23,9 +23,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_brstm, init_vgmstream_bfwav, init_vgmstream_nds_strm, - init_vgmstream_agsc, - init_vgmstream_ngc_adpdtk, - init_vgmstream_rsf, init_vgmstream_afc, init_vgmstream_ast, init_vgmstream_halpst, @@ -45,15 +42,11 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_ngc_dsp_stm, init_vgmstream_exst, init_vgmstream_svag_kcet, - init_vgmstream_mib_mih, init_vgmstream_ngc_mpdsp, - init_vgmstream_ps2_mic, init_vgmstream_ngc_dsp_std_int, init_vgmstream_vag, init_vgmstream_vag_aaap, - init_vgmstream_seb, - init_vgmstream_ps2_ild, - init_vgmstream_ps2_pnb, + init_vgmstream_ild, init_vgmstream_ngc_str, init_vgmstream_ea_schl, init_vgmstream_caf, @@ -93,7 +86,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_leg, init_vgmstream_filp, init_vgmstream_ikm, - init_vgmstream_sfs, + init_vgmstream_ster, init_vgmstream_bg00, init_vgmstream_sat_dvi, init_vgmstream_dc_kcey, @@ -216,7 +209,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_dmsg, init_vgmstream_ngc_dsp_aaap, init_vgmstream_ngc_dsp_konami, - init_vgmstream_ps2_ster, init_vgmstream_ps2_wb, init_vgmstream_bnsf, init_vgmstream_ps2_gcm, @@ -258,7 +250,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_lsf_n1nj4n, init_vgmstream_xwav_new, init_vgmstream_xwav_old, - init_vgmstream_ps2_wmus, init_vgmstream_hyperscan_kvag, init_vgmstream_ios_psnd, init_vgmstream_adp_bos, @@ -526,15 +517,26 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_lopu_fb, init_vgmstream_lpcm_fb, init_vgmstream_wbk, + init_vgmstream_wbk_nslb, init_vgmstream_dsp_apex, + /* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */ + init_vgmstream_agsc, + init_vgmstream_dtk, + init_vgmstream_rsf, + init_vgmstream_ps2_wmus, + init_vgmstream_mib_mih, + init_vgmstream_mic_koei, + init_vgmstream_seb, + init_vgmstream_ps2_pnb, + /* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */ init_vgmstream_encrypted, /* encrypted stuff */ init_vgmstream_btsnd, /* semi-headerless */ init_vgmstream_raw_int, /* .int raw PCM */ init_vgmstream_ps_headerless, /* tries to detect a bunch of PS-ADPCM formats */ - init_vgmstream_raw_snds, /* .snds raw SNDS IMA (*after* ps_headerless) */ + init_vgmstream_raw_snds, /* .snds raw SNDS IMA */ init_vgmstream_raw_wavm, /* .wavm raw xbox */ init_vgmstream_raw_pcm, /* .raw raw PCM */ init_vgmstream_s14_sss, /* .s14/sss raw siren14 */ diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.h b/Frameworks/vgmstream/vgmstream/src/vgmstream.h index 1be7422de..8d144cb3c 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.h +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.h @@ -342,8 +342,8 @@ typedef enum { meta_AAX, /* CRI AAX */ meta_UTF_DSP, /* CRI ADPCM_WII, like AAX with DSP */ - meta_NGC_ADPDTK, /* NGC DTK/ADP (.adp/dkt DTK) [no header_id] */ - meta_RSF, /* Retro Studios RSF (Metroid Prime .rsf) [no header_id] */ + meta_DTK, + meta_RSF, meta_HALPST, /* HAL Labs HALPST */ meta_GCSW, /* GCSW (PCM) */ meta_CAF, /* tri-Crescendo CAF */ @@ -367,7 +367,7 @@ typedef enum { meta_PS2_VAGp_AAAP, /* Acclaim Austin Audio VAG header */ meta_SEB, meta_STR_WAV, /* Blitz Games STR+WAV files */ - meta_PS2_ILD, /* ILD File */ + meta_ILD, meta_PS2_PNB, /* PsychoNauts Bgm File */ meta_VPK, /* VPK Audio File */ meta_PS2_BMDX, /* Beatmania thing */ @@ -392,7 +392,7 @@ typedef enum { meta_LEG, /* Legaia 2 [no header_id] */ meta_FILP, /* Resident Evil - Dead Aim */ meta_IKM, - meta_SFS, /* Baroque */ + meta_STER, meta_BG00, /* Ibara, Mushihimesama */ meta_PS2_RSTM, /* Midnight Club 3 */ meta_PS2_KCES, /* Dance Dance Revolution */ @@ -522,7 +522,6 @@ typedef enum { meta_AST_MMV, meta_DMSG, /* Nightcaster II - Equinox (XBOX) */ meta_NGC_DSP_AAAP, /* Turok: Evolution (NGC), Vexx (NGC) */ - meta_PS2_STER, /* Juuni Kokuki: Kakukaku Taru Ou Michi Beni Midori no Uka */ meta_PS2_WB, /* Shooting Love. ~TRIZEAL~ */ meta_S14, /* raw Siren 14, 24kbit mono */ meta_SSS, /* raw Siren 14, 48kbit stereo */ @@ -762,6 +761,7 @@ typedef enum { meta_LOPU_FB, meta_LPCM_FB, meta_WBK, + meta_WBK_NSLB, meta_DSP_APEX, } meta_t;