Updated VGMStream to r1050-554-g883d0a4f.

CQTexperiment
Christopher Snowhill 2017-07-03 16:13:01 -07:00
parent 7a70c1c80e
commit 1d30e1a235
26 changed files with 1502 additions and 879 deletions

View File

@ -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 = "<group>"; };
836F6DE418BDC2180095E648 /* at3_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = at3_decoder.c; sourceTree = "<group>"; };
836F6DE518BDC2180095E648 /* coding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coding.h; sourceTree = "<group>"; };
836F6DE618BDC2180095E648 /* eaxa_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eaxa_decoder.c; sourceTree = "<group>"; };
836F6DE618BDC2180095E648 /* ea_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_decoder.c; sourceTree = "<group>"; };
836F6DE718BDC2180095E648 /* g721_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = g721_decoder.c; sourceTree = "<group>"; };
836F6DE818BDC2180095E648 /* g7221_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = g7221_decoder.c; sourceTree = "<group>"; };
836F6DE918BDC2180095E648 /* g72x_state.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = g72x_state.h; sourceTree = "<group>"; };
@ -619,7 +619,7 @@
836F6E4318BDC2180095E648 /* dmsg_segh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dmsg_segh.c; sourceTree = "<group>"; };
836F6E4418BDC2180095E648 /* dsp_bdsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dsp_bdsp.c; sourceTree = "<group>"; };
836F6E4518BDC2180095E648 /* dsp_sth_str.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dsp_sth_str.c; sourceTree = "<group>"; };
836F6E4618BDC2180095E648 /* ea_header.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_header.c; sourceTree = "<group>"; };
836F6E4618BDC2180095E648 /* ea_schl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_schl.c; sourceTree = "<group>"; };
836F6E4718BDC2180095E648 /* ea_old.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_old.c; sourceTree = "<group>"; };
836F6E4818BDC2180095E648 /* emff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = emff.c; sourceTree = "<group>"; };
836F6E4918BDC2180095E648 /* exakt_sc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exakt_sc.c; sourceTree = "<group>"; };
@ -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 */,

View File

@ -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);

View File

@ -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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
outbuf[sample_count] = read_16bitBE(stream->offset+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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t sample_byte = (uint8_t)read_8bit(stream->offset+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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t sample_byte;
int32_t sample;
sample_byte = (uint8_t)read_8bit(stream->offset+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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t sample_byte;
int32_t sample;
sample_byte = (uint8_t)read_8bit(stream->offset+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;
}
}

View File

@ -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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
outbuf[sample_count]=read_16bitBE(stream->offset+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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t sample_byte = (uint8_t)read_8bit(stream->offset+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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t sample_byte;
int32_t sample;
sample_byte = (uint8_t)read_8bit(stream->offset+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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t sample_byte;
int32_t sample;
sample_byte = (uint8_t)read_8bit(stream->offset+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;
}
}

View File

@ -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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t byte_offset = stream->offset + 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) */

View File

@ -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,6 +371,10 @@ 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++) {
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);
}
@ -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);
/* 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;
}
else if (data->interleave_type == MPEG_P3D) { /* varying frames size, even though the frame header says 0x120 */
uint32_t header = read_32bitBE(offset,streamfile);
//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();
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;
/* 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];

View File

@ -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"},

View File

@ -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;

View File

@ -3,98 +3,113 @@
#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;
init_get_high_nibble(vgmstream); /* swap nibble for codecs with stereo subinterleave */
/* 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;
}
}
} while (read_32bitBE(block_offset,vgmstream->ch[0].streamfile)!=0x5343446C);
// reset channel offset
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++) {
vgmstream->ch[i].channel_start_offset=0;
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;
if(vgmstream->ea_big_endian) {
vgmstream->current_block_size = read_32bitBE(block_offset+8,vgmstream->ch[0].streamfile);
vgmstream->next_block_offset = block_offset + block_size;
vgmstream->current_block_size = 0;
vgmstream->current_block_samples = block_samples;
/* 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++) {
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;
} 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;i<vgmstream->channels;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;i<vgmstream->channels;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;i<vgmstream->channels;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;i<vgmstream->channels;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;i<vgmstream->channels;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;i<vgmstream->channels;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);
}
/* 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;
}
}
/* reset channel sub offset */
if (vgmstream->coding_type == coding_EA_MT10 || vgmstream->coding_type == coding_EA_XA) {
for(i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].channel_start_offset=0;
}
}
}
void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream) {

View File

@ -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);

View File

@ -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_offset<length);
if(ea->platform==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;i<channel_count;i++) {
vgmstream->ch[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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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*/

View File

@ -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;

View File

@ -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 */
if (read_32bitBE(0x0,streamFile) != 0x503344FF && /* "P3D"\FF (LE: PC) */
read_32bitBE(0x0,streamFile) != 0xFF443350) /* \FF"D3P" (BE: PS3, X360) */
goto fail;
header_size = read_32bitLE(0x4,streamFile);
if (0xC != header_size) 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);
text_len = read_32bit(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);
/* 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;
}
}
/* info count? */
if (1 != read_32bitLE(parse_offset,streamFile)) goto fail;
if (0x01 != read_32bit(parse_offset,streamFile)) 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;
/* 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;
}
/* 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;
loop_flag = 0;
/* 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;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
/* 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;
vgmstream->ch[i].offset=vgmstream->ch[i].channel_start_offset=start_offset+interleave*i;
#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;
}
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;
}

View File

@ -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;
}

View File

@ -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;
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;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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:

View File

@ -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 is DSP there is an extra field */
if (codec == 0xF86215B0) {
/* 0x00: approx num samples? 0x04: approx size? */
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 (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;

View File

@ -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;
}

View File

@ -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;chan<vgmstream->channels;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;chan<vgmstream->channels;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;chan<vgmstream->channels;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;
}

View File

@ -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