From 1d30e1a235955f0f95f02eada527c2e9ce05d2a6 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Mon, 3 Jul 2017 16:13:01 -0700 Subject: [PATCH] Updated VGMStream to r1050-554-g883d0a4f. --- .../vgmstream.xcodeproj/project.pbxproj | 16 +- .../vgmstream/vgmstream/src/coding/coding.h | 7 +- .../vgmstream/src/coding/ea_decoder.c | 178 +++++ .../vgmstream/src/coding/eaxa_decoder.c | 170 ----- .../vgmstream/src/coding/ima_decoder.c | 37 ++ .../vgmstream/src/coding/mpeg_decoder.c | 106 +-- Frameworks/vgmstream/vgmstream/src/formats.c | 29 +- .../vgmstream/vgmstream/src/layout/blocked.c | 14 +- .../vgmstream/vgmstream/src/layout/ea_block.c | 261 ++++---- .../vgmstream/vgmstream/src/layout/layout.h | 2 +- .../vgmstream/vgmstream/src/meta/ea_header.c | 308 --------- .../vgmstream/vgmstream/src/meta/ea_schl.c | 608 ++++++++++++++++++ Frameworks/vgmstream/vgmstream/src/meta/fsb.c | 2 +- .../vgmstream/vgmstream/src/meta/fsb5.c | 2 +- .../vgmstream/vgmstream/src/meta/meta.h | 8 +- .../vgmstream/src/meta/ngc_dsp_std.c | 3 +- Frameworks/vgmstream/vgmstream/src/meta/p3d.c | 244 ++++--- .../vgmstream/vgmstream/src/meta/pc_xa30.c | 69 ++ .../vgmstream/vgmstream/src/meta/ps2_xa30.c | 72 +-- .../vgmstream/vgmstream/src/meta/ps3_xvag.c | 2 +- .../vgmstream/vgmstream/src/meta/psx_cdxa.c | 3 + .../vgmstream/vgmstream/src/meta/riff.c | 55 +- Frameworks/vgmstream/vgmstream/src/meta/rws.c | 44 +- .../vgmstream/vgmstream/src/meta/wii_04sw.c | 62 ++ .../vgmstream/vgmstream/src/vgmstream.c | 26 +- .../vgmstream/vgmstream/src/vgmstream.h | 53 +- 26 files changed, 1502 insertions(+), 879 deletions(-) create mode 100644 Frameworks/vgmstream/vgmstream/src/coding/ea_decoder.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/coding/eaxa_decoder.c delete mode 100644 Frameworks/vgmstream/vgmstream/src/meta/ea_header.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/pc_xa30.c create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/wii_04sw.c diff --git a/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj index 4e81af050..627d370d6 100644 --- a/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj +++ b/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj @@ -50,7 +50,7 @@ 836F6F2118BDC2190095E648 /* aica_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DE318BDC2180095E648 /* aica_decoder.c */; }; 836F6F2218BDC2190095E648 /* at3_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DE418BDC2180095E648 /* at3_decoder.c */; }; 836F6F2318BDC2190095E648 /* coding.h in Headers */ = {isa = PBXBuildFile; fileRef = 836F6DE518BDC2180095E648 /* coding.h */; }; - 836F6F2418BDC2190095E648 /* eaxa_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DE618BDC2180095E648 /* eaxa_decoder.c */; }; + 836F6F2418BDC2190095E648 /* ea_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DE618BDC2180095E648 /* ea_decoder.c */; }; 836F6F2518BDC2190095E648 /* g721_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DE718BDC2180095E648 /* g721_decoder.c */; }; 836F6F2618BDC2190095E648 /* g7221_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DE818BDC2180095E648 /* g7221_decoder.c */; }; 836F6F2718BDC2190095E648 /* g72x_state.h in Headers */ = {isa = PBXBuildFile; fileRef = 836F6DE918BDC2180095E648 /* g72x_state.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -135,7 +135,7 @@ 836F6F7F18BDC2190095E648 /* dmsg_segh.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4318BDC2180095E648 /* dmsg_segh.c */; }; 836F6F8018BDC2190095E648 /* dsp_bdsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4418BDC2180095E648 /* dsp_bdsp.c */; }; 836F6F8118BDC2190095E648 /* dsp_sth_str.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4518BDC2180095E648 /* dsp_sth_str.c */; }; - 836F6F8218BDC2190095E648 /* ea_header.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4618BDC2180095E648 /* ea_header.c */; }; + 836F6F8218BDC2190095E648 /* ea_schl.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4618BDC2180095E648 /* ea_schl.c */; }; 836F6F8318BDC2190095E648 /* ea_old.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4718BDC2180095E648 /* ea_old.c */; }; 836F6F8418BDC2190095E648 /* emff.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4818BDC2180095E648 /* emff.c */; }; 836F6F8518BDC2190095E648 /* exakt_sc.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6E4918BDC2180095E648 /* exakt_sc.c */; }; @@ -534,7 +534,7 @@ 836F6DE318BDC2180095E648 /* aica_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aica_decoder.c; sourceTree = ""; }; 836F6DE418BDC2180095E648 /* at3_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = at3_decoder.c; sourceTree = ""; }; 836F6DE518BDC2180095E648 /* coding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coding.h; sourceTree = ""; }; - 836F6DE618BDC2180095E648 /* eaxa_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eaxa_decoder.c; sourceTree = ""; }; + 836F6DE618BDC2180095E648 /* ea_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_decoder.c; sourceTree = ""; }; 836F6DE718BDC2180095E648 /* g721_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = g721_decoder.c; sourceTree = ""; }; 836F6DE818BDC2180095E648 /* g7221_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = g7221_decoder.c; sourceTree = ""; }; 836F6DE918BDC2180095E648 /* g72x_state.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = g72x_state.h; sourceTree = ""; }; @@ -619,7 +619,7 @@ 836F6E4318BDC2180095E648 /* dmsg_segh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dmsg_segh.c; sourceTree = ""; }; 836F6E4418BDC2180095E648 /* dsp_bdsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dsp_bdsp.c; sourceTree = ""; }; 836F6E4518BDC2180095E648 /* dsp_sth_str.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dsp_sth_str.c; sourceTree = ""; }; - 836F6E4618BDC2180095E648 /* ea_header.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_header.c; sourceTree = ""; }; + 836F6E4618BDC2180095E648 /* ea_schl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_schl.c; sourceTree = ""; }; 836F6E4718BDC2180095E648 /* ea_old.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_old.c; sourceTree = ""; }; 836F6E4818BDC2180095E648 /* emff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = emff.c; sourceTree = ""; }; 836F6E4918BDC2180095E648 /* exakt_sc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exakt_sc.c; sourceTree = ""; }; @@ -1026,7 +1026,7 @@ 836F6DE318BDC2180095E648 /* aica_decoder.c */, 836F6DE418BDC2180095E648 /* at3_decoder.c */, 836F6DE518BDC2180095E648 /* coding.h */, - 836F6DE618BDC2180095E648 /* eaxa_decoder.c */, + 836F6DE618BDC2180095E648 /* ea_decoder.c */, 836F6DE718BDC2180095E648 /* g721_decoder.c */, 836F6DE818BDC2180095E648 /* g7221_decoder.c */, 836F6DE918BDC2180095E648 /* g72x_state.h */, @@ -1160,7 +1160,7 @@ 836F6E4318BDC2180095E648 /* dmsg_segh.c */, 836F6E4418BDC2180095E648 /* dsp_bdsp.c */, 836F6E4518BDC2180095E648 /* dsp_sth_str.c */, - 836F6E4618BDC2180095E648 /* ea_header.c */, + 836F6E4618BDC2180095E648 /* ea_schl.c */, 836F6E4718BDC2180095E648 /* ea_old.c */, 836F6E4818BDC2180095E648 /* emff.c */, 836F6E4918BDC2180095E648 /* exakt_sc.c */, @@ -1635,7 +1635,7 @@ 836F6F1E18BDC2190095E648 /* acm_decoder.c in Sources */, 836F6FD818BDC2190095E648 /* ps2_gbts.c in Sources */, 83709E0A1ECBC1A4005C03D3 /* waa_wac_wad_wam.c in Sources */, - 836F6F2418BDC2190095E648 /* eaxa_decoder.c in Sources */, + 836F6F2418BDC2190095E648 /* ea_decoder.c in Sources */, 836F6F7A18BDC2190095E648 /* dc_dcsw_dcs.c in Sources */, 836F6F5318BDC2190095E648 /* ps2_iab_blocked.c in Sources */, 831BA61A1EAC61A500CF89B0 /* ps2_vds_vdm.c in Sources */, @@ -1691,7 +1691,7 @@ 836F701A18BDC2190095E648 /* psx_fag.c in Sources */, 836F703B18BDC2190095E648 /* vsf.c in Sources */, 836F6F3D18BDC2190095E648 /* aax_layout.c in Sources */, - 836F6F8218BDC2190095E648 /* ea_header.c in Sources */, + 836F6F8218BDC2190095E648 /* ea_schl.c in Sources */, 836F700A18BDC2190095E648 /* ps2_vpk.c in Sources */, 836F6F7318BDC2190095E648 /* bcstm.c in Sources */, 83299FD11E7660C7003A3242 /* dsp_adx.c in Sources */, diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding.h b/Frameworks/vgmstream/vgmstream/src/coding/coding.h index b994be54c..3e04865e3 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/coding.h +++ b/Frameworks/vgmstream/vgmstream/src/coding/coding.h @@ -30,6 +30,7 @@ void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * out void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); +void decode_ref_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels); /* ngc_dsp_decoder */ @@ -72,9 +73,9 @@ size_t ps_bytes_to_samples(size_t bytes, int channels); void decode_xa(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void init_get_high_nibble(VGMSTREAM * vgmstream); -/*eaxa_decoder */ +/* ea_decoder */ void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); -void decode_ea_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); +void decode_ea_mt10(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_maxis_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); /* sdx2_decoder */ @@ -160,7 +161,7 @@ void free_ogl_vorbis(vorbis_codec_data *data); #ifdef VGM_USE_MPEG /* mpeg_decoder */ mpeg_codec_data *init_mpeg_codec_data(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels); -mpeg_codec_data *init_mpeg_codec_data_interleaved(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels, int fixed_frame_size, int fsb_padding); +mpeg_codec_data *init_mpeg_codec_data_interleaved(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels, mpeg_interleave_type interleave_type, uint32_t interleave_value); mpeg_codec_data *init_mpeg_codec_data_ahx(STREAMFILE *streamFile, off_t start_offset, int channel_count); void decode_mpeg(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels); diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ea_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ea_decoder.c new file mode 100644 index 000000000..b1eb2bf57 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/coding/ea_decoder.c @@ -0,0 +1,178 @@ +#include "coding.h" +#include "../util.h" + +/* Various EA ADPCM codecs */ + +static const int32_t EA_XA_TABLE[28] = { + 0,0,240,0, + 460,-208,0x0188,-220, + 0x0000,0x0000,0x00F0,0x0000, + 0x01CC,0x0000,0x0188,0x0000, + 0x0000,0x0000,0x0000,0x0000, + -208,-1,-220,-1, + 0x0000,0x0000,0x0000,0x3F70 +}; + +static const int32_t EA_TABLE[20]= { + 0x00000000, 0x000000F0, 0x000001CC, 0x00000188, + 0x00000000, 0x00000000, 0xFFFFFF30, 0xFFFFFF24, + 0x00000000, 0x00000001, 0x00000003, 0x00000004, + 0x00000007, 0x00000008, 0x0000000A, 0x0000000B, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFC +}; + +/* EA EAXA, evolved from CDXA */ +void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { + uint8_t frame_info; + int32_t sample_count; + int32_t coef1,coef2; + int i,shift; + off_t channel_offset = stream->channel_start_offset; //suboffset within channel + + first_sample = first_sample%28; + + /* header */ + frame_info = (uint8_t)read_8bit(stream->offset+channel_offset,stream->streamfile); + channel_offset++; + + if (frame_info == 0xEE) { /* PCM frame (used in later revisions), always BE */ + stream->adpcm_history1_32 = read_16bitBE(stream->offset+channel_offset+0x00,stream->streamfile); + stream->adpcm_history2_32 = read_16bitBE(stream->offset+channel_offset+0x02,stream->streamfile); + channel_offset += 4; + + for (i=first_sample,sample_count=0; ioffset+channel_offset,stream->streamfile); + channel_offset+=2; + } + + // Only increment offset on complete frame + if (channel_offset-stream->channel_start_offset == (2*28)+5) + stream->channel_start_offset += (2*28)+5; + + } else { /* ADPCM frame */ + coef1 = EA_XA_TABLE[(((frame_info >> 4) & 0x0F) << 1)]; + coef2 = EA_XA_TABLE[(((frame_info >> 4) & 0x0F) << 1) + 1]; + shift = (frame_info & 0x0F) + 8; + + for (i=first_sample,sample_count=0; ioffset+channel_offset+i/2,stream->streamfile); + int32_t sample = ((((i&1? + sample_byte & 0x0F: + sample_byte >> 4 + ) << 0x1C) >> shift) + + (coef1 * stream->adpcm_history1_32) + (coef2 * stream->adpcm_history2_32)) >> 8; + + outbuf[sample_count] = clamp16(sample); + stream->adpcm_history2_32 = stream->adpcm_history1_32; + stream->adpcm_history1_32 = sample; + } + + channel_offset+=i/2; + + // Only increment offset on complete frame + if(channel_offset - stream->channel_start_offset == 0x0F) + stream->channel_start_offset += 0x0F; + } +} + +/* EA MicroTalk 10:1 (aka "EA ADPCM") */ +void decode_ea_mt10(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { + uint8_t frame_info; + int32_t sample_count; + int32_t coef1,coef2; + int i, shift; + VGMSTREAMCHANNEL *stream = &(vgmstream->ch[channel]); + off_t channel_offset=stream->channel_start_offset; + + vgmstream->get_high_nibble = !vgmstream->get_high_nibble; /* for stereo subinterleave, L=high nibble, R=low nibble */ + + first_sample = first_sample%28; + + /* header */ //todo mono/interleave decoder + frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile); + channel_offset++; + coef1 = EA_TABLE[(vgmstream->get_high_nibble ? frame_info & 0x0F: frame_info >> 4)]; + coef2 = EA_TABLE[(vgmstream->get_high_nibble ? frame_info & 0x0F: frame_info >> 4) + 4]; + + frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile); + channel_offset++; + shift = (vgmstream->get_high_nibble ? frame_info & 0x0F : frame_info >> 4) + 8; + + + for (i=first_sample,sample_count=0; ioffset+channel_offset+i,stream->streamfile); + + sample = ((((vgmstream->get_high_nibble? + sample_byte & 0x0F: + sample_byte >> 4 + ) << 0x1C) >> shift) + + (coef1 * stream->adpcm_history1_32) + (coef2 * stream->adpcm_history2_32) + 0x80) >> 8; + + outbuf[sample_count] = clamp16(sample); + stream->adpcm_history2_32 = stream->adpcm_history1_32; + stream->adpcm_history1_32 = sample; + } + channel_offset+=i; + + // Only increment offset on complete frame + if(channel_offset-stream->channel_start_offset==0x1E) + stream->channel_start_offset+=0x1E; +} + + +/* EA MicroTalk 5:1, unknown variation */ +//void decode_ea_mt5(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) + + +/* Maxis EAXA, yet another CDXA variation */ +void decode_maxis_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { + uint8_t frame_info; + int32_t sample_count; + int32_t coef1,coef2; + int i,shift; + int frameSize = channelspacing*15;//mono samples have a frame of 15, stereo files have frames of 30 + VGMSTREAMCHANNEL *stream = &(vgmstream->ch[channel]); + off_t channel_offset=stream->channel_start_offset; + + first_sample = first_sample%28; + frame_info = read_8bit(channel_offset,stream->streamfile); + + coef1 = EA_TABLE[frame_info >> 4]; + coef2 = EA_TABLE[(frame_info >> 4) + 4]; + shift = (frame_info & 0x0F)+8; + + channel_offset+=channelspacing; + //stream->offset = first_sample*channelspacing/2; + + for (i=first_sample,sample_count=0; ioffset+channel_offset,stream->streamfile); + + sample = (((((i&1)? + sample_byte & 0x0F: + sample_byte >> 4 + ) << 0x1C) >> shift) + + (coef1 * stream->adpcm_history1_32) + (coef2 * stream->adpcm_history2_32) + 0x80) >> 8; + + outbuf[sample_count] = clamp16(sample); + stream->adpcm_history2_32 = stream->adpcm_history1_32; + stream->adpcm_history1_32 = sample; + + if(i&1) + stream->offset+=channelspacing; + } + + channel_offset+=i; + + // Only increment offset on complete frame + + if(channel_offset-stream->channel_start_offset==frameSize) { + stream->channel_start_offset+=frameSize; + stream->offset=0; + } +} diff --git a/Frameworks/vgmstream/vgmstream/src/coding/eaxa_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/eaxa_decoder.c deleted file mode 100644 index 9d748a94b..000000000 --- a/Frameworks/vgmstream/vgmstream/src/coding/eaxa_decoder.c +++ /dev/null @@ -1,170 +0,0 @@ -#include "coding.h" -#include "../util.h" - -int32_t EA_XA_TABLE[28] = {0,0,240,0,460,-208,0x0188,-220, - 0x0000,0x0000,0x00F0,0x0000, - 0x01CC,0x0000,0x0188,0x0000, - 0x0000,0x0000,0x0000,0x0000, - -208,-1,-220,-1, - 0x0000,0x0000,0x0000,0x3F70}; - -int32_t EA_TABLE[20]= { 0x00000000, 0x000000F0, 0x000001CC, 0x00000188, - 0x00000000, 0x00000000, 0xFFFFFF30, 0xFFFFFF24, - 0x00000000, 0x00000001, 0x00000003, 0x00000004, - 0x00000007, 0x00000008, 0x0000000A, 0x0000000B, - 0x00000000, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFC}; - -void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { - uint8_t frame_info; - int32_t sample_count; - int32_t coef1,coef2; - int i,shift; - off_t channel_offset=stream->channel_start_offset; - - first_sample = first_sample%28; - frame_info = (uint8_t)read_8bit(stream->offset+channel_offset,stream->streamfile); - - if(frame_info==0xEE) { - - channel_offset++; - stream->adpcm_history1_32 = read_16bitBE(stream->offset+channel_offset,stream->streamfile); - stream->adpcm_history2_32 = read_16bitBE(stream->offset+channel_offset+2,stream->streamfile); - - channel_offset+=4; - - for (i=first_sample,sample_count=0; ioffset+channel_offset,stream->streamfile); - channel_offset+=2; - } - - // Only increment offset on complete frame - if(channel_offset-stream->channel_start_offset==(2*28)+5) - stream->channel_start_offset+=(2*28)+5; - - } else { - - - coef1 = EA_XA_TABLE[((frame_info >> 4) & 0x0F) << 1]; - coef2 = EA_XA_TABLE[(((frame_info >> 4) & 0x0F) << 1) + 1]; - shift = (frame_info & 0x0F) + 8; - - channel_offset++; - - for (i=first_sample,sample_count=0; ioffset+channel_offset+i/2,stream->streamfile); - int32_t sample = ((((i&1? - sample_byte & 0x0F: - sample_byte >> 4 - ) << 0x1C) >> shift) + - (coef1 * stream->adpcm_history1_32) + (coef2 * stream->adpcm_history2_32)) >> 8; - - outbuf[sample_count] = clamp16(sample); - stream->adpcm_history2_32 = stream->adpcm_history1_32; - stream->adpcm_history1_32 = sample; - } - - channel_offset+=i/2; - - // Only increment offset on complete frame - if(channel_offset-stream->channel_start_offset==0x0F) - stream->channel_start_offset+=0x0F; - } -} - - -void decode_ea_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { - uint8_t frame_info; - int32_t sample_count; - int32_t coef1,coef2; - int i,shift; - VGMSTREAMCHANNEL *stream = &(vgmstream->ch[channel]); - off_t channel_offset=stream->channel_start_offset; - - vgmstream->get_high_nibble=!vgmstream->get_high_nibble; - - first_sample = first_sample%28; - frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile); - - coef1 = EA_TABLE[(vgmstream->get_high_nibble? frame_info & 0x0F: frame_info >> 4)]; - coef2 = EA_TABLE[(vgmstream->get_high_nibble? frame_info & 0x0F: frame_info >> 4) + 4]; - - channel_offset++; - - frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile); - shift = (vgmstream->get_high_nibble? frame_info & 0x0F : frame_info >> 4)+8; - - channel_offset++; - - for (i=first_sample,sample_count=0; ioffset+channel_offset+i,stream->streamfile); - - sample = ((((vgmstream->get_high_nibble? - sample_byte & 0x0F: - sample_byte >> 4 - ) << 0x1C) >> shift) + - (coef1 * stream->adpcm_history1_32) + (coef2 * stream->adpcm_history2_32) + 0x80) >> 8; - - outbuf[sample_count] = clamp16(sample); - stream->adpcm_history2_32 = stream->adpcm_history1_32; - stream->adpcm_history1_32 = sample; - } - - channel_offset+=i; - - // Only increment offset on complete frame - if(channel_offset-stream->channel_start_offset==0x1E) - stream->channel_start_offset+=0x1E; -} - - -void decode_maxis_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { - uint8_t frame_info; - int32_t sample_count; - int32_t coef1,coef2; - int i,shift; - int frameSize = channelspacing*15;//mono samples have a frame of 15, stereo files have frames of 30 - VGMSTREAMCHANNEL *stream = &(vgmstream->ch[channel]); - off_t channel_offset=stream->channel_start_offset; - - first_sample = first_sample%28; - frame_info = read_8bit(channel_offset,stream->streamfile); - - coef1 = EA_TABLE[frame_info >> 4]; - coef2 = EA_TABLE[(frame_info >> 4) + 4]; - shift = (frame_info & 0x0F)+8; - - channel_offset+=channelspacing; - //stream->offset = first_sample*channelspacing/2; - - for (i=first_sample,sample_count=0; ioffset+channel_offset,stream->streamfile); - - sample = (((((i&1)? - sample_byte & 0x0F: - sample_byte >> 4 - ) << 0x1C) >> shift) + - (coef1 * stream->adpcm_history1_32) + (coef2 * stream->adpcm_history2_32) + 0x80) >> 8; - - outbuf[sample_count] = clamp16(sample); - stream->adpcm_history2_32 = stream->adpcm_history1_32; - stream->adpcm_history1_32 = sample; - - if(i&1) - stream->offset+=channelspacing; - } - - channel_offset+=i; - - // Only increment offset on complete frame - - if(channel_offset-stream->channel_start_offset==frameSize) { - stream->channel_start_offset+=frameSize; - stream->offset=0; - } -} diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c index 73bcb899f..b2210ae0f 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ima_decoder.c @@ -653,6 +653,43 @@ void decode_wwise_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * stream->adpcm_step_index = step_index; } +/* Reflection's MS-IMA (some layout info from XA2WAV) */ +void decode_ref_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { + int i, sample_count; + + int32_t hist1 = stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + + //internal interleave (configurable size), mixed channels (4 byte per ch) + int block_channel_size = (vgmstream->interleave_block_size - 4*vgmstream->channels) / vgmstream->channels; + int block_samples = (vgmstream->interleave_block_size - 4*vgmstream->channels) * 2 / vgmstream->channels; + first_sample = first_sample % block_samples; + + //normal header (per channel) + if (first_sample == 0) { + off_t header_offset = stream->offset + 4*channel; + + hist1 = read_16bitLE(header_offset,stream->streamfile); + step_index = read_8bit(header_offset+2,stream->streamfile); + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + } + + //layout: all nibbles from one channel, then all nibbles from other + for (i=first_sample,sample_count=0; ioffset + 4*vgmstream->channels + block_channel_size*channel + i/2; + int nibble_shift = (i&1?4:0); //low nibble first + + ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + outbuf[sample_count] = (short)(hist1); + } + + //internal interleave: increment offset on complete frame + if (i == block_samples) stream->offset += vgmstream->interleave_block_size; + + stream->adpcm_history1_32 = hist1; + stream->adpcm_step_index = step_index; +} size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels) { /* MS IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */ diff --git a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c index 91480e438..ebd0eafeb 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/mpeg_decoder.c @@ -132,7 +132,7 @@ fail: /** * Init interleaved MPEG (also accepts normal MPEGs, but it's less error tolerant than normal MPEG init). */ -mpeg_codec_data *init_mpeg_codec_data_interleaved(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels, int fixed_frame_size, int fsb_padding) { +mpeg_codec_data *init_mpeg_codec_data_interleaved(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels, mpeg_interleave_type interleave_type, uint32_t interleave_value) { mpeg_codec_data *data = NULL; /* init codec */ @@ -163,19 +163,13 @@ mpeg_codec_data *init_mpeg_codec_data_interleaved(STREAMFILE *streamfile, off_t data->sample_rate_per_frame = info.sample_rate; data->samples_per_frame = info.frame_samples; - data->fixed_frame_size = fixed_frame_size; - data->current_frame_size = fixed_frame_size; - data->fsb_padding = fsb_padding; + data->interleave_type = interleave_type; + data->interleave_value = interleave_value; /* get frame size from the first frame as it can be used externally to calc interleave */ if ( !update_frame_sizes(data, streamfile, start_offset) ) goto fail; -//VGM_LOG("ch=%i, sr=%i, spf=%i, v=%i, l=%i\n", data->channels_per_frame, data->sample_rate_per_frame, data->samples_per_frame, info.version, info.layer); -//mpg123_handle *main_m = data->m; -//struct mpg123_frameinfo mi; -//mpg123_info(main_m,&mi); -//VGM_LOG("mi.framesize=%x\n", mi.framesize); /* unlikely, can fixed with bigger buffer or a feed loop */ if (info.frame_size > data->buffer_size) goto fail; @@ -346,11 +340,12 @@ static void decode_mpeg_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data * samples per stream and muxes them into a single internal buffer before copying to outbuf * (to make sure channel samples are orderly copied between decode_mpeg calls). * - * Interleave variations: - * - blocks of frames: fixed block_size per stream (unknown number of samples) [XVAG] + * Interleave modes: + * - FIXED [XVAG]: fixed block_size per stream (unknown number of samples) * (ex. b1 = N samples of ch1, b2 = N samples of ch2, b3 = M samples of ch1, etc) - * - partial frames: single frames per stream with padding (block_size is frame_size+padding) [FSB] + * - FSB: single frames per stream with padding (block_size is frame_size+padding) [FSB] * (ex. f1+f3+f5 = 1152*2 samples of ch1+2, f2+f4 = 1152*2 samples of ch3+4, etc) + * - P3D: unknown layout at the moment (possibly N */ static void decode_mpeg_interleave(VGMSTREAM * vgmstream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) { int samples_done = 0, bytes_max, bytes_to_copy; @@ -376,7 +371,11 @@ static void decode_mpeg_interleave(VGMSTREAM * vgmstream, mpeg_codec_data * data data->bytes_used_in_interleave_buffer = 0; for (i=0; i < data->ms_size; i++) { - decode_mpeg_interleave_samples(&vgmstream->ch[i], data, data->ms[i], channels, i, vgmstream->interleave_block_size); + if (data->interleave_type == MPEG_P3D /* P3D have a strange way to interleave so just use first offset */ + || data->interleave_type == MPEG_EA) /* EA MPEG is simply frame by frame normal MPEG */ + decode_mpeg_interleave_samples(&vgmstream->ch[0], data, data->ms[i], channels, i, vgmstream->interleave_block_size); + else + decode_mpeg_interleave_samples(&vgmstream->ch[i], data, data->ms[i], channels, i, vgmstream->interleave_block_size); } /* discard (for looping): 'remove' decoded samples from the buffer */ @@ -387,10 +386,8 @@ static void decode_mpeg_interleave(VGMSTREAM * vgmstream, mpeg_codec_data * data if (bytes_to_discard > data->bytes_in_interleave_buffer) bytes_to_discard = data->bytes_in_interleave_buffer; - /* pretend the samples were used up */ + /* pretend the samples were used up and readjust discard */ data->bytes_used_in_interleave_buffer = bytes_to_discard; - - /* and readjust discard */ data->samples_to_discard -= bytes_to_discard / sizeof(sample) / channels;; } } @@ -415,8 +412,7 @@ static void decode_mpeg_interleave_samples(VGMSTREAMCHANNEL *stream, mpeg_codec_ rc = update_frame_sizes(data, stream->streamfile, stream->offset); /* ignore any errors and continue; mpg123 will probably sync */ VGM_ASSERT(rc==0, "MPEG: frame error @ 0x%08lx (prev size=0x%x / padding=0x%x)\n", stream->offset, data->current_frame_size, data->current_padding); - - + //VGM_LOG("off=%lx, st=%i, fs=%x, pd=%x\n", stream->offset, num_stream, data->current_frame_size, data->current_padding); /* extra EOF check for edge cases when the caller tries to read more samples than possible */ @@ -426,11 +422,10 @@ static void decode_mpeg_interleave_samples(VGMSTREAMCHANNEL *stream, mpeg_codec_ break; } - /* read more raw data (only 1 frame, to check interleave block end) */ if (!data->buffer_full) { + //VGM_LOG("MPEG: reading more raw data\n"); data->bytes_in_buffer = read_streamfile(data->buffer,stream->offset,data->current_frame_size,stream->streamfile); - //VGM_LOG("read raw: cfs=%x, cp=%x, tot=%x, off=%x\n", data->current_frame_size, data->current_padding, data->current_frame_size + data->current_padding, stream->offset); /* end of stream, fill frame buffer with 0s but continue normally with other streams */ if (!data->bytes_in_buffer) { @@ -442,16 +437,14 @@ static void decode_mpeg_interleave_samples(VGMSTREAMCHANNEL *stream, mpeg_codec_ data->buffer_full = 1; data->buffer_used = 0; - stream->offset += data->current_frame_size + data->current_padding; /* skip FSB frame+garbage */ + stream->offset += data->current_frame_size + data->current_padding; /* skip frame + FSB garbage */ if (block_size && ((stream->offset - stream->channel_start_offset) % block_size==0)) { stream->offset += block_size * (data->ms_size-1); /* skip a block per stream if block done */ } - /* - /// TODO: skip very first frame but add fake silence? - //todo skip only if first frame is fully decodable? (ie.- blank below) - //todo for multich files idem - if (first_frame) { +#if 0 + //TODO: skip very first frame but add fake silence? only if first frame is fully decodable? + if (data->interleave_type == MPEG_FSB && first_frame) { data->buffer_full = 0; VGM_LOG("skip first frame @ %x - %x\n", stream->offset, stream->channel_start_offset); @@ -459,24 +452,20 @@ static void decode_mpeg_interleave_samples(VGMSTREAMCHANNEL *stream, mpeg_codec_ bytes_done = data->frame_buffer_size; break; } - */ +#endif } /* feed new raw data to the decoder if needed, copy decoded results to frame buffer output */ if (!data->buffer_used) { - //VGM_LOG("feed unused: cfs=%x, cp=%x, tot=%x, off=%x\n", data->current_frame_size, data->current_padding, data->current_frame_size + data->current_padding, stream->offset); - //getchar(); - + //VGM_LOG("MPEG: get samples from new raw data\n"); rc = mpg123_decode(m, data->buffer, data->bytes_in_buffer, (unsigned char *)data->frame_buffer, data->frame_buffer_size, &bytes_done); data->buffer_used = 1; } else { - //VGM_LOG("feed used: cfs=%x, cp=%x, tot=%x, off=%x\n", data->current_frame_size, data->current_padding, data->current_frame_size + data->current_padding, stream->offset); - //getchar(); - + //VGM_LOG("MPEG: get samples from old raw data\n"); rc = mpg123_decode(m, NULL,0, (unsigned char *)data->frame_buffer, data->frame_buffer_size, @@ -492,10 +481,12 @@ static void decode_mpeg_interleave_samples(VGMSTREAMCHANNEL *stream, mpeg_codec_ /* not enough raw data, request more */ if (rc == MPG123_NEED_MORE) { + //VGM_LOG("MPEG: need more raw data\n"); data->buffer_full = 0; continue; } + break; } while (1); @@ -527,28 +518,54 @@ static void decode_mpeg_interleave_samples(VGMSTREAMCHANNEL *stream, mpeg_codec_ * Expected to be called at the beginning of a new frame. */ static int update_frame_sizes(mpeg_codec_data * data, STREAMFILE *streamfile, off_t offset) { - if (!data->fixed_frame_size) { + + if (data->interleave_type == MPEG_FIXED) { /* frames of fixed size */ + data->current_frame_size = data->interleave_value; + } + else if (data->interleave_type == MPEG_FSB) { /* padding between frames */ mpeg_frame_info info; /* Manually find new frame size. Not ideal but mpg123_info.framesize is wrong sometimes */ if ( !mpeg_get_frame_info(streamfile, offset, &info) ) goto fail; + data->current_frame_size = info.frame_size; + + /* get FSB padding for MPEG1/2 Layer III (MPEG1 Layer II doesn't use it, and Layer I doesn't seem to be supported) */ + if (data->interleave_value && info.layer == 3) { + data->current_padding = (data->current_frame_size % data->interleave_value) + ? data->interleave_value - (data->current_frame_size % data->interleave_value) + : 0; + } /* could mess some calcs */ VGM_ASSERT(data->sample_rate_per_frame != info.sample_rate || data->samples_per_frame != info.frame_samples, "MPEG: variable frame info found @ 0x%08lx", offset); + } + else if (data->interleave_type == MPEG_P3D) { /* varying frames size, even though the frame header says 0x120 */ + uint32_t header = read_32bitBE(offset,streamfile); - /* new frame */ - data->current_frame_size = info.frame_size; - - /* get FSB padding for MPEG1/2 Layer III (MPEG1 Layer II doesn't use it, and Layer I doesn't seem to be supported) */ - if (data->fsb_padding && info.layer == 3) { - data->current_padding = (data->current_frame_size % data->fsb_padding) ? - data->fsb_padding - (data->current_frame_size % data->fsb_padding) : 0; + if (read_32bitBE(offset+0x120,streamfile) == header) { + data->current_frame_size = 0x120; + } else if (read_32bitBE(offset+0xA0,streamfile) == header) { + data->current_frame_size = 0xA0; + } else if (read_32bitBE(offset+0x1C0,streamfile) == header) { + data->current_frame_size = 0x1C0; + } else if (read_32bitBE(offset+0x180,streamfile) == header) { + data->current_frame_size = 0x180; + //} else if (read_32bitBE(offset+0x120,streamfile) == -1) { /* at EOF */ + // data->current_frame_size = 0x120; + } else { + VGM_LOG("MPEG: unknown frame size @ %lx, %x\n", offset, read_32bitBE(offset+0x120,streamfile)); + goto fail; } + } + else if (data->interleave_type == MPEG_EA) { /* straight frame by frame */ + mpeg_frame_info info; - //VGM_LOG("off=%lx, ch=%i, sr=%i, spf=%i, fs=%x, v=%i, l=%i\n", offset, info.channels, info.sample_rate, info.frame_samples, info.frame_size, info.version, info.layer); - //getchar(); + /* Manually find new frame size. Not ideal but mpg123_info.framesize is wrong sometimes */ + if ( !mpeg_get_frame_info(streamfile, offset, &info) ) + goto fail; + data->current_frame_size = info.frame_size; } return 1; @@ -828,9 +845,6 @@ static int mpeg_get_frame_info(STREAMFILE *streamfile, off_t offset, mpeg_frame_ case 576: info->frame_size = (72l * info->bit_rate * 1000l / info->sample_rate + padding); break; case 1152: info->frame_size = (144l * info->bit_rate * 1000l / info->sample_rate + padding); break; } - //int fs2 = (info->frame_samples / 8 * info->bit_rate * 1000l) / info->sample_rate + padding; - //VGM_LOG("fs=%x, fs2=%x, fsp=%i, br=%i\n", info->frame_size, fs2, info->frame_samples, info->bit_rate); - //getchar(); info->coding_type = coding_types[info->version-1][info->layer-1]; diff --git a/Frameworks/vgmstream/vgmstream/src/formats.c b/Frameworks/vgmstream/vgmstream/src/formats.c index e43a2097b..919b2a953 100644 --- a/Frameworks/vgmstream/vgmstream/src/formats.c +++ b/Frameworks/vgmstream/vgmstream/src/formats.c @@ -8,6 +8,7 @@ /* some formats marked as "not parsed" mean they'll go through FFmpeg, the header/extension is not parsed */ static const char* extension_list[] = { + "04sw", "2dx9", "2pfs", @@ -97,6 +98,7 @@ static const char* extension_list[] = { "eam", "emff", "enth", + "exa", "fag", "ffw", @@ -160,6 +162,7 @@ static const char* extension_list[] = { "mcg", "mds", "mdsp", + "med", "mi4", "mib", "mic", @@ -416,8 +419,8 @@ static const coding_info coding_info_list[] = { {coding_XA, "CD-ROM XA 4-bit ADPCM"}, {coding_XBOX, "XBOX 4-bit IMA ADPCM"}, {coding_XBOX_int, "XBOX 4-bit IMA ADPCM (interleaved)"}, - {coding_EA_XA, "Electronic Arts 4-bit ADPCM (XA based)"}, - {coding_EA_ADPCM, "Electronic Arts R1 4-bit ADPCM (XA based)"}, + {coding_EA_XA, "Electronic Arts EA-XA 4-bit ADPCM"}, + {coding_EA_MT10, "Electronic Arts MicroTalk (10:1) 4-bit ADPCM"}, {coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"}, {coding_SDX2_int, "Squareroot-delta-exact (SDX2) 8-bit DPCM with 1 byte interleave"}, {coding_CBD2, "Cuberoot-delta-exact (CBD2) 8-bit DPCM"}, @@ -425,7 +428,7 @@ static const coding_info coding_info_list[] = { {coding_DVI_IMA, "Intel DVI 4-bit IMA ADPCM"}, {coding_DVI_IMA_int, "Intel DVI 4-bit IMA ADPCM (interleaved)"}, {coding_EACS_IMA, "EACS 4-bit IMA ADPCM"}, - {coding_MAXIS_ADPCM, "Maxis XA (EA ADPCM Variant)"}, + {coding_MAXIS_ADPCM, "Maxis XA ADPCM"}, {coding_IMA_int, "IMA 4-bit ADPCM (interleaved)"}, {coding_IMA, "IMA 4-bit ADPCM"}, {coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"}, @@ -436,6 +439,7 @@ static const coding_info coding_info_list[] = { {coding_OTNS_IMA, "Omikron: The Nomad Soul 4-bit IMA ADPCM"}, {coding_FSB_IMA, "FSB multichannel 4-bit IMA ADPCM"}, {coding_WWISE_IMA, "Audiokinetic Wwise 4-bit IMA ADPCM"}, + {coding_REF_IMA, "Reflections 4-bit IMA ADPCM"}, {coding_WS, "Westwood Studios VBR ADPCM"}, {coding_ACM, "InterPlay ACM"}, {coding_NWA0, "NWA DPCM Level 0"}, @@ -589,12 +593,7 @@ static const meta_info meta_info_list[] = { {meta_XBOX_WAVM, "assumed Xbox WAVM file by .wavm extension"}, {meta_XBOX_RIFF, "Microsoft XWAV RIFF header"}, {meta_DSP_STR, "assumed Conan Gamecube STR File by .str extension"}, - {meta_EAXA_R2, "Electronic Arts XA R2"}, - {meta_EAXA_R3, "Electronic Arts XA R3"}, - {meta_EA_ADPCM, "Electronic Arts XA R1"}, - {meta_EA_IMA, "Electronic Arts container with IMA blocks"}, - {meta_EAXA_PSX, "Electronic Arts With PSX ADPCM"}, - {meta_EA_PCM, "Electronic Arts With PCM"}, + {meta_EA_SCHL, "Electronic Arts SCHl header"}, {meta_CFN, "tri-Crescendo CAF Header"}, {meta_PS2_VPK, "VPK Header"}, {meta_GENH, "GENH Generic Header"}, @@ -618,9 +617,9 @@ static const meta_info meta_info_list[] = { {meta_HGC1, "Knights of the Temple 2 hgC1 Header"}, {meta_AUS, "Capcom AUS Header"}, {meta_RWS, "RenderWare RWS header"}, - {meta_EACS_PC, "EACS Header (PC)"}, - {meta_EACS_PSX, "EACS Header (PSX)"}, - {meta_EACS_SAT, "EACS Header (SATURN)"}, + {meta_EACS_PC, "Electronic Arts EACS header (PC)"}, + {meta_EACS_PSX, "Electronic Arts EACS header (PSX)"}, + {meta_EACS_SAT, "Electronic Arts EACS header (SATURN)"}, {meta_SL3, "SL3 Header"}, {meta_FSB1, "FMOD Sample Bank (FSB1) Header"}, {meta_FSB2, "FMOD Sample Bank (FSB2) Header"}, @@ -629,7 +628,7 @@ static const meta_info meta_info_list[] = { {meta_FSB5, "FMOD Sample Bank (FSB5) Header"}, {meta_RWX, "RWX Header"}, {meta_XWB, "Microsoft XWB Header"}, - {meta_XA30, "XA30 Header"}, + {meta_PS2_XA30, "Reflections XA30 PS2 header"}, {meta_MUSC, "MUSC Header"}, {meta_MUSX_V004, "MUSX / Version 004 Header"}, {meta_MUSX_V005, "MUSX / Version 005 Header"}, @@ -785,7 +784,7 @@ static const meta_info meta_info_list[] = { {meta_PC_SMP, "Ghostbusters .smp Header"}, {meta_NGC_PDT, "PDT DSP header"}, {meta_NGC_BO2, "Blood Omen 2 DSP header"}, - {meta_P3D, "Prototype P3D Header"}, + {meta_P3D, "Radical P3D Header"}, {meta_PS2_TK1, "Tekken TK5STRM1 Header"}, {meta_PS2_ADSC, "ADSC Header"}, {meta_NGC_DSP_MPDS, "MPDS DSP header"}, @@ -870,6 +869,8 @@ static const meta_info meta_info_list[] = { {meta_TA_AAC_PS3, "tri-Ace AAC (PS3) header"}, {meta_PS3_MTA2, "Konami MTA2 header"}, {meta_NGC_ULW, "Criterion ULW raw header"}, + {meta_PC_XA30, "Reflections XA30 PC header"}, + {meta_WII_04SW, "Reflections 04SW header"}, #ifdef VGM_USE_VORBIS {meta_OGG_VORBIS, "Ogg Vorbis"}, diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked.c index 21587c8b9..326fdb013 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked.c @@ -8,7 +8,9 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); int samples_this_block; - if (frame_size == 0) { + if (vgmstream->current_block_samples) { + samples_this_block = vgmstream->current_block_samples; + } else if (frame_size == 0) { /* assume 4 bit */ /* TODO: get_vgmstream_frame_size() really should return bits... */ samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame; @@ -20,7 +22,9 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * int samples_to_do; if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { - if (frame_size == 0) { + if (vgmstream->current_block_samples) { + samples_this_block = vgmstream->current_block_samples; + } else if (frame_size == 0) { samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame; } else { samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame; @@ -65,7 +69,7 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * xa_block_update(vgmstream->next_block_offset,vgmstream); break; case layout_ea_blocked: - ea_block_update(vgmstream->next_block_offset,vgmstream); + ea_schl_block_update(vgmstream->next_block_offset,vgmstream); break; case layout_eacs_blocked: eacs_block_update(vgmstream->next_block_offset,vgmstream); @@ -141,7 +145,9 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * frame_size = get_vgmstream_frame_size(vgmstream); samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); - if (frame_size == 0) { + if (vgmstream->current_block_samples) { + samples_this_block = vgmstream->current_block_samples; + } else if (frame_size == 0) { samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame; } else { samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame; diff --git a/Frameworks/vgmstream/vgmstream/src/layout/ea_block.c b/Frameworks/vgmstream/vgmstream/src/layout/ea_block.c index 800192a18..fea2cf7ab 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/ea_block.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/ea_block.c @@ -3,147 +3,162 @@ #include "../vgmstream.h" /* set up for the block at the given offset */ -void ea_block_update(off_t block_offset, VGMSTREAM * vgmstream) { +void ea_schl_block_update(off_t block_offset, VGMSTREAM * vgmstream) { int i; + STREAMFILE* streamFile = vgmstream->ch[0].streamfile; + uint32_t id; + size_t file_size, block_size = 0, block_samples; + int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE; - init_get_high_nibble(vgmstream); - // Search for next SCDL or SCEl block ... - do { - block_offset+=4; - if(block_offset>=(off_t)get_streamfile_size(vgmstream->ch[0].streamfile)) { - vgmstream->next_block_offset=block_offset; - return; - } - } while (read_32bitBE(block_offset,vgmstream->ch[0].streamfile)!=0x5343446C); + init_get_high_nibble(vgmstream); /* swap nibble for codecs with stereo subinterleave */ - // reset channel offset - for(i=0;ichannels;i++) { - vgmstream->ch[i].channel_start_offset=0; - } + /* find target block ID and skip the rest */ + file_size = get_streamfile_size(streamFile); + while (block_offset < file_size) { + id = read_32bitBE(block_offset+0x00,streamFile); + + block_size = read_32bitLE(block_offset+0x04,streamFile); + if (block_size > 0xF0000000) /* size size is always LE, except in early MAC apparently */ + block_size = read_32bitBE(block_offset+0x04,streamFile); + + if (id == 0x5343446C) /* "SCDl" data block found */ + break; + + block_offset += block_size; /* size includes header */ + + /* Some EA files concat many small subfiles, for mapped music (.map/lin), so after SCEl + * there may be a new SCHl. We'll find it and pretend they are a single stream. */ + if (id == 0x5343456C && block_offset + 0x80 > file_size) + return; + if (id == 0x5343456C) { /* "SCEl" end block found */ + /* Usually there is padding between SCEl and SCHl (aligned to 0x80) */ + block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* also 32b-aligned */ + for (i = 0; i < 0x80 / 4; i++) { + id = read_32bitBE(block_offset,streamFile); + if (id == 0x5343486C) /* "SCHl" new header block found */ + break; /* next loop will parse and skip it */ + block_offset += 0x04; + } + } + + if (block_offset > file_size) + return; + + if (id == 0 || id == 0xFFFFFFFF) + return; /* probably hit padding or EOF */ + } + if (block_offset > file_size) + return; + + + /* use num_samples from header if possible; don't calc as rarely data may have padding (ex. PCM8) or not possible (ex. MP3) */ + switch(vgmstream->coding_type) { + case coding_PSX: + block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels); + break; + + default: + block_samples = read_32bit(block_offset+0x08,streamFile); + break; + } + + /* set new channel offsets */ + switch(vgmstream->coding_type) { + case coding_PSX: + for (i = 0; i < vgmstream->channels; i++) { + size_t interleave = ((block_size-0x10)/vgmstream->channels) * i; + vgmstream->ch[i].offset = block_offset + 0x10 + interleave; + } + /* at 0x08/0x0c: unknown */ + break; + + default: + for (i = 0; i < vgmstream->channels; i++) { + off_t channel_start; + if (vgmstream->coding_type == coding_EA_MT10 && vgmstream->codec_version == 0) + channel_start = 0; /* MT10 R1 (codec1 v0) uses stereo, R2 (codec2 v1+) interleaved mono */ + else + channel_start = read_32bit(block_offset+0x0C+(0x04*i),streamFile); + vgmstream->ch[i].offset = block_offset + 0x0C+(0x04*vgmstream->channels) + channel_start; + } + break; + } vgmstream->current_block_offset = block_offset; - vgmstream->next_block_offset = block_offset+read_32bitLE(block_offset+4,vgmstream->ch[0].streamfile)-4; + vgmstream->next_block_offset = block_offset + block_size; + vgmstream->current_block_size = 0; + vgmstream->current_block_samples = block_samples; - if(vgmstream->ea_big_endian) { - vgmstream->current_block_size = read_32bitBE(block_offset+8,vgmstream->ch[0].streamfile); - - for(i=0;ichannels;i++) { - vgmstream->ch[i].offset=read_32bitBE(block_offset+0x0C+(i*4),vgmstream->ch[0].streamfile)+(4*vgmstream->channels); - vgmstream->ch[i].offset+=vgmstream->current_block_offset+0x0C; - } - vgmstream->current_block_size /= 28; + /* read ADPCM history (there is a small diff vs decoded hist) */ + if (vgmstream->coding_type == coding_NGC_DSP + || (vgmstream->coding_type == coding_EA_XA && vgmstream->codec_version == 0) + ) { + //int16_t (*read_16bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_16bitBE : read_16bitLE; + for (i = 0; i < vgmstream->channels; i++) { + /* makes the output glitchy in rare cases (Harry Potter and the Chamber of Secrets (Xbox)) */ + //vgmstream->ch[i].adpcm_history2_32 = read_16bit(vgmstream->ch[i].offset+0x00,streamFile); + //vgmstream->ch[i].adpcm_history1_32 = read_16bit(vgmstream->ch[i].offset+0x02,streamFile); + vgmstream->ch[i].offset += 4; + } + } - } else { - switch(vgmstream->coding_type) { - case coding_PSX: - vgmstream->ch[0].offset=vgmstream->current_block_offset+0x10; - vgmstream->ch[1].offset=(read_32bitLE(block_offset+0x04,vgmstream->ch[0].streamfile)-0x10)/vgmstream->channels; - vgmstream->ch[1].offset+=vgmstream->ch[0].offset; - vgmstream->current_block_size=read_32bitLE(block_offset+0x04,vgmstream->ch[0].streamfile)-0x10; - vgmstream->current_block_size/=vgmstream->channels; - break; - case coding_EA_ADPCM: - vgmstream->current_block_size = read_32bitLE(block_offset+4,vgmstream->ch[0].streamfile); - for(i=0;ichannels;i++) { - vgmstream->ch[i].offset=vgmstream->current_block_offset+0x0C+(4*vgmstream->channels); - vgmstream->ch[i].adpcm_history1_32=(uint32_t)read_16bitLE(vgmstream->current_block_offset+0x0c+(i*4),vgmstream->ch[0].streamfile); - vgmstream->ch[i].adpcm_history2_32=(uint32_t)read_16bitLE(vgmstream->current_block_offset+0x0e +(i*4),vgmstream->ch[0].streamfile); - } - break; - case coding_PCM16BE: - vgmstream->current_block_size = read_32bitLE(block_offset+4,vgmstream->ch[0].streamfile)-0x14; - for(i=0;ichannels;i++) { - vgmstream->ch[i].offset=block_offset+0x14+vgmstream->current_block_size/vgmstream->channels*i; - } - vgmstream->current_block_size/=vgmstream->channels; - break; - case coding_PCM16LE_int: - vgmstream->current_block_size = read_32bitLE(block_offset+4,vgmstream->ch[0].streamfile)-0x0C; - for(i=0;ichannels;i++) { - vgmstream->ch[i].offset=block_offset+0x0C+(i*2); - } - vgmstream->current_block_size/=2; - vgmstream->current_block_size-=2; - break; - case coding_XBOX: - vgmstream->current_block_size = read_32bitLE(block_offset+0x10,vgmstream->ch[0].streamfile); - for(i=0;ichannels;i++) { - vgmstream->ch[i].offset=read_32bitLE(block_offset+0x0C+(i*4),vgmstream->ch[0].streamfile)+(4*vgmstream->channels); - vgmstream->ch[i].offset+=vgmstream->current_block_offset+0x0C; - } - break; - default: - vgmstream->current_block_size = read_32bitLE(block_offset+8,vgmstream->ch[0].streamfile); - for(i=0;ichannels;i++) { - vgmstream->ch[i].offset=read_32bitLE(block_offset+0x0C+(i*4),vgmstream->ch[0].streamfile)+(4*vgmstream->channels); - vgmstream->ch[i].offset+=vgmstream->current_block_offset+0x0C; - } - vgmstream->current_block_size /= 28; - } - } - if((vgmstream->ea_compression_version<3) && (vgmstream->coding_type!=coding_PSX) && (vgmstream->coding_type!=coding_EA_ADPCM) && (vgmstream->coding_type!=coding_XBOX) && (vgmstream->coding_type!=coding_PCM16BE)) { - for(i=0;ichannels;i++) { - if(vgmstream->ea_big_endian) { - vgmstream->ch[i].adpcm_history1_32=read_16bitBE(vgmstream->ch[i].offset,vgmstream->ch[0].streamfile); - vgmstream->ch[i].adpcm_history2_32=read_16bitBE(vgmstream->ch[i].offset+2,vgmstream->ch[0].streamfile); - } else { - vgmstream->ch[i].adpcm_history1_32=read_16bitLE(vgmstream->ch[i].offset,vgmstream->ch[0].streamfile); - vgmstream->ch[i].adpcm_history2_32=read_16bitLE(vgmstream->ch[i].offset+2,vgmstream->ch[0].streamfile); - } - vgmstream->ch[i].offset+=4; - } - } + /* reset channel sub offset */ + if (vgmstream->coding_type == coding_EA_MT10 || vgmstream->coding_type == coding_EA_XA) { + for(i=0;ichannels;i++) { + vgmstream->ch[i].channel_start_offset=0; + } + } } void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream) { - int i; - off_t block_size=vgmstream->current_block_size; + int i; + off_t block_size=vgmstream->current_block_size; - if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) { - block_offset+=0x0C; - } + if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) { + block_offset+=0x0C; + } vgmstream->current_block_offset = block_offset; - if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E64) { /* 1Snd */ - block_offset+=4; - if(vgmstream->ea_platform==0) - block_size=read_32bitLE(vgmstream->current_block_offset+0x04, - vgmstream->ch[0].streamfile); - else - block_size=read_32bitBE(vgmstream->current_block_offset+0x04, - vgmstream->ch[0].streamfile); - block_offset+=4; - } + if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E64) { /* 1Snd */ + block_offset+=4; + if(vgmstream->ea_platform==0) + block_size=read_32bitLE(vgmstream->current_block_offset+0x04, + vgmstream->ch[0].streamfile); + else + block_size=read_32bitBE(vgmstream->current_block_offset+0x04, + vgmstream->ch[0].streamfile); + block_offset+=4; + } - vgmstream->current_block_size=block_size-8; + vgmstream->current_block_size=block_size-8; - if(vgmstream->coding_type==coding_EACS_IMA) { - init_get_high_nibble(vgmstream); - vgmstream->current_block_size=read_32bitLE(block_offset,vgmstream->ch[0].streamfile); + if(vgmstream->coding_type==coding_EACS_IMA) { + init_get_high_nibble(vgmstream); + vgmstream->current_block_size=read_32bitLE(block_offset,vgmstream->ch[0].streamfile); - for(i=0;ichannels;i++) { - vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset+0x04+i*4,vgmstream->ch[0].streamfile); - vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset+0x04+i*4+(4*vgmstream->channels),vgmstream->ch[0].streamfile); - vgmstream->ch[i].offset = block_offset+0x14; - } - } else { - if(vgmstream->coding_type==coding_PSX) { - for (i=0;ichannels;i++) - vgmstream->ch[i].offset = vgmstream->current_block_offset+8+(i*(vgmstream->current_block_size/2)); - } else { + for(i=0;ichannels;i++) { + vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset+0x04+i*4,vgmstream->ch[0].streamfile); + vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset+0x04+i*4+(4*vgmstream->channels),vgmstream->ch[0].streamfile); + vgmstream->ch[i].offset = block_offset+0x14; + } + } else { + if(vgmstream->coding_type==coding_PSX) { + for (i=0;ichannels;i++) + vgmstream->ch[i].offset = vgmstream->current_block_offset+8+(i*(vgmstream->current_block_size/2)); + } else { - for (i=0;ichannels;i++) { - if(vgmstream->coding_type==coding_PCM16LE_int) - vgmstream->ch[i].offset = block_offset+(i*2); - else - vgmstream->ch[i].offset = block_offset+i; - } - } - vgmstream->current_block_size/=vgmstream->channels; - } - vgmstream->next_block_offset = vgmstream->current_block_offset + - (off_t)block_size; + for (i=0;ichannels;i++) { + if(vgmstream->coding_type==coding_PCM16LE_int) + vgmstream->ch[i].offset = block_offset+(i*2); + else + vgmstream->ch[i].offset = block_offset+i; + } + } + vgmstream->current_block_size/=vgmstream->channels; + } + vgmstream->next_block_offset = vgmstream->current_block_offset + + (off_t)block_size; } diff --git a/Frameworks/vgmstream/vgmstream/src/layout/layout.h b/Frameworks/vgmstream/vgmstream/src/layout/layout.h index bb4cb5605..0c806cb66 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/layout.h +++ b/Frameworks/vgmstream/vgmstream/src/layout/layout.h @@ -15,7 +15,7 @@ void halpst_block_update(off_t block_ofset, VGMSTREAM * vgmstream); void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream); -void ea_block_update(off_t block_offset, VGMSTREAM * vgmstream); +void ea_schl_block_update(off_t block_offset, VGMSTREAM * vgmstream); void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_header.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_header.c deleted file mode 100644 index 293f4c3ef..000000000 --- a/Frameworks/vgmstream/vgmstream/src/meta/ea_header.c +++ /dev/null @@ -1,308 +0,0 @@ -#include "meta.h" -#include "../layout/layout.h" -#include "../coding/coding.h" -#include "../util.h" - -// Platform constants -#define EA_PC 0x00 -#define EA_PSX 0x01 -#define EA_PS2 0x05 -#define EA_GC 0x06 -#define EA_XBOX 0x07 -#define EA_X360 0x09 - -// Compression Version -#define EAXA_R1 0x01 -#define EAXA_R2 0x02 -#define EAXA_R3 0x03 - -// Compression Type -#define EA_VAG 0x01 -#define EA_EAXA 0x0A -#define EA_ADPCM 0x30 -#define EA_PCM_BE 0x07 -#define EA_PCM_LE 0x08 -#define EA_IMA 0x14 - -typedef struct { - int32_t num_samples; - int32_t sample_rate; - uint8_t channels; - uint8_t platform; - int32_t interleave; - uint8_t compression_type; - uint8_t compression_version; -} EA_STRUCT; - -uint32_t readPatch(STREAMFILE* streamFile, off_t* offset) { - - uint32_t result=0; - uint8_t byteCount; - - byteCount = read_8bit(*offset,streamFile); - (*offset)++; - - for(;byteCount>0;byteCount--) { - result <<=8; - result+=(uint8_t)read_8bit(*offset,streamFile); - (*offset)++; - } - return result; -} - -void Parse_Header(STREAMFILE* streamFile,EA_STRUCT* ea, off_t offset, int length) { - - uint8_t byteRead; - off_t begin_offset=offset; - - // default value ... - ea->channels=1; - ea->compression_type=0; - ea->compression_version=0x01; - ea->platform=EA_GC; - - if(read_32bitBE(offset, streamFile)==0x47535452) { // GSTR - ea->compression_version=0x03; - offset+=8; - ea->platform=6; - } else { - if(read_16bitBE(offset,streamFile)!=0x5054) // PT - offset+=4; - - ea->platform=(uint8_t)read_16bitLE(offset+2,streamFile); - offset+=4; - } - - do { - byteRead = read_8bit(offset++,streamFile); - - switch(byteRead) { - case 0xFF: - case 0xFE: - case 0xFC: - case 0xFD: - break; -#if 0 - // was added for My Sims Kingdom, apparently this is not the right - // way to do it (see NFS Most Wanted and Underground 2) - case 0x06: // - if (readPatch(streamFile, &offset) == 0x65) - ea->compression_type = EA_PCM_BE; - break; -#endif - case 0x80: // compression version - ea->compression_version = (uint8_t)readPatch(streamFile, &offset); - break; - case 0x82: // channels count - ea->channels = (uint8_t)readPatch(streamFile, &offset); - break; - case 0x83: // compression type - ea->compression_type = (uint8_t)readPatch(streamFile, &offset); - if(ea->compression_type==0x07) ea->compression_type=0x30; - break; - case 0x84: // sample frequency - ea->sample_rate = readPatch(streamFile,&offset); - break; - case 0x85: // samples count - ea->num_samples = readPatch(streamFile, &offset); - break; - case 0x8A: - offset+=4; - if(ea->compression_type==0) ea->compression_type=EA_PCM_LE; - break; - case 0x86: - case 0x87: - case 0x8C: - case 0x92: - case 0x9C: - case 0x9D: // unknown patch - readPatch(streamFile, &offset); - break; - case 0x88: // interleave - ea->interleave = readPatch(streamFile, &offset); - break; - case 0xA0: // compression type - ea->compression_type = (uint8_t)readPatch(streamFile, &offset); - break; - } - } while(offset-begin_offsetplatform==EA_PSX) - ea->compression_type=EA_VAG; - if(ea->compression_type==0) - ea->compression_type=EA_EAXA; -} - -VGMSTREAM * init_vgmstream_ea(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - EA_STRUCT ea; - char filename[PATH_LIMIT]; - - int loop_flag=0; - int channel_count; - int header_length; - off_t start_offset; - int i; - - memset(&ea,0,sizeof(EA_STRUCT)); - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("strm",filename_extension(filename)) && - strcasecmp("xa",filename_extension(filename)) && - strcasecmp("sng",filename_extension(filename)) && - strcasecmp("asf",filename_extension(filename)) && - strcasecmp("str",filename_extension(filename)) && - strcasecmp("xsf",filename_extension(filename)) && - strcasecmp("eam",filename_extension(filename))) goto fail; - - /* check Header */ - if (read_32bitBE(0x00,streamFile) != 0x5343486C) // SCHl - goto fail; - - header_length = read_32bitLE(0x04,streamFile); - start_offset=8; - - if(header_length>0x100) goto fail; - - Parse_Header(streamFile,&ea,start_offset,header_length-8); - - /* unknown loop value for the moment */ - loop_flag = 0; - - channel_count=ea.channels; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->channels = channel_count; - vgmstream->ea_platform=ea.platform; - - vgmstream->ea_compression_type=ea.compression_type; - vgmstream->ea_compression_version=ea.compression_version; - - // Set defaut sample rate if not define in the header - if(ea.sample_rate!=0) { - vgmstream->sample_rate = ea.sample_rate; - } else { - if(read_32bitBE(0x08,streamFile)==0x47535452) { // GSTR - vgmstream->sample_rate=44100; - } else { - switch(vgmstream->ea_platform) { - case EA_XBOX: - vgmstream->sample_rate=24000; - break; - case EA_X360: - vgmstream->sample_rate=44100; - break; - default: - vgmstream->sample_rate=22050; - } - } - } - - // Set default compression scheme if not define in the header - switch(vgmstream->ea_platform) { - case EA_X360: - vgmstream->ea_compression_version=0x03; - break; - } - - vgmstream->num_samples=ea.num_samples; - - switch(vgmstream->ea_compression_type) { - case EA_EAXA: - if(vgmstream->ea_compression_version==0x03) - vgmstream->meta_type=meta_EAXA_R3; - else { - // seems there's no EAXA R2 on PC - if(ea.platform==EA_PC) { - vgmstream->ea_compression_version=0x03; - vgmstream->meta_type=meta_EAXA_R3; - } else - vgmstream->meta_type=meta_EAXA_R2; - } - - vgmstream->coding_type=coding_EA_XA; - vgmstream->layout_type=layout_ea_blocked; - if((vgmstream->ea_platform==EA_GC) || (vgmstream->ea_platform==EA_X360)) - vgmstream->ea_big_endian=1; - - break; - case EA_VAG: - vgmstream->meta_type=meta_EAXA_PSX; - vgmstream->coding_type=coding_PSX; - vgmstream->layout_type=layout_ea_blocked; - break; - case EA_PCM_LE: - vgmstream->meta_type=meta_EA_PCM; - vgmstream->coding_type=coding_PCM16LE_int; - vgmstream->layout_type=layout_ea_blocked; - break; - case EA_PCM_BE: - vgmstream->meta_type=meta_EA_PCM; - vgmstream->coding_type=coding_PCM16BE; - vgmstream->layout_type=layout_ea_blocked; - break; - case EA_ADPCM: - vgmstream->meta_type=meta_EA_ADPCM; - vgmstream->coding_type=coding_EA_ADPCM; - vgmstream->layout_type=layout_ea_blocked; - break; - case EA_IMA: - vgmstream->meta_type=meta_EA_IMA; - vgmstream->coding_type=coding_XBOX; - vgmstream->layout_type=layout_ea_blocked; - break; - } - - - /* open the file for reading by each channel */ - { - for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,0x8000); - - if (!vgmstream->ch[i].streamfile) goto fail; - } - } - - - // Special function for .EAM files ... - if(!strcasecmp("eam",filename_extension(filename))) { - - size_t file_length=get_streamfile_size(streamFile); - size_t block_length; - - vgmstream->next_block_offset=start_offset+header_length; - vgmstream->num_samples=0; - - // to initialize the block length - ea_block_update(start_offset+header_length,vgmstream); - block_length=vgmstream->next_block_offset-start_offset+header_length; - - do { - ea_block_update(vgmstream->next_block_offset,vgmstream); - if(vgmstream->coding_type==coding_PSX) - vgmstream->num_samples+=(int32_t)vgmstream->current_block_size/16*28; - else if (vgmstream->coding_type==coding_EA_ADPCM) - vgmstream->num_samples+=(int32_t)vgmstream->current_block_size; - else if (vgmstream->coding_type==coding_PCM16LE_int) - vgmstream->num_samples+=(int32_t)vgmstream->current_block_size/vgmstream->channels; - else - vgmstream->num_samples+=(int32_t)vgmstream->current_block_size*28; - } while(vgmstream->next_block_offset<(off_t)(file_length-block_length)); - } - - ea_block_update(start_offset+header_length,vgmstream); - - init_get_high_nibble(vgmstream); - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c b/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c new file mode 100644 index 000000000..1b8fff1bd --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c @@ -0,0 +1,608 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../coding/coding.h" + +/* header version */ +#define EA_VERSION_NONE -1 +#define EA_VERSION_V0 0x00 // ~early PC (when codec1 was used) +#define EA_VERSION_V1 0x01 // ~PC +#define EA_VERSION_V2 0x02 // ~PS era +#define EA_VERSION_V3 0x03 // ~PS2 era + +/* platform constants (unasigned values seem internal only) */ +#define EA_PLATFORM_GENERIC -1 // typically Wii/X360/PS3 +#define EA_PLATFORM_PC 0x00 +#define EA_PLATFORM_PSX 0x01 +#define EA_PLATFORM_N64 0x02 +#define EA_PLATFORM_MAC 0x03 +//#define EA_PLATFORM_SAT 0x04 // ? +#define EA_PLATFORM_PS2 0x05 +#define EA_PLATFORM_GC_WII 0x06 // reused later for Wii +#define EA_PLATFORM_XBOX 0x07 +#define EA_PLATFORM_X360 0x09 // also "Xenon" +#define EA_PLATFORM_PSP 0x0A +#define EA_PLATFORM_3DS 0x14 + +/* codec constants (undefined are probably reserved, ie.- sx.exe encodes PCM24/DVI but no platform decodes them) */ +/* CODEC1 values were used early, then they migrated to CODEC2 values */ +#define EA_CODEC1_NONE -1 +//#define EA_CODEC1_S16BE 0x00 //LE too? +//#define EA_CODEC1_VAG 0x01 +#define EA_CODEC1_MT10 0x07 // Need for Speed 2 PC +//#define EA_CODEC1_N64 ? + +#define EA_CODEC2_NONE -1 +#define EA_CODEC2_MT10 0x04 +#define EA_CODEC2_VAG 0x05 +#define EA_CODEC2_S16BE 0x07 +#define EA_CODEC2_S16LE 0x08 +#define EA_CODEC2_S8 0x09 +#define EA_CODEC2_EAXA 0x0A +#define EA_CODEC2_LAYER2 0x0F +#define EA_CODEC2_LAYER3 0x10 +#define EA_CODEC2_GCADPCM 0x12 +#define EA_CODEC2_XBOXADPCM 0x14 +#define EA_CODEC2_MT5 0x16 +#define EA_CODEC2_EALAYER3 0x17 + +#define EA_MAX_CHANNELS 6 + +typedef struct { + uint8_t id; + int32_t num_samples; + int32_t sample_rate; + int32_t channels; + int32_t platform; + int32_t version; + int32_t codec1; + int32_t codec2; + + int32_t loop_start; + int32_t loop_end; + + off_t offsets[EA_MAX_CHANNELS]; + off_t coefs[EA_MAX_CHANNELS]; + + int big_endian; + int loop_flag; + int codec_version; +} ea_header; + +static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begin_offset, int max_length); +static uint32_t read_patch(STREAMFILE* streamFile, off_t* offset); +static int get_ea_total_samples(STREAMFILE* streamFile, off_t start_offset, const ea_header* ea); +static off_t get_ea_mpeg_start_offset(STREAMFILE* streamFile, off_t start_offset, const ea_header* ea); + + +/* EA SCHl - from EA games (roughly 1997~2010, generated by EA Canada's sx.exe / Sound eXchange) */ +VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + size_t header_size; + ea_header ea; + + + /* check extension; exts don't seem enforced by EA's tools, but usually: + * STR/ASF/MUS ~early, EAM ~mid, SNG/AUD ~late, rest uncommon/one game (ex. STRM: MySims Kingdom Wii) */ + if (!check_extensions(streamFile,"str,asf,mus,eam,sng,aud,strm,xa,xsf,exa,stm")) + goto fail; + + /* check header */ + /* EA's stream files are made of blocks called "chunks" (SCxx, presumably Sound Chunk xx) + * typically: SCHl=header, SCCl=count of SCDl, SCDl=data xN, SCLl=loop end, SCEl=stream end. + * The number/size of blocks is affected by: block rate setting, sample rate, channels, CPU location (SPU/main/DSP/others), etc */ + if (read_32bitBE(0x00,streamFile) != 0x5343486C) /* "SCHl" */ + goto fail; + + header_size = read_32bitLE(0x04,streamFile); + if (header_size > 0xF0000000) /* size is always LE, except in early MAC apparently */ + header_size = read_32bitBE(0x04,streamFile); + + memset(&ea,0,sizeof(ea_header)); + if (!parse_stream_header(streamFile,&ea, 0x08, header_size-4-4)) + goto fail; + + start_offset = header_size; /* start in "SCCl" or very rarely "SCDl" (skipped in block layout, though) */ + if (read_32bitBE(start_offset,streamFile) != 0x5343436C && read_32bitBE(start_offset,streamFile) != 0x5343446C ) /* "SCCl" / "SCDl" */ + goto fail; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(ea.channels, ea.loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = ea.sample_rate; + vgmstream->num_samples = ea.num_samples; + vgmstream->loop_start_sample = ea.loop_start; + vgmstream->loop_end_sample = ea.loop_end; + + vgmstream->codec_endian = ea.big_endian; + vgmstream->codec_version = ea.codec_version; + + vgmstream->meta_type = meta_EA_SCHL; + vgmstream->layout_type = layout_ea_blocked; + + /* EA usually implements their codecs in all platforms (PS2/WII do EAXA/MT/EALAYER3) and + * favors them over platform's natives (ex. EAXA vs VAG/DSP). + * Unneeded codecs are removed over time (ex. LAYER3 when EALAYER3 was introduced). */ + switch (ea.codec2) { + + case EA_CODEC2_EAXA: /* EA-XA, CDXA ADPCM variant */ + vgmstream->coding_type = coding_EA_XA; + break; + + case EA_CODEC2_MT10: /* MicroTalk (10:1), aka EA ADPCM (stereo or interleaved) */ + vgmstream->coding_type = coding_EA_MT10; + break; + + case EA_CODEC2_S8: /* PCM8 */ + vgmstream->coding_type = coding_PCM8; + break; + + case EA_CODEC2_S16BE: /* PCM16BE */ + vgmstream->coding_type = coding_PCM16BE; + break; + + case EA_CODEC2_S16LE: /* PCM16LE */ + vgmstream->coding_type = coding_PCM16LE; + break; + + case EA_CODEC2_VAG: /* PS-ADPCM */ + vgmstream->coding_type = coding_PSX; + break; + + case EA_CODEC2_XBOXADPCM: /* XBOX IMA (interleaved mono) */ + vgmstream->coding_type = coding_XBOX; /* stereo decoder actually, but has a special case for EA */ + break; + + case EA_CODEC2_GCADPCM: /* DSP */ + vgmstream->coding_type = coding_NGC_DSP; + + /* get them coefs (start offsets are not necessarily ordered) */ + { + int ch, i; + int16_t (*read_16bit)(off_t,STREAMFILE*) = ea.big_endian ? read_16bitBE : read_16bitLE; + + for (ch=0; ch < vgmstream->channels; ch++) { + for (i=0; i < 16; i++) { /* actual size 0x21, last byte unknown */ + vgmstream->ch[ch].adpcm_coef[i] = read_16bit(ea.coefs[ch] + i*2, streamFile); + } + } + } + break; + +#ifdef VGM_USE_MPEG + case EA_CODEC2_LAYER2: /* MPEG Layer II, aka MP2 */ + case EA_CODEC2_LAYER3: { /* MPEG Layer III, aka MP3 */ + mpeg_codec_data *mpeg_data = NULL; + coding_t mpeg_coding_type; + + off_t mpeg_start_offset = get_ea_mpeg_start_offset(streamFile, start_offset, &ea); + if (!mpeg_start_offset) goto fail; + + mpeg_data = init_mpeg_codec_data_interleaved(streamFile, mpeg_start_offset, &mpeg_coding_type, vgmstream->channels, MPEG_EA, 0); + if (!mpeg_data) goto fail; + vgmstream->codec_data = mpeg_data; + vgmstream->coding_type = mpeg_coding_type; + //vgmstream->layout_type = layout_mpeg; + //mpeg_set_error_logging(mpeg_data, 0); /* should not be needed anymore with the interleave decoder */ + break; + } +#endif + + case EA_CODEC2_MT5: /* MicroTalk (5:1) */ + case EA_CODEC2_EALAYER3: /* MP3 variant */ + default: + VGM_LOG("EA: unknown codec2 0x%02x for platform 0x%02x\n", ea.codec2, ea.platform); + goto fail; + } + + + /* fix num_samples for multifiles */ + { + int total_samples = get_ea_total_samples(streamFile, start_offset, &ea); + if (total_samples > vgmstream->num_samples) + vgmstream->num_samples = total_samples; + } + + /* open files; channel offsets are updated below */ + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + + ea_schl_block_update(start_offset,vgmstream); + + + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + + +static uint32_t read_patch(STREAMFILE* streamFile, off_t* offset) { + uint32_t result = 0; + uint8_t byte_count = read_8bit(*offset, streamFile); + (*offset)++; + + if (byte_count == 0xFF) { /* signals 32b size (ex. custom user data) */ + (*offset) += 4 + read_32bitBE(*offset, streamFile); + return 0; + } + + if (byte_count > 4) { /* uncommon (ex. coef patches) */ + (*offset) += byte_count; + return 0; + } + + for ( ; byte_count > 0; byte_count--) { /* count of 0 is also possible, means value 0 */ + result <<= 8; + result += (uint8_t)read_8bit(*offset, streamFile); + (*offset)++; + } + + return result; +} + +/* decodes EA's GSTR/PT header (mostly cross-referenced with sx.exe) */ +static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begin_offset, int max_length) { + off_t offset = begin_offset; + uint32_t platform_id; + int is_header_end = 0; + + + /* null defaults as 0 can be valid */ + ea->version = EA_VERSION_NONE; + ea->codec1 = EA_CODEC1_NONE; + ea->codec2 = EA_CODEC2_NONE; + + /* get platform info */ + platform_id = read_32bitBE(offset, streamFile); + if (platform_id != 0x47535452 && (platform_id & 0xFFFF0000) != 0x50540000) { + offset += 4; /* skip unknown field (related to blocks/size?) in "nbapsstream" (NBA2000 PS, FIFA2001 PS) */ + platform_id = read_32bitBE(offset, streamFile); + } + if (platform_id == 0x47535452) { /* "GSTR" = Generic STReam */ + ea->platform = EA_PLATFORM_GENERIC; + offset += 4 + 4; /* GSTRs have an extra field (config?): ex. 0x01000000, 0x010000D8 BE */ + } + else if ((platform_id & 0xFFFF0000) == 0x50540000) { /* "PT" = PlaTform */ + ea->platform = (uint8_t)read_16bitLE(offset + 2,streamFile); + offset += 4; + } + else { + goto fail; + } + + /* parse mini-chunks/tags (variable, ommited if default exists) */ + while (offset - begin_offset < max_length) { + uint8_t patch_type = read_8bit(offset,streamFile); + offset++; + + switch(patch_type) { + + case 0x00: /* signals non-default block rate and maybe other stuff; or padding after 0xFD */ + if (!is_header_end) + read_patch(streamFile, &offset); + break; + + case 0x06: /* always 0x65 */ + ea->id = read_patch(streamFile, &offset); + break; + + case 0x05: /* unknown (usually 0x50 except Madden NFL 3DS: 0x3e800) */ + case 0x0B: /* unknown (always 0x02) */ + case 0x13: /* effect bus (0..127) */ + case 0x14: /* emdedded user data (free size/value) */ + read_patch(streamFile, &offset); + break; + + case 0xFC: /* padding for alignment between patches */ + case 0xFE: /* padding? (actually exists?) */ + case 0xFD: /* info section start marker */ + break; + + case 0xA0: /* codec2 defines */ + ea->codec2 = read_patch(streamFile, &offset); + break; + + case 0x80: /* version, affecting some codecs */ + ea->version = read_patch(streamFile, &offset); + break; + + case 0x82: /* channel count */ + ea->channels = read_patch(streamFile, &offset); + break; + + case 0x83: /* codec1 defines, used early revisions */ + ea->codec1 = read_patch(streamFile, &offset); + break; + + case 0x84: /* sample rate */ + ea->sample_rate = read_patch(streamFile,&offset); + break; + + case 0x85: /* sample count */ + ea->num_samples = read_patch(streamFile, &offset); + break; + case 0x86: /* loop start sample */ + ea->loop_start = read_patch(streamFile, &offset); + break; + case 0x87: /* loop end sample */ + ea->loop_end = read_patch(streamFile, &offset); + break; + + /* channel offsets (BNK only), can be the equal for all channels or interleaved; not necessarily contiguous */ + case 0x88: /* absolute offset of ch1 */ + ea->offsets[0] = read_patch(streamFile, &offset); + break; + case 0x89: /* absolute offset of ch2 */ + ea->offsets[1] = read_patch(streamFile, &offset); + break; + case 0x94: /* absolute offset of ch3 */ + ea->offsets[2] = read_patch(streamFile, &offset); + break; + case 0x95: /* absolute offset of ch4 */ + ea->offsets[3] = read_patch(streamFile, &offset); + break; + case 0xA2: /* absolute offset of ch5 */ + ea->offsets[4] = read_patch(streamFile, &offset); + break; + case 0xA3: /* absolute offset of ch6 */ + ea->offsets[5] = read_patch(streamFile, &offset); + break; + + case 0x8F: /* DSP/N64BLK coefs ch1 */ + ea->coefs[0] = offset+1; + read_patch(streamFile, &offset); + break; + case 0x90: /* DSP/N64BLK coefs ch2 */ + ea->coefs[1] = offset+1; + read_patch(streamFile, &offset); + break; + case 0x91: /* DSP coefs ch3 */ + ea->coefs[2] = offset+1; + read_patch(streamFile, &offset); + break; + case 0xAB: /* DSP coefs ch4 */ + ea->coefs[3] = offset+1; + read_patch(streamFile, &offset); + break; + case 0xAC: /* DSP coefs ch5 */ + ea->coefs[4] = offset+1; + read_patch(streamFile, &offset); + break; + case 0xAD: /* DSP coefs ch6 */ + ea->coefs[5] = offset+1; + read_patch(streamFile, &offset); + break; + + case 0x8A: /* long padding? (always 0x00000000) */ + case 0x8C: /* platform+codec related? */ + /* (ex. PS1 VAG=0, PS2 PCM/LAYER2=4, GC EAXA=4, 3DS DSP=512, Xbox EAXA=36, N64 BLK=05E800, N64 MT=01588805E800) */ + case 0x92: /* bytes per sample? */ + case 0x98: /* embedded time stretch 1 (long data for who-knows-what) */ + case 0x99: /* embedded time stretch 2 */ + case 0x9C: /* azimuth ch1 */ + case 0x9D: /* azimuth ch2 */ + case 0x9E: /* azimuth ch3 */ + case 0x9F: /* azimuth ch4 */ + case 0xA6: /* azimuth ch5 */ + case 0xA7: /* azimuth ch6 */ + case 0xA1: /* unknown and very rare, always 0x02 (FIFA 2001 PS2) */ + read_patch(streamFile, &offset); + break; + + case 0xFF: /* header end (then 0-padded) */ + is_header_end = 1; + break; + + default: + VGM_LOG("EA: unknown patch 0x%02x at 0x%04lx\n", patch_type, (offset-1)); + break; + } + } + + if (ea->id && ea->id != 0x65) /* very rarely not specified (FIFA 14) */ + goto fail; + if (ea->channels > EA_MAX_CHANNELS) + goto fail; + + + /* set defaults per platform, as the header ommits them when possible */ + + ea->loop_flag = (ea->loop_end); + + if (!ea->channels) { + ea->channels = 1; + } + + /* version affects EAXA and MT codecs, but can be found with all other codecs */ + /* For PC/MAC V0 is simply no version when codec1 was used */ + if (ea->version == EA_VERSION_NONE) { + switch(ea->platform) { + case EA_PLATFORM_GENERIC: ea->version = EA_VERSION_V2; break; + case EA_PLATFORM_PC: ea->version = EA_VERSION_V0; break; + case EA_PLATFORM_PSX: ea->version = EA_VERSION_V0; break; // assumed + case EA_PLATFORM_N64: ea->version = EA_VERSION_V0; break; // assumed + case EA_PLATFORM_MAC: ea->version = EA_VERSION_V0; break; + case EA_PLATFORM_PS2: ea->version = EA_VERSION_V1; break; + case EA_PLATFORM_GC_WII: ea->version = EA_VERSION_V2; break; + case EA_PLATFORM_XBOX: ea->version = EA_VERSION_V2; break; + case EA_PLATFORM_X360: ea->version = EA_VERSION_V3; break; + case EA_PLATFORM_PSP: ea->version = EA_VERSION_V3; break; + case EA_PLATFORM_3DS: ea->version = EA_VERSION_V3; break; + default: + VGM_LOG("EA: unknown default version for platform 0x%02x\n", ea->platform); + goto fail; + } + } + + /* codec1 to codec2 to simplify later parsing */ + if (ea->codec1 != EA_CODEC1_NONE && ea->codec2 == EA_CODEC2_NONE) { + switch (ea->codec1) { + case EA_CODEC1_MT10: ea->codec2 = EA_CODEC2_MT10; break; + default: + VGM_LOG("EA: unknown codec1 0x%02x\n", ea->codec1); + goto fail; + } + } + + /* defaults don't seem to change with version or over time, fortunately */ + if (ea->codec2 == EA_CODEC2_NONE) { + switch(ea->platform) { + case EA_PLATFORM_GENERIC: ea->codec2 = EA_CODEC2_EAXA; break; + case EA_PLATFORM_PC: ea->codec2 = EA_CODEC2_EAXA; break; + case EA_PLATFORM_PSX: ea->codec2 = EA_CODEC2_VAG; break; + case EA_PLATFORM_MAC: ea->codec2 = EA_CODEC2_EAXA; break; + case EA_PLATFORM_PS2: ea->codec2 = EA_CODEC2_VAG; break; + case EA_PLATFORM_GC_WII: ea->codec2 = EA_CODEC2_S16BE; break; + case EA_PLATFORM_XBOX: ea->codec2 = EA_CODEC2_S16LE; break; + case EA_PLATFORM_X360: ea->codec2 = EA_CODEC2_EAXA; break; + case EA_PLATFORM_PSP: ea->codec2 = EA_CODEC2_EAXA; break; + case EA_PLATFORM_3DS: ea->codec2 = EA_CODEC2_GCADPCM; break; + default: + VGM_LOG("EA: unknown default codec2 for platform 0x%02x\n", ea->platform); + goto fail; + } + } + + /* somehow doesn't follow machine's sample rate or anything sensical */ + if (!ea->sample_rate) { + switch(ea->platform) { + case EA_PLATFORM_GENERIC: ea->sample_rate = 48000; break; + case EA_PLATFORM_PC: ea->sample_rate = 22050; break; + case EA_PLATFORM_PSX: ea->sample_rate = 22050; break; + case EA_PLATFORM_N64: ea->sample_rate = 22050; break; + case EA_PLATFORM_MAC: ea->sample_rate = 22050; break; + case EA_PLATFORM_PS2: ea->sample_rate = 22050; break; + case EA_PLATFORM_GC_WII: ea->sample_rate = 24000; break; + case EA_PLATFORM_XBOX: ea->sample_rate = 24000; break; + case EA_PLATFORM_X360: ea->sample_rate = 44100; break; + case EA_PLATFORM_PSP: ea->sample_rate = 22050; break; + //case EA_PLATFORM_3DS: ea->sample_rate = 44100; break;//todo (not 22050/16000) + default: + VGM_LOG("EA: unknown default sample rate for platform 0x%02x\n", ea->platform); + goto fail; + } + } + + /* affects blocks/codecs */ + if (ea->platform == EA_PLATFORM_N64 + || ea->platform == EA_PLATFORM_MAC + || ea->platform == EA_PLATFORM_GC_WII + || ea->platform == EA_PLATFORM_X360 + || ea->platform == EA_PLATFORM_GENERIC) { + ea->big_endian = 1; + } + + /* config MT/EAXA variations */ + if (ea->codec2 == EA_CODEC2_MT10) { + if (ea->version > EA_VERSION_V0) + ea->codec_version = 1; /* 0=stereo (early), 1:interleaved */ + } + else if (ea->codec2 == EA_CODEC2_EAXA) { + /* console EAXA V2 uses hist, as does PC/MAC V1 */ + if (ea->version > EA_VERSION_V1 && !(ea->version == EA_VERSION_V2 + && (ea->platform == EA_PLATFORM_PS2|| ea->platform == EA_PLATFORM_GC_WII || ea->platform == EA_PLATFORM_XBOX))) + ea->codec_version = 1; /* 0=has ADPCM history per block (early), 1:doesn't */ + } + + return offset; + +fail: + return 0; +} + +/* 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 as mapped + * music (.map/lin). We get total possible samples (counting all subfiles) and pretend + * they are a single stream. Subfiles always share header, except num_samples. */ +static int get_ea_total_samples(STREAMFILE* streamFile, off_t start_offset, const ea_header* ea) { + int i, num_samples = 0; + size_t file_size = get_streamfile_size(streamFile); + off_t block_offset = start_offset; + int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE; + + while (block_offset < file_size) { + uint32_t id, block_size; + + id = read_32bitBE(block_offset+0x00,streamFile); + + block_size = read_32bitLE(block_offset+0x04,streamFile); + VGM_ASSERT(block_size > 0xF0000000, "EA: BE block size in MAC\n"); + if (block_size > 0xF0000000) /* size is always LE, except in early MAC apparently */ + block_size = read_32bitBE(block_offset+0x04,streamFile); + + if (id == 0x5343446C) { /* "SCDl" data block found */ + /* use num_samples from header if possible */ + switch (ea->codec2) { + case EA_CODEC2_VAG: /* PS-ADPCM */ + num_samples += ps_bytes_to_samples(block_size-0x10, ea->channels); + break; + + default: + num_samples += read_32bit(block_offset+0x08,streamFile); + break; + } + } + + block_offset += block_size; /* size includes header */ + + /* EA sometimes concats many small files, so after SCEl there may be a new SCHl. + * We'll find it and pretend they are a single stream. */ + if (id == 0x5343456C && block_offset + 0x80 > file_size) + break; + if (id == 0x5343456C) { /* "SCEl" end block found */ + /* Usually there is padding between SCEl and SCHl (aligned to 0x80) */ + block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* also 32b-aligned */ + for (i = 0; i < 0x80 / 4; i++) { + id = read_32bitBE(block_offset,streamFile); + if (id == 0x5343486C) /* "SCHl" new header block found */ + break; /* next loop will parse and skip it */ + block_offset += 0x04; + } + } + + if (block_offset > file_size) + break; + + if (id == 0 || id == 0xFFFFFFFF) + return num_samples; /* probably hit padding or EOF */ + + VGM_ASSERT(id != 0x5343486C && id != 0x5343436C && id != 0x5343446C && id != 0x53434C6C && id != 0x5343456C, + "EA: unknown block id 0x%x at 0x%lx\n", id, block_offset); + } + + return num_samples; +} + +/* find data start offset inside the first SCDl; not very elegant but oh well */ +static off_t get_ea_mpeg_start_offset(STREAMFILE* streamFile, off_t start_offset, const ea_header* ea) { + size_t file_size = get_streamfile_size(streamFile); + off_t block_offset = start_offset; + int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE; + + while (block_offset < file_size) { + uint32_t id, block_size; + + id = read_32bitBE(block_offset+0x00,streamFile); + + block_size = read_32bitLE(block_offset+0x04,streamFile); + if (block_size > 0xF0000000) /* size is always LE, except in early MAC apparently */ + block_size = read_32bitBE(block_offset+0x04,streamFile); + + if (id == 0x5343446C) { /* "SCDl" data block found */ + off_t offset = read_32bit(block_offset+0x0c,streamFile); /* first channel offset is ok, MPEG channels share offsets */ + return block_offset + 0x0c + ea->channels*0x04 + offset; + } else if (id == 0x5343436C) { /* "SCCl" data count found */ + block_offset += block_size; /* size includes header */ + continue; + } else { + goto fail; + } + } + +fail: + return 0; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb.c index 2396ef77f..224d249c7 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb.c @@ -292,7 +292,7 @@ VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) { else /* needed by multichannel with no flags */ fsb_padding = fsbh.numchannels > 2 ? 16 : 0; - mpeg_data = init_mpeg_codec_data_interleaved(streamFile, start_offset, &mpeg_coding_type, vgmstream->channels, 0, fsb_padding); + mpeg_data = init_mpeg_codec_data_interleaved(streamFile, start_offset, &mpeg_coding_type, vgmstream->channels, MPEG_FSB, fsb_padding); if (!mpeg_data) goto fail; vgmstream->codec_data = mpeg_data; vgmstream->coding_type = mpeg_coding_type; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c b/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c index efc0ca21b..29c9955ba 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/fsb5.c @@ -264,7 +264,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) { fsb_padding = vgmstream->channels > 2 ? 16 : 4; /* observed default */ - mpeg_data = init_mpeg_codec_data_interleaved(streamFile, StartOffset, &mpeg_coding_type, vgmstream->channels, 0, fsb_padding); + mpeg_data = init_mpeg_codec_data_interleaved(streamFile, StartOffset, &mpeg_coding_type, vgmstream->channels, MPEG_FSB, fsb_padding); if (!mpeg_data) goto fail; vgmstream->codec_data = mpeg_data; vgmstream->coding_type = mpeg_coding_type; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/meta.h b/Frameworks/vgmstream/vgmstream/src/meta/meta.h index 83e879f92..98b4c4e7a 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h @@ -80,7 +80,7 @@ VGMSTREAM * init_vgmstream_xbox_xwav(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ngc_str(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_ea(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_caf(STREAMFILE *streamFile); @@ -188,7 +188,7 @@ VGMSTREAM * init_vgmstream_rwx(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_xwb(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_xa30(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_ps2_xa30(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_musc(STREAMFILE * streamFile); @@ -674,4 +674,8 @@ VGMSTREAM * init_vgmstream_ps3_mta2(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ngc_ulw(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_pc_xa30(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_wii_04sw(STREAMFILE * streamFile); + #endif /*_META_H*/ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ngc_dsp_std.c b/Frameworks/vgmstream/vgmstream/src/meta/ngc_dsp_std.c index 15dbff4c1..19a48b4b1 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ngc_dsp_std.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ngc_dsp_std.c @@ -229,9 +229,10 @@ VGMSTREAM * init_vgmstream_ngc_mdsp_std(STREAMFILE *streamFile) { vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave; + vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave_shortblock; vgmstream->meta_type = meta_DSP_STD; vgmstream->interleave_block_size = header.block_size * 8; + vgmstream->interleave_smallblock_size = (header.nibble_count / 2 % vgmstream->interleave_block_size + 7) / 8 * 8; for (i = 0; i < channel_count; i++) { if (read_dsp_header(&header, header_size * i, streamFile)) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/p3d.c b/Frameworks/vgmstream/vgmstream/src/meta/p3d.c index ebc0ab09f..3978bec1e 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/p3d.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/p3d.c @@ -1,117 +1,187 @@ #include "meta.h" -#include "../util.h" - -/* P3D, with Radical ADPCM, from Prototype */ +#include "../coding/coding.h" +/* P3D - from Radical's Prototype 1/2 (PC/PS3/X360) */ VGMSTREAM * init_vgmstream_p3d(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t parse_offset; - off_t start_offset; - size_t file_size; + off_t start_offset, parse_offset; + size_t header_size, file_size, data_size; + int loop_flag = 0, channel_count, sample_rate, codec; + int i, name_count, text_len, block_size = 0, block_count = 0, num_samples; + int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; - uint32_t header_size; - uint32_t sample_rate; - uint32_t body_bytes; - int loop_flag; - int channel_count; - const int interleave = 0x14; /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("p3d",filename_extension(filename))) goto fail; + if (!check_extensions(streamFile,"p3d")) + goto fail; /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x503344FF) /* P3D\xFF */ - goto fail; - header_size = read_32bitLE(0x4,streamFile); - if (0xC != header_size) goto fail; + if (read_32bitBE(0x0,streamFile) != 0x503344FF && /* "P3D"\FF (LE: PC) */ + read_32bitBE(0x0,streamFile) != 0xFF443350) /* \FF"D3P" (BE: PS3, X360) */ + goto fail; + + read_32bit = read_32bitBE(0x0,streamFile) == 0xFF443350 ? read_32bitBE : read_32bitLE; file_size = get_streamfile_size(streamFile); - if (read_32bitLE(0x8,streamFile) != file_size) goto fail; - if (read_32bitBE(0xC,streamFile) != 0xFE) goto fail; - /* body size twice? */ - if (read_32bitLE(0x10,streamFile) + header_size != file_size) goto fail; - if (read_32bitLE(0x14,streamFile) + header_size != file_size) goto fail; - /* mysterious 10! */ - if (read_32bitLE(0x18,streamFile) != 10) goto fail; + /* base header */ + header_size = read_32bit(0x4,streamFile); + if (0x0C != header_size) goto fail; + if (read_32bit(0x08,streamFile) != file_size) goto fail; + if (read_32bit(0x0C,streamFile) != 0xFE000000) goto fail; /* fixed */ + if (read_32bit(0x10,streamFile) + header_size != file_size) goto fail; + if (read_32bit(0x14,streamFile) + header_size != file_size) goto fail; /* body size again */ + if (read_32bit(0x18,streamFile) != 0x0000000A) goto fail; /* fixed */ - /* parse header text */ + /* header text */ parse_offset = 0x1C; - { - int text_len = read_32bitLE(parse_offset,streamFile); - if (9 != text_len) goto fail; - /* AudioFile */ - if (read_32bitBE(parse_offset+4,streamFile) != 0x41756469 || - read_32bitBE(parse_offset+8,streamFile) != 0x6F46696C || - read_16bitBE(parse_offset+12,streamFile) != 0x6500) goto fail; - parse_offset += 4 + text_len + 1; - } - { - uint32_t name_count = read_32bitLE(parse_offset,streamFile); - int i; - parse_offset += 4; - /* names? */ - for (i = 0; i < name_count; i++) - { - int text_len = read_32bitLE(parse_offset,streamFile); - parse_offset += 4 + text_len + 1; - } - } - /* info count? */ - if (1 != read_32bitLE(parse_offset,streamFile)) goto fail; + text_len = read_32bit(parse_offset,streamFile); + if (9 != text_len) goto fail; parse_offset += 4; - { - int text_len = read_32bitLE(parse_offset,streamFile); - if (4 != text_len) goto fail; - /* radp */ - if (read_32bitBE(parse_offset+4,streamFile) != 0x72616470 || - read_8bit(parse_offset+8,streamFile) != 0) goto fail; + + /* check the type as P3D is just a generic container used in Radical's games */ + if (read_32bitBE(parse_offset+0x00,streamFile) != 0x41756469 || + read_32bitBE(parse_offset+0x04,streamFile) != 0x6F46696C || + read_16bitBE(parse_offset+0x08,streamFile) != 0x6500) goto fail; /* "AudioFile\0" */ + parse_offset += text_len + 1; + + /* file names: always 2 (repeated); but if it's 3 there is an extra string later */ + name_count = read_32bit(parse_offset,streamFile); + if (name_count != 2 && name_count != 3) goto fail; /* 2: Prototype1, 3: Prototype2 */ + parse_offset += 4; + + for (i = 0; i < 2; i++) { /* skip names */ + text_len = read_32bit(parse_offset,streamFile); parse_offset += 4 + text_len + 1; } - /* real RADP header */ - if (0x52414450 != read_32bitBE(parse_offset,streamFile)) goto fail; - channel_count = read_32bitLE(parse_offset+4,streamFile); - sample_rate = read_32bitLE(parse_offset+8,streamFile); - /* codec id? */ - //if (9 != read_32bitLE(parse_offset+0xC,streamFile)) goto fail; - body_bytes = read_32bitLE(parse_offset+0x10,streamFile); - start_offset = parse_offset+0x14; - if (start_offset + body_bytes != file_size) goto fail; + /* info count? */ + if (0x01 != read_32bit(parse_offset,streamFile)) goto fail; + parse_offset += 4; - loop_flag = 0; - - /* build the VGMSTREAM */ + /* next string can be used as a codec id */ + text_len = read_32bit(parse_offset,streamFile); + codec = read_32bitBE(parse_offset+4,streamFile); + parse_offset += 4 + text_len + 1; + + /* extra "Music" string in Prototype 2 */ + if (name_count == 3) { + text_len = read_32bit(parse_offset,streamFile); + parse_offset += 4 + text_len + 1; + } + + + /* sub-header per codec */ + switch(codec) { + case 0x72616470: /* "radp" (PC) */ + if (read_32bitBE(parse_offset,streamFile) != 0x52414450) goto fail; /* "RADP" */ + parse_offset += 0x04; + channel_count = read_32bit(parse_offset+0x00,streamFile); + sample_rate = read_32bit(parse_offset+0x04,streamFile); + /* 0x08: ? (0x0F) */ + data_size = read_32bit(parse_offset+0x0c,streamFile); + block_size = 0x14; + num_samples = data_size / block_size / channel_count * 32; + start_offset = parse_offset+0x10; + break; + + case 0x6D703300: /* "mp3\0" (PS3) */ + if ((read_32bitBE(parse_offset,streamFile) & 0xFFFFFF00) != 0x6D703300) goto fail; /* "mp3" */ + parse_offset += 0x03; + /* all fields LE even though the prev parts were BE */ + sample_rate = read_32bitLE(parse_offset+0x00,streamFile); + /* 0x04: mp3 sample rate (ex. @0x00 is 47999 and @0x04 is 48000) */ + num_samples = read_32bitLE(parse_offset+0x08,streamFile); + data_size = read_32bitLE(parse_offset+0x0c,streamFile); + channel_count = read_32bitLE(parse_offset+0x10,streamFile); + block_size = read_32bitLE(parse_offset+0x14,streamFile); + num_samples = num_samples / channel_count; /* total samples */ + block_size = block_size * channel_count; /* seems ok? */ + start_offset = parse_offset+0x18; + break; + + case 0x786D6100: /* "xma\0" (X360) */ + if (read_32bitBE(parse_offset,streamFile) != 0x584D4132) goto fail; /* "XMA2" */ + parse_offset += 0x04; + /* 0x00: subheader size? (0x2c), 0x04: seek table size */ + data_size = read_32bitBE(parse_offset+0x08,streamFile); + /* 0x0c: ?, 0x10: ?, 0x14/18: 0x0 */ + sample_rate = read_32bitBE(parse_offset+0x1c,streamFile); + /* 0x20: XMA decoder params, 0x24: abr */ + block_size = read_32bitBE(parse_offset+0x28,streamFile); + num_samples = read_32bitBE(parse_offset+0x2c,streamFile); + /* 0x30: original file's samples */ + block_count = read_32bitBE(parse_offset+0x34,streamFile); + channel_count = read_8bit(parse_offset+0x38,streamFile); + /* 0x39: channel related? (stream config? channel layout?) */ + start_offset = parse_offset + 0x3c + read_32bitBE(parse_offset+0x04,streamFile); + break; + + default: + VGM_LOG("unknown codec 0x%04x\n", codec); + goto fail; + } + + if (start_offset + data_size != file_size) goto fail; + + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - vgmstream->channels = channel_count; vgmstream->sample_rate = sample_rate; - vgmstream->coding_type = coding_RAD_IMA_mono; - vgmstream->interleave_block_size = interleave; - vgmstream->num_samples = body_bytes / interleave / channel_count * 32; - vgmstream->layout_type = layout_interleave; + vgmstream->num_samples = num_samples; vgmstream->meta_type = meta_P3D; - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].offset=vgmstream->ch[i].channel_start_offset=start_offset+interleave*i; + /* codec init */ + switch(codec) { + case 0x72616470: /* "radp" (PC) */ + vgmstream->coding_type = coding_RAD_IMA_mono; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = block_size; + break; + +#ifdef VGM_USE_MPEG + case 0x6D703300: { /* "mp3\0" (PS3) */ + mpeg_codec_data *mpeg_data = NULL; + coding_t mpeg_coding_type; + + mpeg_data = init_mpeg_codec_data_interleaved(streamFile, start_offset, &mpeg_coding_type, vgmstream->channels, MPEG_P3D, 0); + if (!mpeg_data) goto fail; + vgmstream->codec_data = mpeg_data; + vgmstream->layout_type = layout_mpeg; + vgmstream->coding_type = mpeg_coding_type; + + goto fail; //todo: not working right (unknown interleave) + //break; } +#endif + +#ifdef VGM_USE_FFMPEG + case 0x786D6100: { /* "xma\0" (X360) */ + uint8_t buf[0x100]; + size_t bytes; + + bytes = ffmpeg_make_riff_xma2(buf,0x100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size); + if (bytes <= 0) goto fail; + + vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size); + if ( !vgmstream->codec_data ) goto fail; + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; + break; + } +#endif + + default: + VGM_LOG("unknown codec 0x%04x\n", codec); + goto fail; } - - 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; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/pc_xa30.c b/Frameworks/vgmstream/vgmstream/src/meta/pc_xa30.c new file mode 100644 index 000000000..f6662cb1e --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/pc_xa30.c @@ -0,0 +1,69 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* XA30 - found in Driver: Parallel Lines (PC) */ +VGMSTREAM * init_vgmstream_pc_xa30(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag, channel_count, codec; + size_t file_size, data_size; + + + /* check extension, case insensitive */ + /* ".xa30" is just the ID, the real filename should be .XA */ + if (!check_extensions(streamFile,"xa,xa30")) + goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x58413330) /* "XA30" */ + goto fail; + if (read_32bitLE(0x04,streamFile) > 2) goto fail; /* extra check to avoid PS2/PC XA30 mixup */ + + + /* reportedly from XA2WAV those are offset+data from a second stream (not seen) */ + if (read_32bitLE(0x14,streamFile) != 0 || read_32bitLE(0x1c,streamFile) != 0) goto fail; + + loop_flag = 0; + channel_count = 2; /* 0x04: channels? (always 2 in practice) */ + + codec = read_32bitLE(0x0c,streamFile); /* reportedly from XA2WAV (not seen) */ + start_offset = read_32bitLE(0x10,streamFile); + + file_size = get_streamfile_size(streamFile); + data_size = read_32bitLE(0x18,streamFile); + if (data_size+start_offset != file_size) goto fail; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = read_32bitLE(0x08,streamFile); + /* 0x20: always 00016000?, rest of the header is null */ + + vgmstream->meta_type = meta_PC_XA30; + + switch(codec) { + case 0x01: /* MS-IMA variation */ + vgmstream->coding_type = coding_REF_IMA; + vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile); + vgmstream->num_samples = ms_ima_bytes_to_samples(data_size, vgmstream->interleave_block_size, channel_count); + break; + + case 0x00: /* PCM? */ + default: + goto fail; + } + + + /* open the file for reading */ + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps2_xa30.c b/Frameworks/vgmstream/vgmstream/src/meta/ps2_xa30.c index 52770d1b9..0f07f7f55 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps2_xa30.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ps2_xa30.c @@ -1,63 +1,55 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* XA30 (found in Driver - Parallel Lines) */ -VGMSTREAM * init_vgmstream_xa30(STREAMFILE *streamFile) { +/* XA30 - found in Driver: Parallel Lines (PS2) */ +VGMSTREAM * init_vgmstream_ps2_xa30(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; off_t start_offset; - int loop_flag = 0; - int channel_count; + int loop_flag, channel_count; + size_t file_size, data_size; + /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("xa30",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x58413330) /* "XA30 */ + /* ".xa30" is just the ID, the real filename inside the file uses .XA */ + if (!check_extensions(streamFile,"xa,xa30")) goto fail; + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x58413330) /* "XA30" */ + goto fail; + if (read_32bitLE(0x04,streamFile) <= 2) goto fail; /* extra check to avoid PS2/PC XA30 mixup */ + loop_flag = 0; - channel_count = 1; - - /* build the VGMSTREAM */ + channel_count = 1 ; /* 0x08(2): interleave? 0x0a(2): channels? (always 1 in practice) */ + + start_offset = read_32bitLE(0x0C,streamFile); + + file_size = get_streamfile_size(streamFile); + data_size = read_32bitLE(0x14,streamFile); /* always off by 0x800 */ + if (data_size-0x0800 != file_size) goto fail; + data_size = file_size - start_offset; + + + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = read_32bitLE(0x0C,streamFile); - vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(0x04,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = read_32bitLE(0x14,streamFile)*28/16/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = read_32bitLE(0x14,streamFile)*28/16/channel_count; - } + vgmstream->num_samples = ps_bytes_to_samples(data_size,channel_count); /* 0x10: some num_samples value (but smaller) */ + vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_none; - vgmstream->meta_type = meta_XA30; + vgmstream->meta_type = meta_PS2_XA30; + /* the rest of the header has unknown values (and several repeats) and the filename */ + /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } + 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; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ps3_xvag.c b/Frameworks/vgmstream/vgmstream/src/meta/ps3_xvag.c index adb6c8436..b6d694b97 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ps3_xvag.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ps3_xvag.c @@ -91,7 +91,7 @@ VGMSTREAM * init_vgmstream_ps3_xvag(STREAMFILE *streamFile) { if (!find_chunk(streamFile, 0x6D70696E,first_offset,0, &chunk_offset,NULL, !little_endian, 1)) goto fail; /*"mpin"*/ fixed_frame_size = read_32bit(chunk_offset+0x1c,streamFile); - mpeg_data = init_mpeg_codec_data_interleaved(streamFile, start_offset, &mpeg_coding_type, vgmstream->channels, fixed_frame_size, 0); + mpeg_data = init_mpeg_codec_data_interleaved(streamFile, start_offset, &mpeg_coding_type, vgmstream->channels, MPEG_FIXED, fixed_frame_size); if (!mpeg_data) goto fail; vgmstream->codec_data = mpeg_data; vgmstream->layout_type = layout_mpeg; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/psx_cdxa.c b/Frameworks/vgmstream/vgmstream/src/meta/psx_cdxa.c index 6d283b242..a3b24ad86 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/psx_cdxa.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/psx_cdxa.c @@ -37,6 +37,9 @@ VGMSTREAM * init_vgmstream_cdxa(STREAMFILE *streamFile) { (read_32bitBE(0x0C,streamFile) == 0x666D7420))) headerless=1; + /* don't misdetect Reflections' XA ("XA30" / "04SW") */ + if (read_32bitBE(0x00,streamFile) == 0x58413330 || read_32bitBE(0x00,streamFile) == 0x30345357) goto fail; + /* First init to have the correct info of the channel */ if (!headerless) { start_offset=init_xa_channel(&xa_channel,streamFile); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/riff.c b/Frameworks/vgmstream/vgmstream/src/meta/riff.c index 2268525f8..e0ac857cc 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/riff.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/riff.c @@ -98,6 +98,7 @@ int read_fmt(int big_endian, int sns, int mwv) { + int codec, bps; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL; @@ -116,9 +117,12 @@ int read_fmt(int big_endian, fmt->channel_count = read_16bit(current_chunk+0x0a,streamFile); fmt->block_size = read_16bit(current_chunk+0x14,streamFile); - switch ((uint16_t)read_16bit(current_chunk+0x8,streamFile)) { - case 1: /* PCM */ - switch (read_16bit(current_chunk+0x16,streamFile)) { + bps = read_16bit(current_chunk+0x16,streamFile); + codec = (uint16_t)read_16bit(current_chunk+0x8,streamFile); + + switch (codec) { + case 0x01: /* PCM */ + switch (bps) { case 16: if (big_endian) { fmt->coding_type = coding_PCM16BE; @@ -135,39 +139,54 @@ int read_fmt(int big_endian, goto fail; } break; - case 2: /* MS ADPCM */ - /* ensure 4bps */ - if (read_16bit(current_chunk+0x16,streamFile)!=4) - goto fail; + case 0x02: /* MS ADPCM */ + if (bps != 4) /* ensure 4bps */ + goto fail; fmt->coding_type = coding_MSADPCM; fmt->interleave = 0; + break; - break; - case 0x11: /* MS IMA ADCM */ - /* ensure 4bps */ - if (read_16bit(current_chunk+0x16,streamFile)!=4) + case 0x11: /* MS IMA ADPCM */ + if (bps != 4) /* ensure 4bps */ goto fail; fmt->coding_type = coding_MS_IMA; fmt->interleave = 0; break; - case 0x69: /* MS IMA ADCM - Rayman Raving Rabbids 2 (PC) */ - /* ensure 4bps */ - if (read_16bit(current_chunk+0x16,streamFile)!=4) + + case 0x69: /* MS IMA ADPCM - Rayman Raving Rabbids 2 (PC) */ + if (bps != 4) /* ensure 4bps */ goto fail; fmt->coding_type = coding_MS_IMA; fmt->interleave = 0; break; - case 0x555: /* Level-5 0x555 ADPCM */ + + case 0x007A: /* MS IMA ADPCM (LA Rush, Psi Ops PC) */ + /* 0x007A is apparently "Voxware SC3" but in .MED it's just MS-IMA */ + if (!check_extensions(streamFile,"med")) + goto fail; + + if (bps == 4) /* normal MS IMA */ + fmt->coding_type = coding_MS_IMA; + else if (bps == 3) /* 3-bit MS IMA, used in a very few files */ + goto fail; //fmt->coding_type = coding_MS_IMA_3BIT; + else + goto fail; + fmt->interleave = 0; + break; + + case 0x0555: /* Level-5 0x555 ADPCM */ if (!mwv) goto fail; fmt->coding_type = coding_L5_555; fmt->interleave = 0x12; break; + case 0x5050: /* Ubisoft .sns uses this for DSP */ if (!sns) goto fail; fmt->coding_type = coding_NGC_DSP; fmt->interleave = 8; break; + #ifdef VGM_USE_FFMPEG case 0x270: /* ATRAC3 */ #if defined(VGM_USE_FFMPEG) && !defined(VGM_USE_MAIATRAC3PLUS) @@ -177,6 +196,7 @@ int read_fmt(int big_endian, fmt->interleave = 0; break; #endif /* VGM_USE_FFMPEG */ + #ifdef VGM_USE_MAIATRAC3PLUS case 0xFFFE: /* WAVEFORMATEXTENSIBLE / ATRAC3plus */ if (read_32bit(current_chunk+0x20,streamFile) == 0xE923AABF && @@ -246,6 +266,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { #ifndef VGM_USE_FFMPEG && strcasecmp("sgb",filename_extension(filename)) /* SGB has proper support with FFmpeg in sgxd */ #endif + && strcasecmp("med",filename_extension(filename)) ) { if (!strcasecmp("mwv",filename_extension(filename))) @@ -378,7 +399,9 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { * To ensure their stuff is parsed in wwise.c we reject their JUNK, which they put almost always. * As JUNK is legal (if unusual) we only reject those codecs. * (ex. Cave PC games have PCM16LE + JUNK + smpl created by "Samplitude software") */ - if (JunkFound && (fmt.coding_type==coding_MSADPCM || fmt.coding_type==coding_MS_IMA)) goto fail; + if (JunkFound + && check_extensions(streamFile,"wav,lwav") /* for some .MED IMA */ + && (fmt.coding_type==coding_MSADPCM || fmt.coding_type==coding_MS_IMA)) goto fail; switch (fmt.coding_type) { case coding_PCM16LE: diff --git a/Frameworks/vgmstream/vgmstream/src/meta/rws.c b/Frameworks/vgmstream/vgmstream/src/meta/rws.c index e33f23f0f..3e63690ae 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/rws.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/rws.c @@ -10,9 +10,8 @@ static off_t get_rws_string_size(off_t off, STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset, off, coefs_offset = 0, stream_offset = 0; - int loop_flag = 0, channel_count, codec; - size_t file_size, header_size, data_size, stream_size = 0, info_size; - int block_size_max = 0, block_size = 0, sample_rate; + int loop_flag = 0, channel_count = 0, codec = 0, sample_rate = 0; + size_t file_size, header_size, data_size, stream_size = 0, block_size_max = 0, block_size = 0; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; int i, total_segments, total_streams, target_stream = 0; @@ -43,7 +42,7 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) { /* inside header chunk (many unknown fields are probably IDs/config, as two same-sized files vary a lot) */ off = 0x0c + 0x0c; - /* 0x00: actual header size (less than chunk size), useful to check endianness (Wii/X360 = BE) */ + /* 0x00: actual header size (less than chunk size), useful to check endianness (GC/Wii/X360 = BE) */ read_32bit = (read_32bitLE(off+0x00,streamFile) > header_size) ? read_32bitBE : read_32bitLE; /* 0x04-14: sizes of various sections?, others: ? */ @@ -54,15 +53,15 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) { /* check streams/segments */ /* Data can be divided into segments (cues/divisions within data, ex. intro+main, voice1+2+..N) or - * tracks/streams in interleaved blocks that can contain padding and don't need to match between tracks - * (ex 0x1800 data + 0 pad of stream_0 2ch, 0x1800 data + 0x200 pad of stream1 2ch, etc). */ + * tracks/streams in interleaved blocks; last track (only?) has some padding. Tracks seems to be used for multichannel. + * ex.- 0x1800 data + 0 pad of stream_0 2ch, 0x1800 data + 0x200 pad of stream1 2ch (xN) */ if (target_stream == 0) target_stream = 1; if (target_stream < 0 || target_stream > total_streams || total_streams < 1) goto fail; /* skip segment stuff and get stream size (from sizes for all segments, repeated per track) */ off += 0x20 * total_segments; /* segment data (mostly unknown except @ 0x18: full data size, 0x1c: offset) */ for (i = 0; i < total_segments; i++) { /* sum usable segment sizes (no padding) */ - stream_size += read_32bit(off + 0x04 * i + total_segments*(target_stream-1),streamFile); + stream_size += read_32bit(off + 0x04 * i + 0x04 * total_segments*(target_stream-1),streamFile); } off += 0x04 * (total_segments * total_streams); off += 0x10 * total_segments; /* segment uuids? */ @@ -82,24 +81,31 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) { off += 0x28 * total_streams; /* get stream config: 0x0c(1): bits per sample, others: ? */ - info_size = total_streams > 1 ? 0x30 : 0x2c; //todo this doesn't look right - sample_rate = read_32bit(off+0x00 + info_size*(target_stream-1),streamFile); - //unk_size = read_32bit(off+0x08 + info_size*(target_stream-1),streamFile); /* segment size? loop-related? */ - channel_count = read_8bit(off+0x0d + info_size*(target_stream-1),streamFile); - codec = read_32bitBE(off+0x1c + info_size*(target_stream-1),streamFile); /* uuid of 128b but the first is enough */ - off += info_size * total_streams; + for (i = 0; i < total_streams; i++) {/* size depends on codec so we must parse it */ + sample_rate = read_32bit(off+0x00, streamFile); + //unk_size = read_32bit(off+0x08, streamFile); /* segment size? loop-related? */ + channel_count = read_8bit(off+0x0d, streamFile); + codec = read_32bitBE(off+0x1c, streamFile); /* uuid of 128b but first 32b is enough */ + off += 0x2c; + if (codec == 0xF86215B0) { /* if codec is DSP there is an extra field per stream */ + /* 0x00: approx num samples? 0x04: approx size/loop related? (can be 0) */ + coefs_offset = off + 0x1c; + off += 0x60; + } - /* if codec is DSP there is an extra field */ - if (codec == 0xF86215B0) { - /* 0x00: approx num samples? 0x04: approx size? */ - coefs_offset = off + 0x1c; + if (total_streams > 1) /* multitracks have an unknown field */ + off += 0x04; + + if (i == target_stream-1) + break; } /* next is 0x14 * streams = ?(4) + uuid? (header ends), rest is garbage/padding until chunk end (may contain strings and weird stuff) */ start_offset = 0x0c + 0x0c + header_size + 0x0c + stream_offset; /* usually 0x800 but not always */ + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; @@ -129,8 +135,8 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) { vgmstream->num_samples = ps_bytes_to_samples(stream_size, channel_count); break; - case 0xF86215B0: /* DSP Wii (F86215B0 31D54C29 BD37CDBF 9BD10C53) */ - /* ex. Alice in Wonderland (Wii) */ + case 0xF86215B0: /* DSP GC/Wii (F86215B0 31D54C29 BD37CDBF 9BD10C53) */ + /* ex. Burnout 2 (GC), Alice in Wonderland (Wii) */ vgmstream->coding_type = coding_NGC_DSP; vgmstream->interleave_block_size = block_size / 2; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/wii_04sw.c b/Frameworks/vgmstream/vgmstream/src/meta/wii_04sw.c new file mode 100644 index 000000000..845b6fa6d --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/wii_04sw.c @@ -0,0 +1,62 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* 04SW - found in Driver: Parallel Lines (Wii) */ +VGMSTREAM * init_vgmstream_wii_04sw(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag, channel_count; + size_t file_size, data_size; + + + /* check extension, case insensitive */ + /* ".04sw" is just the ID, the real filename inside the file uses .XA */ + if (!check_extensions(streamFile,"xa,04sw")) + goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x30345357) /* "04SW" */ + goto fail; + + /* after the ID goes a semi-standard DSP header */ + if (read_32bitBE(0x10,streamFile) != 0) goto fail; /* should be non looping */ + loop_flag = 0; + /* not in header it seems so just dual header check */ + channel_count = (read_32bitBE(0x04,streamFile) == read_32bitBE(0x64,streamFile)) ? 2 : 1; + + start_offset = read_32bitBE(0x04 + 0x60*channel_count,streamFile); + + file_size = get_streamfile_size(streamFile); + data_size = read_32bitBE(0x04 + 0x60*channel_count + 0x04,streamFile); + if (data_size+start_offset != file_size) goto fail; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = read_32bitBE(0x0c,streamFile); + vgmstream->num_samples = read_32bitBE(0x04,streamFile); + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave_shortblock; + vgmstream->interleave_block_size = 0x8000; + vgmstream->interleave_smallblock_size = (read_32bitBE(0x08,streamFile) / 2 % vgmstream->interleave_block_size + 7) / 8 * 8; + + dsp_read_coefs_be(vgmstream,streamFile,0x20, 0x60); + /* the initial history offset seems different thatn standard DSP and possibly always zero */ + + vgmstream->meta_type = meta_WII_04SW; + /* the rest of the header has unknown values (several repeats) and the filename */ + + + /* open the file for reading */ + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.c b/Frameworks/vgmstream/vgmstream/src/vgmstream.c index c0889b3df..11d8979b3 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.c @@ -63,7 +63,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_xbox_wavm, init_vgmstream_xbox_xwav, init_vgmstream_ngc_str, - init_vgmstream_ea, + init_vgmstream_ea_schl, init_vgmstream_caf, init_vgmstream_ps2_vpk, init_vgmstream_genh, @@ -105,7 +105,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_fsb5, init_vgmstream_rwx, init_vgmstream_xwb, - init_vgmstream_xa30, + init_vgmstream_ps2_xa30, init_vgmstream_musc, init_vgmstream_musx_v004, init_vgmstream_musx_v005, @@ -362,6 +362,8 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_ta_aac_ps3, init_vgmstream_ps3_mta2, init_vgmstream_ngc_ulw, + init_vgmstream_pc_xa30, + init_vgmstream_wii_04sw, #ifdef VGM_USE_FFMPEG init_vgmstream_mp4_aac_ffmpeg, @@ -1045,7 +1047,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_EA_XA: return 28; case coding_MAXIS_ADPCM: - case coding_EA_ADPCM: + case coding_EA_MT10: return 14*vgmstream->channels; case coding_WS: /* only works if output sample size is 8 bit, which always is for WS ADPCM */ @@ -1057,6 +1059,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_MS_IMA: case coding_RAD_IMA: case coding_WWISE_IMA: + case coding_REF_IMA: return (vgmstream->interleave_block_size-4*vgmstream->channels)*2/vgmstream->channels; case coding_RAD_IMA_mono: return 32; @@ -1156,6 +1159,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_NDS_IMA: case coding_DAT4_IMA: case coding_WWISE_IMA: + case coding_REF_IMA: return vgmstream->interleave_block_size; case coding_RAD_IMA_mono: return 0x14; @@ -1187,7 +1191,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { return 36; case coding_MAXIS_ADPCM: return 15*vgmstream->channels; - case coding_EA_ADPCM: + case coding_EA_MT10: return 30; case coding_EA_XA: return 1; // the frame is variant in size @@ -1486,9 +1490,9 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do,chan); } break; - case coding_EA_ADPCM: + case coding_EA_MT10: for (chan=0;chanchannels;chan++) { - decode_ea_adpcm(vgmstream,buffer+samples_written*vgmstream->channels+chan, + decode_ea_mt10(vgmstream,buffer+samples_written*vgmstream->channels+chan, vgmstream->channels,vgmstream->samples_into_block, samples_to_do,chan); } @@ -1631,6 +1635,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do,chan); } break; + case coding_REF_IMA: + for (chan=0;chanchannels;chan++) { + decode_ref_ima(vgmstream,&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do,chan); + } + break; case coding_WS: for (chan=0;chanchannels;chan++) { @@ -2045,6 +2056,7 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { case coding_MS_IMA: case coding_MC3: case coding_WWISE_IMA: + case coding_REF_IMA: snprintf(temp,TEMPSIZE, "block size: %#x bytes\n", (int32_t)vgmstream->interleave_block_size); @@ -2399,7 +2411,7 @@ int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t s #endif /* if interleave is big enough keep a buffer per channel */ - if (vgmstream->interleave_block_size >= STREAMFILE_DEFAULT_BUFFER_SIZE) { + if (vgmstream->interleave_block_size * vgmstream->channels >= STREAMFILE_DEFAULT_BUFFER_SIZE) { use_streamfile_per_channel = 1; } diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.h b/Frameworks/vgmstream/vgmstream/src/vgmstream.h index 54549f685..c7283aaf9 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.h +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.h @@ -108,15 +108,14 @@ typedef enum { coding_XA, /* CD-ROM XA */ coding_PSX, /* Sony PS ADPCM (VAG) */ - coding_PSX_badflags, /* Sony PS ADPCM with garbage in the flag byte */ + coding_PSX_badflags, /* Sony PS ADPCM with custom flag byte */ coding_PSX_bmdx, /* Sony PS ADPCM with BMDX encryption */ coding_PSX_cfg, /* Sony PS ADPCM with configurable frame size (FF XI, SGXD type 5, Bizarre Creations) */ coding_HEVAG, /* Sony PSVita ADPCM */ - coding_EA_XA, /* Electronic Arts XA ADPCM */ - coding_EA_ADPCM, /* Electronic Arts R1 ADPCM */ + coding_EA_MT10, /* Electronic Arts MicroTalk (10:1) ADPCM ('EA ADPCM')*/ + coding_EA_XA, /* Electronic Arts EA-XA ADPCM */ coding_MAXIS_ADPCM, /* Maxis ADPCM */ - coding_NDS_PROCYON, /* Procyon Studio ADPCM */ coding_XBOX, /* XBOX IMA ADPCM */ coding_XBOX_int, /* XBOX IMA ADPCM (interleaved) */ @@ -125,8 +124,8 @@ typedef enum { coding_DVI_IMA, /* DVI IMA ADPCM (high nibble first), aka ADP4 */ coding_DVI_IMA_int, /* DVI IMA ADPCM (Interleaved) */ coding_NDS_IMA, /* IMA ADPCM w/ NDS layout */ - coding_EACS_IMA, - coding_MS_IMA, /* Microsoft IMA */ + coding_EACS_IMA, /* Electronic Arts IMA ADPCM */ + coding_MS_IMA, /* Microsoft IMA ADPCM */ coding_RAD_IMA, /* Radical IMA ADPCM */ coding_RAD_IMA_mono, /* Radical IMA ADPCM, mono (for interleave) */ coding_APPLE_IMA4, /* Apple Quicktime IMA4 */ @@ -135,10 +134,12 @@ typedef enum { coding_OTNS_IMA, /* Omikron The Nomad Soul IMA ADPCM */ coding_FSB_IMA, /* FMOD's FSB multichannel IMA ADPCM */ coding_WWISE_IMA, /* Audiokinetic Wwise IMA ADPCM */ + coding_REF_IMA, /* Reflections IMA ADPCM */ coding_MSADPCM, /* Microsoft ADPCM */ coding_WS, /* Westwood Studios VBR ADPCM */ coding_AICA, /* Yamaha AICA ADPCM */ + coding_NDS_PROCYON, /* Procyon Studio ADPCM */ coding_L5_555, /* Level-5 0x555 ADPCM */ coding_SASSC, /* Activision EXAKT SASSC DPCM */ coding_LSF, /* lsf ADPCM (Fastlane Street Racing iPhone)*/ @@ -172,9 +173,9 @@ typedef enum { #ifdef VGM_USE_MPEG coding_fake_MPEG2_L2, /* MPEG-2 Layer 2 (AHX), with lying headers */ - /* I don't even know offhand if all these combinations exist... */ - coding_MPEG1_L1, - coding_MPEG1_L2, + /* MPEG audio variations (depending on sample rate and other config) */ + coding_MPEG1_L1, /* MP1 */ + coding_MPEG1_L2, /* MP2 */ coding_MPEG1_L3, /* good ol' MPEG-1 Layer 3 (MP3) */ coding_MPEG2_L1, coding_MPEG2_L2, @@ -357,7 +358,7 @@ typedef enum { meta_FSB5, /* FMOD Sample Bank, version 5 */ meta_RWX, /* Air Force Delta Storm (XBOX) */ meta_XWB, /* Microsoft XACT framework (Xbox, X360, Windows) */ - meta_XA30, /* Driver - Parallel Lines (PS2) */ + meta_PS2_XA30, /* Driver - Parallel Lines (PS2) */ meta_MUSC, /* Spyro Games, possibly more */ meta_MUSX_V004, /* Spyro Games, possibly more */ meta_MUSX_V005, /* Spyro Games, possibly more */ @@ -463,15 +464,10 @@ typedef enum { meta_XBOX_XMU, /* XBOX XMU */ meta_XBOX_XVAS, /* XBOX VAS */ - meta_EAXA_R2, /* EA XA Release 2 */ - meta_EAXA_R3, /* EA XA Release 3 */ - meta_EAXA_PSX, /* EA with PSX ADPCM */ - meta_EACS_PC, /* EACS PC */ - meta_EACS_PSX, /* EACS PSX */ - meta_EACS_SAT, /* EACS SATURN */ - meta_EA_ADPCM, /* EA header using XA ADPCM */ - meta_EA_IMA, /* EA header using IMA */ - meta_EA_PCM, /* EA header using PCM */ + meta_EA_SCHL, /* Electronic Arts SCHl */ + meta_EACS_PC, /* Electronic Arts EACS PC */ + meta_EACS_PSX, /* Electronic Arts EACS PSX */ + meta_EACS_SAT, /* Electronic Arts EACS SATURN */ meta_RAW, /* RAW PCM file */ @@ -628,6 +624,8 @@ typedef enum { meta_TA_AAC_PS3, /* tri-ace AAC (Star Ocean International, Resonance of Fate) */ meta_PS3_MTA2, /* Metal Gear Solid 4 MTA2 */ meta_NGC_ULW, /* Burnout 1 (GC only) */ + meta_PC_XA30, /* Driver - Parallel Lines (PC) */ + meta_WII_04SW, /* Driver - Parallel Lines (Wii) */ #ifdef VGM_USE_VORBIS meta_OGG_VORBIS, /* Ogg Vorbis */ @@ -735,7 +733,8 @@ typedef struct { size_t interleave_smallblock_size; /* smaller interleave for last block */ /* headered blocks */ off_t current_block_offset; /* start of this block (offset of block header) */ - size_t current_block_size; /* size of the block we're in now (usable data) */ + size_t current_block_size; /* size in usable bytes of the block we're in now (used to calculate num_samples per block) */ + size_t current_block_samples; /* size in samples of the block we're in now (used over current_block_size if possible) */ size_t full_block_size; /* size including padding and other unusable data */ off_t next_block_offset; /* offset of header of the next block */ int block_count; /* count of "semi" block in total block */ @@ -756,6 +755,7 @@ typedef struct { /* decoder specific */ int codec_endian; /* little/big endian marker; name is left vague but usually means big endian */ + int codec_version; /* flag for codecs with minor variations */ uint8_t xa_channel; /* XA ADPCM: selected channel */ int32_t xa_sector_length; /* XA ADPCM: XA block */ @@ -764,8 +764,6 @@ typedef struct { int8_t get_high_nibble; /* ADPCM: which nibble (XA, IMA, EA) */ uint8_t ea_big_endian; /* EA ADPCM stuff */ - uint8_t ea_compression_type; - uint8_t ea_compression_version; uint8_t ea_platform; int32_t ws_output_size; /* WS ADPCM: output bytes for this block */ @@ -835,6 +833,7 @@ typedef struct { #endif #ifdef VGM_USE_MPEG +typedef enum { /*MPEG_NONE,*/ MPEG_FIXED, MPEG_FSB, MPEG_P3D, MPEG_EA } mpeg_interleave_type; typedef struct { uint8_t *buffer; /* raw (coded) data buffer */ size_t buffer_size; @@ -852,7 +851,10 @@ typedef struct { size_t samples_to_discard; /* for interleaved looping */ /* interleaved MPEG internals */ - int interleaved; /* flag */ + int interleaved; + mpeg_interleave_type interleave_type; /* flag */ + uint32_t interleave_value; /* varies with type */ + mpg123_handle **ms; /* array of MPEG streams */ size_t ms_size; uint8_t *frame_buffer; /* temp buffer with samples from a single decoded frame */ @@ -862,11 +864,8 @@ typedef struct { size_t bytes_in_interleave_buffer; size_t bytes_used_in_interleave_buffer; - /* messy stuff for padded FSB frames */ - size_t fixed_frame_size; /* when given a fixed size (XVAG) */ size_t current_frame_size; - int fsb_padding; /* for FSBs that have extra garbage between frames */ - size_t current_padding; /* padding needed for current frame size */ + size_t current_padding; /* FSB padding between frames */ } mpeg_codec_data; #endif