Updated VMStream to r1050-2028-gac28ccc5
parent
4d18505da5
commit
95141cab76
|
@ -93,7 +93,6 @@
|
|||
83299FD11E7660C7003A3242 /* dsp_adx.c in Sources */ = {isa = PBXBuildFile; fileRef = 83299FCF1E7660C7003A3242 /* dsp_adx.c */; };
|
||||
832BF7FF21E050B7006F50F1 /* circus_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF7FC21E050B6006F50F1 /* circus_decoder.c */; };
|
||||
832BF80021E050B7006F50F1 /* mpeg_custom_utils_eamp3.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF7FD21E050B7006F50F1 /* mpeg_custom_utils_eamp3.c */; };
|
||||
832BF80121E050B7006F50F1 /* pcfx_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF7FE21E050B7006F50F1 /* pcfx_decoder.c */; };
|
||||
832BF80521E050DC006F50F1 /* blocked_mul.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80221E050DB006F50F1 /* blocked_mul.c */; };
|
||||
832BF80621E050DC006F50F1 /* blocked_vs_square.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80321E050DC006F50F1 /* blocked_vs_square.c */; };
|
||||
832BF80721E050DC006F50F1 /* blocked_vs_str.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF80421E050DC006F50F1 /* blocked_vs_str.c */; };
|
||||
|
@ -349,7 +348,6 @@
|
|||
836F6FE018BDC2190095E648 /* ps2_joe.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA418BDC2180095E648 /* ps2_joe.c */; };
|
||||
836F6FE118BDC2190095E648 /* ps2_jstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA518BDC2180095E648 /* ps2_jstm.c */; };
|
||||
836F6FE218BDC2190095E648 /* ps2_kces.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA618BDC2180095E648 /* ps2_kces.c */; };
|
||||
836F6FE318BDC2190095E648 /* ps2_khv.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA718BDC2180095E648 /* ps2_khv.c */; };
|
||||
836F6FE418BDC2190095E648 /* ps2_leg.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA818BDC2180095E648 /* ps2_leg.c */; };
|
||||
836F6FE518BDC2190095E648 /* ps2_lpcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EA918BDC2180095E648 /* ps2_lpcm.c */; };
|
||||
836F6FE618BDC2190095E648 /* ps2_mcg.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EAA18BDC2180095E648 /* ps2_mcg.c */; };
|
||||
|
@ -452,6 +450,9 @@
|
|||
83709E091ECBC1A4005C03D3 /* ta_aac.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E031ECBC1A4005C03D3 /* ta_aac.c */; };
|
||||
83709E0D1ECBC1C3005C03D3 /* mc3_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E0B1ECBC1C3005C03D3 /* mc3_decoder.c */; };
|
||||
83709E0E1ECBC1C3005C03D3 /* psv_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 83709E0C1ECBC1C3005C03D3 /* psv_decoder.c */; };
|
||||
8375737321F9507D00F01AF5 /* oki_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 8375737221F9507D00F01AF5 /* oki_decoder.c */; };
|
||||
8375737621F950ED00F01AF5 /* gin.c in Sources */ = {isa = PBXBuildFile; fileRef = 8375737421F950EC00F01AF5 /* gin.c */; };
|
||||
8375737721F950ED00F01AF5 /* ubi_sb_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8375737521F950EC00F01AF5 /* ubi_sb_streamfile.h */; };
|
||||
838BDB641D3AF08C0022CA6F /* libavcodec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB611D3AF08C0022CA6F /* libavcodec.a */; };
|
||||
838BDB651D3AF08C0022CA6F /* libavformat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB621D3AF08C0022CA6F /* libavformat.a */; };
|
||||
838BDB661D3AF08C0022CA6F /* libavutil.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB631D3AF08C0022CA6F /* libavutil.a */; };
|
||||
|
@ -733,7 +734,6 @@
|
|||
83299FCF1E7660C7003A3242 /* dsp_adx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dsp_adx.c; sourceTree = "<group>"; };
|
||||
832BF7FC21E050B6006F50F1 /* circus_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = circus_decoder.c; sourceTree = "<group>"; };
|
||||
832BF7FD21E050B7006F50F1 /* mpeg_custom_utils_eamp3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mpeg_custom_utils_eamp3.c; sourceTree = "<group>"; };
|
||||
832BF7FE21E050B7006F50F1 /* pcfx_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pcfx_decoder.c; sourceTree = "<group>"; };
|
||||
832BF80221E050DB006F50F1 /* blocked_mul.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_mul.c; sourceTree = "<group>"; };
|
||||
832BF80321E050DC006F50F1 /* blocked_vs_square.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_vs_square.c; sourceTree = "<group>"; };
|
||||
832BF80421E050DC006F50F1 /* blocked_vs_str.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blocked_vs_str.c; sourceTree = "<group>"; };
|
||||
|
@ -989,7 +989,6 @@
|
|||
836F6EA418BDC2180095E648 /* ps2_joe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_joe.c; sourceTree = "<group>"; };
|
||||
836F6EA518BDC2180095E648 /* ps2_jstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_jstm.c; sourceTree = "<group>"; };
|
||||
836F6EA618BDC2180095E648 /* ps2_kces.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_kces.c; sourceTree = "<group>"; };
|
||||
836F6EA718BDC2180095E648 /* ps2_khv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_khv.c; sourceTree = "<group>"; };
|
||||
836F6EA818BDC2180095E648 /* ps2_leg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_leg.c; sourceTree = "<group>"; };
|
||||
836F6EA918BDC2180095E648 /* ps2_lpcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_lpcm.c; sourceTree = "<group>"; };
|
||||
836F6EAA18BDC2180095E648 /* ps2_mcg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_mcg.c; sourceTree = "<group>"; };
|
||||
|
@ -1092,6 +1091,9 @@
|
|||
83709E031ECBC1A4005C03D3 /* ta_aac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ta_aac.c; sourceTree = "<group>"; };
|
||||
83709E0B1ECBC1C3005C03D3 /* mc3_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mc3_decoder.c; sourceTree = "<group>"; };
|
||||
83709E0C1ECBC1C3005C03D3 /* psv_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = psv_decoder.c; sourceTree = "<group>"; };
|
||||
8375737221F9507D00F01AF5 /* oki_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = oki_decoder.c; sourceTree = "<group>"; };
|
||||
8375737421F950EC00F01AF5 /* gin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gin.c; sourceTree = "<group>"; };
|
||||
8375737521F950EC00F01AF5 /* ubi_sb_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ubi_sb_streamfile.h; sourceTree = "<group>"; };
|
||||
838BDB611D3AF08C0022CA6F /* libavcodec.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavcodec.a; path = ../../ThirdParty/ffmpeg/lib/libavcodec.a; sourceTree = "<group>"; };
|
||||
838BDB621D3AF08C0022CA6F /* libavformat.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavformat.a; path = ../../ThirdParty/ffmpeg/lib/libavformat.a; sourceTree = "<group>"; };
|
||||
838BDB631D3AF08C0022CA6F /* libavutil.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavutil.a; path = ../../ThirdParty/ffmpeg/lib/libavutil.a; sourceTree = "<group>"; };
|
||||
|
@ -1357,7 +1359,7 @@
|
|||
836F6DF618BDC2180095E648 /* nwa_decoder.c */,
|
||||
836F6DF718BDC2180095E648 /* nwa_decoder.h */,
|
||||
836F6DF818BDC2180095E648 /* ogg_vorbis_decoder.c */,
|
||||
832BF7FE21E050B7006F50F1 /* pcfx_decoder.c */,
|
||||
8375737221F9507D00F01AF5 /* oki_decoder.c */,
|
||||
836F6DF918BDC2180095E648 /* pcm_decoder.c */,
|
||||
83709E0C1ECBC1C3005C03D3 /* psv_decoder.c */,
|
||||
836F6DFA18BDC2180095E648 /* psx_decoder.c */,
|
||||
|
@ -1516,6 +1518,7 @@
|
|||
836F6E4D18BDC2180095E648 /* gca.c */,
|
||||
836F6E4E18BDC2180095E648 /* gcsw.c */,
|
||||
836F6E4F18BDC2180095E648 /* genh.c */,
|
||||
8375737421F950EC00F01AF5 /* gin.c */,
|
||||
836F6E5118BDC2180095E648 /* gsp_gsb.c */,
|
||||
83709DFF1ECBC1A4005C03D3 /* gtd.c */,
|
||||
8342469020C4D22F00926E48 /* h4m.c */,
|
||||
|
@ -1639,7 +1642,6 @@
|
|||
836F6EA418BDC2180095E648 /* ps2_joe.c */,
|
||||
836F6EA518BDC2180095E648 /* ps2_jstm.c */,
|
||||
836F6EA618BDC2180095E648 /* ps2_kces.c */,
|
||||
836F6EA718BDC2180095E648 /* ps2_khv.c */,
|
||||
836F6EA818BDC2180095E648 /* ps2_leg.c */,
|
||||
836F6EA918BDC2180095E648 /* ps2_lpcm.c */,
|
||||
836F6EAA18BDC2180095E648 /* ps2_mcg.c */,
|
||||
|
@ -1739,6 +1741,7 @@
|
|||
8306B0C62098458D000302D4 /* ubi_lyn_ogg_streamfile.h */,
|
||||
8306B0CA2098458E000302D4 /* ubi_lyn.c */,
|
||||
831BA6131EAC61A500CF89B0 /* ubi_raki.c */,
|
||||
8375737521F950EC00F01AF5 /* ubi_sb_streamfile.h */,
|
||||
8349A8F41FE6257D00E26435 /* ubi_sb.c */,
|
||||
834FE0C5215C79E6000A5D3D /* ue4opus.c */,
|
||||
834FE0DD215C79EB000A5D3D /* utk.c */,
|
||||
|
@ -1852,6 +1855,7 @@
|
|||
8306B0E020984590000302D4 /* ppst_streamfile.h in Headers */,
|
||||
834FE0BA215C798C000A5D3D /* ea_mt_decoder_utk.h in Headers */,
|
||||
832BF82021E0514B006F50F1 /* zsnd_streamfile.h in Headers */,
|
||||
8375737721F950ED00F01AF5 /* ubi_sb_streamfile.h in Headers */,
|
||||
839E21E01F2EDAF100EE54D7 /* vorbis_custom_data_fsb.h in Headers */,
|
||||
836F705418BDC2190095E648 /* streamfile.h in Headers */,
|
||||
83A3F0761E3AD8B900D6A794 /* stack_alloc.h in Headers */,
|
||||
|
@ -2279,7 +2283,6 @@
|
|||
836F6FAF18BDC2190095E648 /* ngc_dsp_std.c in Sources */,
|
||||
836F6F7118BDC2190095E648 /* ast.c in Sources */,
|
||||
834FE0BF215C79A9000A5D3D /* flat.c in Sources */,
|
||||
836F6FE318BDC2190095E648 /* ps2_khv.c in Sources */,
|
||||
836F6F6B18BDC2190095E648 /* agsc.c in Sources */,
|
||||
836F700E18BDC2190095E648 /* ps2_xa2.c in Sources */,
|
||||
836F6FF718BDC2190095E648 /* ps2_sl3.c in Sources */,
|
||||
|
@ -2288,6 +2291,7 @@
|
|||
836F702118BDC2190095E648 /* rs03.c in Sources */,
|
||||
836F6F8818BDC2190095E648 /* fsb.c in Sources */,
|
||||
836F6FE518BDC2190095E648 /* ps2_lpcm.c in Sources */,
|
||||
8375737321F9507D00F01AF5 /* oki_decoder.c in Sources */,
|
||||
836F6FB318BDC2190095E648 /* ngc_lps.c in Sources */,
|
||||
836F6FC018BDC2190095E648 /* p3d.c in Sources */,
|
||||
836F6FC718BDC2190095E648 /* pona.c in Sources */,
|
||||
|
@ -2301,7 +2305,6 @@
|
|||
834FE106215C79ED000A5D3D /* utk.c in Sources */,
|
||||
831BA6281EAC61CB00CF89B0 /* coding_utils.c in Sources */,
|
||||
836F700218BDC2190095E648 /* ps2_tk5.c in Sources */,
|
||||
832BF80121E050B7006F50F1 /* pcfx_decoder.c in Sources */,
|
||||
83AA5D271F6E2F9C0020821C /* stm.c in Sources */,
|
||||
831BA61D1EAC61A500CF89B0 /* ubi_raki.c in Sources */,
|
||||
8306B0A520984552000302D4 /* blocked_ea_wve_au00.c in Sources */,
|
||||
|
@ -2411,6 +2414,7 @@
|
|||
836F6FB118BDC2190095E648 /* ngc_ffcc_str.c in Sources */,
|
||||
8306B0B620984552000302D4 /* blocked_hwas.c in Sources */,
|
||||
836F6FC218BDC2190095E648 /* pc_mxst.c in Sources */,
|
||||
8375737621F950ED00F01AF5 /* gin.c in Sources */,
|
||||
836F6FC918BDC2190095E648 /* ps2_2pfs.c in Sources */,
|
||||
836F704818BDC2190095E648 /* xbox_ims.c in Sources */,
|
||||
836F6F7518BDC2190095E648 /* bnsf.c in Sources */,
|
||||
|
|
|
@ -71,6 +71,8 @@ void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
|
|||
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
@ -99,7 +101,8 @@ void decode_ea_xa_v2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
|
|||
void decode_maxis_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
|
||||
/* ea_xas_decoder */
|
||||
void decode_ea_xas(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_ea_xas_v0(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_ea_xas_v1(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
|
||||
/* sdx2_decoder */
|
||||
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
@ -168,9 +171,10 @@ void decode_derf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
|||
/* circus_decoder */
|
||||
void decode_circus_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
/* pcfx_decoder */
|
||||
/* oki_decoder */
|
||||
void decode_pcfx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int mode);
|
||||
size_t pcfx_bytes_to_samples(size_t bytes, int channels);
|
||||
void decode_oki16(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
size_t oki_bytes_to_samples(size_t bytes, int channels);
|
||||
|
||||
/* ea_mt_decoder*/
|
||||
ea_mt_codec_data *init_ea_mt(int channels, int type);
|
||||
|
@ -339,6 +343,7 @@ void xma2_parse_fmt_chunk_extra(STREAMFILE *streamFile, off_t chunk_offset, int
|
|||
void xma2_parse_xma2_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * channels, int * sample_rate, int * loop_flag, int32_t * num_samples, int32_t * loop_start_sample, int32_t * loop_end_sample);
|
||||
|
||||
void xma_fix_raw_samples(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stream_offset, size_t stream_size, off_t chunk_offset, int fix_num_samples, int fix_loop_samples);
|
||||
void xma_fix_raw_samples_ch(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stream_offset, size_t stream_size, int channel_per_stream, int fix_num_samples, int fix_loop_samples);
|
||||
|
||||
int riff_get_fact_skip_samples(STREAMFILE * streamFile, off_t start_offset);
|
||||
|
||||
|
|
|
@ -799,14 +799,13 @@ void wma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_ali
|
|||
/* XMA hell for precise looping and gapless support, fixes raw sample values from headers
|
||||
* that don't count XMA's final subframe/encoder delay/encoder padding, and FFmpeg stuff.
|
||||
* Configurable since different headers vary for maximum annoyance. */
|
||||
void xma_fix_raw_samples(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stream_offset, size_t stream_size, off_t chunk_offset, int fix_num_samples, int fix_loop_samples) {
|
||||
void xma_fix_raw_samples_ch(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stream_offset, size_t stream_size, int channels_per_stream, int fix_num_samples, int fix_loop_samples) {
|
||||
const int bytes_per_packet = 2048;
|
||||
const int samples_per_frame = 512;
|
||||
const int samples_per_subframe = 128;
|
||||
const int bits_frame_size = 15;
|
||||
|
||||
int xma_version = 2; /* works ok even for XMA1 */
|
||||
int channels_per_stream = xma_get_channels_per_stream(streamFile, chunk_offset, vgmstream->channels);
|
||||
off_t first_packet = stream_offset;
|
||||
off_t last_packet = stream_offset + stream_size - bytes_per_packet;
|
||||
int32_t start_skip = 0, end_skip = 0;
|
||||
|
@ -872,6 +871,12 @@ void xma_fix_raw_samples(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stre
|
|||
#endif
|
||||
}
|
||||
|
||||
void xma_fix_raw_samples(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stream_offset, size_t stream_size, off_t chunk_offset, int fix_num_samples, int fix_loop_samples) {
|
||||
int channels_per_stream = xma_get_channels_per_stream(streamFile, chunk_offset, vgmstream->channels);
|
||||
xma_fix_raw_samples_ch(vgmstream, streamFile, stream_offset, stream_size, channels_per_stream, fix_num_samples, fix_loop_samples);
|
||||
}
|
||||
|
||||
|
||||
/* ******************************************** */
|
||||
/* HEADER PARSING */
|
||||
/* ******************************************** */
|
||||
|
|
|
@ -9,11 +9,11 @@ static const int EA_XA_TABLE[20] = {
|
|||
0, -1, -3, -4
|
||||
};
|
||||
|
||||
/* EA-XAS, evolution of EA-XA and cousin of MTA2. From FFmpeg (general info) + MTA2 (layout) + EA-XA (decoding)
|
||||
/* EA-XAS v1, evolution of EA-XA/XAS and cousin of MTA2. From FFmpeg (general info) + MTA2 (layout) + EA-XA (decoding)
|
||||
*
|
||||
* Layout: blocks of 0x4c per channel (128 samples), divided into 4 headers + 4 vertical groups of 15 bytes (for parallelism?).
|
||||
* To simplify, always decodes the block and discards unneeded samples, so doesn't use external hist. */
|
||||
void decode_ea_xas(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_ea_xas_v1(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int group, row, i;
|
||||
int samples_done = 0, sample_count = 0;
|
||||
|
||||
|
@ -77,3 +77,64 @@ void decode_ea_xas(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacin
|
|||
stream->offset += 0x4c * channelspacing;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* EA-XAS v0, without complex layouts and closer to EA-XA. Somewhat based on daemon1's decoder */
|
||||
void decode_ea_xas_v0(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
off_t frame_offset;
|
||||
int i;
|
||||
int block_samples, frames_in, samples_done = 0, sample_count = 0;
|
||||
|
||||
/* external interleave (fixed size), mono */
|
||||
block_samples = 32;
|
||||
frames_in = first_sample / block_samples;
|
||||
first_sample = first_sample % block_samples;
|
||||
|
||||
frame_offset = stream->offset + (0x0f+0x02+0x02)*frames_in;
|
||||
|
||||
/* process frames */
|
||||
{
|
||||
int coef1, coef2;
|
||||
int16_t hist1, hist2;
|
||||
uint8_t shift;
|
||||
uint32_t frame_header = (uint32_t)read_32bitLE(frame_offset, stream->streamfile); /* always LE */
|
||||
|
||||
coef1 = EA_XA_TABLE[(uint8_t)(frame_header & 0x0F) + 0];
|
||||
coef2 = EA_XA_TABLE[(uint8_t)(frame_header & 0x0F) + 4];
|
||||
hist2 = (int16_t)(frame_header & 0xFFF0);
|
||||
hist1 = (int16_t)((frame_header >> 16) & 0xFFF0);
|
||||
shift = 20 - ((frame_header >> 16) & 0x0F);
|
||||
|
||||
/* write header samples (needed) */
|
||||
if (sample_count >= first_sample && samples_done < samples_to_do) {
|
||||
outbuf[samples_done * channelspacing] = hist2;
|
||||
samples_done++;
|
||||
}
|
||||
sample_count++;
|
||||
if (sample_count >= first_sample && samples_done < samples_to_do) {
|
||||
outbuf[samples_done * channelspacing] = hist1;
|
||||
samples_done++;
|
||||
}
|
||||
sample_count++;
|
||||
|
||||
/* process nibbles */
|
||||
for (i = 0; i < 0x0f*2; i++) {
|
||||
uint8_t sample_byte = (uint8_t)read_8bit(frame_offset + 0x02 + 0x02 + i/2, stream->streamfile);
|
||||
int sample;
|
||||
|
||||
sample = get_nibble_signed(sample_byte, !(i&1)); /* upper first */
|
||||
sample = sample << shift;
|
||||
sample = (sample + hist1 * coef1 + hist2 * coef2 + 128) >> 8;
|
||||
sample = clamp16(sample);
|
||||
|
||||
if (sample_count >= first_sample && samples_done < samples_to_do) {
|
||||
outbuf[samples_done * channelspacing] = sample;
|
||||
samples_done++;
|
||||
}
|
||||
sample_count++;
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#include "coding.h"
|
||||
|
||||
|
||||
static const int step_sizes[49] = { /* OKI table */
|
||||
static const int step_sizes[49] = { /* OKI table (subsection of IMA's table) */
|
||||
16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50,
|
||||
55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157,
|
||||
173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449,
|
||||
494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
|
||||
};
|
||||
|
||||
static const int stex_indexes[16] = { /* IMA table */
|
||||
static const int stex_indexes[16] = { /* OKI table (also from IMA) */
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
-1, -1, -1, -1, 2, 4, 6, 8
|
||||
};
|
||||
|
@ -54,6 +54,26 @@ static void pcfx_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int
|
|||
}
|
||||
}
|
||||
|
||||
static void oki16_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index, int16_t *out_sample) {
|
||||
int code, step, delta;
|
||||
|
||||
code = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift) & 0xf;
|
||||
step = step_sizes[*step_index];
|
||||
|
||||
delta = (code & 0x7);
|
||||
delta = (((delta * 2) + 1) * step) >> 3; /* IMA 'mul' style (standard OKI uses 'shift-add') */
|
||||
if (code & 0x8)
|
||||
delta = -delta;
|
||||
*hist1 += delta;
|
||||
|
||||
/* standard OKI clamps hist to 2047,-2048 here */
|
||||
|
||||
*step_index += stex_indexes[code];
|
||||
if (*step_index < 0) *step_index = 0;
|
||||
if (*step_index > 48) *step_index = 48;
|
||||
|
||||
*out_sample = *hist1;
|
||||
}
|
||||
|
||||
/* PC-FX ADPCM decoding, variation of OKI/Dialogic/VOX ADPCM. Based on mednafen/pcfx-music-dump.
|
||||
* Apparently most ADPCM was made with a buggy encoder, resulting in incorrect sound in real hardware
|
||||
|
@ -65,7 +85,7 @@ static void pcfx_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int
|
|||
*
|
||||
* PC-FX ISOs don't have a standard filesystem nor file formats (raw data must be custom-ripped),
|
||||
* so it's needs GENH/TXTH. Sample rate can only be base_value divided by 1/2/3/4, where
|
||||
* base_value is approximately ~31468.5 (follows hardware clocks), mono or stereo-interleaved.
|
||||
* base_value is approximately ~31468.5 (follows hardware clocks), mono or interleaved for stereo.
|
||||
*/
|
||||
void decode_pcfx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int mode) {
|
||||
int i, sample_count = 0;
|
||||
|
@ -86,7 +106,40 @@ void decode_pcfx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
|||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
||||
size_t pcfx_bytes_to_samples(size_t bytes, int channels) {
|
||||
/* OKI variation with 16-bit output (vs standard's 12-bit), found in FrontWing's PS2 games (Sweet Legacy, Hooligan).
|
||||
* Reverse engineered from the ELF with help from the folks at hcs. */
|
||||
void decode_oki16(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, sample_count = 0;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
int16_t out_sample;
|
||||
int is_stereo = channelspacing > 1;
|
||||
|
||||
|
||||
/* external interleave */
|
||||
|
||||
/* no header (external setup), pre-clamp for wrong values */
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 48) step_index=48;
|
||||
|
||||
/* decode nibbles (layout: varies) */
|
||||
for (i = first_sample; i < first_sample + samples_to_do; i++, sample_count += channelspacing) {
|
||||
off_t byte_offset = is_stereo ?
|
||||
stream->offset + i : /* stereo: one nibble per channel */
|
||||
stream->offset + i/2; /* mono: consecutive nibbles (assumed) */
|
||||
int nibble_shift =
|
||||
is_stereo ? (!(channel&1) ? 0:4) : (!(i&1) ? 0:4); /* even = low, odd = high */
|
||||
|
||||
oki16_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index, &out_sample);
|
||||
outbuf[sample_count] = (out_sample);
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
||||
|
||||
size_t oki_bytes_to_samples(size_t bytes, int channels) {
|
||||
/* 2 samples per byte (2 nibbles) in stereo or mono config */
|
||||
return bytes * 2 / channels;
|
||||
}
|
|
@ -78,6 +78,52 @@ void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
|||
}
|
||||
}
|
||||
|
||||
void decode_pcm4(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, nibble_shift, is_high_first, is_stereo;
|
||||
int32_t sample_count;
|
||||
int16_t v;
|
||||
off_t byte_offset;
|
||||
|
||||
is_high_first = (vgmstream->codec_config & 1);
|
||||
is_stereo = (vgmstream->channels != 1);
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
byte_offset = is_stereo ?
|
||||
stream->offset + i : /* stereo: one nibble per channel (assumed, not sure if stereo version actually exists) */
|
||||
stream->offset + i/2; /* mono: consecutive nibbles */
|
||||
nibble_shift = is_high_first ?
|
||||
is_stereo ? (!(channel&1) ? 4:0) : (!(i&1) ? 4:0) : /* even = high, odd = low */
|
||||
is_stereo ? (!(channel&1) ? 0:4) : (!(i&1) ? 0:4); /* even = low, odd = high */
|
||||
|
||||
v = (int16_t)read_8bit(byte_offset, stream->streamfile);
|
||||
v = (v >> nibble_shift) & 0x0F;
|
||||
outbuf[sample_count] = v*0x11*0x100;
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcm4_unsigned(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, nibble_shift, is_high_first, is_stereo;
|
||||
int32_t sample_count;
|
||||
int16_t v;
|
||||
off_t byte_offset;
|
||||
|
||||
is_high_first = (vgmstream->codec_config & 1);
|
||||
is_stereo = (vgmstream->channels != 1);
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
byte_offset = is_stereo ?
|
||||
stream->offset + i : /* stereo: one nibble per channel (assumed, not sure if stereo version actually exists) */
|
||||
stream->offset + i/2; /* mono: consecutive nibbles */
|
||||
nibble_shift = is_high_first ?
|
||||
is_stereo ? (!(channel&1) ? 4:0) : (!(i&1) ? 4:0) : /* even = high, odd = low */
|
||||
is_stereo ? (!(channel&1) ? 0:4) : (!(i&1) ? 0:4); /* even = low, odd = high */
|
||||
|
||||
v = (int16_t)read_8bit(byte_offset, stream->streamfile);
|
||||
v = (v >> nibble_shift) & 0x0F;
|
||||
outbuf[sample_count] = v*0x11*0x100 - 0x8000;
|
||||
}
|
||||
}
|
||||
|
||||
static int expand_ulaw(uint8_t ulawbyte) {
|
||||
int sign, segment, quantization, new_sample;
|
||||
const int bias = 0x84;
|
||||
|
@ -175,5 +221,5 @@ void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
|
|||
}
|
||||
|
||||
size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample) {
|
||||
return bytes / channels / (bits_per_sample/8);
|
||||
return (bytes * 8) / channels / bits_per_sample;
|
||||
}
|
||||
|
|
|
@ -155,6 +155,7 @@ static const char* extension_list[] = {
|
|||
"gcub",
|
||||
"gcw",
|
||||
"genh",
|
||||
"gin",
|
||||
"gms",
|
||||
"gsb",
|
||||
//"gsf", //conflicts with GBA gsf plugins?
|
||||
|
@ -194,7 +195,7 @@ static const char* extension_list[] = {
|
|||
|
||||
"kces",
|
||||
"kcey", //fake extension/header id for .pcm (renamed, to be removed)
|
||||
"khv",
|
||||
"khv", //fake extension/header id for .vas (renamed, to be removed)
|
||||
"km9",
|
||||
"kovs", //fake extension/header id for .kvs
|
||||
"kns",
|
||||
|
@ -205,6 +206,7 @@ static const char* extension_list[] = {
|
|||
"l",
|
||||
"laac", //fake extension for .aac (tri-Ace)
|
||||
"lac3", //fake extension for .ac3, FFmpeg/not parsed
|
||||
"lasf", //fake extension for .asf (various)
|
||||
"leg",
|
||||
"lflac", //fake extension for .flac, FFmpeg/not parsed
|
||||
"lin",
|
||||
|
@ -348,6 +350,7 @@ static const char* extension_list[] = {
|
|||
"sb5",
|
||||
"sb6",
|
||||
"sb7",
|
||||
"sbr",
|
||||
"sm0",
|
||||
"sm1",
|
||||
"sm2",
|
||||
|
@ -551,11 +554,13 @@ static const coding_info coding_info_list[] = {
|
|||
{coding_PCM16LE, "Little Endian 16-bit PCM"},
|
||||
{coding_PCM16BE, "Big Endian 16-bit PCM"},
|
||||
{coding_PCM16_int, "16-bit PCM with 2 byte interleave (block)"},
|
||||
{coding_PCM8, "8-bit PCM"},
|
||||
{coding_PCM8_int, "8-bit PCM with 1 byte interleave (block)"},
|
||||
{coding_PCM8, "8-bit signed PCM"},
|
||||
{coding_PCM8_int, "8-bit signed PCM with 1 byte interleave (block)"},
|
||||
{coding_PCM8_U, "8-bit unsigned PCM"},
|
||||
{coding_PCM8_U_int, "8-bit unsigned PCM with 1 byte interleave (block)"},
|
||||
{coding_PCM8_SB, "8-bit PCM with sign bit"},
|
||||
{coding_PCM4, "4-bit signed PCM"},
|
||||
{coding_PCM4_U, "4-bit unsigned PCM"},
|
||||
{coding_ULAW, "8-bit u-Law"},
|
||||
{coding_ULAW_int, "8-bit u-Law with 1 byte interleave (block)"},
|
||||
{coding_ALAW, "8-bit a-Law"},
|
||||
|
@ -584,7 +589,8 @@ static const coding_info coding_info_list[] = {
|
|||
{coding_EA_XA_int, "Electronic Arts EA-XA 4-bit ADPCM v1 (mono/interleave)"},
|
||||
{coding_EA_XA_V2, "Electronic Arts EA-XA 4-bit ADPCM v2"},
|
||||
{coding_MAXIS_XA, "Maxis EA-XA 4-bit ADPCM"},
|
||||
{coding_EA_XAS, "Electronic Arts EA-XAS 4-bit ADPCM"},
|
||||
{coding_EA_XAS_V0, "Electronic Arts EA-XAS 4-bit ADPCM v0"},
|
||||
{coding_EA_XAS_V1, "Electronic Arts EA-XAS 4-bit ADPCM v1"},
|
||||
|
||||
{coding_IMA, "IMA 4-bit ADPCM"},
|
||||
{coding_IMA_int, "IMA 4-bit ADPCM (mono/interleave)"},
|
||||
|
@ -615,6 +621,7 @@ static const coding_info coding_info_list[] = {
|
|||
{coding_H4M_IMA, "Hudson HVQM4 4-bit IMA ADPCM"},
|
||||
|
||||
{coding_MSADPCM, "Microsoft 4-bit ADPCM"},
|
||||
{coding_MSADPCM_int, "Microsoft 4-bit ADPCM (mono/interleave)"},
|
||||
{coding_MSADPCM_ck, "Microsoft 4-bit ADPCM (Cricket Audio)"},
|
||||
{coding_WS, "Westwood Studios VBR ADPCM"},
|
||||
{coding_AICA, "Yamaha AICA 4-bit ADPCM"},
|
||||
|
@ -631,6 +638,7 @@ static const coding_info coding_info_list[] = {
|
|||
{coding_ASF, "Argonaut ASF 4-bit ADPCM"},
|
||||
{coding_XMD, "Konami XMD 4-bit ADPCM"},
|
||||
{coding_PCFX, "PC-FX 4-bit ADPCM"},
|
||||
{coding_OKI16, "OKI 4-bit ADPCM (16-bit output)"},
|
||||
|
||||
{coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"},
|
||||
{coding_SDX2_int, "Squareroot-delta-exact (SDX2) 8-bit DPCM with 1 byte interleave"},
|
||||
|
@ -763,7 +771,7 @@ static const meta_info meta_info_list[] = {
|
|||
{meta_PS_HEADERLESS, "Headerless PS-ADPCM raw header"},
|
||||
{meta_PS2_MIB_MIH, "Sony MultiStream MIH+MIB header"},
|
||||
{meta_DSP_MPDSP, "Single DSP header stereo by .mpdsp extension"},
|
||||
{meta_PS2_MIC, "assume KOEI MIC file by .mic extension"},
|
||||
{meta_PS2_MIC, "KOEI .MIC header"},
|
||||
{meta_DSP_JETTERS, "Double DSP header stereo by _lr.dsp extension"},
|
||||
{meta_DSP_MSS, "Double DSP header stereo by .mss extension"},
|
||||
{meta_DSP_GCM, "Double DSP header stereo by .gcm extension"},
|
||||
|
@ -993,7 +1001,7 @@ static const meta_info meta_info_list[] = {
|
|||
{meta_PS3_CPS, "tri-Crescendo CPS Header"},
|
||||
{meta_SQEX_SCD, "Square-Enix SCD header"},
|
||||
{meta_NGC_NST_DSP, "Animaniacs NST header"},
|
||||
{meta_BAF, ".baf WAVE header"},
|
||||
{meta_BAF, "Bizarre Creations .baf header"},
|
||||
{meta_PS3_MSF, "Sony MSF header"},
|
||||
{meta_NUB_VAG, "Namco NUB VAG header"},
|
||||
{meta_PS3_PAST, "SNDP header"},
|
||||
|
@ -1153,6 +1161,7 @@ static const meta_info meta_info_list[] = {
|
|||
{meta_DSP_ADPCMX, "AQUASTYLE ADPY header"},
|
||||
{meta_OGG_OPUS, "Ogg Opus header"},
|
||||
{meta_IMC, "iNiS .IMC header"},
|
||||
{meta_GIN, "Electronic Arts Gnsu header"},
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@ VGMSTREAM * init_vgmstream_asf(STREAMFILE *streamFile) {
|
|||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "asf"))
|
||||
/* .asf: original
|
||||
* .lasf: fake for plugins */
|
||||
if (!check_extensions(streamFile, "asf,lasf"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) != 0x41534600) /* "ASF\0" */
|
||||
|
|
|
@ -1,9 +1,189 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .BAF - Bizarre Creations (Blur, James Bond 007: Blood Stone, etc) */
|
||||
|
||||
/* .BAF - Bizarre Creations bank file [Blur (PS3), Project Gotham Racing 4 (X360), Geometry Wars (PC)] */
|
||||
VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t WAVE_size, DATA_size;
|
||||
off_t start_offset, header_offset, name_offset;
|
||||
size_t stream_size;
|
||||
int loop_flag, channel_count, sample_rate, version, codec;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*);
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "baf"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x42414E4B) /* "BANK" */
|
||||
goto fail;
|
||||
|
||||
/* use BANK size to check endianness */
|
||||
if (guess_endianness32bit(0x04,streamFile)) {
|
||||
read_32bit = read_32bitBE;
|
||||
} else {
|
||||
read_32bit = read_32bitLE;
|
||||
}
|
||||
|
||||
/* 0x04: bank size */
|
||||
version = read_32bit(0x08,streamFile);
|
||||
if (version != 0x03 && version != 0x04)
|
||||
goto fail;
|
||||
total_subsongs = read_32bit(0x0c,streamFile);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
/* - in v3 */
|
||||
/* 0x10: 0? */
|
||||
/* 0x11: bank name */
|
||||
/* - in v4 */
|
||||
/* 0x10: 1? */
|
||||
/* 0x11: padding flag? */
|
||||
/* 0x12: bank name */
|
||||
|
||||
/* find target WAVE chunk */
|
||||
{
|
||||
int i;
|
||||
off_t offset = read_32bit(0x04, streamFile);
|
||||
|
||||
for (i = 0; i < total_subsongs; i++) {
|
||||
if (i+1 == target_subsong)
|
||||
break;
|
||||
offset += read_32bit(offset+0x04, streamFile); /* WAVE size, variable per codec */
|
||||
}
|
||||
header_offset = offset;
|
||||
}
|
||||
|
||||
/* parse header */
|
||||
if (read_32bitBE(header_offset+0x00, streamFile) != 0x57415645) /* "WAVE" */
|
||||
goto fail;
|
||||
codec = read_32bit(header_offset+0x08, streamFile);
|
||||
name_offset = header_offset + 0x0c;
|
||||
start_offset = read_32bit(header_offset+0x2c, streamFile);
|
||||
stream_size = read_32bit(header_offset+0x30, streamFile);
|
||||
switch(codec) {
|
||||
case 0x03:
|
||||
switch(version) {
|
||||
case 0x03: /* Geometry Wars (PC) */
|
||||
sample_rate = read_32bit(header_offset + 0x38, streamFile);
|
||||
channel_count = read_32bit(header_offset + 0x40, streamFile);
|
||||
/* no actual flag, just loop +15sec songs */
|
||||
loop_flag = (pcm_bytes_to_samples(stream_size, channel_count, 16) > 15*sample_rate);
|
||||
break;
|
||||
|
||||
case 0x04: /* Project Gotham Racing 4 (X360) */
|
||||
sample_rate = read_32bit(header_offset + 0x3c, streamFile);
|
||||
channel_count = read_32bit(header_offset + 0x44, streamFile);
|
||||
loop_flag = read_8bit(header_offset+0x4b, streamFile);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x07: /* Blur (PS3) */
|
||||
sample_rate = read_32bit(header_offset+0x40, streamFile);
|
||||
loop_flag = read_8bit(header_offset+0x48, streamFile);
|
||||
channel_count = read_8bit(header_offset+0x4b, streamFile);
|
||||
break;
|
||||
|
||||
case 0x08: /* Project Gotham Racing (X360) */
|
||||
sample_rate = read_32bit(header_offset+0x3c, streamFile);
|
||||
channel_count = read_32bit(header_offset+0x44, streamFile);
|
||||
loop_flag = read_8bit(header_offset+0x54, streamFile) != 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("BAF: unknown version %x\n", version);
|
||||
goto fail;
|
||||
}
|
||||
/* others: pan/vol? fixed values? (0x19, 0x10) */
|
||||
|
||||
/* after WAVEs there may be padding then DATAs chunks, but offsets point after DATA size */
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_BAF;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = stream_size;
|
||||
|
||||
switch(codec) {
|
||||
case 0x03:
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16);
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
break;
|
||||
|
||||
case 0x07:
|
||||
vgmstream->coding_type = coding_PSX_cfg;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x21;
|
||||
|
||||
vgmstream->num_samples = read_32bit(header_offset+0x44, streamFile);
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
break;
|
||||
|
||||
case 0x08: {
|
||||
uint8_t buf[0x100];
|
||||
int bytes;
|
||||
|
||||
bytes = ffmpeg_make_riff_xma1(buf,0x100, vgmstream->num_samples, stream_size, vgmstream->channels, vgmstream->sample_rate, 0);
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,stream_size);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
/* need to manually find sample offsets, it was a thing with XMA1 */
|
||||
{
|
||||
ms_sample_data msd = {0};
|
||||
|
||||
msd.xma_version = 1;
|
||||
msd.channels = channel_count;
|
||||
msd.data_offset = start_offset;
|
||||
msd.data_size = stream_size;
|
||||
msd.loop_flag = loop_flag;
|
||||
msd.loop_start_b = read_32bit(header_offset+0x4c, streamFile);
|
||||
msd.loop_end_b = read_32bit(header_offset+0x50, streamFile);
|
||||
msd.loop_start_subframe = (read_8bit(header_offset+0x55, streamFile) >> 0) & 0x0f;
|
||||
msd.loop_end_subframe = (read_8bit(header_offset+0x55, streamFile) >> 4) & 0x0f;
|
||||
xma_get_samples(&msd, streamFile);
|
||||
|
||||
vgmstream->num_samples = msd.num_samples; /* also at 0x58, but unreliable? */
|
||||
vgmstream->loop_start_sample = msd.loop_start_sample;
|
||||
vgmstream->loop_end_sample = msd.loop_end_sample;
|
||||
}
|
||||
|
||||
xma_fix_raw_samples_ch(vgmstream, streamFile, start_offset, stream_size, channel_count, 1,1);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
VGM_LOG("BAF: unknown codec %x\n", codec);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
read_string(vgmstream->stream_name,0x20+1, name_offset,streamFile);
|
||||
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* awful PS3 splits of the above with bad offsets and all */
|
||||
VGMSTREAM * init_vgmstream_baf_badrip(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t WAVE_size, stream_size;
|
||||
off_t start_offset;
|
||||
long sample_count;
|
||||
int sample_rate;
|
||||
|
@ -13,38 +193,31 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) {
|
|||
int channels;
|
||||
int loop_flag = 0;
|
||||
|
||||
/* check extensions */
|
||||
/* checks */
|
||||
if ( !check_extensions(streamFile, "baf") )
|
||||
goto fail;
|
||||
|
||||
/* check WAVE */
|
||||
if (read_32bitBE(0,streamFile) != 0x57415645) /* "WAVE" */
|
||||
goto fail;
|
||||
WAVE_size = read_32bitBE(4,streamFile);
|
||||
if (WAVE_size != 0x4c) /* && WAVE_size != 0x50*/
|
||||
goto fail;
|
||||
/* check for DATA after WAVE */
|
||||
if (read_32bitBE(WAVE_size,streamFile) != 0x44415441) /* "DATA"*/
|
||||
goto fail;
|
||||
/* check that WAVE size is data size */
|
||||
DATA_size = read_32bitBE(0x30,streamFile);
|
||||
if (read_32bitBE(WAVE_size+4,streamFile)-8 != DATA_size) goto fail;
|
||||
stream_size = read_32bitBE(0x30,streamFile);
|
||||
if (read_32bitBE(WAVE_size+4,streamFile)-8 != stream_size) goto fail;
|
||||
|
||||
/*if (WAVE_size == 0x50) sample_count = DATA_size * frame_samples / frame_size / channels;*/
|
||||
sample_count = read_32bitBE(0x44,streamFile);
|
||||
|
||||
/*if (WAVE_size == 0x50) sample_rate = read_32bitBE(0x3c,streamFile);*/
|
||||
sample_rate = read_32bitBE(0x40,streamFile);
|
||||
|
||||
/* unsure how to detect channel count, so use a hack */
|
||||
channels = (long long)DATA_size / frame_size * frame_samples / sample_count;
|
||||
channels = (long long)stream_size / frame_size * frame_samples / sample_count;
|
||||
start_offset = WAVE_size + 8;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = WAVE_size + 8;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = sample_count;
|
||||
|
||||
|
@ -53,14 +226,11 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) {
|
|||
vgmstream->interleave_block_size = frame_size;
|
||||
vgmstream->meta_type = meta_BAF;
|
||||
|
||||
/* open the file for reading */
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
|
||||
typedef enum { PSX, PCM16, ATRAC9, HEVAG } bnk_codec;
|
||||
|
||||
/* BNK - Sony's Scream Tool bank format [Puyo Puyo Tetris (PS4), NekoBuro: Cats Block (Vita)] */
|
||||
/* .BNK - Sony's Scream Tool bank format [Puyo Puyo Tetris (PS4), NekoBuro: Cats Block (Vita)] */
|
||||
VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
||||
#if 1
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, stream_offset, name_offset = 0;
|
||||
size_t stream_size, interleave = 0;
|
||||
off_t sblk_offset, data_offset;
|
||||
size_t data_size;
|
||||
int channel_count = 0, loop_flag, sample_rate, parts, version;
|
||||
int channel_count = 0, loop_flag, sample_rate, parts, version, big_endian;
|
||||
int loop_start = 0, loop_end = 0;
|
||||
uint32_t pitch, flags;
|
||||
uint32_t atrac9_info = 0;
|
||||
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
|
@ -28,10 +28,12 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
if (read_32bitBE(0x00,streamFile) == 0x00000003) { /* PS3 */
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
big_endian = 1;
|
||||
}
|
||||
else if (read_32bitBE(0x00,streamFile) == 0x03000000) { /* Vita/PS4 */
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
big_endian = 0;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
|
@ -44,11 +46,13 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
/* 0x0c: sklb size */
|
||||
data_offset = read_32bit(0x10,streamFile);
|
||||
data_size = read_32bit(0x14,streamFile);
|
||||
/* when sblk_offset >= 0x20: */
|
||||
/* 0x18: ZLSD small footer, rare [Yakuza 6's Puyo Puyo (PS4)] */
|
||||
/* 0x1c: ZLSD size */
|
||||
|
||||
/* SE banks, also used for music. Most table fields seems reserved/defaults and
|
||||
* don't change much between subsongs or files, so they aren't described in detail */
|
||||
* don't change much between subsongs or files, so they aren't described in detail.
|
||||
* Entry sizes are variable (usually flag + extra size xN) so table offsets are needed. */
|
||||
|
||||
|
||||
/* SBlk part: parse header */
|
||||
|
@ -63,7 +67,7 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
off_t table1_offset, table2_offset, table3_offset, table4_offset;
|
||||
size_t section_entries, material_entries, stream_entries;
|
||||
size_t table1_entry_size;
|
||||
off_t table1_suboffset, table2_suboffset, table3_suboffset;
|
||||
off_t table1_suboffset, table2_suboffset;
|
||||
off_t table2_entry_offset = 0, table3_entry_offset = 0;
|
||||
int table4_entry_id = -1;
|
||||
off_t table4_entries_offset, table4_names_offset;
|
||||
|
@ -75,7 +79,7 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
case 0x09: /* Puyo Puyo Tetris (PS4) */
|
||||
section_entries = (uint16_t)read_16bit(sblk_offset+0x16,streamFile); /* entry size: ~0x0c */
|
||||
material_entries = (uint16_t)read_16bit(sblk_offset+0x18,streamFile); /* entry size: ~0x08 */
|
||||
stream_entries = (uint16_t)read_16bit(sblk_offset+0x1a,streamFile); /* entry size: ~0x60 */
|
||||
stream_entries = (uint16_t)read_16bit(sblk_offset+0x1a,streamFile); /* entry size: ~0x18 + variable */
|
||||
table1_offset = sblk_offset + read_32bit(sblk_offset+0x1c,streamFile);
|
||||
table2_offset = sblk_offset + read_32bit(sblk_offset+0x20,streamFile);
|
||||
table3_offset = sblk_offset + read_32bit(sblk_offset+0x34,streamFile);
|
||||
|
@ -84,7 +88,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
table1_entry_size = 0x0c;
|
||||
table1_suboffset = 0x08;
|
||||
table2_suboffset = 0x00;
|
||||
table3_suboffset = 0x10;
|
||||
break;
|
||||
|
||||
case 0x0d: /* Polara (Vita), Crypt of the Necrodancer (Vita) */
|
||||
|
@ -95,12 +98,11 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
table4_offset = sblk_offset + read_32bit(sblk_offset+0x30,streamFile);
|
||||
section_entries = (uint16_t)read_16bit(sblk_offset+0x38,streamFile); /* entry size: ~0x24 */
|
||||
material_entries = (uint16_t)read_16bit(sblk_offset+0x3a,streamFile); /* entry size: ~0x08 */
|
||||
stream_entries = (uint16_t)read_16bit(sblk_offset+0x3c,streamFile); /* entry size: ~0x90 + variable (sometimes) */
|
||||
stream_entries = (uint16_t)read_16bit(sblk_offset+0x3c,streamFile); /* entry size: ~0x5c + variable */
|
||||
|
||||
table1_entry_size = 0x24;
|
||||
table1_suboffset = 0x0c;
|
||||
table2_suboffset = 0x00;
|
||||
table3_suboffset = 0x44;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -150,14 +152,64 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
/* this means some subsongs repeat streams, that can happen in some sfx banks, whatevs */
|
||||
if (total_subsongs != stream_entries) {
|
||||
//;VGM_LOG("BNK: subsongs %i vs table3 %i don't match\n", total_subsongs, stream_entries);
|
||||
VGM_LOG("BNK: subsongs %i vs table3 %i don't match\n", total_subsongs, stream_entries);
|
||||
/* find_dupes...? */
|
||||
}
|
||||
|
||||
//;VGM_LOG("BNK: header entry at %lx\n", table3_offset+table3_entry_offset);
|
||||
|
||||
/* parse sounds */
|
||||
stream_offset = read_32bit(table3_offset+table3_entry_offset+table3_suboffset+0x00,streamFile);
|
||||
stream_size = read_32bit(table3_offset+table3_entry_offset+table3_suboffset+0x04,streamFile);
|
||||
switch(version) {
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
case 0x09:
|
||||
pitch = (uint8_t)read_8bit(table3_offset+table3_entry_offset+0x02,streamFile);
|
||||
flags = (uint8_t)read_8bit(table3_offset+table3_entry_offset+0x0f,streamFile);
|
||||
stream_offset = read_32bit(table3_offset+table3_entry_offset+0x10,streamFile);
|
||||
stream_size = read_32bit(table3_offset+table3_entry_offset+0x14,streamFile);
|
||||
|
||||
/* must use some log/formula but whatevs */
|
||||
switch(pitch) {
|
||||
case 0xC6: sample_rate = 50000; break; //?
|
||||
case 0xC4: sample_rate = 48000; break;
|
||||
case 0xC3: sample_rate = 46000; break; //?
|
||||
case 0xC2: sample_rate = 44100; break;
|
||||
case 0xBC: sample_rate = 36000; break; //?
|
||||
case 0xBA: sample_rate = 32000; break; //?
|
||||
case 0xB6: sample_rate = 22050; break;
|
||||
case 0xAA: sample_rate = 11025; break;
|
||||
default:
|
||||
VGM_LOG("BNK: unknown pitch %x\n", pitch);
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0d:
|
||||
case 0x0e:
|
||||
flags = (uint8_t)read_8bit(table3_offset+table3_entry_offset+0x12,streamFile);
|
||||
stream_offset = read_32bit(table3_offset+table3_entry_offset+0x44,streamFile);
|
||||
stream_size = read_32bit(table3_offset+table3_entry_offset+0x48,streamFile);
|
||||
pitch = (uint32_t)read_32bit(table3_offset+table3_entry_offset+0x4c,streamFile);
|
||||
|
||||
/* this looks like "((pitch >> 9) & 0xC000) | ((pitch >> 8) & 0xFFFF)" but... why??? */
|
||||
switch(pitch) {
|
||||
case 0x467A0000: sample_rate = 64000; break; //?
|
||||
case 0x46BB8000: sample_rate = 48000; break;
|
||||
case 0x473B8000: sample_rate = 48000; break;
|
||||
case 0x46AC4400: sample_rate = 44100; break;
|
||||
case 0x47AC4400: sample_rate = 44100; break;
|
||||
case 0x472C4400: sample_rate = 44100; break;
|
||||
default:
|
||||
VGM_LOG("BNK: unknown pitch %x\n", pitch);
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
//;VGM_LOG("BNK: stream at %lx + %x\n", stream_offset, stream_size);
|
||||
|
||||
/* parse names */
|
||||
switch(version) {
|
||||
|
@ -215,7 +267,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
switch(version) {
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
sample_rate = 48000; /* seems ok */
|
||||
channel_count = 1;
|
||||
|
||||
/* hack for PS3 files that use dual subsongs as stereo */
|
||||
|
@ -224,14 +275,19 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
stream_size = stream_size*channel_count;
|
||||
total_subsongs = 1;
|
||||
}
|
||||
|
||||
interleave = stream_size / channel_count;
|
||||
|
||||
if (flags & 0x80) {
|
||||
codec = PCM16; /* rare [Wipeout HD (PS3)] */
|
||||
}
|
||||
else {
|
||||
loop_flag = ps_find_loop_offsets(streamFile, start_offset, stream_size, channel_count, interleave, &loop_start, &loop_end);
|
||||
loop_flag = (flags & 0x40); /* no loops values in sight so may only apply to PS-ADPCM flags */
|
||||
|
||||
codec = PSX;
|
||||
}
|
||||
|
||||
//postdata_size = 0x10; /* last frame may be garbage */
|
||||
|
||||
loop_flag = ps_find_loop_offsets(streamFile, start_offset, stream_size, channel_count, interleave, &loop_start, &loop_end);
|
||||
loop_flag = (loop_start > 28); /* ignore full loops since they just fadeout + repeat */
|
||||
|
||||
codec = PSX;
|
||||
break;
|
||||
|
||||
case 0x09:
|
||||
|
@ -243,7 +299,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
case 0x05: /* ATRAC9 stereo */
|
||||
if (read_32bit(start_offset+0x08,streamFile) + 0x08 != extradata_size) /* repeat? */
|
||||
goto fail;
|
||||
sample_rate = 48000; /* seems ok */
|
||||
channel_count = (type == 0x02) ? 1 : 2;
|
||||
|
||||
atrac9_info = (uint32_t)read_32bitBE(start_offset+0x0c,streamFile);
|
||||
|
@ -274,7 +329,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
case 0x05: /* ATRAC9 stereo */
|
||||
if (read_32bit(start_offset+0x10,streamFile) + 0x10 != extradata_size) /* repeat? */
|
||||
goto fail;
|
||||
sample_rate = 48000; /* seems ok */
|
||||
channel_count = (type == 0x02) ? 1 : 2;
|
||||
|
||||
atrac9_info = (uint32_t)read_32bitBE(start_offset+0x14,streamFile);
|
||||
|
@ -291,7 +345,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
|
||||
case 0x01: /* PCM16LE mono? (NekoBuro/Polara sfx) */
|
||||
case 0x04: /* PCM16LE stereo? (NekoBuro/Polara sfx) */
|
||||
sample_rate = 48000; /* seems ok */
|
||||
/* 0x10: null? */
|
||||
channel_count = read_32bit(start_offset+0x14,streamFile);
|
||||
interleave = 0x02;
|
||||
|
@ -304,7 +357,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
break;
|
||||
|
||||
case 0x00: /* PS-ADPCM (test banks) */
|
||||
sample_rate = 48000; /* seems ok */
|
||||
/* 0x10: null? */
|
||||
channel_count = read_32bit(start_offset+0x14,streamFile);
|
||||
interleave = 0x02;
|
||||
|
@ -366,7 +418,7 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
}
|
||||
#endif
|
||||
case PCM16:
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
|
||||
|
@ -376,7 +428,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
break;
|
||||
|
||||
case PSX:
|
||||
vgmstream->sample_rate = 48000;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
|
@ -387,7 +438,6 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
break;
|
||||
|
||||
case HEVAG:
|
||||
vgmstream->sample_rate = 48000;
|
||||
vgmstream->coding_type = coding_HEVAG;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
|
@ -410,6 +460,22 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) {
|
|||
return vgmstream;
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/* .BNK - Sony's bank, earlier version [Jak and Daxter (PS2), NCAA Gamebreaker 2001 (PS2)] */
|
||||
VGMSTREAM * init_vgmstream_bnk_sony_v2(STREAMFILE *streamFile) {
|
||||
/* 0x00: 0x00000001
|
||||
* 0x04: sections (2 or 3)
|
||||
* 0x08+ similar to v3 but "SBv2"
|
||||
* table formats is a bit different
|
||||
* header is like v3 but stream size is in other table?
|
||||
*/
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -40,11 +40,12 @@ VGMSTREAM * init_vgmstream_ea_1snh(STREAMFILE *streamFile) {
|
|||
|
||||
|
||||
/* checks */
|
||||
/* .asf/as4: common
|
||||
/* .asf/as4: common,
|
||||
* .lasf: fake for plugins
|
||||
* .cnk: some PS games
|
||||
* .sng: fake for plugins (to mimic EA SCHl's common extension)
|
||||
* .uv/tgq: some SAT games (video only?) */
|
||||
if (!check_extensions(streamFile,"asf,as4,cnk,sng,uv,tgq"))
|
||||
if (!check_extensions(streamFile,"asf,lasf,as4,cnk,sng,uv,tgq"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) != 0x31534E68 && /* "1SNh" */
|
||||
|
|
|
@ -121,7 +121,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) {
|
|||
}
|
||||
|
||||
header_offset = 0x10; /* SNR header */
|
||||
start_offset = read_32bit(0x08,streamFile); /* SPS blocks */
|
||||
start_offset = read_32bit(0x08,streamFile); /* SNS blocks */
|
||||
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, header_offset, start_offset, meta_EA_SNU);
|
||||
if (!vgmstream) goto fail;
|
||||
|
@ -134,7 +134,7 @@ fail:
|
|||
}
|
||||
|
||||
/* EA ABK - ABK header seems to be same as in the old games but the sound table is different and it contains SNR/SNS sounds instead */
|
||||
VGMSTREAM * init_vgmstream_ea_abk_new(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * init_vgmstream_ea_abk_eaac(STREAMFILE *streamFile) {
|
||||
int is_dupe, total_sounds = 0, target_stream = streamFile->stream_index;
|
||||
off_t bnk_offset, header_table_offset, base_offset, unk_struct_offset, table_offset, snd_entry_offset, ast_offset;
|
||||
off_t num_entries_off, base_offset_off, entries_off, sound_table_offset_off;
|
||||
|
@ -143,8 +143,8 @@ VGMSTREAM * init_vgmstream_ea_abk_new(STREAMFILE *streamFile) {
|
|||
uint8_t num_entries, extra_entries;
|
||||
off_t sound_table_offsets[0x2000];
|
||||
VGMSTREAM *vgmstream;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*);
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*);
|
||||
int32_t(*read_32bit)(off_t, STREAMFILE*);
|
||||
int16_t(*read_16bit)(off_t, STREAMFILE*);
|
||||
|
||||
/* check extension */
|
||||
if (!check_extensions(streamFile, "abk"))
|
||||
|
@ -154,7 +154,7 @@ VGMSTREAM * init_vgmstream_ea_abk_new(STREAMFILE *streamFile) {
|
|||
goto fail;
|
||||
|
||||
/* use table offset to check endianness */
|
||||
if (guess_endianness32bit(0x1C,streamFile)) {
|
||||
if (guess_endianness32bit(0x1C, streamFile)) {
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
} else {
|
||||
|
@ -183,15 +183,13 @@ VGMSTREAM * init_vgmstream_ea_abk_new(STREAMFILE *streamFile) {
|
|||
base_offset_off = 0x2C;
|
||||
entries_off = 0x3C;
|
||||
sound_table_offset_off = 0x04;
|
||||
}
|
||||
else if (header_table_offset == 0x78) {
|
||||
} else if (header_table_offset == 0x78) {
|
||||
/* FIFA 08 has a bunch of extra zeroes all over the place, don't know what's up with that */
|
||||
num_entries_off = 0x40;
|
||||
base_offset_off = 0x54;
|
||||
entries_off = 0x68;
|
||||
sound_table_offset_off = 0x0C;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -207,10 +205,8 @@ VGMSTREAM * init_vgmstream_ea_abk_new(STREAMFILE *streamFile) {
|
|||
|
||||
/* For some reason, there are duplicate entries pointing at the same sound tables */
|
||||
is_dupe = 0;
|
||||
for (k = 0; k < total_sound_tables; k++)
|
||||
{
|
||||
if (table_offset==sound_table_offsets[k])
|
||||
{
|
||||
for (k = 0; k < total_sound_tables; k++) {
|
||||
if (table_offset == sound_table_offsets[k]) {
|
||||
is_dupe = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -248,7 +244,7 @@ VGMSTREAM * init_vgmstream_ea_abk_new(STREAMFILE *streamFile) {
|
|||
|
||||
if (bnk_target_index == 0xFFFF || ast_offset == 0)
|
||||
goto fail;
|
||||
|
||||
|
||||
vgmstream = parse_s10a_header(streamFile, bnk_offset, bnk_target_index, ast_offset);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
@ -288,8 +284,7 @@ static VGMSTREAM * parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint1
|
|||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/* streamed asset */
|
||||
astFile = open_streamfile_by_ext(streamFile, "ast");
|
||||
if (!astFile)
|
||||
|
@ -314,7 +309,90 @@ fail:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* EA HDR/STH/DAT - seen in early 7th-gen games, used for storing speech */
|
||||
/* EA SBR/SBS - used in older 7th gen games for storing SFX */
|
||||
VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE *streamFile) {
|
||||
uint32_t num_sounds, type_desc;
|
||||
uint16_t num_metas, meta_type;
|
||||
uint32_t i;
|
||||
off_t table_offset, types_offset, entry_offset, metas_offset, data_offset, snr_offset, sns_offset;
|
||||
STREAMFILE *sbsFile = NULL, *streamData = NULL;
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
int target_stream = streamFile->stream_index;
|
||||
|
||||
if (!check_extensions(streamFile, "sbr"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00, streamFile) != 0x53424B52) /* "SBKR" */
|
||||
goto fail;
|
||||
|
||||
/* SBR files are always big endian */
|
||||
num_sounds = read_32bitBE(0x1c, streamFile);
|
||||
table_offset = read_32bitBE(0x24, streamFile);
|
||||
types_offset = read_32bitBE(0x28, streamFile);
|
||||
|
||||
if (target_stream == 0) target_stream = 1;
|
||||
if (target_stream < 0 || num_sounds == 0 || target_stream > num_sounds)
|
||||
goto fail;
|
||||
|
||||
entry_offset = table_offset + 0x0a * (target_stream - 1);
|
||||
num_metas = read_16bitBE(entry_offset + 0x04, streamFile);
|
||||
metas_offset = read_32bitBE(entry_offset + 0x06, streamFile);
|
||||
|
||||
snr_offset = 0xFFFFFFFF;
|
||||
sns_offset = 0xFFFFFFFF;
|
||||
|
||||
for (i = 0; i < num_metas; i++) {
|
||||
entry_offset = metas_offset + 0x06 * i;
|
||||
meta_type = read_16bitBE(entry_offset, streamFile);
|
||||
data_offset = read_32bitBE(entry_offset + 0x02, streamFile);
|
||||
|
||||
type_desc = read_32bitBE(types_offset + 0x06 * meta_type, streamFile);
|
||||
|
||||
switch (type_desc) {
|
||||
case 0x534E5231: /* "SNR1" */
|
||||
snr_offset = data_offset;
|
||||
break;
|
||||
case 0x534E5331: /* "SNS1" */
|
||||
sns_offset = read_32bitBE(data_offset, streamFile);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (snr_offset == 0xFFFFFFFF)
|
||||
goto fail;
|
||||
|
||||
if (sns_offset == 0xFFFFFFFF) {
|
||||
/* RAM asset */
|
||||
streamData = streamFile;
|
||||
sns_offset = snr_offset + get_snr_size(streamFile, snr_offset);
|
||||
} else {
|
||||
/* streamed asset */
|
||||
sbsFile = open_streamfile_by_ext(streamFile, "sbs");
|
||||
if (!sbsFile)
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00, sbsFile) != 0x53424B53) /* "SBKS" */
|
||||
goto fail;
|
||||
|
||||
streamData = sbsFile;
|
||||
}
|
||||
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamData, snr_offset, sns_offset, meta_EA_SNR_SNS);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
vgmstream->num_streams = num_sounds;
|
||||
close_streamfile(sbsFile);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(sbsFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* EA HDR/STH/DAT - seen in older 7th gen games, used for storing speech */
|
||||
VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) {
|
||||
int target_stream = streamFile->stream_index;
|
||||
uint32_t i;
|
||||
|
@ -372,7 +450,7 @@ VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) {
|
|||
sns_offset = 0;
|
||||
|
||||
for (i = 0; i < total_sounds; i++) {
|
||||
snr_offset = (off_t)read_16bitBE(0x10 + (0x02+userdata_size) * i, streamFile) + 0x04;
|
||||
snr_offset = (uint16_t)read_16bitBE(0x10 + (0x02+userdata_size) * i, streamFile) + 0x04;
|
||||
|
||||
if (i == target_stream - 1)
|
||||
break;
|
||||
|
@ -416,7 +494,7 @@ fail:
|
|||
}
|
||||
|
||||
/* EA MPF/MUS combo - used in older 7th gen games for storing music */
|
||||
VGMSTREAM * init_vgmstream_ea_mpf_mus_new(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) {
|
||||
uint32_t num_sounds;
|
||||
uint8_t version, sub_version, block_id;
|
||||
off_t table_offset, entry_offset, snr_offset, sns_offset;
|
||||
|
@ -491,6 +569,179 @@ fail:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* EA Harmony Sample Bank - used in 8th gen EA Sports games */
|
||||
VGMSTREAM * init_vgmstream_ea_sbr_harmony(STREAMFILE *streamFile) {
|
||||
uint32_t num_dsets, set_sounds, chunk_id;
|
||||
uint32_t i;
|
||||
uint8_t set_type, flag, offset_size;
|
||||
off_t data_offset, table_offset, dset_offset, base_offset, sound_table_offset, sound_offset, header_offset, start_offset;
|
||||
STREAMFILE *sbsFile = NULL, *streamData = NULL;
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
int target_stream = streamFile->stream_index, total_sounds, local_target, is_streamed = 0;
|
||||
int32_t(*read_32bit)(off_t, STREAMFILE*);
|
||||
int16_t(*read_16bit)(off_t, STREAMFILE*);
|
||||
|
||||
if (!check_extensions(streamFile, "sbr"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00, streamFile) == 0x53426C65) { /* "SBle" */
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
/* Logically, big endian version starts with SBbe. However, this format is
|
||||
* only used on 8th gen systems so far so big endian version probably doesn't exist. */
|
||||
#if 0
|
||||
} else if (read_32bitBE(0x00, streamFile) == 0x53426265) { /* "SBbe" */
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
#endif
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
num_dsets = read_16bit(0x0a, streamFile);
|
||||
data_offset = read_32bit(0x20, streamFile);
|
||||
table_offset = read_32bit(0x24, streamFile);
|
||||
|
||||
if (target_stream == 0) target_stream = 1;
|
||||
if (target_stream < 0)
|
||||
goto fail;
|
||||
|
||||
total_sounds = 0;
|
||||
sound_offset = 0xFFFFFFFF;
|
||||
|
||||
/* The bank is split into DSET sections each of which references one or multiple sounds. */
|
||||
/* Each set can contain RAM sounds (stored in SBR in data section) or streamed sounds (stored separately in SBS file). */
|
||||
for (i = 0; i < num_dsets; i++) {
|
||||
dset_offset = read_32bit(table_offset + 0x08 * i, streamFile);
|
||||
if (read_32bit(dset_offset, streamFile) != 0x44534554) /* "DSET" */
|
||||
goto fail;
|
||||
|
||||
set_sounds = read_32bit(dset_offset + 0x38, streamFile);
|
||||
local_target = target_stream - total_sounds - 1;
|
||||
dset_offset += 0x48;
|
||||
|
||||
/* Find RAM or OFF chunk */
|
||||
while(1) {
|
||||
chunk_id = read_32bit(dset_offset, streamFile);
|
||||
if (chunk_id == 0x2E52414D) { /* ".RAM" */
|
||||
break;
|
||||
} else if (chunk_id == 0x2E4F4646) { /* ".OFF" */
|
||||
break;
|
||||
} else if (chunk_id == 0x2E4C4452 || /* ".LDR" */
|
||||
chunk_id == 0x2E4F424A || /* ".OBJ" */
|
||||
(chunk_id & 0xFF00FFFF) == 0x2E00534C) { /* ".?SL */
|
||||
dset_offset += 0x18;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Different set types store offsets differently */
|
||||
set_type = read_8bit(dset_offset + 0x05, streamFile);
|
||||
|
||||
if (set_type == 0x00) {
|
||||
total_sounds++;
|
||||
if (local_target < 0 || local_target > 0)
|
||||
continue;
|
||||
|
||||
sound_offset = read_32bit(dset_offset + 0x08, streamFile);
|
||||
} else if (set_type == 0x01) {
|
||||
total_sounds += 2;
|
||||
if (local_target < 0 || local_target > 1)
|
||||
continue;
|
||||
|
||||
base_offset = read_32bit(dset_offset + 0x08, streamFile);
|
||||
|
||||
if (local_target == 0) {
|
||||
sound_offset = base_offset;
|
||||
} else {
|
||||
sound_offset = base_offset + (uint16_t)read_16bit(dset_offset + 0x06, streamFile);
|
||||
}
|
||||
} else if (set_type == 0x02 || set_type == 0x03) {
|
||||
flag = read_8bit(dset_offset + 0x06, streamFile);
|
||||
offset_size = read_8bit(dset_offset + 0x07, streamFile);
|
||||
base_offset = read_32bit(dset_offset + 0x08, streamFile);
|
||||
sound_table_offset = read_32bit(dset_offset + 0x10, streamFile);
|
||||
|
||||
if (offset_size == 0x04 && flag != 0x00) {
|
||||
set_sounds = base_offset;
|
||||
}
|
||||
|
||||
total_sounds += set_sounds;
|
||||
if (local_target < 0 || local_target >= set_sounds)
|
||||
continue;
|
||||
|
||||
if (offset_size == 0x02) {
|
||||
sound_offset = (uint16_t)read_16bit(sound_table_offset + 0x02 * local_target, streamFile);
|
||||
if (flag != 0x00) sound_offset *= (off_t)pow(2, flag);
|
||||
sound_offset += base_offset;
|
||||
} else if (offset_size == 0x04) {
|
||||
sound_offset = read_32bit(sound_table_offset + 0x04 * local_target, streamFile);
|
||||
if (flag == 0x00) sound_offset += base_offset;
|
||||
}
|
||||
} else if (set_type == 0x04) {
|
||||
total_sounds += set_sounds;
|
||||
if (local_target < 0 || local_target >= set_sounds)
|
||||
continue;
|
||||
|
||||
sound_table_offset = read_32bit(dset_offset + 0x10, streamFile);
|
||||
sound_offset = read_32bit(sound_table_offset + 0x08 * local_target, streamFile);
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (chunk_id == 0x2E52414D) { /* ".RAM" */
|
||||
is_streamed = 0;
|
||||
} else if (chunk_id == 0x2E4F4646) { /* ".OFF" */
|
||||
is_streamed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (sound_offset == 0xFFFFFFFF)
|
||||
goto fail;
|
||||
|
||||
if (!is_streamed) {
|
||||
/* RAM asset */
|
||||
if (read_32bitBE(data_offset, streamFile) != 0x64617461) /* "data" */
|
||||
goto fail;
|
||||
|
||||
streamData = streamFile;
|
||||
sound_offset += data_offset;
|
||||
} else {
|
||||
/* streamed asset */
|
||||
sbsFile = open_streamfile_by_ext(streamFile, "sbs");
|
||||
if (!sbsFile)
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00, sbsFile) != 0x64617461) /* "data" */
|
||||
goto fail;
|
||||
|
||||
streamData = sbsFile;
|
||||
|
||||
if (read_32bitBE(sound_offset, streamData) == 0x736C6F74) {
|
||||
/* skip "slot" section */
|
||||
sound_offset += 0x30;
|
||||
}
|
||||
}
|
||||
|
||||
if (read_8bit(sound_offset, streamData) != EAAC_BLOCKID1_HEADER)
|
||||
goto fail;
|
||||
|
||||
header_offset = sound_offset + 0x04;
|
||||
start_offset = sound_offset + (read_32bitBE(sound_offset, streamData) & 0x00FFFFFF);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamData, streamData, header_offset, start_offset, meta_EA_SNR_SNS);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
vgmstream->num_streams = total_sounds;
|
||||
close_streamfile(sbsFile);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(sbsFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
||||
typedef struct {
|
||||
|
@ -562,11 +813,28 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
|||
eaac.loop_start = read_32bitBE(header_offset+0x08, streamHead);
|
||||
eaac.loop_end = eaac.num_samples;
|
||||
|
||||
/* RAM assets only have one block, even if they (rarely) set loop_start > 0 */
|
||||
if (eaac.streamed)
|
||||
if (eaac.streamed) {
|
||||
eaac.loop_offset = read_32bitBE(header_offset+0x0c, streamHead);
|
||||
else
|
||||
|
||||
if (eaac.version == EAAC_VERSION_V0) {
|
||||
/* SNR+SNS are separate so offsets are relative to the data start
|
||||
* (first .SNS block, or extra data before the .SNS block in case of .SNU) */
|
||||
eaac.loop_offset = eaac.stream_offset + eaac.loop_offset;
|
||||
} else {
|
||||
/* SPS have headers+data together so offsets are relative to the file start [ex. FIFA 18 (PC)] */
|
||||
eaac.loop_offset = header_offset - 0x04 + eaac.loop_offset;
|
||||
}
|
||||
}
|
||||
else if (eaac.loop_start > 0) {
|
||||
/* RAM assets have two blocks in case of actual loops */
|
||||
/* find the second block by getting the first block size */
|
||||
eaac.loop_offset = read_32bitBE(eaac.stream_offset, streamData) & 0x00FFFFF;
|
||||
eaac.loop_offset = eaac.stream_offset + eaac.loop_offset;
|
||||
}
|
||||
else {
|
||||
/* RAM assets only one block in case in case of full loops */
|
||||
eaac.loop_offset = eaac.stream_offset; /* implicit */
|
||||
}
|
||||
|
||||
//todo EATrax has extra values in header, which would coexist with loop values
|
||||
if (eaac.codec == EAAC_CODEC_EATRAX) {
|
||||
|
@ -621,7 +889,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
|||
case EAAC_CODEC_EAXMA: { /* "EXm0": EA-XMA [Dante's Inferno (X360)] */
|
||||
|
||||
/* special (if hacky) loop handling, see comments */
|
||||
if (eaac.streamed && eaac.loop_start > 0) {
|
||||
if (eaac.loop_start > 0) {
|
||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamData, &eaac);
|
||||
if (!data) goto fail;
|
||||
vgmstream->layout_data = data;
|
||||
|
@ -640,7 +908,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
|||
#endif
|
||||
|
||||
case EAAC_CODEC_XAS: /* "Xas1": EA-XAS [Dead Space (PC/PS3)] */
|
||||
vgmstream->coding_type = coding_EA_XAS;
|
||||
vgmstream->coding_type = coding_EA_XAS_V1;
|
||||
vgmstream->layout_type = layout_blocked_ea_sns;
|
||||
break;
|
||||
|
||||
|
@ -658,7 +926,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
|||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||
|
||||
/* special (if hacky) loop handling, see comments */
|
||||
if (eaac.streamed && eaac.loop_start > 0) {
|
||||
if (eaac.loop_start > 0) {
|
||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamData, &eaac);
|
||||
if (!data) goto fail;
|
||||
vgmstream->layout_data = data;
|
||||
|
@ -785,7 +1053,7 @@ static size_t get_snr_size(STREAMFILE *streamFile, off_t offset) {
|
|||
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *streamData, eaac_header *eaac) {
|
||||
segmented_layout_data *data = NULL;
|
||||
STREAMFILE* temp_streamFile[2] = {0};
|
||||
off_t offsets[2] = { eaac->stream_offset, eaac->stream_offset + eaac->loop_offset };
|
||||
off_t offsets[2] = { eaac->stream_offset, eaac->loop_offset };
|
||||
int num_samples[2] = { eaac->loop_start, eaac->num_samples - eaac->loop_start};
|
||||
int segment_count = 2; /* intro/loop */
|
||||
int i;
|
||||
|
|
|
@ -115,11 +115,12 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) {
|
|||
|
||||
/* check extension */
|
||||
/* they don't seem enforced by EA's tools but usually:
|
||||
* .asf: ~early [ex. Need for Speed (PC)]
|
||||
* .asf: ~early (audio stream file?) [ex. Need for Speed (PC)]
|
||||
* .lasf: fake for plugins
|
||||
* .str: ~early [ex. FIFA 2002 (PS1)]
|
||||
* .eam: ~mid (fake?)
|
||||
* .exa: ~mid [ex. 007 - From Russia with Love]
|
||||
* .sng: ~late (fake?)
|
||||
* .sng: ~late (FIFA games)
|
||||
* .aud: ~late [ex. FIFA 14 (3DS)]
|
||||
* .strm: MySims Kingdom (Wii)
|
||||
* .stm: FIFA 12 (3DS)
|
||||
|
@ -129,7 +130,7 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) {
|
|||
* .gsf: 007 - Everything or Nothing (GC)
|
||||
* .mus: map/mpf+mus only?
|
||||
* (extensionless): SSX (PS2) (inside .big) */
|
||||
if (!check_extensions(streamFile,"asf,str,eam,exa,sng,aud,sx,xa,strm,stm,hab,xsf,gsf,mus,"))
|
||||
if (!check_extensions(streamFile,"asf,lasf,str,eam,exa,sng,aud,sx,xa,strm,stm,hab,xsf,gsf,mus,"))
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
|
@ -187,15 +188,16 @@ fail:
|
|||
/* streamed assets are stored externally in AST file (mostly seen in earlier 6th-gen games) */
|
||||
VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
|
||||
int bnk_target_stream, is_dupe, total_sounds = 0, target_stream = streamFile->stream_index;
|
||||
off_t bnk_offset, header_table_offset, base_offset, value_offset, table_offset, entry_offset, target_entry_offset, schl_offset;
|
||||
off_t bnk_offset, header_table_offset, base_offset, value_offset, table_offset, entry_offset, target_entry_offset, schl_offset, schl_loop_offset;
|
||||
uint32_t i, j, k, num_sounds, total_sound_tables;
|
||||
uint16_t num_tables;
|
||||
uint8_t sound_type, num_entries;
|
||||
off_t sound_table_offsets[0x2000];
|
||||
STREAMFILE * astData = NULL;
|
||||
VGMSTREAM * vgmstream;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*);
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*);
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
segmented_layout_data *data_s = NULL;
|
||||
int32_t(*read_32bit)(off_t, STREAMFILE*);
|
||||
int16_t(*read_16bit)(off_t, STREAMFILE*);
|
||||
|
||||
/* check extension */
|
||||
if (!check_extensions(streamFile, "abk"))
|
||||
|
@ -205,7 +207,7 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
|
|||
goto fail;
|
||||
|
||||
/* use table offset to check endianness */
|
||||
if (guess_endianness32bit(0x1C,streamFile)) {
|
||||
if (guess_endianness32bit(0x1C, streamFile)) {
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
} else {
|
||||
|
@ -240,10 +242,8 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
|
|||
|
||||
/* For some reason, there are duplicate entries pointing at the same sound tables */
|
||||
is_dupe = 0;
|
||||
for (k = 0; k < total_sound_tables; k++)
|
||||
{
|
||||
if (table_offset==sound_table_offsets[k])
|
||||
{
|
||||
for (k = 0; k < total_sound_tables; k++) {
|
||||
if (table_offset == sound_table_offsets[k]) {
|
||||
is_dupe = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -278,45 +278,85 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
|
|||
if (target_entry_offset == 0)
|
||||
goto fail;
|
||||
|
||||
/* 0x00: type (0x00 - normal, 0x01 - streamed, 0x02 - streamed and prefetched(?) */
|
||||
/* 0x00: type (0x00 - normal, 0x01 - streamed, 0x02 - streamed looped */
|
||||
/* 0x01: ??? */
|
||||
/* 0x04: index for normal sounds, offset for streamed sounds */
|
||||
/* 0x08: offset for prefetched sounds */
|
||||
/* 0x08: loop offset for streamed sounds */
|
||||
sound_type = read_8bit(target_entry_offset + 0x00, streamFile);
|
||||
|
||||
|
||||
switch (sound_type) {
|
||||
case 0x00:
|
||||
if (!bnk_offset)
|
||||
goto fail;
|
||||
case 0x00:
|
||||
if (!bnk_offset)
|
||||
goto fail;
|
||||
|
||||
bnk_target_stream = read_32bit(target_entry_offset + 0x04, streamFile) + 1;
|
||||
vgmstream = parse_bnk_header(streamFile, bnk_offset, bnk_target_stream, 1);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
break;
|
||||
bnk_target_stream = read_32bit(target_entry_offset + 0x04, streamFile) + 1;
|
||||
vgmstream = parse_bnk_header(streamFile, bnk_offset, bnk_target_stream, 1);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
astData = open_streamfile_by_ext(streamFile, "ast");
|
||||
if (!astData)
|
||||
goto fail;
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
astData = open_streamfile_by_ext(streamFile, "ast");
|
||||
if (!astData)
|
||||
goto fail;
|
||||
|
||||
if (sound_type == 0x01)
|
||||
schl_offset = read_32bit(target_entry_offset + 0x04, streamFile);
|
||||
else
|
||||
schl_offset = read_32bit(target_entry_offset + 0x08, streamFile);
|
||||
if (read_32bitBE(schl_offset, astData) != EA_BLOCKID_HEADER)
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(schl_offset, astData) != EA_BLOCKID_HEADER)
|
||||
vgmstream = parse_schl_block(astData, schl_offset, 0);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
astData = open_streamfile_by_ext(streamFile, "ast");
|
||||
if (!astData)
|
||||
goto fail;
|
||||
|
||||
/* looped sounds basically consist of two independent segments
|
||||
* the first one is loop start, the second one is loop body */
|
||||
schl_offset = read_32bit(target_entry_offset + 0x04, streamFile);
|
||||
schl_loop_offset = read_32bit(target_entry_offset + 0x08, streamFile);
|
||||
|
||||
if (read_32bitBE(schl_offset, astData) != EA_BLOCKID_HEADER ||
|
||||
read_32bitBE(schl_loop_offset, astData) != EA_BLOCKID_HEADER)
|
||||
goto fail;
|
||||
|
||||
/* init layout */
|
||||
data_s = init_layout_segmented(2);
|
||||
if (!data_s) goto fail;
|
||||
|
||||
/* load intro and loop segments */
|
||||
data_s->segments[0] = parse_schl_block(astData, schl_offset, 0);
|
||||
if (!data_s->segments[0]) goto fail;
|
||||
data_s->segments[1] = parse_schl_block(astData, schl_loop_offset, 0);
|
||||
if (!data_s->segments[1]) goto fail;
|
||||
|
||||
/* setup segmented VGMSTREAMs */
|
||||
if (!setup_layout_segmented(data_s))
|
||||
goto fail;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(data_s->segments[0]->channels, 1);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = data_s->segments[0]->sample_rate;
|
||||
vgmstream->num_samples = data_s->segments[0]->num_samples + data_s->segments[1]->num_samples;
|
||||
vgmstream->loop_start_sample = data_s->segments[0]->num_samples;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->meta_type = meta_EA_SCHL;
|
||||
vgmstream->coding_type = data_s->segments[0]->coding_type;
|
||||
vgmstream->layout_type = layout_segmented;
|
||||
vgmstream->layout_data = data_s;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
|
||||
vgmstream = parse_schl_block(astData, schl_offset, 0);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
vgmstream->num_streams = total_sounds;
|
||||
|
@ -325,6 +365,7 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
|
|||
|
||||
fail:
|
||||
close_streamfile(astData);
|
||||
free_layout_segmented(data_s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -344,7 +385,7 @@ VGMSTREAM * init_vgmstream_ea_hdr_dat(STREAMFILE *streamFile) {
|
|||
/* 0x05: number of files */
|
||||
/* 0x06: ??? */
|
||||
/* 0x07: offset multiplier flag */
|
||||
/* 0x08: combined size of all sounds without padding divided by 0x0100 */
|
||||
/* 0x08: combined size of all sounds without padding divided by offset mult */
|
||||
/* 0x0C: table start */
|
||||
|
||||
/* no nice way to validate these so we do what we can */
|
||||
|
@ -358,14 +399,14 @@ VGMSTREAM * init_vgmstream_ea_hdr_dat(STREAMFILE *streamFile) {
|
|||
|
||||
userdata_size = read_8bit(0x04, streamFile) & 0x0F;
|
||||
total_sounds = read_8bit(0x05, streamFile);
|
||||
offset_mult = (off_t)read_8bit(0x07, streamFile) * 0x0100 + 0x0100;
|
||||
offset_mult = (uint8_t)read_8bit(0x07, streamFile) * 0x0100 + 0x0100;
|
||||
|
||||
if (target_stream == 0) target_stream = 1;
|
||||
if (target_stream < 0 || total_sounds == 0 || target_stream > total_sounds)
|
||||
goto fail;
|
||||
|
||||
/* offsets are always big endian */
|
||||
schl_offset = (off_t)read_16bitBE(0x0C + (0x02+userdata_size) * (target_stream-1), streamFile) * offset_mult;
|
||||
schl_offset = (uint16_t)read_16bitBE(0x0C + (0x02+userdata_size) * (target_stream-1), streamFile) * offset_mult;
|
||||
if (read_32bitBE(schl_offset, datFile) != EA_BLOCKID_HEADER)
|
||||
goto fail;
|
||||
|
||||
|
@ -460,7 +501,7 @@ VGMSTREAM * init_vgmstream_ea_map_mus(STREAMFILE *streamFile) {
|
|||
}
|
||||
|
||||
/*
|
||||
* 0x04: ???
|
||||
* 0x04: version
|
||||
* 0x05: intro segment
|
||||
* 0x06: number of segments
|
||||
* 0x07: userdata entry size (incorrect?)
|
||||
|
@ -548,14 +589,14 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE *streamFile) {
|
|||
if (version == 3 && sub_version == 1) { /* SSX Tricky */
|
||||
/* we need to go through the first two sections to find sound table */
|
||||
sec1_num = read_16bit(0x12, streamFile);
|
||||
sec2_size = read_8bit(0x0e, streamFile);
|
||||
sec2_size = read_8bit(0x0d, streamFile) * read_8bit(0x0e, streamFile);
|
||||
sec2_num = read_8bit(0x0f, streamFile);
|
||||
sec3_num = read_8bit(0x10, streamFile);
|
||||
sec4_num = read_8bit(0x11, streamFile);
|
||||
|
||||
/* get the last entry offset */
|
||||
section_offset = 0x24;
|
||||
entry_offset = read_16bit(section_offset + (sec1_num - 1) * 0x02, streamFile) * 0x04;
|
||||
entry_offset = (uint16_t)read_16bit(section_offset + (sec1_num - 1) * 0x02, streamFile) * 0x04;
|
||||
subentry_num = read_8bit(entry_offset + 0x0b, streamFile);
|
||||
|
||||
section_offset = entry_offset + 0x0c + subentry_num * 0x04;
|
||||
|
@ -570,14 +611,14 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE *streamFile) {
|
|||
off_mult = 0x04;
|
||||
} else if (version == 3 && sub_version == 4) { /* Harry Potter and the Chamber of Secrets */
|
||||
sec1_num = read_16bit(0x12, streamFile);
|
||||
sec2_size = read_8bit(0x0e, streamFile);
|
||||
sec2_size = read_8bit(0x0d, streamFile) * read_8bit(0x0e, streamFile);
|
||||
sec2_num = read_8bit(0x0f, streamFile);
|
||||
sec3_num = read_8bit(0x10, streamFile);
|
||||
sec4_num = read_8bit(0x11, streamFile);
|
||||
|
||||
/* get the last entry offset */
|
||||
section_offset = 0x24;
|
||||
entry_offset = read_16bit(section_offset + (sec1_num - 1) * 0x02, streamFile) * 0x04;
|
||||
entry_offset = (uint16_t)read_16bit(section_offset + (sec1_num - 1) * 0x02, streamFile) * 0x04;
|
||||
if (big_endian) {
|
||||
subentry_num = (read_32bitBE(entry_offset + 0x04, streamFile) >> 19) & 0xFF;
|
||||
} else {
|
||||
|
@ -601,7 +642,7 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE *streamFile) {
|
|||
|
||||
/* get the last entry offset */
|
||||
section_offset = 0x20;
|
||||
entry_offset = read_16bit(section_offset + (sec1_num - 1) * 0x02, streamFile) * 0x04;
|
||||
entry_offset = (uint16_t)read_16bit(section_offset + (sec1_num - 1) * 0x02, streamFile) * 0x04;
|
||||
if (big_endian) {
|
||||
subentry_num = (read_32bitBE(entry_offset + 0x04, streamFile) >> 15) & 0xFF;
|
||||
} else {
|
||||
|
@ -609,7 +650,7 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE *streamFile) {
|
|||
}
|
||||
|
||||
section_offset = entry_offset + 0x10 + subentry_num * 0x04;
|
||||
entry_offset = read_16bit(section_offset + (sec2_num - 1) * 0x02, streamFile) * 0x04;
|
||||
entry_offset = (uint16_t)read_16bit(section_offset + (sec2_num - 1) * 0x02, streamFile) * 0x04;
|
||||
if (big_endian) {
|
||||
subentry_num = (read_32bitBE(entry_offset + 0x0c, streamFile) >> 10) & 0xFF;
|
||||
} else {
|
||||
|
@ -1423,15 +1464,15 @@ static void update_ea_stream_size_and_samples(STREAMFILE* streamFile, off_t star
|
|||
multiple_schl = 1;
|
||||
}
|
||||
|
||||
/* HACK: fix num_samples for streams with multiple SCHl. Need to eventually get rid of this.
|
||||
* Get total samples by parsing block headers, needed when multiple files are stitched together.
|
||||
* Some EA files (.mus/eam/sng/etc) concat many small subfiles, used for interactive/mapped
|
||||
* music (.map/lin). Subfiles always share header, except num_samples. */
|
||||
num_samples += vgmstream->current_block_samples;
|
||||
if (vgmstream->current_block_samples > 0) {
|
||||
/* HACK: fix num_samples for streams with multiple SCHl. Need to eventually get rid of this.
|
||||
* Get total samples by parsing block headers, needed when multiple files are stitched together.
|
||||
* Some EA files (.mus/eam/sng/etc) concat many small subfiles, used for interactive/mapped
|
||||
* music (.map/lin). Subfiles always share header, except num_samples. */
|
||||
num_samples += vgmstream->current_block_samples;
|
||||
|
||||
/* Stream size is almost never provided in bank files so we have to calc it manually */
|
||||
if (vgmstream->current_block_samples != 0) {
|
||||
stream_size += vgmstream->next_block_offset - vgmstream->current_block_offset - 0x0c;
|
||||
/* Stream size is almost never provided in bank files so we have to calc it manually */
|
||||
stream_size += vgmstream->next_block_offset - vgmstream->ch[0].offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,10 @@ VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE *streamFile) {
|
|||
ea_header ea = {0};
|
||||
|
||||
|
||||
/* check extension */
|
||||
if (!check_extensions(streamFile,"asf"))
|
||||
/* checks */
|
||||
/* .asf: original
|
||||
* .lasf: fake for plugins */
|
||||
if (!check_extensions(streamFile,"asf,lasf"))
|
||||
goto fail;
|
||||
|
||||
/* check header (see ea_schl.c for more info about blocks) */
|
||||
|
|
|
@ -32,7 +32,7 @@ VGMSTREAM * init_vgmstream_fag(STREAMFILE *streamFile) {
|
|||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_FAG;
|
||||
vgmstream->sample_rate = 24000;
|
||||
vgmstream->sample_rate = 22050;
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = stream_size;
|
||||
|
||||
|
|
|
@ -6,38 +6,42 @@
|
|||
|
||||
/* known GENH types */
|
||||
typedef enum {
|
||||
PSX = 0, /* PSX ADPCM */
|
||||
XBOX = 1, /* XBOX IMA ADPCM */
|
||||
NGC_DTK = 2, /* NGC ADP/DTK ADPCM */
|
||||
PCM16BE = 3, /* 16bit big endian PCM */
|
||||
PCM16LE = 4, /* 16bit little endian PCM */
|
||||
PCM8 = 5, /* 8bit PCM */
|
||||
SDX2 = 6, /* SDX2 (3D0 games) */
|
||||
DVI_IMA = 7, /* DVI IMA ADPCM */
|
||||
MPEG = 8, /* MPEG (MP3) */
|
||||
IMA = 9, /* IMA ADPCM */
|
||||
AICA = 10, /* AICA ADPCM (dreamcast) */
|
||||
MSADPCM = 11, /* MS ADPCM (windows) */
|
||||
NGC_DSP = 12, /* NGC DSP (GC) */
|
||||
PCM8_U_int = 13, /* 8bit unsigned PCM (interleaved) */
|
||||
PSX_bf = 14, /* PSX ADPCM bad flagged */
|
||||
MS_IMA = 15, /* Microsoft IMA ADPCM */
|
||||
PCM8_U = 16, /* 8bit unsigned PCM */
|
||||
APPLE_IMA4 = 17, /* Apple Quicktime 4-bit IMA ADPCM */
|
||||
ATRAC3 = 18, /* raw ATRAC3 */
|
||||
ATRAC3PLUS = 19, /* raw ATRAC3PLUS */
|
||||
XMA1 = 20, /* raw XMA1 */
|
||||
XMA2 = 21, /* raw XMA2 */
|
||||
FFMPEG = 22, /* any headered FFmpeg format */
|
||||
AC3 = 23, /* AC3/SPDIF */
|
||||
PCFX = 24, /* PC-FX ADPCM */
|
||||
PSX = 0, /* PS-ADPCM */
|
||||
XBOX = 1, /* XBOX IMA ADPCM */
|
||||
NGC_DTK = 2, /* NGC ADP/DTK ADPCM */
|
||||
PCM16BE = 3, /* 16-bit big endian PCM */
|
||||
PCM16LE = 4, /* 16-bit little endian PCM */
|
||||
PCM8 = 5, /* 8-bit PCM */
|
||||
SDX2 = 6, /* SDX2 (3D0 games) */
|
||||
DVI_IMA = 7, /* DVI IMA ADPCM (high nibble first) */
|
||||
MPEG = 8, /* MPEG (MP3) */
|
||||
IMA = 9, /* IMA ADPCM (low nibble first) */
|
||||
AICA = 10, /* AICA ADPCM (Dreamcast games) */
|
||||
MSADPCM = 11, /* MS ADPCM (Windows games) */
|
||||
NGC_DSP = 12, /* NGC DSP (Nintendo games) */
|
||||
PCM8_U_int = 13, /* 8-bit unsigned PCM (interleaved) */
|
||||
PSX_bf = 14, /* PS-ADPCM with bad flags */
|
||||
MS_IMA = 15, /* Microsoft IMA ADPCM */
|
||||
PCM8_U = 16, /* 8-bit unsigned PCM */
|
||||
APPLE_IMA4 = 17, /* Apple Quicktime 4-bit IMA ADPCM */
|
||||
ATRAC3 = 18, /* Raw ATRAC3 */
|
||||
ATRAC3PLUS = 19, /* Raw ATRAC3PLUS */
|
||||
XMA1 = 20, /* Raw XMA1 */
|
||||
XMA2 = 21, /* Raw XMA2 */
|
||||
FFMPEG = 22, /* Any headered FFmpeg format */
|
||||
AC3 = 23, /* AC3/SPDIF */
|
||||
PCFX = 24, /* PC-FX ADPCM */
|
||||
PCM4 = 25, /* 4-bit signed PCM (3rd and 4th gen games) */
|
||||
PCM4_U = 26, /* 4-bit unsigned PCM (3rd and 4th gen games) */
|
||||
OKI16 = 27, /* OKI ADPCM with 16-bit output (unlike OKI/VOX/Dialogic ADPCM's 12-bit) */
|
||||
} genh_type;
|
||||
|
||||
typedef struct {
|
||||
genh_type codec;
|
||||
int codec_mode;
|
||||
size_t interleave;
|
||||
|
||||
size_t interleave;
|
||||
size_t interleave_last;
|
||||
int channels;
|
||||
int32_t sample_rate;
|
||||
|
||||
|
@ -114,6 +118,9 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
|||
case FFMPEG: coding = coding_FFmpeg; break;
|
||||
#endif
|
||||
case PCFX: coding = coding_PCFX; break;
|
||||
case PCM4: coding = coding_PCM4; break;
|
||||
case PCM4_U: coding = coding_PCM4_U; break;
|
||||
case OKI16: coding = coding_OKI16; break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
@ -137,6 +144,8 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
|||
case coding_PCM16BE:
|
||||
case coding_PCM8:
|
||||
case coding_PCM8_U:
|
||||
case coding_PCM4:
|
||||
case coding_PCM4_U:
|
||||
case coding_SDX2:
|
||||
case coding_PSX:
|
||||
case coding_PSX_badflags:
|
||||
|
@ -145,6 +154,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
|||
case coding_AICA:
|
||||
case coding_APPLE_IMA4:
|
||||
vgmstream->interleave_block_size = genh.interleave;
|
||||
vgmstream->interleave_last_block_size = genh.interleave_last;
|
||||
if (vgmstream->channels > 1)
|
||||
{
|
||||
if (coding == coding_SDX2) {
|
||||
|
@ -185,15 +195,24 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
|||
}
|
||||
}
|
||||
|
||||
if (coding == coding_PCM4 || coding == coding_PCM4_U) {
|
||||
/* high nibble or low nibble first */
|
||||
vgmstream->codec_config = genh.codec_mode;
|
||||
}
|
||||
break;
|
||||
|
||||
case coding_PCFX:
|
||||
vgmstream->interleave_block_size = genh.interleave;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_last_block_size = genh.interleave_last;
|
||||
if (genh.codec_mode >= 0 && genh.codec_mode <= 3)
|
||||
vgmstream->codec_config = genh.codec_mode;
|
||||
break;
|
||||
|
||||
case coding_OKI16:
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
|
||||
case coding_MS_IMA:
|
||||
if (!genh.interleave) goto fail; /* creates garbage */
|
||||
|
||||
|
@ -211,11 +230,13 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
|||
if (genh.codec_mode == 1) { /* mono interleave */
|
||||
coding = coding_XBOX_IMA_int;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_last_block_size = genh.interleave_last;
|
||||
vgmstream->interleave_block_size = genh.interleave;
|
||||
}
|
||||
else { /* 1ch mono, or stereo interleave */
|
||||
vgmstream->layout_type = genh.interleave ? layout_interleave : layout_none;
|
||||
vgmstream->interleave_block_size = genh.interleave;
|
||||
vgmstream->interleave_last_block_size = genh.interleave_last;
|
||||
if (vgmstream->channels > 2 && vgmstream->channels % 2 != 0)
|
||||
goto fail; /* only 2ch+..+2ch layout is known */
|
||||
}
|
||||
|
@ -229,6 +250,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
|||
if (!genh.interleave) goto fail;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = genh.interleave;
|
||||
vgmstream->interleave_last_block_size = genh.interleave_last;
|
||||
} else if (genh.coef_interleave_type == 1) {
|
||||
if (!genh.interleave) goto fail;
|
||||
coding = coding_NGC_DSP_subint;
|
||||
|
@ -403,8 +425,8 @@ static int parse_genh(STREAMFILE * streamFile, genh_header * genh) {
|
|||
genh->coef_split_spacing = read_32bitLE(0x38,streamFile);
|
||||
}
|
||||
|
||||
/* extended fields */
|
||||
if (header_size >= 0x54) {
|
||||
/* extended + reserved fields */
|
||||
if (header_size >= 0x100) {
|
||||
genh->num_samples = read_32bitLE(0x40,streamFile);
|
||||
genh->skip_samples = read_32bitLE(0x44,streamFile); /* for FFmpeg based codecs */
|
||||
genh->skip_samples_mode = read_8bit(0x48,streamFile); /* 0=autodetect, 1=force manual value @ 0x44 */
|
||||
|
@ -414,6 +436,7 @@ static int parse_genh(STREAMFILE * streamFile, genh_header * genh) {
|
|||
if ((genh->codec == XMA1 || genh->codec == XMA2) && genh->codec_mode==0)
|
||||
genh->codec_mode = read_8bit(0x4a,streamFile);
|
||||
genh->data_size = read_32bitLE(0x50,streamFile);
|
||||
genh->interleave_last = read_32bitLE(0x54,streamFile);
|
||||
}
|
||||
|
||||
if (genh->data_size == 0)
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .gin - EA engine sounds [Need for Speed: Most Wanted (multi)] */
|
||||
VGMSTREAM * init_vgmstream_gin(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count, sample_rate, num_samples;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "gin"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) != 0x476E7375) /* "Gnsu" */
|
||||
goto fail;
|
||||
|
||||
/* contains mapped values for engine RPM sounds but we'll just play the whole thing */
|
||||
/* 0x04: size? "20\00\00"? */
|
||||
/* 0x08/0c: min/max float RPM? */
|
||||
/* 0x10: RPM up? (pitch/frequency) table size */
|
||||
/* 0x14: RPM ??? table size */
|
||||
/* always LE even on X360/PS3 */
|
||||
|
||||
num_samples = read_32bitLE(0x18, streamFile);
|
||||
sample_rate = read_32bitLE(0x1c, streamFile);
|
||||
start_offset = 0x20 +
|
||||
(read_32bitLE(0x10, streamFile) + 1) * 0x04 +
|
||||
(read_32bitLE(0x14, streamFile) + 1) * 0x04;
|
||||
channel_count = 1;
|
||||
loop_flag = 0;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_GIN;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_EA_XAS_V0;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x13;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -472,8 +472,6 @@ VGMSTREAM * init_vgmstream_ps2_msa(STREAMFILE* streamFile);
|
|||
|
||||
VGMSTREAM * init_vgmstream_ps2_voi(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_khv(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_rkv(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_p3d(STREAMFILE* streamFile);
|
||||
|
@ -511,6 +509,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE* streamFile);
|
|||
VGMSTREAM * init_vgmstream_ngc_nst_dsp(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_baf(STREAMFILE* streamFile);
|
||||
VGMSTREAM * init_vgmstream_baf_badrip(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE* streamFile);
|
||||
|
||||
|
@ -679,9 +678,11 @@ VGMSTREAM * init_vgmstream_vxn(STREAMFILE * streamFile);
|
|||
VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_sps(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_abk_new(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_abk_eaac(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_mpf_mus_new(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_sbr_harmony(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_vid1(STREAMFILE * streamFile);
|
||||
|
||||
|
@ -823,4 +824,6 @@ VGMSTREAM * init_vgmstream_imc_container(STREAMFILE * streamFile);
|
|||
|
||||
VGMSTREAM * init_vgmstream_smp(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_gin(STREAMFILE * streamFile);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
|
|
@ -174,7 +174,13 @@ VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile) {
|
|||
loop_end_offset = loop_end * 0x10;
|
||||
}
|
||||
#endif
|
||||
if (loop_end <= body_size / 0x70 && coding_type == coding_PCM16LE) { /* close to body_size */
|
||||
if (loop_end <= body_size / 0x200 && coding_type == coding_PCM16LE) { /* close to body_size */
|
||||
/* Gofun-go no Sekai: loops is address * 0x200 */
|
||||
loop_flag = 1;
|
||||
loop_start_offset = loop_start * 0x200;
|
||||
loop_end_offset = loop_end * 0x200;
|
||||
}
|
||||
else if (loop_end <= body_size / 0x70 && coding_type == coding_PCM16LE) { /* close to body_size */
|
||||
/* Armored Core - Nexus: loops is address * 0x70 */
|
||||
loop_flag = 1;
|
||||
loop_start_offset = loop_start * 0x70;
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* KHV (from Kingdom Hearts 2) */
|
||||
/* VAG files with custom headers */
|
||||
VGMSTREAM * init_vgmstream_ps2_khv(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
off_t start_offset;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("khv",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x56414770) /* "VAGp" */
|
||||
goto fail;
|
||||
|
||||
loop_flag = (read_32bitBE(0x14,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 = 0x60;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitBE(0x10,streamFile);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->num_samples = read_32bitBE(0x0C,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile);
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
vgmstream->meta_type = meta_PS2_KHV;
|
||||
|
||||
/* open the file for reading */
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * file;
|
||||
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file) goto fail;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = file;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=start_offset+
|
||||
vgmstream->interleave_block_size*i;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
|
@ -1,75 +1,48 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* MIC
|
||||
|
||||
PS2 MIC format is an interleaved format found in most of KOEI Games
|
||||
The header always start the long value 0x800 which is the start
|
||||
of the BGM datas.
|
||||
|
||||
2008-05-15 - Fastelbja : First version ...
|
||||
*/
|
||||
#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;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count, loop_start, loop_end, sample_rate;
|
||||
size_t interleave, block_size;
|
||||
|
||||
int loop_flag=0;
|
||||
int channel_count;
|
||||
int i;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("mic",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check Header */
|
||||
if (read_32bitLE(0x00,streamFile) != 0x800)
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "mic"))
|
||||
goto fail;
|
||||
|
||||
/* check loop */
|
||||
loop_flag = (read_32bitLE(0x14,streamFile)!=1);
|
||||
|
||||
channel_count=read_32bitLE(0x08,streamFile);
|
||||
start_offset = read_32bitLE(0x00,streamFile);
|
||||
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);
|
||||
loop_flag = (loop_start != 1);
|
||||
block_size = interleave * channel_count;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
|
||||
|
||||
/* Compression Scheme */
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->num_samples = read_32bitLE(0x10,streamFile)*14*channel_count;
|
||||
|
||||
/* Get loop point values */
|
||||
if(vgmstream->loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile)*14*channel_count;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x10,streamFile)*14*channel_count;
|
||||
}
|
||||
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x0C,streamFile);
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->meta_type = meta_PS2_MIC;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=
|
||||
(off_t)(0x800+vgmstream->interleave_block_size*i);
|
||||
}
|
||||
}
|
||||
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->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
static VGMSTREAM *parse_riff_ogg(STREAMFILE * streamFile, off_t start_offset, size_t data_size);
|
||||
#endif
|
||||
|
||||
|
||||
/* return milliseconds */
|
||||
static long parse_adtl_marker(unsigned char * marker) {
|
||||
long hh,mm,ss,ms;
|
||||
|
@ -236,6 +237,9 @@ fail:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* streamFile, riff_fmt_chunk* fmt, int fact_sample_count, off_t start_offset);
|
||||
|
||||
|
||||
VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
riff_fmt_chunk fmt = {0};
|
||||
|
@ -682,17 +686,74 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||
vgmstream->meta_type = meta_RIFF_WAVE_MWV;
|
||||
}
|
||||
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
/* UE4 uses half-interleave mono MSADPCM, try to autodetect without breaking normal MSADPCM */
|
||||
if (fmt.coding_type == coding_MSADPCM && is_ue4_msadpcm(vgmstream, streamFile, &fmt, fact_sample_count, start_offset)) {
|
||||
int ch;
|
||||
size_t half_interleave = data_size / vgmstream->channels;
|
||||
|
||||
vgmstream->coding_type = coding_MSADPCM_int;
|
||||
|
||||
/* only works with half-interleave as frame_size and interleave are merged ATM*/
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
vgmstream->ch[ch].channel_start_offset =
|
||||
vgmstream->ch[ch].offset = start_offset + half_interleave*ch;
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* UE4 MSADPCM is quite normal but has a few minor quirks we can use to detect it */
|
||||
static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* streamFile, riff_fmt_chunk* fmt, int fact_sample_count, off_t start_offset) {
|
||||
|
||||
/* stereo only */
|
||||
if (fmt->channel_count != 2)
|
||||
goto fail;
|
||||
|
||||
/* UE4 class is "ADPCM", assume it's the extension too */
|
||||
if (!check_extensions(streamFile, "adpcm"))
|
||||
goto fail;
|
||||
|
||||
/* UE4 encoder doesn't add "fact" */
|
||||
if (fact_sample_count != 0)
|
||||
goto fail;
|
||||
|
||||
/* fixed block size */
|
||||
if (fmt->block_size != 0x200)
|
||||
goto fail;
|
||||
|
||||
/* later UE4 versions use 0x36 (at 0x32 may be fact_samples?) */
|
||||
if (fmt->size != 0x32 && fmt->size != 0x36)
|
||||
goto fail;
|
||||
|
||||
/* size 0x32 in older UE4 matches standard MSADPCM, so add extra detection */
|
||||
if (fmt->size == 0x32) {
|
||||
off_t offset = start_offset;
|
||||
off_t max_offset = 5 * fmt->block_size; /* try N blocks */
|
||||
if (max_offset > get_streamfile_size(streamFile))
|
||||
max_offset = get_streamfile_size(streamFile);
|
||||
|
||||
/* their encoder doesn't calculate optimal coefs and uses fixed values every frame
|
||||
* (could do it for fmt size 0x36 too but maybe they'll fix it in the future) */
|
||||
while (offset <= max_offset) {
|
||||
if (read_8bit(offset+0x00, streamFile) != 0 || read_16bitLE(offset+0x01, streamFile) != 0x00E6)
|
||||
goto fail;
|
||||
offset += fmt->block_size;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
riff_fmt_chunk fmt = {0};
|
||||
|
|
|
@ -1,81 +1,61 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* SD9 (found in beatmaniaIIDX16 - EMPRESS (Arcade) */
|
||||
/* SD9 (found in beatmania IIDX Arcade games) */
|
||||
VGMSTREAM * init_vgmstream_sd9(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("sd9",filename_extension(filename))) goto fail;
|
||||
/* check extension */
|
||||
if (!check_extensions(streamFile, "sd9"))
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x0,streamFile) != 0x53443900) /* SD9 */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x20,streamFile) != 0x52494646) /* RIFF */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x28,streamFile) != 0x57415645) /* WAVE */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x2c,streamFile) != 0x666D7420) /* fmt */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x72,streamFile) != 0x64617461) /* data */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x0, streamFile) != 0x53443900) /* SD9 */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x20, streamFile) != 0x52494646) /* RIFF */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x28, streamFile) != 0x57415645) /* WAVE */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x2c, streamFile) != 0x666D7420) /* fmt */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x72, streamFile) != 0x64617461) /* data */
|
||||
goto fail;
|
||||
|
||||
loop_flag = (read_16bitLE(0x0e,streamFile)==0x1);
|
||||
channel_count = read_16bitLE(0x36,streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
/* Probably better to check if loop end exists and use as loop flag.
|
||||
Blame SD9s from beatmania IIDX 21: Spada that have a flase flag
|
||||
but still "loop" */
|
||||
|
||||
//loop_flag = (read_16bitLE(0x0e,streamFile)==0x1);
|
||||
loop_flag = read_32bitLE(0x18, streamFile); // use loop end
|
||||
channel_count = read_16bitLE(0x36, streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x7a;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x38,streamFile);
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x38, streamFile);
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->num_samples = read_32bitLE(0x6e,streamFile);
|
||||
if (loop_flag) {
|
||||
if (read_16bitLE(0x1C,streamFile)==1)
|
||||
{
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile)/2/channel_count;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x18,streamFile)/2/channel_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
vgmstream->num_samples = read_32bitLE(0x6e, streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x14, streamFile) / 2 / channel_count;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x18, streamFile) / 2 / channel_count;
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = read_16bitLE(0x40,streamFile);
|
||||
vgmstream->interleave_block_size = read_16bitLE(0x40, streamFile);
|
||||
vgmstream->meta_type = meta_SD9;
|
||||
|
||||
/* open the file for reading */
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * file;
|
||||
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file) goto fail;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = file;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=start_offset+
|
||||
vgmstream->interleave_block_size*i;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return vgmstream;
|
||||
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
/* clean up anything we may have opened */
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
}
|
|
@ -6,31 +6,34 @@
|
|||
|
||||
/* known TXTH types */
|
||||
typedef enum {
|
||||
PSX = 0, /* PSX ADPCM */
|
||||
XBOX = 1, /* XBOX IMA ADPCM */
|
||||
NGC_DTK = 2, /* NGC ADP/DTK ADPCM */
|
||||
PCM16BE = 3, /* 16bit big endian PCM */
|
||||
PCM16LE = 4, /* 16bit little endian PCM */
|
||||
PCM8 = 5, /* 8bit PCM */
|
||||
SDX2 = 6, /* SDX2 (3D0 games) */
|
||||
DVI_IMA = 7, /* DVI IMA ADPCM */
|
||||
MPEG = 8, /* MPEG (MP3) */
|
||||
IMA = 9, /* IMA ADPCM */
|
||||
AICA = 10, /* AICA ADPCM (dreamcast) */
|
||||
MSADPCM = 11, /* MS ADPCM (windows) */
|
||||
NGC_DSP = 12, /* NGC DSP (GC) */
|
||||
PCM8_U_int = 13, /* 8bit unsigned PCM (interleaved) */
|
||||
PSX_bf = 14, /* PSX ADPCM bad flagged */
|
||||
MS_IMA = 15, /* Microsoft IMA ADPCM */
|
||||
PCM8_U = 16, /* 8bit unsigned PCM */
|
||||
APPLE_IMA4 = 17, /* Apple Quicktime 4-bit IMA ADPCM */
|
||||
ATRAC3 = 18, /* raw ATRAC3 */
|
||||
ATRAC3PLUS = 19, /* raw ATRAC3PLUS */
|
||||
XMA1 = 20, /* raw XMA1 */
|
||||
XMA2 = 21, /* raw XMA2 */
|
||||
FFMPEG = 22, /* any headered FFmpeg format */
|
||||
AC3 = 23, /* AC3/SPDIF */
|
||||
PCFX = 24, /* PC-FX ADPCM */
|
||||
PSX = 0, /* PS-ADPCM */
|
||||
XBOX = 1, /* XBOX IMA ADPCM */
|
||||
NGC_DTK = 2, /* NGC ADP/DTK ADPCM */
|
||||
PCM16BE = 3, /* 16-bit big endian PCM */
|
||||
PCM16LE = 4, /* 16-bit little endian PCM */
|
||||
PCM8 = 5, /* 8-bit PCM */
|
||||
SDX2 = 6, /* SDX2 (3D0 games) */
|
||||
DVI_IMA = 7, /* DVI IMA ADPCM (high nibble first) */
|
||||
MPEG = 8, /* MPEG (MP3) */
|
||||
IMA = 9, /* IMA ADPCM (low nibble first) */
|
||||
AICA = 10, /* AICA ADPCM (Dreamcast games) */
|
||||
MSADPCM = 11, /* MS ADPCM (Windows games) */
|
||||
NGC_DSP = 12, /* NGC DSP (Nintendo games) */
|
||||
PCM8_U_int = 13, /* 8-bit unsigned PCM (interleaved) */
|
||||
PSX_bf = 14, /* PS-ADPCM with bad flags */
|
||||
MS_IMA = 15, /* Microsoft IMA ADPCM */
|
||||
PCM8_U = 16, /* 8-bit unsigned PCM */
|
||||
APPLE_IMA4 = 17, /* Apple Quicktime 4-bit IMA ADPCM */
|
||||
ATRAC3 = 18, /* Raw ATRAC3 */
|
||||
ATRAC3PLUS = 19, /* Raw ATRAC3PLUS */
|
||||
XMA1 = 20, /* Raw XMA1 */
|
||||
XMA2 = 21, /* Raw XMA2 */
|
||||
FFMPEG = 22, /* Any headered FFmpeg format */
|
||||
AC3 = 23, /* AC3/SPDIF */
|
||||
PCFX = 24, /* PC-FX ADPCM */
|
||||
PCM4 = 25, /* 4-bit signed PCM (3rd and 4th gen games) */
|
||||
PCM4_U = 26, /* 4-bit unsigned PCM (3rd and 4th gen games) */
|
||||
OKI16 = 27, /* OKI ADPCM with 16-bit output (unlike OKI/VOX/Dialogic ADPCM's 12-bit) */
|
||||
} txth_type;
|
||||
|
||||
typedef struct {
|
||||
|
@ -46,6 +49,7 @@ typedef struct {
|
|||
uint32_t id_offset;
|
||||
|
||||
uint32_t interleave;
|
||||
uint32_t interleave_last;
|
||||
uint32_t channels;
|
||||
uint32_t sample_rate;
|
||||
|
||||
|
@ -176,6 +180,9 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
|||
case FFMPEG: coding = coding_FFmpeg; break;
|
||||
#endif
|
||||
case PCFX: coding = coding_PCFX; break;
|
||||
case PCM4: coding = coding_PCM4; break;
|
||||
case PCM4_U: coding = coding_PCM4_U; break;
|
||||
case OKI16: coding = coding_OKI16; break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
@ -212,6 +219,8 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
|||
case coding_PCM16BE:
|
||||
case coding_PCM8:
|
||||
case coding_PCM8_U:
|
||||
case coding_PCM4:
|
||||
case coding_PCM4_U:
|
||||
case coding_SDX2:
|
||||
case coding_PSX:
|
||||
case coding_PSX_badflags:
|
||||
|
@ -220,6 +229,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
|||
case coding_AICA:
|
||||
case coding_APPLE_IMA4:
|
||||
vgmstream->interleave_block_size = txth.interleave;
|
||||
vgmstream->interleave_last_block_size = txth.interleave_last;
|
||||
if (vgmstream->channels > 1)
|
||||
{
|
||||
if (coding == coding_SDX2) {
|
||||
|
@ -260,15 +270,25 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
|||
vgmstream->ch[i].adpcm_step_index = 0x7f;
|
||||
}
|
||||
}
|
||||
|
||||
if (coding == coding_PCM4 || coding == coding_PCM4_U) {
|
||||
/* high nibble or low nibble first */
|
||||
vgmstream->codec_config = txth.codec_mode;
|
||||
}
|
||||
break;
|
||||
|
||||
case coding_PCFX:
|
||||
vgmstream->interleave_block_size = txth.interleave;
|
||||
vgmstream->interleave_last_block_size = txth.interleave_last;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
if (txth.codec_mode >= 0 && txth.codec_mode <= 3)
|
||||
vgmstream->codec_config = txth.codec_mode;
|
||||
break;
|
||||
|
||||
case coding_OKI16:
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
|
||||
case coding_MS_IMA:
|
||||
if (!txth.interleave) goto fail; /* creates garbage */
|
||||
|
||||
|
@ -287,10 +307,12 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
|||
coding = coding_XBOX_IMA_int;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = txth.interleave;
|
||||
vgmstream->interleave_last_block_size = txth.interleave_last;
|
||||
}
|
||||
else { /* 1ch mono, or stereo interleave */
|
||||
vgmstream->layout_type = txth.interleave ? layout_interleave : layout_none;
|
||||
vgmstream->interleave_block_size = txth.interleave;
|
||||
vgmstream->interleave_last_block_size = txth.interleave_last;
|
||||
if (vgmstream->channels > 2 && vgmstream->channels % 2 != 0)
|
||||
goto fail; /* only 2ch+..+2ch layout is known */
|
||||
}
|
||||
|
@ -303,6 +325,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
|||
if (txth.channels > 1 && txth.codec_mode == 0) {
|
||||
if (!txth.interleave) goto fail;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_last_block_size = txth.interleave_last;
|
||||
vgmstream->interleave_block_size = txth.interleave;
|
||||
} else if (txth.channels > 1 && txth.codec_mode == 1) {
|
||||
if (!txth.interleave) goto fail;
|
||||
|
@ -466,8 +489,10 @@ fail:
|
|||
|
||||
|
||||
static STREAMFILE * open_txth(STREAMFILE * streamFile) {
|
||||
char basename[PATH_LIMIT];
|
||||
char filename[PATH_LIMIT];
|
||||
char fileext[PATH_LIMIT];
|
||||
const char *subext;
|
||||
STREAMFILE * streamText;
|
||||
|
||||
/* try "(path/)(name.ext).txth" */
|
||||
|
@ -476,6 +501,22 @@ static STREAMFILE * open_txth(STREAMFILE * streamFile) {
|
|||
streamText = open_streamfile(streamFile,filename);
|
||||
if (streamText) return streamText;
|
||||
|
||||
/* try "(path/)(.sub.ext).txth" */
|
||||
get_streamfile_basename(streamFile,basename,PATH_LIMIT);
|
||||
subext = filename_extension(basename);
|
||||
if (subext != NULL) {
|
||||
get_streamfile_path(streamFile,filename,PATH_LIMIT);
|
||||
get_streamfile_ext(streamFile,fileext,PATH_LIMIT);
|
||||
strcat(filename,".");
|
||||
strcat(filename, subext);
|
||||
strcat(filename,".");
|
||||
strcat(filename, fileext);
|
||||
strcat(filename, ".txth");
|
||||
|
||||
streamText = open_streamfile(streamFile,filename);
|
||||
if (streamText) return streamText;
|
||||
}
|
||||
|
||||
/* try "(path/)(.ext).txth" */
|
||||
get_streamfile_path(streamFile,filename,PATH_LIMIT);
|
||||
get_streamfile_ext(streamFile,fileext,PATH_LIMIT);
|
||||
|
@ -583,6 +624,9 @@ static int parse_keyval(STREAMFILE * streamFile_, txth_header * txth, const char
|
|||
else if (0==strcmp(val,"FFMPEG")) txth->codec = FFMPEG;
|
||||
else if (0==strcmp(val,"AC3")) txth->codec = AC3;
|
||||
else if (0==strcmp(val,"PCFX")) txth->codec = PCFX;
|
||||
else if (0==strcmp(val,"PCM4")) txth->codec = PCM4;
|
||||
else if (0==strcmp(val,"PCM4_U")) txth->codec = PCM4_U;
|
||||
else if (0==strcmp(val,"OKI16")) txth->codec = OKI16;
|
||||
else goto fail;
|
||||
}
|
||||
else if (0==strcmp(key,"codec_mode")) {
|
||||
|
@ -617,6 +661,15 @@ static int parse_keyval(STREAMFILE * streamFile_, txth_header * txth, const char
|
|||
if (!parse_num(txth->streamHead,txth,val, &txth->interleave)) goto fail;
|
||||
}
|
||||
}
|
||||
else if (0==strcmp(key,"interleave_last")) {
|
||||
if (0==strcmp(val,"auto")) {
|
||||
if (txth->channels > 0 && txth->interleave > 0)
|
||||
txth->interleave_last = (txth->data_size % (txth->interleave * txth->channels)) / txth->channels;
|
||||
}
|
||||
else {
|
||||
if (!parse_num(txth->streamHead,txth,val, &txth->interleave_last)) goto fail;
|
||||
}
|
||||
}
|
||||
else if (0==strcmp(key,"channels")) {
|
||||
if (!parse_num(txth->streamHead,txth,val, &txth->channels)) goto fail;
|
||||
}
|
||||
|
@ -863,6 +916,7 @@ static int parse_num(STREAMFILE * streamFile, txth_header * txth, const char * v
|
|||
}
|
||||
else { /* known field */
|
||||
if (0==strcmp(val,"interleave")) *out_value = txth->interleave;
|
||||
if (0==strcmp(val,"interleave_last")) *out_value = txth->interleave_last;
|
||||
else if (0==strcmp(val,"channels")) *out_value = txth->channels;
|
||||
else if (0==strcmp(val,"sample_rate")) *out_value = txth->sample_rate;
|
||||
else if (0==strcmp(val,"start_offset")) *out_value = txth->start_offset;
|
||||
|
@ -913,6 +967,9 @@ static int get_bytes_to_samples(txth_header * txth, uint32_t bytes) {
|
|||
case PCM8_U_int:
|
||||
case PCM8_U:
|
||||
return pcm_bytes_to_samples(bytes, txth->channels, 8);
|
||||
case PCM4:
|
||||
case PCM4_U:
|
||||
return pcm_bytes_to_samples(bytes, txth->channels, 4);
|
||||
case MSADPCM:
|
||||
if (!txth->interleave) return 0;
|
||||
return msadpcm_bytes_to_samples(bytes, txth->interleave, txth->channels);
|
||||
|
@ -938,7 +995,8 @@ static int get_bytes_to_samples(txth_header * txth, uint32_t bytes) {
|
|||
case AICA:
|
||||
return aica_bytes_to_samples(bytes, txth->channels);
|
||||
case PCFX:
|
||||
return pcfx_bytes_to_samples(bytes, txth->channels);
|
||||
case OKI16:
|
||||
return oki_bytes_to_samples(bytes, txth->channels);
|
||||
|
||||
/* untested */
|
||||
case SDX2:
|
||||
|
|
|
@ -32,7 +32,7 @@ typedef struct {
|
|||
int subtypes_count[9];
|
||||
} ubi_bao_header;
|
||||
|
||||
static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset);
|
||||
static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset, int target_subsong);
|
||||
static int parse_pk_header(ubi_bao_header * bao, STREAMFILE *streamFile);
|
||||
static VGMSTREAM * init_vgmstream_ubi_bao_main(ubi_bao_header * bao, STREAMFILE *streamFile);
|
||||
static STREAMFILE * setup_bao_streamfile(ubi_bao_header *bao, STREAMFILE *streamFile);
|
||||
|
@ -265,7 +265,7 @@ static int parse_pk_header(ubi_bao_header * bao, STREAMFILE *streamFile) {
|
|||
size_t index_size, index_header_size;
|
||||
off_t bao_offset, resources_offset;
|
||||
int target_subsong = streamFile->stream_index;
|
||||
uint8_t *index_buffer = NULL;
|
||||
STREAMFILE *streamIndex = NULL;
|
||||
STREAMFILE *streamTest = NULL;
|
||||
|
||||
|
||||
|
@ -274,6 +274,8 @@ static int parse_pk_header(ubi_bao_header * bao, STREAMFILE *streamFile) {
|
|||
goto fail;
|
||||
/* index and resources always LE */
|
||||
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
|
||||
/* 0x01(3): version, major/minor/release (numbering continues from .sb0/sm0) */
|
||||
index_size = read_32bitLE(0x04, streamFile); /* can be 0, not including */
|
||||
resources_offset = read_32bitLE(0x08, streamFile); /* always found even if not used */
|
||||
|
@ -294,21 +296,22 @@ static int parse_pk_header(ubi_bao_header * bao, STREAMFILE *streamFile) {
|
|||
VGM_LOG("BAO: index too big\n");
|
||||
goto fail;
|
||||
}
|
||||
index_buffer = malloc(index_size);
|
||||
read_streamfile(index_buffer, index_header_size, index_size, streamFile);
|
||||
|
||||
/* use smaller I/O buffer for performance, as this read lots of small BAO headers all over the place */
|
||||
/* use smaller I/O buffers for performance, as this read lots of small headers all over the place */
|
||||
streamIndex = reopen_streamfile(streamFile, index_size);
|
||||
if (!streamIndex) goto fail;
|
||||
|
||||
streamTest = reopen_streamfile(streamFile, 0x100);
|
||||
if (!streamTest) goto fail;
|
||||
|
||||
/* parse index to get target subsong N = Nth audio header BAO */
|
||||
bao_offset = index_header_size + index_size;
|
||||
for (i = 0; i < index_entries; i++) {
|
||||
//uint32_t bao_id = get_32bitLE(index_buffer + 0x08*i+ 0x00);
|
||||
size_t bao_size = get_32bitLE(index_buffer + 0x08*i + 0x04);
|
||||
//uint32_t bao_id = read_32bitLE(index_header_size + 0x08*i + 0x00, streamIndex);
|
||||
size_t bao_size = read_32bitLE(index_header_size + 0x08*i + 0x04, streamIndex);
|
||||
|
||||
/* parse and continue to find out total_subsongs */
|
||||
if (!parse_bao(bao, streamTest, bao_offset))
|
||||
if (!parse_bao(bao, streamTest, bao_offset, target_subsong))
|
||||
goto fail;
|
||||
|
||||
bao_offset += bao_size; /* files simply concat BAOs */
|
||||
|
@ -407,21 +410,20 @@ static int parse_pk_header(ubi_bao_header * bao, STREAMFILE *streamFile) {
|
|||
|
||||
;VGM_LOG("BAO stream: id=%x, offset=%x, size=%x, res=%s\n", bao->stream_id, (uint32_t)bao->stream_offset, bao->stream_size, (bao->is_external ? bao->resource_name : "internal"));
|
||||
|
||||
free(index_buffer);
|
||||
close_streamfile(streamIndex);
|
||||
close_streamfile(streamTest);
|
||||
return 1;
|
||||
fail:
|
||||
free(index_buffer);
|
||||
close_streamfile(streamIndex);
|
||||
close_streamfile(streamTest);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* parse a single BAO (binary audio object) descriptor */
|
||||
static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset) {
|
||||
static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset, int target_subsong) {
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
uint32_t bao_version, descriptor_type, descriptor_subtype;
|
||||
size_t header_size;
|
||||
int target_subsong = streamFile->stream_index;
|
||||
|
||||
|
||||
/* 0x00(1): class? usually 0x02 but older BAOs have 0x01 too */
|
||||
|
@ -463,11 +465,11 @@ static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset)
|
|||
/* for debugging purposes */
|
||||
switch(descriptor_subtype) {
|
||||
case 0x00000001: bao->subtypes_count[1]++; break; /* standard */
|
||||
case 0x00000002: bao->subtypes_count[2]++; break; /* multilayer??? related to other header BAOs? */
|
||||
case 0x00000002: bao->subtypes_count[2]++; break; /* related to localized BAOs? (.lpk) */
|
||||
case 0x00000003: bao->subtypes_count[3]++; break; /* related to other header BAOs? */
|
||||
case 0x00000004: bao->subtypes_count[4]++; break; /* related to other header BAOs? */
|
||||
case 0x00000005: bao->subtypes_count[5]++; break; /* related to other header BAOs? */
|
||||
case 0x00000006: bao->subtypes_count[6]++; break; /* some multilayer/table? may contain sounds??? */
|
||||
case 0x00000006: bao->subtypes_count[6]++; break; /* multilayer with multiple sounds */
|
||||
case 0x00000007: bao->subtypes_count[7]++; break; /* related to other header BAOs? */
|
||||
case 0x00000008: bao->subtypes_count[8]++; break; /* ? (almost empty with some unknown value) */
|
||||
default:
|
||||
|
@ -476,13 +478,26 @@ static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset)
|
|||
}
|
||||
//;VGM_ASSERT(descriptor_subtype != 0x01, "UBI BAO: subtype %x at %lx (%lx)\n", descriptor_subtype, offset, offset+header_size+0x04);
|
||||
|
||||
if (descriptor_subtype == 0x06) {
|
||||
;VGM_LOG("UBI BAO: layer subtype at %lx (%lx)\n", offset, offset+header_size+0x04);
|
||||
/* todo fix layers
|
||||
* for scott pilgrim:
|
||||
* - 0x50: layer count
|
||||
* - 0x78: layer headers size?
|
||||
* - 0x7c: prefetch size
|
||||
* - 0xb4: layer header xN (size 0x30)
|
||||
* (this header has sample rate, channels, codec, various sizes/num samples)
|
||||
* - 0x114: good ol' Ubi SB layer header v0x00100009 with classic v0x03 blocked data
|
||||
* (standard prefetch style, part of data then cut in the middle and links to stream)
|
||||
*/
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* ignore unknown subtypes */
|
||||
if (descriptor_subtype != 0x00000001)
|
||||
return 1;
|
||||
|
||||
bao->total_subsongs++;
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
|
||||
if (target_subsong != bao->total_subsongs)
|
||||
return 1;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,363 @@
|
|||
#ifndef _UBI_SB_STREAMFILE_H_
|
||||
#define _UBI_SB_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* config */
|
||||
off_t stream_offset;
|
||||
off_t stream_size;
|
||||
int layer_number;
|
||||
int layer_count;
|
||||
int layer_max;
|
||||
int big_endian;
|
||||
|
||||
/* internal config */
|
||||
off_t header_next_start; /* offset to header field */
|
||||
off_t header_sizes_start; /* offset to header table */
|
||||
off_t header_data_start; /* offset to header data */
|
||||
off_t block_next_start; /* offset to block field */
|
||||
off_t block_sizes_start; /* offset to block table */
|
||||
off_t block_data_start; /* offset to block data */
|
||||
size_t header_size; /* derived */
|
||||
|
||||
/* state */
|
||||
off_t logical_offset; /* fake offset */
|
||||
off_t physical_offset; /* actual offset */
|
||||
size_t block_size; /* current size */
|
||||
size_t next_block_size; /* next size */
|
||||
size_t skip_size; /* size from block start to reach data */
|
||||
size_t data_size; /* usable size in a block */
|
||||
|
||||
size_t logical_size;
|
||||
} ubi_sb_io_data;
|
||||
|
||||
|
||||
static size_t ubi_sb_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, ubi_sb_io_data* data) {
|
||||
int32_t(*read_32bit)(off_t, STREAMFILE*) = data->big_endian ? read_32bitBE : read_32bitLE;
|
||||
size_t total_read = 0;
|
||||
int i;
|
||||
|
||||
|
||||
/* re-start when previous offset (can't map logical<>physical offsets) */
|
||||
if (data->logical_offset < 0 || offset < data->logical_offset) {
|
||||
data->physical_offset = data->stream_offset;
|
||||
data->logical_offset = 0x00;
|
||||
data->data_size = 0;
|
||||
|
||||
/* process header block (slightly different and data size may be 0) */
|
||||
{
|
||||
data->block_size = data->header_size;
|
||||
data->next_block_size = read_32bit(data->physical_offset + data->header_next_start, streamfile);
|
||||
|
||||
if (data->header_sizes_start) {
|
||||
data->skip_size = data->header_data_start;
|
||||
for (i = 0; i < data->layer_number; i++) {
|
||||
data->skip_size += read_32bit(data->physical_offset + data->header_sizes_start + i*0x04, streamfile);
|
||||
}
|
||||
data->data_size = read_32bit(data->physical_offset + data->header_sizes_start + data->layer_number*0x04, streamfile);
|
||||
}
|
||||
|
||||
if (data->data_size == 0) {
|
||||
data->physical_offset += data->block_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* read blocks */
|
||||
while (length > 0) {
|
||||
|
||||
/* ignore EOF */
|
||||
if (offset < 0 || data->physical_offset >= data->stream_offset + data->stream_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* process new block */
|
||||
if (data->data_size == 0) {
|
||||
data->block_size = data->next_block_size;
|
||||
if (data->block_next_start) /* not set when fixed block size */
|
||||
data->next_block_size = read_32bit(data->physical_offset + data->block_next_start, streamfile);
|
||||
|
||||
data->skip_size = data->block_data_start;
|
||||
for (i = 0; i < data->layer_number; i++) {
|
||||
data->skip_size += read_32bit(data->physical_offset + data->block_sizes_start + i*0x04, streamfile);
|
||||
}
|
||||
data->data_size = read_32bit(data->physical_offset + data->block_sizes_start + data->layer_number*0x04, streamfile);
|
||||
}
|
||||
|
||||
/* move to next block */
|
||||
if (offset >= data->logical_offset + data->data_size) {
|
||||
if (data->block_size == 0 || data->block_size == 0xFFFFFFFF)
|
||||
break;
|
||||
data->physical_offset += data->block_size;
|
||||
data->logical_offset += data->data_size;
|
||||
data->data_size = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read data */
|
||||
{
|
||||
size_t bytes_consumed, bytes_done, to_read;
|
||||
|
||||
bytes_consumed = offset - data->logical_offset;
|
||||
to_read = data->data_size - bytes_consumed;
|
||||
if (to_read > length)
|
||||
to_read = length;
|
||||
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
|
||||
|
||||
total_read += bytes_done;
|
||||
dest += bytes_done;
|
||||
offset += bytes_done;
|
||||
length -= bytes_done;
|
||||
|
||||
if (bytes_done != to_read || bytes_done == 0) {
|
||||
break; /* error/EOF */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t ubi_sb_io_size(STREAMFILE *streamfile, ubi_sb_io_data* data) {
|
||||
uint8_t buf[1];
|
||||
|
||||
if (data->logical_size)
|
||||
return data->logical_size;
|
||||
|
||||
/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
|
||||
ubi_sb_io_read(streamfile, buf, 0x7FFFFFFF, 1, data);
|
||||
data->logical_size = data->logical_offset;
|
||||
|
||||
return data->logical_size;
|
||||
}
|
||||
|
||||
|
||||
static int ubi_sb_io_init(STREAMFILE *streamfile, ubi_sb_io_data* data) {
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = data->big_endian ? read_32bitBE : read_32bitLE;
|
||||
off_t offset = data->stream_offset;
|
||||
uint32_t version;
|
||||
int i;
|
||||
|
||||
if (data->stream_offset + data->stream_size > get_streamfile_size(streamfile)) {
|
||||
VGM_LOG("UBI SB: bad size\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Layers have a main header, then headered blocks with data.
|
||||
* We configure stuff to unify parsing of all variations. */
|
||||
version = (uint32_t)read_32bit(offset+0x00, streamfile);
|
||||
switch(version) {
|
||||
case 0x00000002: /* Splinter Cell */
|
||||
/* - layer header
|
||||
* 0x04: layer count
|
||||
* 0x08: stream size
|
||||
* 0x0c: block header size
|
||||
* 0x10: block size (fixed)
|
||||
* 0x14: min layer size?
|
||||
* - block header
|
||||
* 0x00: block number
|
||||
* 0x04: block offset
|
||||
* 0x08+(04*N): layer size per layer
|
||||
* 0xNN: layer data per layer */
|
||||
data->layer_max = read_32bit(offset+0x04, streamfile);
|
||||
|
||||
data->header_next_start = 0x10;
|
||||
data->header_sizes_start = 0;
|
||||
data->header_data_start = 0x18;
|
||||
|
||||
data->block_next_start = 0;
|
||||
data->block_sizes_start = 0x08;
|
||||
data->block_data_start = 0x08 + data->layer_max*0x04;
|
||||
break;
|
||||
|
||||
case 0x00000004: /* Prince of Persia: Sands of Time, Batman: Rise of Sin Tzu */
|
||||
/* - layer header
|
||||
* 0x04: layer count
|
||||
* 0x08: stream size
|
||||
* 0x0c: block count
|
||||
* 0x10: block header size
|
||||
* 0x14: block size (fixed)
|
||||
* 0x18: min layer data?
|
||||
* 0x1c: size of header sizes
|
||||
* 0x20+(04*N): header size per layer
|
||||
* - block header
|
||||
* 0x00: block number
|
||||
* 0x04: block offset
|
||||
* 0x08: always 0x03
|
||||
* 0x0c+(04*N): layer size per layer
|
||||
* 0xNN: layer data per layer */
|
||||
data->layer_max = read_32bit(offset+0x04, streamfile);
|
||||
|
||||
data->header_next_start = 0x14;
|
||||
data->header_sizes_start = 0x20;
|
||||
data->header_data_start = 0x20 + data->layer_max*0x04;
|
||||
|
||||
data->block_next_start = 0;
|
||||
data->block_sizes_start = 0x0c;
|
||||
data->block_data_start = 0x0c + data->layer_max*0x04;
|
||||
break;
|
||||
|
||||
case 0x00000007: /* Splinter Cell: Essentials, Splinter Cell 3D */
|
||||
/* - layer header
|
||||
* 0x04: config?
|
||||
* 0x08: layer count
|
||||
* 0x0c: stream size
|
||||
* 0x10: block count
|
||||
* 0x14: block header size
|
||||
* 0x18: block size (fixed)
|
||||
* 0x1c+(04*8): min layer data? for 8 layers (-1 after layer count)
|
||||
* 0x3c: size of header sizes
|
||||
* 0x40+(04*N): header size per layer
|
||||
* 0xNN: header data per layer
|
||||
* - block header
|
||||
* 0x00: block number
|
||||
* 0x04: block offset
|
||||
* 0x08: always 0x03
|
||||
* 0x0c+(04*N): layer size per layer
|
||||
* 0xNN: layer data per layer */
|
||||
data->layer_max = read_32bit(offset+0x08, streamfile);
|
||||
|
||||
data->header_next_start = 0x18;
|
||||
data->header_sizes_start = 0x40;
|
||||
data->header_data_start = 0x40 + data->layer_max*0x04;
|
||||
|
||||
data->block_next_start = 0;
|
||||
data->block_sizes_start = 0x0c;
|
||||
data->block_data_start = 0x0c + data->layer_max*0x04;
|
||||
break;
|
||||
|
||||
case 0x00040008: /* Assassin's Creed */
|
||||
case 0x000B0008: /* Open Season, Surf's Up, TMNT, Splinter Cell HD */
|
||||
case 0x000C0008: /* Splinter Cell: Double Agent */
|
||||
case 0x00100008: /* Rainbow Six 2 */
|
||||
/* - layer header
|
||||
* 0x04: config?
|
||||
* 0x08: layer count
|
||||
* 0x0c: blocks count
|
||||
* 0x10: block header size
|
||||
* 0x14: size of header sizes/data
|
||||
* 0x18: next block size
|
||||
* 0x1c+(04*N): layer header size
|
||||
* 0xNN: header data per layer
|
||||
* - block header:
|
||||
* 0x00: always 0x03
|
||||
* 0x04: next block size
|
||||
* 0x08+(04*N): layer size per layer
|
||||
* 0xNN: layer data per layer */
|
||||
data->layer_max = read_32bit(offset+0x08, streamfile);
|
||||
|
||||
data->header_next_start = 0x18;
|
||||
data->header_sizes_start = 0x1c;
|
||||
data->header_data_start = 0x1c + data->layer_max*0x04;
|
||||
|
||||
data->block_next_start = 0x04;
|
||||
data->block_sizes_start = 0x08;
|
||||
data->block_data_start = 0x08 + data->layer_max*0x04;
|
||||
break;
|
||||
|
||||
case 0x00100009: /* Splinter Cell: Pandora Tomorrow HD, Prince of Persia 2008, Scott Pilgrim */
|
||||
/* - layer header
|
||||
* 0x04: config?
|
||||
* 0x08: layer count
|
||||
* 0x0c: blocks count
|
||||
* 0x10: block header size
|
||||
* 0x14: size of header sizes/data
|
||||
* 0x18: next block size
|
||||
* 0x1c+(04*10): usable size per layer
|
||||
* 0x5c+(04*N): layer header size
|
||||
* 0xNN: header data per layer
|
||||
* - block header:
|
||||
* 0x00: always 0x03
|
||||
* 0x04: next block size
|
||||
* 0x08+(04*N): layer size per layer
|
||||
* 0xNN: layer data per layer */
|
||||
data->layer_max = read_32bit(offset+0x08, streamfile);
|
||||
|
||||
data->header_next_start = 0x18;
|
||||
data->header_sizes_start = 0x5c;
|
||||
data->header_data_start = 0x5c + data->layer_max*0x04;
|
||||
|
||||
data->block_next_start = 0x04;
|
||||
data->block_sizes_start = 0x08;
|
||||
data->block_data_start = 0x08 + data->layer_max*0x04;
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("UBI SB: unknown layer header %08x\n", version);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* get base size to simplify later parsing */
|
||||
data->header_size = data->header_data_start;
|
||||
if (data->header_sizes_start) {
|
||||
for (i = 0; i < data->layer_max; i++) {
|
||||
data->header_size += read_32bit(offset + data->header_sizes_start + i*0x04, streamfile);
|
||||
}
|
||||
}
|
||||
|
||||
/* force read header block */
|
||||
data->logical_offset = -1;
|
||||
|
||||
/* just in case some headers may use less layers that stream has */
|
||||
VGM_ASSERT(data->layer_count != data->layer_max, "UBI SB: non-matching layer counts\n");
|
||||
if (data->layer_count > data->layer_max) {
|
||||
VGM_LOG("UBI SB: layer count bigger than layer max\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Common layer quirks:
|
||||
* - layer format depends on its own version and not on platform or DARE engine version
|
||||
* - codec header may be in the layer header, or in the first block
|
||||
* - stream size doesn't include padding
|
||||
* - block number goes from 1 to block_count
|
||||
* - block offset is relative to layer start
|
||||
* - blocks data size varies between blocks and between layers in the same block
|
||||
* - "config?" is a small value that varies between streams of the same game
|
||||
* - next block size is 0 at last block
|
||||
* - both Ubi SB and Ubi BAO use same-version layers
|
||||
*/
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Handles deinterleaving of Ubisoft's headered+blocked 'multitrack' streams */
|
||||
static STREAMFILE* setup_ubi_sb_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t stream_size, int layer_number, int layer_count, int big_endian) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
ubi_sb_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(ubi_sb_io_data);
|
||||
|
||||
io_data.stream_offset = stream_offset;
|
||||
io_data.stream_size = stream_size;
|
||||
io_data.layer_number = layer_number;
|
||||
io_data.layer_count = layer_count;
|
||||
io_data.big_endian = big_endian;
|
||||
|
||||
if (!ubi_sb_io_init(streamFile, &io_data))
|
||||
goto fail;
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, ubi_sb_io_read,ubi_sb_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_buffer_streamfile(new_streamFile,0);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _UBI_SB_STREAMFILE_H_ */
|
|
@ -19,8 +19,10 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
|
|||
* .swag: Frantix (PSP)
|
||||
* .str: Ben10 Galactic Racing
|
||||
* .vig: MX vs. ATV Untamed (PS2)
|
||||
* .l/r: Crash Nitro Kart (PS2), Gradius V (PS2) */
|
||||
if ( !check_extensions(streamFile,"vag,swag,str,vig,l,r") )
|
||||
* .l/r: Crash Nitro Kart (PS2), Gradius V (PS2)
|
||||
* .vas: Kingdom Hearts II (PS2)
|
||||
* .khv: fake for .vas */
|
||||
if ( !check_extensions(streamFile,"vag,swag,str,vig,l,r,vas,khv") )
|
||||
goto fail;
|
||||
|
||||
/* check VAG Header */
|
||||
|
@ -112,7 +114,7 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
|
|||
interleave = 0x10;
|
||||
loop_flag = 0;
|
||||
}
|
||||
else if (check_extensions(streamFile,"swag")) { /* algo "VAGp" at (file_size / channels) */
|
||||
else if (check_extensions(streamFile,"swag")) { /* also "VAGp" at (file_size / channels) */
|
||||
/* Frantix (PSP) */
|
||||
start_offset = 0x40; /* channel_size ignores empty frame */
|
||||
channel_count = 2;
|
||||
|
@ -188,6 +190,19 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) {
|
|||
channel_size = channel_size / channel_count;
|
||||
loop_flag = ps_find_loop_offsets(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start_sample, &loop_end_sample);
|
||||
}
|
||||
else if (version == 0x00000004 && channel_size == file_size - 0x60 && read_32bitBE(0x1c, streamFile) != 0) { /* also .vas */
|
||||
/* Kingdom Hearts II (PS2) */
|
||||
start_offset = 0x60;
|
||||
interleave = 0x10;
|
||||
|
||||
loop_start_sample = read_32bitBE(0x14,streamFile);
|
||||
loop_end_sample = read_32bitBE(0x18,streamFile);
|
||||
loop_flag = (loop_end_sample > 0); /* maybe at 0x1d */
|
||||
channel_count = read_8bit(0x1e,streamFile);
|
||||
/* 0x1f: possibly volume */
|
||||
channel_size = channel_size / channel_count;
|
||||
/* mono files also have channel/volume, but start at 0x30 and are probably named .vag */
|
||||
}
|
||||
else {
|
||||
/* standard PS1/PS2/PS3 .vag [Ecco the Dolphin (PS2), Legasista (PS3)] */
|
||||
start_offset = 0x30;
|
||||
|
|
|
@ -22,7 +22,8 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) {
|
|||
platform = read_8bit(0x03,streamFile);
|
||||
big_endian = (platform == 'x');
|
||||
|
||||
if (read_8bit(0x04,streamFile) != 0x05) /* XNA 4.0 version only */
|
||||
if (read_8bit(0x04,streamFile) != 0x04 && /* XNA 3.0? found on Scare Me (XBLIG), no notable diffs */
|
||||
read_8bit(0x04,streamFile) != 0x05) /* XNA 4.0 version */
|
||||
goto fail;
|
||||
|
||||
flags = read_8bit(0x05,streamFile);
|
||||
|
|
|
@ -253,7 +253,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
|||
init_vgmstream_ps2_smpl,
|
||||
init_vgmstream_ps2_msa,
|
||||
init_vgmstream_ps2_voi,
|
||||
init_vgmstream_ps2_khv,
|
||||
init_vgmstream_ngc_rkv,
|
||||
init_vgmstream_dsp_ddsp,
|
||||
init_vgmstream_p3d,
|
||||
|
@ -279,6 +278,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
|||
init_vgmstream_sqex_scd,
|
||||
init_vgmstream_ngc_nst_dsp,
|
||||
init_vgmstream_baf,
|
||||
init_vgmstream_baf_badrip,
|
||||
init_vgmstream_ps3_msf,
|
||||
init_vgmstream_nub_vag,
|
||||
init_vgmstream_ps3_past,
|
||||
|
@ -375,9 +375,11 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
|||
init_vgmstream_vxn,
|
||||
init_vgmstream_ea_snr_sns,
|
||||
init_vgmstream_ea_sps,
|
||||
init_vgmstream_ea_abk_new,
|
||||
init_vgmstream_ea_abk_eaac,
|
||||
init_vgmstream_ea_hdr_sth_dat,
|
||||
init_vgmstream_ea_mpf_mus_new,
|
||||
init_vgmstream_ea_mpf_mus_eaac,
|
||||
init_vgmstream_ea_sbr,
|
||||
init_vgmstream_ea_sbr_harmony,
|
||||
init_vgmstream_ngc_vid1,
|
||||
init_vgmstream_flx,
|
||||
init_vgmstream_mogg,
|
||||
|
@ -460,6 +462,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
|||
init_vgmstream_imc,
|
||||
init_vgmstream_imc_container,
|
||||
init_vgmstream_smp,
|
||||
init_vgmstream_gin,
|
||||
|
||||
/* 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 */
|
||||
|
@ -1142,6 +1145,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
|||
case coding_SNDS_IMA:
|
||||
case coding_OTNS_IMA:
|
||||
case coding_UBI_IMA:
|
||||
case coding_OKI16:
|
||||
return 1;
|
||||
case coding_IMA_int:
|
||||
case coding_DVI_IMA_int:
|
||||
|
@ -1188,11 +1192,14 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
|||
case coding_EA_XA_V2:
|
||||
case coding_MAXIS_XA:
|
||||
return 28;
|
||||
case coding_EA_XAS:
|
||||
case coding_EA_XAS_V0:
|
||||
return 32;
|
||||
case coding_EA_XAS_V1:
|
||||
return 128;
|
||||
|
||||
case coding_MSADPCM:
|
||||
return (vgmstream->interleave_block_size - 0x07*vgmstream->channels)*2 / vgmstream->channels + 2;
|
||||
case coding_MSADPCM_int:
|
||||
case coding_MSADPCM_ck:
|
||||
return (vgmstream->interleave_block_size - 0x07)*2 + 2;
|
||||
case coding_WS: /* only works if output sample size is 8 bit, which always is for WS ADPCM */
|
||||
|
@ -1323,6 +1330,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
|||
case coding_ALP_IMA:
|
||||
case coding_FFTA2_IMA:
|
||||
case coding_PCFX:
|
||||
case coding_OKI16:
|
||||
return 0x01;
|
||||
case coding_MS_IMA:
|
||||
case coding_RAD_IMA:
|
||||
|
@ -1370,10 +1378,13 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
|||
return 0x0F*vgmstream->channels;
|
||||
case coding_EA_XA_V2:
|
||||
return 0; /* variable (ADPCM frames of 0x0f or PCM frames of 0x3d) */
|
||||
case coding_EA_XAS:
|
||||
case coding_EA_XAS_V0:
|
||||
return 0xF+0x02+0x02;
|
||||
case coding_EA_XAS_V1:
|
||||
return 0x4c*vgmstream->channels;
|
||||
|
||||
case coding_MSADPCM:
|
||||
case coding_MSADPCM_int:
|
||||
case coding_MSADPCM_ck:
|
||||
return vgmstream->interleave_block_size;
|
||||
case coding_WS:
|
||||
|
@ -1550,6 +1561,18 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
|||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_PCM4:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_pcm4(vgmstream,&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do,ch);
|
||||
}
|
||||
break;
|
||||
case coding_PCM4_U:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_pcm4_unsigned(vgmstream, &vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do,ch);
|
||||
}
|
||||
break;
|
||||
|
||||
case coding_ULAW:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
|
@ -1694,9 +1717,15 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
|||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch);
|
||||
}
|
||||
break;
|
||||
case coding_EA_XAS:
|
||||
case coding_EA_XAS_V0:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_ea_xas(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
decode_ea_xas_v0(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch);
|
||||
}
|
||||
break;
|
||||
case coding_EA_XAS_V1:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_ea_xas_v1(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch);
|
||||
}
|
||||
break;
|
||||
|
@ -1923,14 +1952,17 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
|||
buffer+samples_written*vgmstream->channels, samples_to_do);
|
||||
break;
|
||||
case coding_MSADPCM:
|
||||
if (vgmstream->channels == 2) {
|
||||
case coding_MSADPCM_int:
|
||||
if (vgmstream->channels == 1 || vgmstream->coding_type == coding_MSADPCM_int) {
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_msadpcm_mono(vgmstream,buffer+samples_written*vgmstream->channels+ch,
|
||||
vgmstream->channels,vgmstream->samples_into_block, samples_to_do, ch);
|
||||
}
|
||||
}
|
||||
else if (vgmstream->channels == 2) {
|
||||
decode_msadpcm_stereo(vgmstream,buffer+samples_written*vgmstream->channels,
|
||||
vgmstream->samples_into_block,samples_to_do);
|
||||
}
|
||||
else if (vgmstream->channels == 1) {
|
||||
decode_msadpcm_mono(vgmstream,buffer+samples_written*vgmstream->channels,
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, 0);
|
||||
}
|
||||
break;
|
||||
case coding_MSADPCM_ck:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
|
@ -2028,6 +2060,12 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
|||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, vgmstream->codec_config);
|
||||
}
|
||||
break;
|
||||
case coding_OKI16:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_oki16(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch);
|
||||
}
|
||||
break;
|
||||
|
||||
case coding_EA_MT:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
|
@ -2277,11 +2315,18 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
|||
snprintf(temp,TEMPSIZE,
|
||||
"\nlayout: ");
|
||||
concatn(length,desc,temp);
|
||||
|
||||
description = get_vgmstream_layout_description(vgmstream->layout_type);
|
||||
if (!description)
|
||||
description = "INCONCEIVABLE";
|
||||
switch (vgmstream->layout_type) {
|
||||
case layout_layered:
|
||||
snprintf(temp,TEMPSIZE,"%s (%i layers)",description, ((layered_layout_data*)vgmstream->layout_data)->layer_count);
|
||||
break;
|
||||
case layout_segmented:
|
||||
snprintf(temp,TEMPSIZE,"%s (%i segments)",description, ((segmented_layout_data*)vgmstream->layout_data)->segment_count);
|
||||
break;
|
||||
default:
|
||||
description = get_vgmstream_layout_description(vgmstream->layout_type);
|
||||
if (!description)
|
||||
description = "INCONCEIVABLE";
|
||||
snprintf(temp,TEMPSIZE,"%s",description);
|
||||
break;
|
||||
}
|
||||
|
@ -2309,6 +2354,7 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
|||
if (vgmstream->layout_type == layout_none && vgmstream->interleave_block_size > 0) {
|
||||
switch (vgmstream->coding_type) {
|
||||
case coding_MSADPCM:
|
||||
case coding_MSADPCM_int:
|
||||
case coding_MSADPCM_ck:
|
||||
case coding_MS_IMA:
|
||||
case coding_MC3:
|
||||
|
@ -2723,14 +2769,13 @@ int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t s
|
|||
if (!file) goto fail;
|
||||
}
|
||||
|
||||
for (ch=0; ch < vgmstream->channels; ch++) {
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
off_t offset;
|
||||
if (use_same_offset_per_channel) {
|
||||
offset = start_offset;
|
||||
} else if (is_stereo_codec) {
|
||||
int ch_mod = (ch & 1) ? ch - 1 : ch; /* adjust odd channels (ch 0,1,2,3,4,5 > ch 0,0,2,2,4,4) */
|
||||
offset = start_offset + vgmstream->interleave_block_size*ch_mod;
|
||||
//VGM_LOG("ch%i offset=%lx\n", ch,offset);
|
||||
} else {
|
||||
offset = start_offset + vgmstream->interleave_block_size*ch;
|
||||
}
|
||||
|
@ -2741,6 +2786,7 @@ int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t s
|
|||
if (!file) goto fail;
|
||||
}
|
||||
|
||||
VGM_LOG("ch%i offset=%lx\n", ch,offset);
|
||||
vgmstream->ch[ch].streamfile = file;
|
||||
vgmstream->ch[ch].channel_start_offset =
|
||||
vgmstream->ch[ch].offset = offset;
|
||||
|
|
|
@ -80,6 +80,8 @@ typedef enum {
|
|||
coding_PCM8_U, /* 8-bit PCM, unsigned (0x80 = 0) */
|
||||
coding_PCM8_U_int, /* 8-bit PCM, unsigned (0x80 = 0) with sample-level interleave (for blocks) */
|
||||
coding_PCM8_SB, /* 8-bit PCM, sign bit (others are 2's complement) */
|
||||
coding_PCM4, /* 4-bit PCM, signed */
|
||||
coding_PCM4_U, /* 4-bit PCM, unsigned */
|
||||
|
||||
coding_ULAW, /* 8-bit u-Law (non-linear PCM) */
|
||||
coding_ULAW_int, /* 8-bit u-Law (non-linear PCM) with sample-level interleave (for blocks) */
|
||||
|
@ -111,7 +113,8 @@ typedef enum {
|
|||
coding_EA_XA_int, /* Electronic Arts EA-XA ADPCM v1 (mono/interleave) */
|
||||
coding_EA_XA_V2, /* Electronic Arts EA-XA ADPCM v2 */
|
||||
coding_MAXIS_XA, /* Maxis EA-XA ADPCM */
|
||||
coding_EA_XAS, /* Electronic Arts EA-XAS ADPCM */
|
||||
coding_EA_XAS_V0, /* Electronic Arts EA-XAS ADPCM v0 */
|
||||
coding_EA_XAS_V1, /* Electronic Arts EA-XAS ADPCM v1 */
|
||||
|
||||
coding_IMA, /* IMA ADPCM (stereo or mono, low nibble first) */
|
||||
coding_IMA_int, /* IMA ADPCM (mono/interleave, low nibble first) */
|
||||
|
@ -141,6 +144,7 @@ typedef enum {
|
|||
coding_H4M_IMA, /* H4M IMA ADPCM (stereo or mono, high nibble first) */
|
||||
|
||||
coding_MSADPCM, /* Microsoft ADPCM (stereo/mono) */
|
||||
coding_MSADPCM_int, /* Microsoft ADPCM (mono) */
|
||||
coding_MSADPCM_ck, /* Microsoft ADPCM (Cricket Audio variation) */
|
||||
coding_WS, /* Westwood Studios VBR ADPCM */
|
||||
coding_AICA, /* Yamaha AICA ADPCM (stereo) */
|
||||
|
@ -157,6 +161,7 @@ typedef enum {
|
|||
coding_ASF, /* Argonaut ASF 4-bit ADPCM */
|
||||
coding_XMD, /* Konami XMD 4-bit ADPCM */
|
||||
coding_PCFX, /* PC-FX 4-bit ADPCM */
|
||||
coding_OKI16, /* OKI 4-bit ADPCM with 16-bit output */
|
||||
|
||||
/* others */
|
||||
coding_SDX2, /* SDX2 2:1 Squareroot-Delta-Exact compression DPCM */
|
||||
|
@ -537,7 +542,6 @@ typedef enum {
|
|||
meta_PS2_SMPL, /* Homura */
|
||||
meta_PS2_MSA, /* Psyvariar -Complete Edition- */
|
||||
meta_PS2_VOI, /* RAW Danger (Zettaizetsumei Toshi 2 - Itetsuita Kiokutachi) [PS2] */
|
||||
meta_PS2_KHV, /* Kingdom Hearts 2 VAG streams */
|
||||
meta_P3D, /* Prototype P3D */
|
||||
meta_PS2_TK1, /* Tekken (NamCollection) */
|
||||
meta_NGC_RKV, /* Legacy of Kain - Blood Omen 2 (GC) */
|
||||
|
@ -717,6 +721,7 @@ typedef enum {
|
|||
meta_DSP_ADPCMX,
|
||||
meta_OGG_OPUS,
|
||||
meta_IMC,
|
||||
meta_GIN,
|
||||
|
||||
} meta_t;
|
||||
|
||||
|
|
Loading…
Reference in New Issue