Updated VGMStream to r1050-590-gbb8966a6.

CQTexperiment
Christopher Snowhill 2017-07-23 16:49:07 -07:00
parent 628697f4b0
commit a558f9b8b5
28 changed files with 1864 additions and 683 deletions

View File

@ -8,6 +8,10 @@
/* Begin PBXBuildFile section */
48C2650F1A5D420800A0A3D6 /* vorbisfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 48C2650E1A5D420800A0A3D6 /* vorbisfile.h */; };
8301659A1F256BD000CA0941 /* txth.c in Sources */ = {isa = PBXBuildFile; fileRef = 830165971F256BD000CA0941 /* txth.c */; };
8301659B1F256BD000CA0941 /* ea_schl_fixed.c in Sources */ = {isa = PBXBuildFile; fileRef = 830165981F256BD000CA0941 /* ea_schl_fixed.c */; };
8301659C1F256BD000CA0941 /* nds_strm_ffta2.c in Sources */ = {isa = PBXBuildFile; fileRef = 830165991F256BD000CA0941 /* nds_strm_ffta2.c */; };
830165A21F256BF400CA0941 /* hwas_blocked.c in Sources */ = {isa = PBXBuildFile; fileRef = 830165A11F256BF400CA0941 /* hwas_blocked.c */; };
8313E3E61902020400B4B6F1 /* mpg123.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8313E3431901FBDD00B4B6F1 /* mpg123.framework */; };
8313E3E71902021800B4B6F1 /* mpg123.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8313E3431901FBDD00B4B6F1 /* mpg123.framework */; };
831BA6181EAC61A500CF89B0 /* adx.c in Sources */ = {isa = PBXBuildFile; fileRef = 831BA60E1EAC61A500CF89B0 /* adx.c */; };
@ -492,6 +496,10 @@
/* Begin PBXFileReference section */
48C2650E1A5D420800A0A3D6 /* vorbisfile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = vorbisfile.h; path = ../Vorbis/include/vorbis/vorbisfile.h; sourceTree = "<group>"; };
830165971F256BD000CA0941 /* txth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = txth.c; sourceTree = "<group>"; };
830165981F256BD000CA0941 /* ea_schl_fixed.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ea_schl_fixed.c; sourceTree = "<group>"; };
830165991F256BD000CA0941 /* nds_strm_ffta2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nds_strm_ffta2.c; sourceTree = "<group>"; };
830165A11F256BF400CA0941 /* hwas_blocked.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hwas_blocked.c; sourceTree = "<group>"; };
8313E33D1901FBDC00B4B6F1 /* mpg123.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = mpg123.xcodeproj; path = ../mpg123/mpg123.xcodeproj; sourceTree = "<group>"; };
831BA60E1EAC61A500CF89B0 /* adx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adx.c; sourceTree = "<group>"; };
831BA60F1EAC61A500CF89B0 /* ogl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ogl.c; sourceTree = "<group>"; };
@ -1061,6 +1069,7 @@
836F6DFF18BDC2180095E648 /* layout */ = {
isa = PBXGroup;
children = (
830165A11F256BF400CA0941 /* hwas_blocked.c */,
831BD1201EEE1D2A00198540 /* rws_blocked.c */,
836F6E0018BDC2180095E648 /* aax_layout.c */,
836F6E0118BDC2180095E648 /* aix_layout.c */,
@ -1102,6 +1111,9 @@
836F6E2718BDC2180095E648 /* meta */ = {
isa = PBXGroup;
children = (
830165971F256BD000CA0941 /* txth.c */,
830165981F256BD000CA0941 /* ea_schl_fixed.c */,
830165991F256BD000CA0941 /* nds_strm_ffta2.c */,
83CAB8DC1F0B0744001BC993 /* pc_xa30.c */,
83CAB8E11F0B0745001BC993 /* wii_04sw.c */,
831BD11F1EEE1CF200198540 /* ngc_ulw.c */,
@ -1570,6 +1582,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8301659A1F256BD000CA0941 /* txth.c in Sources */,
8301659B1F256BD000CA0941 /* ea_schl_fixed.c in Sources */,
8301659C1F256BD000CA0941 /* nds_strm_ffta2.c in Sources */,
83CAB8E31F0B0755001BC993 /* pc_xa30.c in Sources */,
83CAB8E21F0B0752001BC993 /* wii_04sw.c in Sources */,
839B54571EEE1DA000048A2D /* rws_blocked.c in Sources */,
@ -1708,6 +1723,7 @@
836F6F3218BDC2190095E648 /* ngc_dsp_decoder.c in Sources */,
836F704218BDC2190095E648 /* wii_sts.c in Sources */,
836F703918BDC2190095E648 /* vgs.c in Sources */,
830165A21F256BF400CA0941 /* hwas_blocked.c in Sources */,
836F6F2C18BDC2190095E648 /* mp4_aac_decoder.c in Sources */,
836F701F18BDC2190095E648 /* riff.c in Sources */,
836F6F9318BDC2190095E648 /* ivaud.c in Sources */,

View File

@ -18,7 +18,7 @@ void g72x_init_state(struct g72x_state *state_ptr);
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_int_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_xbox_ima_int(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_dvi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_eacs_ima(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
@ -32,6 +32,7 @@ void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * o
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);
size_t ima_bytes_to_samples(size_t bytes, int channels);
/* ngc_dsp_decoder */
void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
@ -74,9 +75,10 @@ void decode_xa(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t
void init_get_high_nibble(VGMSTREAM * vgmstream);
/* 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_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);
void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_ea_xa_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_ea_xa_v2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_maxis_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
/* sdx2_decoder */
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);

View File

@ -1,33 +1,40 @@
#include "coding.h"
#include "../util.h"
/* Various EA ADPCM codecs */
/* Various EA ADPCM codecs evolved from CDXA */
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
/*
* Another way to get coefs in EAXA v2, with no diffs (no idea which table is actually used in games):
* coef1 = EA_XA_TABLE2[(((frame_info >> 4) & 0x0F) << 1) + 0];
* coef2 = EA_XA_TABLE2[(((frame_info >> 4) & 0x0F) << 1) + 1];
*/
/*
static const int32_t EA_XA_TABLE2[28] = {
0, 0, 240, 0,
460, -208, 392, -220,
0, 0, 240, 0,
460, 0, 392, 0,
0, 0, 0, 0,
-208, -1, -220, -1,
0, 0, 0, 0x3F70
};
*/
static const int EA_XA_TABLE[20] = {
0, 240, 460, 392,
0, 0, -208, -220,
0, 1, 3, 4,
7, 8, 10, 11,
0, -1, -3, -4
};
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) {
/* EA XA v2 (inconsistently called EAXA or EA-XA too); like ea_xa_int but with "PCM samples" flag and doesn't add 128 on nibble expand */
void decode_ea_xa_v2(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
int32_t coef1, coef2;
int i, shift;
off_t channel_offset = stream->channel_start_offset; /* suboffset within frame */
first_sample = first_sample%28;
@ -35,7 +42,7 @@ void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing
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 */
if (frame_info == 0xEE) { /* PCM frame (used in later revisions), samples 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;
@ -45,134 +52,182 @@ void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing
channel_offset+=2;
}
// Only increment offset on complete frame
/* 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];
coef1 = EA_XA_TABLE[(frame_info >> 4) + 0];
coef2 = EA_XA_TABLE[(frame_info >> 4) + 4];
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;
uint8_t sample_byte, sample_nibble;
int32_t sample;
off_t byte_offset = (stream->offset + channel_offset + i/2);
outbuf[sample_count] = clamp16(sample);
sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile);
sample_nibble = (!(i%2) ? sample_byte >> 4 : sample_byte & 0x0F); /* i=even > high nibble */
sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */
sample = (sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32) >> 8;
sample = clamp16(sample);
outbuf[sample_count] = sample;
stream->adpcm_history2_32 = stream->adpcm_history1_32;
stream->adpcm_history1_32 = sample;
}
channel_offset += i/2;
channel_offset+=i/2;
// Only increment offset on complete frame
if(channel_offset - stream->channel_start_offset == 0x0F)
/* 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) {
/* EA XA v1 stereo (aka "EA ADPCM") */
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;
VGMSTREAMCHANNEL *stream = &(vgmstream->ch[channel]);
off_t channel_offset=stream->channel_start_offset;
int32_t coef1, coef2;
int i, sample_count, shift;
off_t channel_offset = stream->channel_start_offset; /* suboffset within frame */
int hn = (channel==0); /* high nibble marker for stereo subinterleave, ch0/L=high nibble, ch1/R=low nibble */
vgmstream->get_high_nibble = !vgmstream->get_high_nibble; /* for stereo subinterleave, L=high nibble, R=low nibble */
first_sample = first_sample % 28;
first_sample = first_sample%28;
/* header */ //todo mono/interleave decoder
/* header (coefs ch0+ch1 + shift ch0+ch1) */
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];
coef1 = EA_XA_TABLE[(hn ? frame_info >> 4 : frame_info & 0x0F) + 0];
coef2 = EA_XA_TABLE[(hn ? frame_info >> 4 : frame_info & 0x0F) + 4];
shift = (frame_info & 0x0F) + 8;
frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile);
channel_offset++;
shift = (vgmstream->get_high_nibble ? frame_info & 0x0F : frame_info >> 4) + 8;
shift = (hn ? frame_info >> 4 : frame_info & 0x0F) + 8;
/* samples */
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t sample_byte;
uint8_t sample_byte, sample_nibble;
int32_t sample;
off_t byte_offset = (stream->offset + channel_offset + i);
sample_byte = (uint8_t)read_8bit(stream->offset+channel_offset+i,stream->streamfile);
sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile);
sample_nibble = (hn ? sample_byte >> 4 : sample_byte & 0x0F);
sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */
sample = (sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32 + 128) >> 8;
sample = clamp16(sample);
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);
outbuf[sample_count] = sample;
stream->adpcm_history2_32 = stream->adpcm_history1_32;
stream->adpcm_history1_32 = sample;
}
channel_offset+=i;
channel_offset += i;
// Only increment offset on complete frame
if(channel_offset-stream->channel_start_offset==0x1E)
stream->channel_start_offset+=0x1E;
/* 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) {
/* EA-XA v1 mono/interleave */
void decode_ea_xa_int(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;
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;
int32_t coef1, coef2;
int i, sample_count, shift;
off_t channel_offset = stream->channel_start_offset; /* suboffset within frame */
first_sample = first_sample%28;
frame_info = read_8bit(channel_offset,stream->streamfile);
first_sample = first_sample % 28;
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;
/* header (coefs+shift ch0) */
frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile);
channel_offset++;
coef1 = EA_XA_TABLE[(frame_info >> 4) + 0];
coef2 = EA_XA_TABLE[(frame_info >> 4) + 4];
shift = (frame_info & 0x0F) + 8;
/* samples */
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t sample_byte;
uint8_t sample_byte, sample_nibble;
int32_t sample;
off_t byte_offset = (stream->offset + channel_offset + i/2);
sample_byte = (uint8_t)read_8bit(stream->offset+channel_offset,stream->streamfile);
sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile);
sample_nibble = (!(i%2) ? sample_byte >> 4 : sample_byte & 0x0F); /* i=even > high nibble */
sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */
sample = (sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32 + 128) >> 8;
sample = clamp16(sample);
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] = sample;
stream->adpcm_history2_32 = stream->adpcm_history1_32;
stream->adpcm_history1_32 = sample;
}
channel_offset += i/2;
outbuf[sample_count] = clamp16(sample);
/* Only increment offset on complete frame */
if(channel_offset - stream->channel_start_offset == 0x0F)
stream->channel_start_offset += 0x0F;
}
/* Maxis EA-XA v1 (mono+stereo), differing slightly in the header layout in stereo mode */
void decode_maxis_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
uint8_t frame_info;
int32_t coef1, coef2;
int i, sample_count, shift;
off_t channel_offset = stream->channel_start_offset;
int frame_size = channelspacing * 15; /* mono samples have a frame of 15, stereo files have frames of 30 */
first_sample = first_sample % 28;
/* header (coefs+shift ch0 + coefs+shift ch1) */
frame_info = read_8bit(channel_offset,stream->streamfile);
channel_offset += channelspacing;
coef1 = EA_XA_TABLE[(frame_info >> 4) + 0];
coef2 = EA_XA_TABLE[(frame_info >> 4) + 4];
shift = (frame_info & 0x0F) + 8;
/* samples */
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t sample_byte, sample_nibble;
int32_t sample;
off_t byte_offset = (stream->offset + channel_offset);
sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile);
sample_nibble = (i&1) ? sample_byte & 0x0F : sample_byte >> 4;
sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */
sample = (sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32 + 128) >> 8;
sample = clamp16(sample);
outbuf[sample_count] = 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;
/* Only increment offset on complete frame */
if (channel_offset - stream->channel_start_offset == frame_size) {
stream->channel_start_offset += frame_size;
stream->offset=0;
}
}
/* EA MicroTalk 10:1 / 5:1 */
/**
* Rarely used but can be found in the wild: FIFA 2001 (PS2), FIFA Soccer 2002 (PS2)
*
* Decoding algorithm is unknown; some info found by analyzing sx.exe output:
* - Comes in 10:1 or 5:1 compression varieties (the later's byte layout looks similar but has roughly double frame size)
* - Also with "PCM samples" flag before each frame (later version) or without (first version)
* - When PCM flag is 0xEE it has 16b ? + 16b num_samples + PCM samples placed right after the frame, but they
* are written *before* (presumably so they have something while the frame is decoded), like EALayer3.
* - VBR ADPCM, apparently similar to Westwood VBR ADPCM: first byte seems a header with mode+count, but after it may
* be 8 bytes(?) of coefs/hist (unlike Westwood's), then data. Samples per frame changes with the mode used.
* ex. decoding pure silence (0000) takes 0x2E (10:1) or 0x48 (5:1) into 432 samples (RLE mode)
* - Variable frame size but seems to range from 0x20 to 0x80 (in 5:1 at least)
* - After a new SCDl block, first byte (in each channel) is a flag but various values have no effect in the output
* (01=first block, 00=normal block?) and should be skipped in the block parser.
*
*/
//void decode_ea_mt10(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {

View File

@ -307,8 +307,7 @@ void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
stream->adpcm_step_index = step_index;
}
/* For multichannel the internal layout is (I think) mixed stereo channels (ex. 6ch: 2ch + 2ch + 2ch)
* Has extra support for EA blocks, probably could be simplified */
/* For multichannel the internal layout is (I think) mixed stereo channels (ex. 6ch: 2ch + 2ch + 2ch) */
void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
int i, sample_count;
@ -326,11 +325,7 @@ void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * o
//normal header (per channel)
if (first_sample == 0) {
off_t header_offset;
if(vgmstream->layout_type==layout_ea_blocked) {
header_offset = stream->offset;
} else {
header_offset = stream->offset + 4*(channel%2);
}
header_offset = stream->offset + 4*(channel%2);
hist1 = read_16bitLE(header_offset,stream->streamfile);
step_index = read_16bitLE(header_offset+2,stream->streamfile);
@ -341,13 +336,9 @@ void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * o
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift;
if(vgmstream->layout_type==layout_ea_blocked)
offset = stream->offset + 4 + i/8*4 + (i%8)/2;
else {
offset = (channelspacing==1) ?
stream->offset + 4*(channel%2) + 4 + i/8*4 + (i%8)/2 :
stream->offset + 4*(channel%2) + 4*2 + i/8*4*2 + (i%8)/2;
}
offset = (channelspacing==1) ?
stream->offset + 4*(channel%2) + 4 + i/8*4 + (i%8)/2 :
stream->offset + 4*(channel%2) + 4*2 + i/8*4*2 + (i%8)/2;
nibble_shift = (i&1?4:0); //low nibble first
ms_ima_expand_nibble(stream, offset,nibble_shift, &hist1, &step_index);
@ -355,35 +346,27 @@ void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * o
}
//internal interleave: increment offset on complete frame
if(vgmstream->layout_type==layout_ea_blocked) {
if (channelspacing==1) {
if(offset-stream->offset==32+3) // ??
stream->offset+=36;
} else {
if(channelspacing==1) {
if(offset-stream->offset==32+3) // ??
stream->offset+=36;
} else {
if(offset-stream->offset==64+(4*(channel%2))+3) // ??
stream->offset+=36*channelspacing;
}
if(offset-stream->offset==64+(4*(channel%2))+3) // ??
stream->offset+=36*channelspacing;
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
}
void decode_int_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
int i, sample_count;
/* mono XBOX ADPCM for interleave */
void decode_xbox_ima_int(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count = 0;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
off_t offset = stream->offset;
//semi-internal interleave (0x24 size), mixed channels (4 byte per ch)?
int block_samples = (vgmstream->channels==1) ?
32 :
32*(vgmstream->channels&2);//todo this can be zero in 4/5/8ch = SEGFAULT using % below
//internal interleave (0x24 size), mono
int block_samples = (0x24 - 0x4) * 2; /* block size - header, 2 samples per byte */
first_sample = first_sample % block_samples;
//normal header
@ -394,27 +377,31 @@ void decode_int_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample
step_index = read_16bitLE(header_offset+2,stream->streamfile);
if (step_index < 0) step_index=0;
if (step_index > 88) step_index=88;
}
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int nibble_shift;
offset = stream->offset + 4 + i/8*4 + (i%8)/2;
nibble_shift = (i&1?4:0); //low nibble first
ms_ima_expand_nibble(stream, offset,nibble_shift, &hist1, &step_index);
//must write history from header as last nibble/sample in block is almost always 0 / not encoded
outbuf[sample_count] = (short)(hist1);
sample_count += channelspacing;
first_sample += 1;
samples_to_do -= 1;
}
//internal interleave: increment offset on complete frame
if(channelspacing==1) {
if(offset-stream->offset==32+3) // ??
stream->offset+=36;
} else {
if(offset-stream->offset==64+(4*(channel%2))+3) // ??
stream->offset+=36*channelspacing;
for (i=first_sample; i < first_sample + samples_to_do; i++) { /* first_sample + samples_to_do should be block_samples at most */
off_t byte_offset = stream->offset + 4 + (i-1)/2;
int nibble_shift = ((i-1)&1?4:0); //low nibble first
//last nibble/sample in block is ignored (next header sample contains it)
if (i < block_samples) {
ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
outbuf[sample_count] = (short)(hist1);
sample_count+=channelspacing;
}
}
//internal interleave: increment offset on complete frame; layout test so it works in full mono
// (EA SCHl, internally moves offset) or full interleave (XBOX ADS, externally moves offset in layout)
if (i == block_samples && vgmstream->layout_type != layout_interleave)
stream->offset += 0x24; /*full mono */
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
}
@ -441,6 +428,7 @@ void decode_dvi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
stream->adpcm_step_index = step_index;
}
/* basically DVI stereo (high=L + low=R nibbles) and DVI mono (high=L, low=L) all-in-one, can be simplified/removed */
void decode_eacs_ima(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]);//todo pass externally for consistency
int i, sample_count;
@ -452,14 +440,13 @@ void decode_eacs_ima(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing,
//no header
//variable nibble order
vgmstream->get_high_nibble = !vgmstream->get_high_nibble;
if((first_sample) && (channelspacing==1))
vgmstream->get_high_nibble = !vgmstream->get_high_nibble;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t byte_offset = stream->offset + i;
int nibble_shift = (vgmstream->get_high_nibble?0:4); //variable nibble order
off_t byte_offset = channelspacing == 1 ?
stream->offset + i/2 : /* mono mode */
stream->offset + i; /* stereo mode */
int nibble_shift = channelspacing == 1 ?
(!(i%2) ? 4:0) : /* mono mode (high first) */
(channel==0 ? 4:0); /* stereo mode (high=L,low=R) */
ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
outbuf[sample_count] = (short)(hist1);
@ -695,3 +682,8 @@ 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) */
return (bytes / block_align) * (block_align - 4 * channels) * 2 / channels;
}
size_t ima_bytes_to_samples(size_t bytes, int channels) {
/* 2 samples per byte (2 nibbles) in stereo or mono config */
return bytes / channels * 2;
}

View File

@ -197,6 +197,7 @@ static const char* extension_list[] = {
"omu",
"otm",
"p1d", //txth/reserved [Farming Simulator 18 (3DS)]
"p2bt",
"p3d",
"past",
@ -275,6 +276,7 @@ static const char* extension_list[] = {
"swag",
"swav",
"swd",
"sx",
"sxd",
"sxd2",
@ -315,11 +317,13 @@ static const char* extension_list[] = {
"wb",
"wem",
"wii",
"wip", //txth/reserved [Colin McRae DiRT (PC)]
"wmus",
"wp2",
"wpd",
"wsd",
"wsi",
"wv2", //txth/reserved [Slave Zero (PC)]
"wvs",
"xa",
@ -419,8 +423,10 @@ 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 EA-XA 4-bit ADPCM"},
{coding_EA_MT10, "Electronic Arts MicroTalk (10:1) 4-bit ADPCM"},
{coding_EA_XA, "Electronic Arts EA-XA 4-bit ADPCM (v1)"},
{coding_EA_XA_int, "Electronic Arts EA-XA 4-bit ADPCM (v1) (interleaved)"},
{coding_EA_XA_V2, "Electronic Arts EA-XA 4-bit ADPCM (v2)"},
{coding_MAXIS_XA, "Maxis EA-XA 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"},
@ -428,7 +434,6 @@ 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 ADPCM"},
{coding_IMA_int, "IMA 4-bit ADPCM (interleaved)"},
{coding_IMA, "IMA 4-bit ADPCM"},
{coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"},
@ -522,6 +527,7 @@ static const layout_info layout_info_list[] = {
{layout_ps2_iab_blocked, "IAB blocked"},
{layout_ps2_strlr_blocked, "The Bouncer STR blocked"},
{layout_rws_blocked, "RWS blocked"},
{layout_hwas_blocked, "HWAS blocked"},
{layout_tra_blocked, "TRA blocked"},
{layout_acm, "ACM blocked"},
{layout_mus_acm, "multiple ACM files, ACM blocked"},
@ -593,7 +599,8 @@ 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_EA_SCHL, "Electronic Arts SCHl header"},
{meta_EA_SCHL, "Electronic Arts SCHl header (variable)"},
{meta_EA_SCHL_fixed, "Electronic Arts SCHl header (fixed)"},
{meta_CFN, "tri-Crescendo CAF Header"},
{meta_PS2_VPK, "VPK Header"},
{meta_GENH, "GENH Generic Header"},
@ -744,7 +751,7 @@ static const meta_info meta_info_list[] = {
{meta_WII_NDP, "Vertigo NDP Header"},
{meta_PS2_SPS, "Ape Escape 2 SPS Header"},
{meta_PS2_XA2_RRP, "Acclaim XA2 Header"},
{meta_NDS_HWAS, "NDS 'HWAS' Header"},
{meta_NDS_HWAS, "Vicarious Visions HWAS header"},
{meta_NGC_LPS, "Rave Master LPS Header"},
{meta_NAOMI_ADPCM, "NAOMI/NAOMI2 Arcade games ADPCM header"},
{meta_SD9, "beatmania IIDX SD9 header"},
@ -871,6 +878,8 @@ static const meta_info meta_info_list[] = {
{meta_NGC_ULW, "Criterion ULW raw header"},
{meta_PC_XA30, "Reflections XA30 PC header"},
{meta_WII_04SW, "Reflections 04SW header"},
{meta_TXTH, "TXTH Generic Header"},
{meta_EA_BNK, "Electronic Arts BNK header"},
#ifdef VGM_USE_VORBIS
{meta_OGG_VORBIS, "Ogg Vorbis"},

View File

@ -136,6 +136,9 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
break;
case layout_rws_blocked:
rws_block_update(vgmstream->next_block_offset,vgmstream);
break;
case layout_hwas_blocked:
hwas_block_update(vgmstream->next_block_offset,vgmstream);
break;
default:
break;

View File

@ -1,164 +1,200 @@
#include "layout.h"
#include "../coding/coding.h"
#include "../vgmstream.h"
/* set up for the block at the given offset */
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); /* 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;
}
}
if (block_offset > file_size)
return;
if (id == 0 || id == 0xFFFFFFFF)
return; /* probably hit padding or EOF */
}
if (block_offset > file_size)
return;
/* use num_samples from header if possible; don't calc as rarely data may have padding (ex. PCM8) or not possible (ex. MP3) */
switch(vgmstream->coding_type) {
case coding_PSX:
block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels);
break;
default:
block_samples = read_32bit(block_offset+0x08,streamFile);
break;
}
/* set new channel offsets */
switch(vgmstream->coding_type) {
case coding_PSX:
for (i = 0; i < vgmstream->channels; i++) {
size_t interleave = ((block_size-0x10)/vgmstream->channels) * i;
vgmstream->ch[i].offset = block_offset + 0x10 + interleave;
}
/* at 0x08/0x0c: unknown */
break;
default:
for (i = 0; i < vgmstream->channels; i++) {
off_t channel_start;
if (vgmstream->coding_type == coding_EA_MT10 && vgmstream->codec_version == 0)
channel_start = 0; /* MT10 R1 (codec1 v0) uses stereo, R2 (codec2 v1+) interleaved mono */
else
channel_start = read_32bit(block_offset+0x0C+(0x04*i),streamFile);
vgmstream->ch[i].offset = block_offset + 0x0C+(0x04*vgmstream->channels) + channel_start;
}
break;
}
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset + 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++) {
/* 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) {
int i;
off_t block_size=vgmstream->current_block_size;
if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) {
block_offset+=0x0C;
}
vgmstream->current_block_offset = block_offset;
if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E64) { /* 1Snd */
block_offset+=4;
if(vgmstream->ea_platform==0)
block_size=read_32bitLE(vgmstream->current_block_offset+0x04,
vgmstream->ch[0].streamfile);
else
block_size=read_32bitBE(vgmstream->current_block_offset+0x04,
vgmstream->ch[0].streamfile);
block_offset+=4;
}
vgmstream->current_block_size=block_size-8;
if(vgmstream->coding_type==coding_EACS_IMA) {
init_get_high_nibble(vgmstream);
vgmstream->current_block_size=read_32bitLE(block_offset,vgmstream->ch[0].streamfile);
for(i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset+0x04+i*4,vgmstream->ch[0].streamfile);
vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset+0x04+i*4+(4*vgmstream->channels),vgmstream->ch[0].streamfile);
vgmstream->ch[i].offset = block_offset+0x14;
}
} else {
if(vgmstream->coding_type==coding_PSX) {
for (i=0;i<vgmstream->channels;i++)
vgmstream->ch[i].offset = vgmstream->current_block_offset+8+(i*(vgmstream->current_block_size/2));
} else {
for (i=0;i<vgmstream->channels;i++) {
if(vgmstream->coding_type==coding_PCM16LE_int)
vgmstream->ch[i].offset = block_offset+(i*2);
else
vgmstream->ch[i].offset = block_offset+i;
}
}
vgmstream->current_block_size/=vgmstream->channels;
}
vgmstream->next_block_offset = vgmstream->current_block_offset +
(off_t)block_size;
}
#include "layout.h"
#include "../coding/coding.h"
#include "../vgmstream.h"
/* set up for the block at the given offset */
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;
//int16_t (*read_16bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_16bitBE : read_16bitLE;
/* 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 > 0x00F00000) /* size is always LE, except in early SS/MAC */
block_size = read_32bitBE(block_offset+0x04,streamFile);
/* SCxx blocks have size in the header, but others may not. To simplify we just try to find
* a SCDl (main data) every 0x04. EA sometimes concats many small files, so after a SCEl (end block)
* there may be a new SCHl + SCDl too, so this pretends they are a single stream. */
if (id == 0x5343446C) { /* "SCDl" data block found */
/* use num_samples from header if possible; don't calc as 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;
}
/* guard against false positives (happens in "pIQT" blocks) */
if (block_size > 0xFFFF || block_samples > 0xFFFF) { /* observed max is ~0xf00 but who knows */
block_offset += 0x04;
continue;
}
break;
}
else {
/* movie "pIQT" may be bigger than what block_size says, but seems to help */
if (id == 0x5343486C || id == 0x5343436C || id == 0x53434C6C || id == 0x70495154) { /* "SCHl" "SCCl" "SCLl" "SCEl" "pIQT" */
block_offset += block_size;
} else {
block_offset += 0x04;
}
if (id == 0x5343456C) { /* "SCEl" end block found */
block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* 32b-aligned, important */
/* Usually there is padding between SCEl and SCHl too (aligned to 0x80) */
}
continue;
}
}
/* EOF reads: pretend we have samples to please the layout (unsure if this helps) */
if (block_offset >= file_size) {
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset + 0x04;
vgmstream->current_block_samples = vgmstream->num_samples;
return;
}
/* set new channel offsets and ADPCM history */
/* ADPCM hist could be considered part of the stream/decoder (some EAXA decoders call it "EAXA R1" when it has hist), and BNKs
* (with no blocks) may also have them in the first offset, but also may not. To simplify we just read them here. */
switch(vgmstream->coding_type) {
/* id, size, unk1, unk2, interleaved data */
case coding_PSX:
for (i = 0; i < vgmstream->channels; i++) {
size_t interleave = (block_size-0x10) / vgmstream->channels;
vgmstream->ch[i].offset = block_offset + 0x10 + i*interleave;
}
/* 0x08/0x0c: unknown (doesn't look like hist or offsets, as 1ch files has them too) */
break;
/* id, size, IMA hist, stereo/mono data */
case coding_EACS_IMA:
for(i = 0; i < vgmstream->channels; i++) {
off_t header_offset = block_offset + 0xc + i*4;
vgmstream->ch[i].adpcm_history1_32 = read_16bitLE(header_offset+0x00, vgmstream->ch[i].streamfile);
vgmstream->ch[i].adpcm_step_index = read_16bitLE(header_offset+0x02, vgmstream->ch[i].streamfile);
vgmstream->ch[i].offset = block_offset + 0xc + (4*vgmstream->channels);
}
break;
/* id, size, samples, hists-per-channel, stereo/interleaved data */
case coding_EA_XA:
case coding_EA_XA_int:
for (i = 0; i < vgmstream->channels; i++) {
int is_interleaved = vgmstream->coding_type == coding_EA_XA_int;
size_t interleave;
/* read ADPCM history from all channels before data (not actually read in sx.exe) */
//vgmstream->ch[i].adpcm_history1_32 = read_16bit(block_offset + 0x0C + (i*0x04) + 0x00,streamFile);
//vgmstream->ch[i].adpcm_history2_32 = read_16bit(block_offset + 0x0C + (i*0x04) + 0x02,streamFile);
/* the block can have padding so find the channel size from num_samples */
interleave = is_interleaved ? (block_samples / 28 * 0x0f) : 0;
vgmstream->ch[i].offset = block_offset + 0x0c + vgmstream->channels*0x04 + i*interleave;
}
break;
/* id, size, samples, offsets-per-channel, interleaved data (w/ optional hist per channel) */
default:
for (i = 0; i < vgmstream->channels; i++) {
off_t channel_start = read_32bit(block_offset + 0x0C + (0x04*i),streamFile);
vgmstream->ch[i].offset = block_offset + 0x0C + (0x04*vgmstream->channels) + channel_start;
}
/* read ADPCM history before each channel if needed (not actually read in sx.exe) */
if (vgmstream->codec_version == 1) {
for (i = 0; i < vgmstream->channels; i++) {
//vgmstream->ch[i].adpcm_history1_32 = read_16bit(vgmstream->ch[i].offset+0x00,streamFile);
//vgmstream->ch[i].adpcm_history3_32 = read_16bit(vgmstream->ch[i].offset+0x02,streamFile);
vgmstream->ch[i].offset += 4;
}
}
break;
}
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset + block_size;
vgmstream->current_block_samples = block_samples;
vgmstream->current_block_size = 0; /* uses current_block_samples instead */
/* reset channel sub offset for codecs using it */
if (vgmstream->coding_type == coding_EA_XA
|| vgmstream->coding_type == coding_EA_XA_int
|| vgmstream->coding_type == coding_EA_XA_V2) {
for(i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].channel_start_offset=0;
}
}
}
void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
off_t block_size=vgmstream->current_block_size;
if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) {
block_offset+=0x0C;
}
vgmstream->current_block_offset = block_offset;
if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E64) { /* 1Snd */
block_offset+=4;
if(vgmstream->ea_platform==0)
block_size=read_32bitLE(vgmstream->current_block_offset+0x04,
vgmstream->ch[0].streamfile);
else
block_size=read_32bitBE(vgmstream->current_block_offset+0x04,
vgmstream->ch[0].streamfile);
block_offset+=4;
}
vgmstream->current_block_size=block_size-8;
if(vgmstream->coding_type==coding_EACS_IMA) {
vgmstream->current_block_size=read_32bitLE(block_offset,vgmstream->ch[0].streamfile);
for(i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset+0x04+i*4,vgmstream->ch[0].streamfile);
vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset+0x04+i*4+(4*vgmstream->channels),vgmstream->ch[0].streamfile);
vgmstream->ch[i].offset = block_offset+0x14;
}
} else {
if(vgmstream->coding_type==coding_PSX) {
for (i=0;i<vgmstream->channels;i++)
vgmstream->ch[i].offset = vgmstream->current_block_offset+8+(i*(vgmstream->current_block_size/2));
} else {
for (i=0;i<vgmstream->channels;i++) {
if(vgmstream->coding_type==coding_PCM16LE_int)
vgmstream->ch[i].offset = block_offset+(i*2);
else
vgmstream->ch[i].offset = block_offset+i;
}
}
vgmstream->current_block_size/=vgmstream->channels;
}
vgmstream->next_block_offset = vgmstream->current_block_offset +
(off_t)block_size;
}

View File

@ -0,0 +1,24 @@
#include "layout.h"
#include "../vgmstream.h"
/* a simple headerless block with special adpcm history handling */
void hwas_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
size_t block_size;
/* no header */
block_size = vgmstream->full_block_size;
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset
+ block_size;
vgmstream->current_block_size = block_size;
/* reset ADPCM history every block (no header with hist or anything) */
/* probably not 100% exact but good enough to get something decently playable (otherwise there are wild volume swings) */
for (i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].adpcm_history1_32 = 0;
vgmstream->ch[i].adpcm_step_index = 0;
vgmstream->ch[i].offset = block_offset;
}
}

View File

@ -61,6 +61,8 @@ void ps2_strlr_block_update(off_t block_offset, VGMSTREAM * vgmstream);
void rws_block_update(off_t block_offset, VGMSTREAM * vgmstream);
void hwas_block_update(off_t block_offset, VGMSTREAM * vgmstream);
/* other layouts */
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);

View File

@ -6,6 +6,7 @@
VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
coding_t coding_type;
coding_t coding_PCM16;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
@ -30,9 +31,11 @@ VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) {
if ((uint16_t)read_16bitBE(4, streamFile) == 0xFEFF) { /* endian marker (BE most common) */
read_32bit = read_32bitBE;
read_16bit = read_16bitBE;
coding_PCM16 = coding_PCM16BE;
} else if ((uint16_t)read_16bitBE(4, streamFile) == 0xFFFE) { /* Blaster Master Zero 3DS */
read_32bit = read_32bitLE;
read_16bit = read_16bitLE;
coding_PCM16 = coding_PCM16LE;
} else {
goto fail;
}
@ -81,7 +84,7 @@ VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) {
coding_type = coding_PCM8;
break;
case 1:
coding_type = coding_PCM16BE;
coding_type = coding_PCM16;
break;
case 2:
coding_type = coding_NGC_DSP;

View File

@ -6,11 +6,12 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) {
char filename[PATH_LIMIT];
coding_t coding_type;
coding_t coding_PCM16;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
/*int ima = 0;*/
int nsmbu_flag = 0;
int32_t(*read_32bit)(off_t, STREAMFILE*) = read_32bitBE;
int16_t(*read_16bit)(off_t, STREAMFILE*) = read_16bitBE;
off_t data_offset;
off_t head_offset;
@ -30,8 +31,17 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) {
if ((uint32_t)read_32bitBE(0, streamFile) != 0x46574156) /* "FWAV" */
goto fail;
if ((uint32_t)read_32bitBE(4, streamFile) != 0xFEFF0040) /* "FWAV" */
if ((uint16_t)read_16bitBE(4, streamFile) == 0xFEFF) { /* endian marker (BE most common) */
read_32bit = read_32bitBE;
read_16bit = read_16bitBE;
coding_PCM16 = coding_PCM16BE;
} else if ((uint16_t)read_16bitBE(4, streamFile) == 0xFFFE) { /* LE endian marker */
read_32bit = read_32bitLE;
read_16bit = read_16bitLE;
coding_PCM16 = coding_PCM16LE;
} else {
goto fail;
}
/* get head offset, check */
head_offset = read_32bit(0x18, streamFile);
@ -44,14 +54,14 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) {
/* check type details */
codec_number = read_8bit(head_offset + 0x8, streamFile);
loop_flag = read_8bit(head_offset + 0x9, streamFile);
channel_count = read_8bit(head_offset + 0x1F, streamFile);
channel_count = read_32bit(head_offset + 0x1C, streamFile);
switch (codec_number) {
case 0:
coding_type = coding_PCM8;
break;
case 1:
coding_type = coding_PCM16BE;
coding_type = coding_PCM16;
break;
case 2:
coding_type = coding_NGC_DSP;
@ -72,7 +82,7 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) {
if (nsmbu_flag)
vgmstream->sample_rate = 16000;
else
vgmstream->sample_rate = (uint16_t)read_16bit(head_offset + 0xE, streamFile);
vgmstream->sample_rate = (uint16_t)read_32bit(head_offset + 0xC, streamFile);
/* channels and loop flag are set by allocate_vgmstream */
vgmstream->loop_start_sample = read_32bit(head_offset + 0x10, streamFile);
@ -87,34 +97,22 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) {
vgmstream->meta_type = meta_FWAV;
vgmstream->interleave_block_size = read_32bitBE(read_32bitBE(0x6c, streamFile) + 0x60, streamFile) - 0x18;
vgmstream->interleave_block_size = read_32bit(read_32bit(0x6c, streamFile) + 0x60, streamFile) - 0x18;
start_offset = data_offset + 0x20;
if (vgmstream->coding_type == coding_NGC_DSP) {
off_t coef_offset;
int i, j;
int coef_spacing = 0x2E;
off_t coeffheader = head_offset + 0x28;
int foundcoef = 0;
while (!(foundcoef))
{
if ((uint32_t)read_32bit(coeffheader, streamFile) == 0x1F000000)
{
coef_offset = read_32bit(coeffheader + 0xC, streamFile) + coeffheader;
foundcoef = 1;
break;
}
coeffheader++;
}
for (j = 0; j<vgmstream->channels; j++) {
for (i = 0; i<16; i++) {
vgmstream->ch[j].adpcm_coef[i] = read_16bit(coef_offset + j*coef_spacing + i * 2, streamFile);
off_t coeffheader = head_offset + 0x1C + read_32bit(head_offset + 0x24 + (j*8), streamFile);
off_t coef_offset;
if ((uint32_t)read_16bit(coeffheader, streamFile) != 0x1F00) goto fail;
coef_offset = read_32bit(coeffheader + 0xC, streamFile) + coeffheader;
vgmstream->ch[j].adpcm_coef[i] = read_16bit(coef_offset + i * 2, streamFile);
}
}
}

View File

@ -15,7 +15,7 @@
#define EA_PLATFORM_PSX 0x01
#define EA_PLATFORM_N64 0x02
#define EA_PLATFORM_MAC 0x03
//#define EA_PLATFORM_SAT 0x04 // ?
#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
@ -26,9 +26,10 @@
/* 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_PCM 0x00
#define EA_CODEC1_VAG 0x01 // unsure
#define EA_CODEC1_EAXA 0x07 // Need for Speed 2 PC, Fifa 98 SAT
#define EA_CODEC1_MT10 0x09
//#define EA_CODEC1_N64 ?
#define EA_CODEC2_NONE -1
@ -48,12 +49,12 @@
#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 bps;
int32_t codec1;
int32_t codec2;
@ -68,23 +69,23 @@ typedef struct {
int codec_version;
} ea_header;
static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begin_offset, int max_length);
static int parse_variable_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);
static int get_ea_stream_total_samples(STREAMFILE* streamFile, off_t start_offset, const ea_header* ea);
static off_t get_ea_stream_mpeg_start_offset(STREAMFILE* streamFile, off_t start_offset, const ea_header* ea);
static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_header *ea, off_t start_offset, int is_bnk, int total_streams);
/* EA SCHl - from EA games (roughly 1997~2010, generated by EA Canada's sx.exe / Sound eXchange) */
/* EA SCHl with variable header - 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;
off_t start_offset, header_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"))
if (!check_extensions(streamFile,"str,asf,mus,eam,sng,aud,sx,strm,xa,xsf,exa,stm"))
goto fail;
/* check header */
@ -95,44 +96,173 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) {
goto fail;
header_size = read_32bitLE(0x04,streamFile);
if (header_size > 0xF0000000) /* size is always LE, except in early MAC apparently */
if (header_size > 0x00F00000) /* size is always LE, except in early SS/MAC */
header_size = read_32bitBE(0x04,streamFile);
header_offset = 0x08;
memset(&ea,0,sizeof(ea_header));
if (!parse_stream_header(streamFile,&ea, 0x08, header_size-4-4))
if (!parse_variable_header(streamFile,&ea, 0x08, header_size - header_offset))
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" */
start_offset = header_size; /* starts in "SCCl" (skipped in block layout) or very rarely "SCDl" and maybe movie blocks */
/* rest is common */
return init_vgmstream_ea_variable_header(streamFile, &ea, start_offset, 0, 1);
fail:
return NULL;
}
/* EA BNK with variable header - from EA games SFXs; also created by sx.exe */
VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE *streamFile) {
off_t start_offset, header_offset, offset;
size_t header_size;
ea_header ea;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
int i, bnk_version;
int target_stream = 0, total_streams;
/* check extension */
/* .bnk: sfx, .sdt: speech, .mus: streams/jingles (rare) */
if (!check_extensions(streamFile,"bnk,sdt,mus"))
goto fail;
/* check header (doesn't use EA blocks, otherwise very similar to SCHl) */
if (read_32bitBE(0x00,streamFile) == 0x424E4B6C || /* "BNKl" (common) */
read_32bitBE(0x00,streamFile) == 0x424E4B62) /* "BNKb" (FIFA 98 SS) */
offset = 0;
else if (read_32bitBE(0x100,streamFile) == 0x424E4B6C) /* "BNKl" (common) */
offset = 0x100; /* Harry Potter and the Goblet of Fire (PS2) .mus have weird extra 0x100 bytes */
else
goto fail;
/* use header size as endianness flag */
if ((uint32_t)read_32bitLE(0x08,streamFile) > 0x00F00000) {
read_32bit = read_32bitBE;
read_16bit = read_16bitBE;
} else {
read_32bit = read_32bitLE;
read_16bit = read_16bitLE;
}
bnk_version = read_8bit(offset + 0x04,streamFile);
total_streams = read_16bit(offset + 0x06,streamFile);
/* check multi-streams */
if (target_stream == 0) target_stream = 1;
if (target_stream < 0 || target_stream > total_streams || total_streams < 1) goto fail;
switch(bnk_version) {
case 0x02: /* early (Need For Speed PC, Fifa 98 SS) */
header_size = read_32bit(offset + 0x08,streamFile); /* full size */
header_offset = offset + 0x0c + 0x04*(target_stream-1) + read_32bit(offset + 0x0c + 0x04*(target_stream-1),streamFile);
break;
case 0x04: /* mid (last used in PSX banks) */
case 0x05: /* late (generated by sx.exe ~v2+) */
/* 0x08: header/file size, 0x0C: file size/null, 0x10: always null */
header_size = get_streamfile_size(streamFile); /* unknown (header is variable and may have be garbage until data) */
header_offset = offset + 0x14 + 0x04*(target_stream-1) + read_32bit(offset + 0x14 + 0x04*(target_stream-1),streamFile);
break;
default:
VGM_LOG("EA BNK: unknown version %x\n", bnk_version);
goto fail;
}
if (!parse_variable_header(streamFile,&ea, header_offset, header_size - header_offset))
goto fail;
/* fix absolute offsets so it works in next funcs */
if (offset) {
for (i = 0; i < ea.channels; i++) {
ea.coefs[i] += offset;
ea.offsets[i] += offset;
}
}
start_offset = ea.offsets[0]; /* first channel, presumably needed for MPEG */
/* special case found in some tests (pcstream had hist, pcbnk no hist, no patch diffs)
* I think this works but what decides if hist is used or not a secret to everybody */
if (ea.codec2 == EA_CODEC2_EAXA && ea.codec1 == EA_CODEC1_NONE && ea.version == EA_VERSION_V1) {
ea.codec_version = 0;
}
/* rest is common */
return init_vgmstream_ea_variable_header(streamFile, &ea, start_offset, bnk_version, total_streams);
fail:
return NULL;
}
/* inits VGMSTREAM from a EA header */
static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_header * ea, off_t start_offset, int bnk_version, int total_streams) {
VGMSTREAM * vgmstream = NULL;
int i, ch;
int is_bnk = bnk_version;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(ea.channels, ea.loop_flag);
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->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->codec_endian = ea->big_endian;
vgmstream->codec_version = ea->codec_version;
vgmstream->meta_type = meta_EA_SCHL;
vgmstream->layout_type = layout_ea_blocked;
vgmstream->meta_type = is_bnk ? meta_EA_BNK : meta_EA_SCHL;
if (is_bnk) {
vgmstream->layout_type = layout_none;
/* BNKs usually have absolute offsets for all channels ("full" interleave) except in some versions */
if (vgmstream->channels > 1 && ea->codec1 == EA_CODEC1_PCM) {
int interleave = (vgmstream->num_samples * (ea->bps == 8 ? 0x01 : 0x02)); /* full interleave */
for (i = 0; i < vgmstream->channels; i++) {
ea->offsets[i] = ea->offsets[0] + interleave*i;
}
}
else if (vgmstream->channels > 1 && ea->codec1 == EA_CODEC1_VAG) {
int interleave = (vgmstream->num_samples / 28 * 16); /* full interleave */
for (i = 0; i < vgmstream->channels; i++) {
ea->offsets[i] = ea->offsets[0] + interleave*i;
}
}
else if (vgmstream->channels > 1 && ea->codec2 == EA_CODEC2_GCADPCM && ea->offsets[0] == ea->offsets[1]) {
/* pcstream+gcadpcm with sx.exe v2, this is probably an bug (even with this parts of the wave are off) */
int interleave = (vgmstream->num_samples / 14 * 8); /* full interleave */
for (i = 0; i < vgmstream->channels; i++) {
ea->offsets[i] = ea->offsets[0] + interleave*i;
}
}
}
else {
vgmstream->layout_type = layout_ea_blocked;
}
if (is_bnk)
vgmstream->num_streams = total_streams;
/* 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) {
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;
if (ea->codec1 == EA_CODEC1_EAXA) {
if (ea->platform != EA_PLATFORM_SAT && ea->channels > 1)
vgmstream->coding_type = coding_EA_XA; /* original version, stereo stream */
else
vgmstream->coding_type = coding_EA_XA_int; /* interleaved mono streams */
}
else { /* later revision with PCM blocks and slighty modified decoding */
vgmstream->coding_type = coding_EA_XA_V2;
}
break;
case EA_CODEC2_S8: /* PCM8 */
@ -152,7 +282,7 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) {
break;
case EA_CODEC2_XBOXADPCM: /* XBOX IMA (interleaved mono) */
vgmstream->coding_type = coding_XBOX; /* stereo decoder actually, but has a special case for EA */
vgmstream->coding_type = coding_XBOX_int;
break;
case EA_CODEC2_GCADPCM: /* DSP */
@ -160,12 +290,11 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) {
/* 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;
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);
vgmstream->ch[ch].adpcm_coef[i] = read_16bit(ea->coefs[ch] + i*2, streamFile);
}
}
}
@ -174,42 +303,92 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) {
#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);
off_t mpeg_start_offset = is_bnk ?
start_offset :
get_ea_stream_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 */
vgmstream->codec_data = init_mpeg_codec_data_interleaved(streamFile, mpeg_start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_EA, 0);
if (!vgmstream->codec_data) goto fail;
break;
}
#endif
case EA_CODEC2_MT5: /* MicroTalk (5:1) */
case EA_CODEC2_MT10: /* MicroTalk (10:1 compression) */
case EA_CODEC2_MT5: /* MicroTalk (5:1 compression) */
case EA_CODEC2_EALAYER3: /* MP3 variant */
default:
VGM_LOG("EA: unknown codec2 0x%02x for platform 0x%02x\n", ea.codec2, ea.platform);
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);
/* fix num_samples for streams with multiple SCHl */
if (!is_bnk) {
int total_samples = get_ea_stream_total_samples(streamFile, start_offset, ea);
if (total_samples > vgmstream->num_samples)
vgmstream->num_samples = total_samples;
}
if (is_bnk) {
/* setup channel offsets */
if (vgmstream->coding_type == coding_EA_XA) { /* shared */
for (i = 0; i < vgmstream->channels; i++) {
vgmstream->ch[i].offset = ea->offsets[0];
}
//} else if (vgmstream->layout_type == layout_interleave) { /* interleaved */
// for (i = 0; i < vgmstream->channels; i++) {
// vgmstream->ch[i].offset = ea->offsets[0] + vgmstream->interleave_block_size*i;
// }
} else { /* absolute */
for (i = 0; i < vgmstream->channels; i++) {
vgmstream->ch[i].offset = ea->offsets[i];
}
}
/* setup ADPCM hist */
switch(vgmstream->coding_type) {
/* id, size, samples, hists-per-channel, stereo/interleaved data */
case coding_EA_XA:
/* read ADPCM history from all channels before data (not actually read in sx.exe) */
for (i = 0; i < vgmstream->channels; i++) {
//vgmstream->ch[i].adpcm_history1_32 = read_16bit(block_offset + 0x0C + (i*0x04) + 0x00,streamFile);
//vgmstream->ch[i].adpcm_history2_32 = read_16bit(block_offset + 0x0C + (i*0x04) + 0x02,streamFile);
vgmstream->ch[i].offset += vgmstream->channels*0x04;
}
break;
default:
/* read ADPCM history before each channel if needed (not actually read in sx.exe) */
if (vgmstream->codec_version == 1) {
for (i = 0; i < vgmstream->channels; i++) {
//vgmstream->ch[i].adpcm_history1_32 = read_16bit(vgmstream->ch[i].offset+0x00,streamFile);
//vgmstream->ch[i].adpcm_history3_32 = read_16bit(vgmstream->ch[i].offset+0x02,streamFile);
vgmstream->ch[i].offset += 4;
}
}
break;
}
/* reset channel sub offset for codecs using it */
if (vgmstream->coding_type == coding_EA_XA
|| vgmstream->coding_type == coding_EA_XA_int
|| vgmstream->coding_type == coding_EA_XA_V2) {
for(i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].channel_start_offset = 0;
}
}
}
else {
/* setup first block to update offsets */
ea_schl_block_update(start_offset,vgmstream);
}
return vgmstream;
@ -245,11 +424,12 @@ static uint32_t read_patch(STREAMFILE* streamFile, off_t* offset) {
}
/* 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) {
static int parse_variable_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;
memset(ea,0,sizeof(ea_header));
/* null defaults as 0 can be valid */
ea->version = EA_VERSION_NONE;
@ -274,26 +454,37 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
goto fail;
}
/* parse mini-chunks/tags (variable, ommited if default exists) */
while (offset - begin_offset < max_length) {
/* parse mini-chunks/tags (variable, ommited if default exists; some are removed in later versions of sx.exe) */
while (!is_header_end && 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 */
case 0x00: /* signals non-default block rate and maybe other stuff; or padding after 0xFF */
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 0x06: /* priority (0..100, always 0x65 for streams, others for BNKs; rarely ommited) */
case 0x07: /* unknown (BNK only: 36|3A) */
case 0x08: /* release envelope (BNK only) */
case 0x09: /* related to playback envelope (BNK only) */
case 0x0A: /* bend range (BNK only) */
case 0x0B: /* unknown (always 0x02) */
case 0x0C: /* pan offset (BNK only) */
case 0x0D: /* random pan offset range (BNK only) */
case 0x0E: /* volume (BNK only) */
case 0x0F: /* random volume range (BNK only) */
case 0x10: /* detune (BNK only) */
case 0x11: /* random detune range (BNK only) */
case 0x13: /* effect bus (0..127) */
case 0x14: /* emdedded user data (free size/value) */
case 0x19: /* related to playback envelope (BNK only) */
case 0x1B: /* unknown (movie only?) */
case 0x1C: /* initial envelope volume (BNK only) */
case 0x24: /* master random detune range (BNK only) */
read_patch(streamFile, &offset);
break;
@ -302,6 +493,9 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
case 0xFD: /* info section start marker */
break;
case 0x83: /* codec1 defines, used early revisions */
ea->codec1 = read_patch(streamFile, &offset);
break;
case 0xA0: /* codec2 defines */
ea->codec2 = read_patch(streamFile, &offset);
break;
@ -309,15 +503,13 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
case 0x80: /* version, affecting some codecs */
ea->version = read_patch(streamFile, &offset);
break;
case 0x81: /* bits per sample for codec1 PCM */
ea->bps = 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;
@ -333,7 +525,7 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
break;
/* channel offsets (BNK only), can be the equal for all channels or interleaved; not necessarily contiguous */
case 0x88: /* absolute offset of ch1 */
case 0x88: /* absolute offset of ch1 (or ch1+ch2 for stereo EAXA) */
ea->offsets[0] = read_patch(streamFile, &offset);
break;
case 0x89: /* absolute offset of ch2 */
@ -360,7 +552,7 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
ea->coefs[1] = offset+1;
read_patch(streamFile, &offset);
break;
case 0x91: /* DSP coefs ch3 */
case 0x91: /* DSP coefs ch3, and unknown in older versions */
ea->coefs[2] = offset+1;
read_patch(streamFile, &offset);
break;
@ -377,9 +569,9 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
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 0x8A: /* long padding (always 0x00000000) */
case 0x8C: /* flags (ex. play type = 01=static/02=dynamic | spatialize = 20=pan/etc) */
/* (ex. PS1 VAG=0, PS2 PCM/LAYER2=4, GC EAXA=4, 3DS DSP=512, Xbox EAXA=36, N64 BLK=05E800, N64 MT10=01588805E800) */
case 0x92: /* bytes per sample? */
case 0x98: /* embedded time stretch 1 (long data for who-knows-what) */
case 0x99: /* embedded time stretch 2 */
@ -393,7 +585,7 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
read_patch(streamFile, &offset);
break;
case 0xFF: /* header end (then 0-padded) */
case 0xFF: /* header end (then 0-padded so it's 32b aligned) */
is_header_end = 1;
break;
@ -403,44 +595,72 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
}
}
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 */
/* Set defaults per platform, as the header ommits them when possible */
ea->loop_flag = (ea->loop_end);
/* affects blocks/codecs */
if (ea->platform == EA_PLATFORM_N64
|| ea->platform == EA_PLATFORM_MAC
|| ea->platform == EA_PLATFORM_SAT
|| ea->platform == EA_PLATFORM_GC_WII
|| ea->platform == EA_PLATFORM_X360
|| ea->platform == EA_PLATFORM_GENERIC) {
ea->big_endian = 1;
}
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 */
/* version mainly affects defaults and minor stuff, can come with all codecs */
/* V0 is often just null but it's specified in some files (uncommon, with patch size 0x00) */
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_N64: ea->version = EA_VERSION_V0; break;
case EA_PLATFORM_MAC: ea->version = EA_VERSION_V0; break;
case EA_PLATFORM_SAT: 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;
case EA_PLATFORM_GENERIC: ea->version = EA_VERSION_V2; break;
default:
VGM_LOG("EA: unknown default version for platform 0x%02x\n", ea->platform);
goto fail;
}
}
/* codec1 defaults */
if (ea->codec1 == EA_CODEC1_NONE && ea->version == EA_VERSION_V0) {
switch(ea->platform) {
case EA_PLATFORM_PC: ea->codec1 = EA_CODEC1_PCM; break;
case EA_PLATFORM_PSX: ea->codec1 = EA_CODEC1_VAG; break; // assumed
//case EA_PLATFORM_N64: ea->codec1 = EA_CODEC1_N64; break;
case EA_PLATFORM_MAC: ea->codec1 = EA_CODEC1_PCM; break; // assumed
case EA_PLATFORM_SAT: ea->codec1 = EA_CODEC1_PCM; break;
default:
VGM_LOG("EA: unknown default codec1 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_PCM:
ea->codec2 = ea->bps==8 ? EA_CODEC2_S8 : (ea->big_endian ? EA_CODEC2_S16BE : EA_CODEC2_S16LE);
break;
case EA_CODEC1_VAG: ea->codec2 = EA_CODEC2_VAG; break;
case EA_CODEC1_EAXA: ea->codec2 = EA_CODEC2_EAXA; break;
case EA_CODEC1_MT10: ea->codec2 = EA_CODEC2_MT10; break;
default:
VGM_LOG("EA: unknown codec1 0x%02x\n", ea->codec1);
@ -448,7 +668,7 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
}
}
/* defaults don't seem to change with version or over time, fortunately */
/* codec2 defaults */
if (ea->codec2 == EA_CODEC2_NONE) {
switch(ea->platform) {
case EA_PLATFORM_GENERIC: ea->codec2 = EA_CODEC2_EAXA; break;
@ -475,6 +695,7 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
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_SAT: 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;
@ -487,26 +708,19 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
}
}
/* 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;
/* special flag: 1=has ADPCM history per block, 0=doesn't */
if (ea->codec2 == EA_CODEC2_GCADPCM && ea->platform == EA_PLATFORM_3DS) {
ea->codec_version = 1;
}
else if (ea->codec2 == EA_CODEC2_EAXA && ea->codec1 == EA_CODEC1_NONE) {
/* console V2 uses hist, as does PC/MAC V1 (but not later versions) */
if (ea->version <= EA_VERSION_V1 ||
((ea->platform == EA_PLATFORM_PS2 || ea->platform == EA_PLATFORM_GC_WII || ea->platform == EA_PLATFORM_XBOX)
&& ea->version == EA_VERSION_V2)) {
ea->codec_version = 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;
@ -518,67 +732,70 @@ fail:
/* 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;
static int get_ea_stream_total_samples(STREAMFILE* streamFile, off_t start_offset, const ea_header* ea) {
int 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;
uint32_t id, block_size, block_samples;
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 */
if (block_size > 0x00F00000) /* size is always LE, except in early SS/MAC */
block_size = read_32bitBE(block_offset+0x04,streamFile);
/* SCxx blocks have size in the header, but others may not. To simplify we just try to
* find a SCDl (main data) every 0x04. EA sometimes concats many small files, so after a SCEl (end block)
* there may be a new SCHl + SCDl too, so this pretends they are a single stream. */
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);
block_samples = ps_bytes_to_samples(block_size-0x10, ea->channels);
break;
default:
num_samples += read_32bit(block_offset+0x08,streamFile);
block_samples = read_32bit(block_offset+0x08,streamFile);
break;
}
/* guard against false positives (happens in "pIQT" blocks) */
if (block_size > 0xFFFF || block_samples > 0xFFFF) { /* observed max is ~0xf00 but who knows */
block_offset += 0x04;
continue;
}
num_samples += block_samples;
block_offset += block_size; /* size includes header */
}
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 */
else {
/* movie "pIQT" may be bigger than what block_size says, but seems to help */
if (id == 0x5343486C || id == 0x5343436C || id == 0x53434C6C || id == 0x70495154) { /* "SCHl" "SCCl" "SCLl" "SCEl" "pIQT" */
block_offset += block_size;
} else {
block_offset += 0x04;
}
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, important */
}
block_offset += 0x04;
continue;
}
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) {
static off_t get_ea_stream_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;
@ -589,7 +806,7 @@ static off_t get_ea_mpeg_start_offset(STREAMFILE* streamFile, off_t start_offset
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 */
if (block_size > 0x00F00000) /* size is always LE, except in early SS/MAC */
block_size = read_32bitBE(block_offset+0x04,streamFile);
if (id == 0x5343446C) { /* "SCDl" data block found */

View File

@ -0,0 +1,124 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
/* Possibly the same as EA_CODEC_x in variable SCHl */
#define EA_CODEC_PCM 0x00
#define EA_CODEC_IMA 0x02
typedef struct {
int8_t version;
int8_t bps;
int8_t channels;
int8_t codec;
int16_t sample_rate;
int32_t num_samples;
int big_endian;
int loop_flag;
} ea_header;
static int parse_fixed_header(STREAMFILE* streamFile, ea_header* ea, off_t begin_offset);
/* EA SCHl with fixed header - from EA games (~1997? ex. NHL 97 PC) */
VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
size_t header_size;
ea_header ea;
/* check extension */
if (!check_extensions(streamFile,"asf"))
goto fail;
/* check header (see ea_schl.c for more info about blocks) */
if (read_32bitBE(0x00,streamFile) != 0x5343486C) /* "SCHl" */
goto fail;
header_size = read_32bitLE(0x04,streamFile);
if (!parse_fixed_header(streamFile,&ea, 0x08))
goto fail;
start_offset = header_size;
/* 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->meta_type = meta_EA_SCHL_fixed;
vgmstream->layout_type = layout_ea_blocked;
switch (ea.codec) {
case EA_CODEC_PCM:
vgmstream->coding_type = ea.bps==8 ? coding_PCM8 : (ea.big_endian ? coding_PCM16BE : coding_PCM16LE);
break;
case EA_CODEC_IMA:
vgmstream->coding_type = coding_EACS_IMA;
break;
default:
VGM_LOG("EA: unknown codec 0x%02x\n", ea.codec);
goto fail;
}
/* open files; channel offsets are updated below */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
/* setup first block to update offsets */
ea_schl_block_update(start_offset,vgmstream);
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
static int parse_fixed_header(STREAMFILE* streamFile, ea_header* ea, off_t begin_offset) {
off_t offset = begin_offset;
memset(ea,0,sizeof(ea_header));
if (read_32bitBE(offset+0x00, streamFile) != 0x5041546C && /* "PATl" */
read_32bitBE(offset+0x38, streamFile) != 0x544D706C) /* "TMpl" */
goto fail;
offset += 0x3c; /* after TMpl */
ea->version = read_8bit(offset+0x00, streamFile);
ea->bps = read_8bit(offset+0x01, streamFile);
ea->channels = read_8bit(offset+0x02, streamFile);
ea->codec = read_8bit(offset+0x03, streamFile);
VGM_ASSERT(read_16bitLE(offset+0x04, streamFile) != 0, "EA SCHl fixed: unknown1 found\n");
/* 0x04(16): unknown */
ea->sample_rate = (uint16_t)read_16bitLE(offset+0x06, streamFile);
ea->num_samples = read_32bitLE(offset+0x08, streamFile);
VGM_ASSERT(read_32bitLE(offset+0x0c, streamFile) != -1, "EA SCHl fixed: unknown2 found\n"); /* loop start? */
VGM_ASSERT(read_32bitLE(offset+0x10, streamFile) != -1, "EA SCHl fixed: unknown3 found\n"); /* loop end? */
VGM_ASSERT(read_32bitLE(offset+0x14, streamFile) != 0, "EA SCHl fixed: unknown4 found\n"); /* data start? */
VGM_ASSERT(read_32bitLE(offset+0x18, streamFile) != -1, "EA SCHl fixed: unknown5 found\n");
VGM_ASSERT(read_32bitLE(offset+0x1c, streamFile) != 0x7F, "EA SCHl fixed: unknown6 found\n");
//ea->loop_flag = (ea->loop_end_sample);
return 1;
fail:
return 0;
}

View File

@ -1,63 +1,50 @@
#include "meta.h"
#include "../util.h"
/* Maxis XA - found in 'Sim City 3000' */
/* Maxis XA - found in Sim City 3000 (PC) */
VGMSTREAM * init_vgmstream_maxis_xa(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag;
int channel_count;
int loop_flag, channel_count, i;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("xa",filename_extension(filename))) goto fail;
if (!check_extensions(streamFile,"xa"))
goto fail;
/* check header */
if ((read_32bitBE(0x00,streamFile) != 0x58414900)&& /* "XAI\0" */
(read_32bitBE(0x00,streamFile) != 0x58414A00)) /* "XAJ\0" */
if ((read_32bitBE(0x00,streamFile) != 0x58414900) && /* "XAI\0" */
(read_32bitBE(0x00,streamFile) != 0x58414A00)) /* "XAJ\0" (some odd song uses this, no apparent diffs) */
goto fail;
loop_flag = 0;
channel_count = read_16bitLE(0xA,streamFile);
/* build the VGMSTREAM */
channel_count = read_16bitLE(0x0A,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x18;
vgmstream->channels = channel_count;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x0C,streamFile);
vgmstream->coding_type = coding_MAXIS_ADPCM;
vgmstream->coding_type = coding_MAXIS_XA;
vgmstream->num_samples = read_32bitLE(0x04,streamFile)/2/channel_count;
if (loop_flag) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = (read_32bitBE(0x0C,streamFile)-start_offset)/8/channel_count*14;
}
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_MAXIS_XA;
/* 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=start_offset+i;
vgmstream->ch[i].offset=0;
}
/* open streams */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
/* fix channel offsets as needed by the codec (could be simplified) */
for (i = 0; i < channel_count; i++) {
vgmstream->ch[i].channel_start_offset = start_offset+i;
vgmstream->ch[i].offset = 0;
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -678,4 +678,10 @@ VGMSTREAM * init_vgmstream_pc_xa30(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_wii_04sw(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_txth(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE * streamFile);
#endif /*_META_H*/

View File

@ -1,69 +1,51 @@
#include "meta.h"
#include "../util.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
/* HWAS (found in Spider-Man 3, Tony Hawk's Downhill Jam, possibly more...) */
/* HWAS - found in Vicarious Visions NDS games (Spider-Man 3, Tony Hawk's Downhill Jam, etc) */
VGMSTREAM * init_vgmstream_nds_hwas(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag = 0;
int channel_count;
int channel_count, loop_flag = 0;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("hwas",filename_extension(filename))) goto fail;
if (!check_extensions(streamFile,"hwas"))
goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x73617768) /* "sawh" */
goto fail;
loop_flag = 0;
loop_flag = 1; /* almost all files seem to loop (usually if num_samples != loop_end doesn't loop, but not always) */
channel_count = read_32bitLE(0x0C,streamFile);
/* build the VGMSTREAM */
if (channel_count > 1) goto fail; /* unknown block layout when stereo, not seen */
start_offset = 0x200;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x200;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
vgmstream->coding_type = coding_IMA_int;
vgmstream->num_samples = read_32bitLE(0x14,streamFile);
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(0x10,streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x18,streamFile);
}
if (channel_count == 1) {
vgmstream->layout_type = layout_none;
} else {
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10; // Not sure if there are stereo files
}
vgmstream->num_samples = ima_bytes_to_samples(read_32bitLE(0x14,streamFile), channel_count);
vgmstream->loop_start_sample = ima_bytes_to_samples(read_32bitLE(0x10,streamFile), channel_count); //assumed, always 0
vgmstream->loop_end_sample = ima_bytes_to_samples(read_32bitLE(0x18,streamFile), channel_count);
vgmstream->meta_type = meta_NDS_HWAS;
/* open the file for reading by each channel */
{
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->coding_type = coding_IMA;
vgmstream->layout_type = layout_hwas_blocked;
vgmstream->full_block_size = read_32bitLE(0x04,streamFile); /* usually 0x2000, 0x4000 or 0x8000 */
/* open the file for reading by each channel */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
hwas_block_update(start_offset, vgmstream);
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,6 +1,7 @@
#include "meta.h"
#include "../util.h"
/* STRM - common Nintendo NDS streaming format */
VGMSTREAM * init_vgmstream_nds_strm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
@ -103,69 +104,3 @@ fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
/* STRM (from Final Fantasy Tactics A2 - Fuuketsu no Grimoire) */
VGMSTREAM * init_vgmstream_nds_strm_ffta2(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("strm",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x52494646 || /* RIFF */
read_32bitBE(0x08,streamFile) != 0x494D4120) /* "IMA " */
goto fail;
loop_flag = (read_32bitLE(0x20,streamFile) !=0);
channel_count = read_32bitLE(0x24,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x2C;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x0C,streamFile);
vgmstream->coding_type = coding_IMA_int;
vgmstream->num_samples = (read_32bitLE(0x04,streamFile)-start_offset);
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x28,streamFile);
}
vgmstream->interleave_block_size = 0x80;
vgmstream->interleave_smallblock_size = (vgmstream->loop_end_sample)%((vgmstream->loop_end_sample)/vgmstream->interleave_block_size);
vgmstream->layout_type = layout_interleave_shortblock;
vgmstream->meta_type = meta_NDS_STRM_FFTA2;
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -0,0 +1,48 @@
#include "meta.h"
#include "../util.h"
/* STRM - from Final Fantasy Tactics A2 (NDS) */
VGMSTREAM * init_vgmstream_nds_strm_ffta2(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
/* check extension, case insensitive (the ROM seems to use simply .bin though) */
if (!check_extensions(streamFile,"strm"))
goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x52494646 || /* "RIFF" */
read_32bitBE(0x08,streamFile) != 0x494D4120) /* "IMA " */
goto fail;
loop_flag = (read_32bitLE(0x20,streamFile) !=0);
channel_count = read_32bitLE(0x24,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
start_offset = 0x2C;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x0C,streamFile);
vgmstream->coding_type = coding_IMA_int; //todo: seems it has some diffs vs regular IMA
vgmstream->num_samples = (read_32bitLE(0x04,streamFile)-start_offset);
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x28,streamFile);
}
vgmstream->interleave_block_size = 0x80;
vgmstream->layout_type = layout_interleave;
vgmstream->meta_type = meta_NDS_STRM_FFTA2;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -4,50 +4,43 @@
VGMSTREAM * init_vgmstream_ngc_adpdtk(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * chstreamfile;
char filename[PATH_LIMIT];
size_t file_size;
int i;
off_t start_offset = 0;
int channel_count = 2, loop_flag = 0; /* always stereo, no loop */
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("adp",filename_extension(filename)) &&
strcasecmp("dtk",filename_extension(filename))) goto fail;
if ( !check_extensions(streamFile,"dtk,adp"))
goto fail;
/* file size is the only way to determine sample count */
file_size = get_streamfile_size(streamFile);
/* .adp files have no header, and the ext is common, so all we can do is look for valid first frames */
if (check_extensions(streamFile,"adp")) {
int i;
for (i = 0; i < 10; i++) { /* try a bunch of frames */
if (read_8bit(0x00 + i*0x20,streamFile) != read_8bit(0x02 + i*0x20,streamFile) ||
read_8bit(0x01 + i*0x20,streamFile) != read_8bit(0x03 + i*0x20,streamFile))
goto fail;
}
}
/* .adp files have no header, so all we can do is look for a valid first frame */
if (read_8bit(0,streamFile)!=read_8bit(2,streamFile) || read_8bit(1,streamFile)!=read_8bit(3,streamFile)) goto fail;
/* Hopefully we haven't falsely detected something else... */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(2,0); /* always stereo, no loop */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->num_samples = file_size/32*28;
vgmstream->num_samples = get_streamfile_size(streamFile) / 32 * 28;
vgmstream->sample_rate = 48000;
vgmstream->coding_type = coding_NGC_DTK;
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_NGC_ADPDTK;
/* locality is such that two streamfiles is silly */
chstreamfile = streamFile->open(streamFile,filename,32*0x400);
if (!chstreamfile) goto fail;
for (i=0;i<2;i++) {
vgmstream->ch[i].channel_start_offset =
vgmstream->ch[i].offset = 0;
vgmstream->ch[i].streamfile = chstreamfile;
}
/* open the file for reading */
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

@ -60,9 +60,9 @@ VGMSTREAM * init_vgmstream_pc_adp_otns(STREAMFILE *streamFile) {
/* no ID, only a basic 0x10 header with filesize and nulls; do some extra checks */
datasize = read_32bitLE(0x00,streamFile) & 0x00FFFFFF; /*24 bit*/
if (datasize + 0x10 != streamFile->get_size(streamFile)
&& read_32bitLE(0x04,streamFile) != 0
&& read_32bitLE(0x08,streamFile) != 0
&& read_32bitLE(0x10,streamFile) != 0)
|| read_32bitLE(0x04,streamFile) != 0
|| read_32bitLE(0x08,streamFile) != 0
|| read_32bitLE(0x10,streamFile) != 0)
goto fail;
stereo_flag = read_8bit(0x03, streamFile);

View File

@ -23,8 +23,14 @@ VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE *streamFile) {
goto fail;
#endif
/* don't hijack Sonic & Sega All Stars Racing X360 (xma) */
if (read_32bitBE(0x00,streamFile) == 0x52494646) /* "RIFF"*/
/* don't hijack Sonic & Sega All Stars Racing X360 (xma) */
if (read_32bitBE(0x00,streamFile) == 0x52494646)
goto fail; /* "RIFF"*/
/* don't hijack Mad Dash Racing (Xbox) */
if (read_32bitLE(0x0c,streamFile) == 1
&& read_32bitLE(0x010,streamFile) == 0
&& read_32bitLE(0x400,streamFile) == 0
&& read_32bitLE(0x7f0,streamFile) == 0)
goto fail;
loop_flag = 0;

View File

@ -39,6 +39,8 @@ VGMSTREAM * init_vgmstream_cdxa(STREAMFILE *streamFile) {
/* don't misdetect Reflections' XA ("XA30" / "04SW") */
if (read_32bitBE(0x00,streamFile) == 0x58413330 || read_32bitBE(0x00,streamFile) == 0x30345357) goto fail;
/* don't misdetect Maxis XA ("XAI\0" / "XAJ\0") */
if (read_32bitBE(0x00,streamFile) == 0x58414900 || read_32bitBE(0x00,streamFile) == 0x58414A00) goto fail;
/* First init to have the correct info of the channel */
if (!headerless) {

View File

@ -0,0 +1,678 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
#include "../util.h"
/* known TXTH types */
typedef enum {
PSX = 0, /* PSX ADPCM */
XBOX = 1, /* XBOX IMA ADPCM */
NGC_DTK = 2, /* NGC ADP/DTK ADPCM */
PCM16BE = 3, /* 16bit big endian PCM */
PCM16LE = 4, /* 16bit little endian PCM */
PCM8 = 5, /* 8bit PCM */
SDX2 = 6, /* SDX2 (3D0 games) */
DVI_IMA = 7, /* DVI IMA ADPCM */
MPEG = 8, /* MPEG (MP3) */
IMA = 9, /* IMA ADPCM */
AICA = 10, /* AICA ADPCM (dreamcast) */
MSADPCM = 11, /* MS ADPCM (windows) */
NGC_DSP = 12, /* NGC DSP (GC) */
PCM8_U_int = 13, /* 8bit unsigned PCM (interleaved) */
PSX_bf = 14, /* PSX ADPCM bad flagged */
MS_IMA = 15, /* Microsoft IMA ADPCM */
PCM8_U = 16, /* 8bit unsigned PCM */
APPLE_IMA4 = 17, /* Apple Quicktime 4-bit IMA ADPCM */
ATRAC3 = 18, /* raw ATRAC3 */
ATRAC3PLUS = 19, /* raw ATRAC3PLUS */
XMA1 = 20, /* raw XMA1 */
XMA2 = 21, /* raw XMA2 */
FFMPEG = 22, /* any headered FFmpeg format */
} txth_type;
typedef struct {
txth_type codec;
txth_type codec_mode;
uint32_t interleave;
uint32_t id_value;
uint32_t id_offset;
uint32_t channels;
uint32_t sample_rate;
uint32_t data_size;
int data_size_set;
uint32_t start_offset;
int sample_type_bytes;
uint32_t num_samples;
uint32_t loop_start_sample;
uint32_t loop_end_sample;
uint32_t loop_adjust;
int skip_samples_set;
uint32_t skip_samples;
uint32_t loop_flag;
int loop_flag_set;
uint32_t coef_offset;
uint32_t coef_spacing;
uint32_t coef_mode;
uint32_t coef_big_endian;
} txth_header;
static int parse_txth(STREAMFILE * streamFile, STREAMFILE * streamText, txth_header * txth);
static int parse_keyval(STREAMFILE * streamFile, STREAMFILE * streamText, txth_header * txth, const char * key, const char * val);
static int parse_num(STREAMFILE * streamFile, const char * val, uint32_t * out_value);
static int get_bytes_to_samples(txth_header * txth, uint32_t bytes);
/* TXTH - an artificial "generic" header for headerless streams.
* Similar to GENH, but with a single separate .txth file in the dir and text-based. */
VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * streamText = NULL;
txth_header txth;
coding_t coding;
int i, j;
/* no need for ID or ext checks -- if a .TXTH exists all is good
* (player still needs to accept the ext, so at worst rename to .vgmstream) */
{
char filename[PATH_LIMIT];
char fileext[PATH_LIMIT];
/* try "(path/)(name.ext).txth" */
if (!get_streamfile_name(streamFile,filename,PATH_LIMIT)) goto fail;
strcat(filename, ".txth");
streamText = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (streamText) goto found;
/* try "(path/)(.ext).txth" */
if (!get_streamfile_path(streamFile,filename,PATH_LIMIT)) goto fail;
if (!get_streamfile_ext(streamFile,fileext,PATH_LIMIT)) goto fail;
strcat(filename,".");
strcat(filename, fileext);
strcat(filename, ".txth");
streamText = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (streamText) goto found;
/* try "(path/).txth" */
if (!get_streamfile_path(streamFile,filename,PATH_LIMIT)) goto fail;
strcat(filename, ".txth");
streamText = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (streamText) goto found;
/* not found */
goto fail;
}
found:
/* process the text file */
memset(&txth,0,sizeof(txth_header));
if (!parse_txth(streamFile, streamText, &txth))
goto fail;
/* type to coding conversion */
switch (txth.codec) {
case PSX: coding = coding_PSX; break;
case XBOX: coding = coding_XBOX; break;
case NGC_DTK: coding = coding_NGC_DTK; break;
case PCM16BE: coding = coding_PCM16BE; break;
case PCM16LE: coding = coding_PCM16LE; break;
case PCM8: coding = coding_PCM8; break;
case SDX2: coding = coding_SDX2; break;
case DVI_IMA: coding = coding_DVI_IMA; break;
#ifdef VGM_USE_MPEG
case MPEG: coding = coding_MPEG1_L3; break; /* we later find out exactly which */
#endif
case IMA: coding = coding_IMA; break;
case AICA: coding = coding_AICA; break;
case MSADPCM: coding = coding_MSADPCM; break;
case NGC_DSP: coding = coding_NGC_DSP; break;
case PCM8_U_int: coding = coding_PCM8_U_int; break;
case PSX_bf: coding = coding_PSX_badflags; break;
case MS_IMA: coding = coding_MS_IMA; break;
case PCM8_U: coding = coding_PCM8_U; break;
case APPLE_IMA4: coding = coding_APPLE_IMA4; break;
#ifdef VGM_USE_FFMPEG
case ATRAC3:
case ATRAC3PLUS:
case XMA1:
case XMA2:
case FFMPEG: coding = coding_FFmpeg; break;
#endif
default:
goto fail;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(txth.channels,txth.loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = txth.sample_rate;
vgmstream->num_samples = txth.num_samples;
vgmstream->loop_start_sample = txth.loop_start_sample;
vgmstream->loop_end_sample = txth.loop_end_sample;
/* codec specific (taken from GENH with minimal changes) */
switch (coding) {
case coding_PCM8_U_int:
vgmstream->layout_type = layout_none;
break;
case coding_PCM16LE:
case coding_PCM16BE:
case coding_PCM8:
case coding_PCM8_U:
case coding_SDX2:
case coding_PSX:
case coding_PSX_badflags:
case coding_DVI_IMA:
case coding_IMA:
case coding_AICA:
case coding_APPLE_IMA4:
vgmstream->interleave_block_size = txth.interleave;
if (vgmstream->channels > 1)
{
if (coding == coding_SDX2) {
coding = coding_SDX2_int;
}
if (vgmstream->interleave_block_size==0xffffffff || vgmstream->interleave_block_size == 0) {
vgmstream->layout_type = layout_none;
}
else {
vgmstream->layout_type = layout_interleave;
if (coding == coding_DVI_IMA)
coding = coding_DVI_IMA_int;
if (coding == coding_IMA)
coding = coding_IMA_int;
}
/* to avoid endless loops */
if (!txth.interleave && (
coding == coding_PSX ||
coding == coding_PSX_badflags ||
coding == coding_IMA_int ||
coding == coding_DVI_IMA_int ||
coding == coding_SDX2_int) ) {
goto fail;
}
} else {
vgmstream->layout_type = layout_none;
}
/* setup adpcm */
if (coding == coding_AICA) {
int i;
for (i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].adpcm_step_index = 0x7f;
}
}
break;
case coding_MS_IMA:
if (!txth.interleave) goto fail; /* creates garbage */
vgmstream->interleave_block_size = txth.interleave;
vgmstream->layout_type = layout_none;
break;
case coding_MSADPCM:
if (vgmstream->channels > 2) goto fail;
if (!txth.interleave) goto fail; /* creates garbage */
vgmstream->interleave_block_size = txth.interleave;
vgmstream->layout_type = layout_none;
break;
case coding_XBOX:
vgmstream->layout_type = layout_none;
break;
case coding_NGC_DTK:
if (vgmstream->channels != 2) goto fail;
vgmstream->layout_type = layout_none;
break;
case coding_NGC_DSP:
if (txth.channels > 1 && txth.codec_mode == 0) {
if (!txth.interleave) goto fail;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = txth.interleave;
} else if (txth.channels > 1 && txth.codec_mode == 1) {
if (!txth.interleave) goto fail;
vgmstream->layout_type = layout_interleave_byte;
vgmstream->interleave_block_size = txth.interleave;
} else if (txth.channels == 1 || txth.codec_mode == 2) {
vgmstream->layout_type = layout_none;
} else {
goto fail;
}
/* get coefs */
for (i=0;i<vgmstream->channels;i++) {
int16_t (*read_16bit)(off_t , STREAMFILE*) = txth.coef_big_endian ? read_16bitBE : read_16bitLE;
/* normal/split coefs */
if (txth.coef_mode == 0) {
for (j=0;j<16;j++) {
vgmstream->ch[i].adpcm_coef[j] = read_16bit(txth.coef_offset + i*txth.coef_spacing + j*2,streamFile);
}
} else {
goto fail; //IDK what is this
/*
for (j=0;j<8;j++) {
vgmstream->ch[i].adpcm_coef[j*2]=read_16bit(coef[i]+j*2,streamFile);
vgmstream->ch[i].adpcm_coef[j*2+1]=read_16bit(coef_splitted[i]+j*2,streamFile);
}
*/
}
}
break;
#ifdef VGM_USE_MPEG
case coding_MPEG1_L3:
vgmstream->layout_type = layout_mpeg;
vgmstream->codec_data = init_mpeg_codec_data(streamFile, txth.start_offset, &coding, vgmstream->channels);
if (!vgmstream->codec_data) goto fail;
break;
#endif
#ifdef VGM_USE_FFMPEG
case coding_FFmpeg: {
ffmpeg_codec_data *ffmpeg_data = NULL;
if (txth.codec == FFMPEG) {
/* default FFmpeg */
ffmpeg_data = init_ffmpeg_offset(streamFile, txth.start_offset,txth.data_size);
if ( !ffmpeg_data ) goto fail;
}
else {
/* fake header FFmpeg */
uint8_t buf[200];
int32_t bytes;
if (txth.codec == ATRAC3) {
int block_size = txth.interleave;
int joint_stereo;
switch(txth.codec_mode) {
case 0: joint_stereo = vgmstream->channels > 1 && txth.interleave/vgmstream->channels==0x60 ? 1 : 0; break; /* autodetect */
case 1: joint_stereo = 1; break; /* force joint stereo */
case 2: joint_stereo = 0; break; /* force stereo */
default: goto fail;
}
bytes = ffmpeg_make_riff_atrac3(buf, 200, vgmstream->num_samples, txth.data_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, txth.skip_samples);
}
else if (txth.codec == ATRAC3PLUS) {
int block_size = txth.interleave;
bytes = ffmpeg_make_riff_atrac3plus(buf, 200, vgmstream->num_samples, txth.data_size, vgmstream->channels, vgmstream->sample_rate, block_size, txth.skip_samples);
}
else if (txth.codec == XMA1) {
int xma_stream_mode = txth.codec_mode == 1 ? 1 : 0;
bytes = ffmpeg_make_riff_xma1(buf, 100, vgmstream->num_samples, txth.data_size, vgmstream->channels, vgmstream->sample_rate, xma_stream_mode);
}
else if (txth.codec == XMA2) {
int block_size = txth.interleave ? txth.interleave : 2048;
int block_count = txth.data_size / block_size;
bytes = ffmpeg_make_riff_xma2(buf, 200, vgmstream->num_samples, txth.data_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
}
else {
goto fail;
}
if (bytes <= 0) goto fail;
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, txth.start_offset,txth.data_size);
if ( !ffmpeg_data ) goto fail;
}
vgmstream->codec_data = ffmpeg_data;
vgmstream->layout_type = layout_none;
/* force encoder delay */
if (txth.skip_samples_set) {
ffmpeg_set_skip_samples(ffmpeg_data, txth.skip_samples);
}
break;
}
#endif
default:
break;
}
#ifdef VGM_USE_FFMPEG
if (txth.sample_type_bytes && (txth.codec == XMA1 || txth.codec == XMA2)) {
/* manually find sample offsets */
ms_sample_data msd;
memset(&msd,0,sizeof(ms_sample_data));
msd.xma_version = 1;
msd.channels = txth.channels;
msd.data_offset = txth.start_offset;
msd.data_size = txth.data_size;
msd.loop_flag = txth.loop_flag;
msd.loop_start_b = txth.loop_start_sample;
msd.loop_end_b = txth.loop_end_sample;
msd.loop_start_subframe = txth.loop_adjust & 0xF; /* lower 4b: subframe where the loop starts, 0..4 */
msd.loop_end_subframe = txth.loop_adjust >> 4; /* upper 4b: subframe where the loop ends, 0..3 */
xma_get_samples(&msd, streamFile);
vgmstream->num_samples = msd.num_samples;
vgmstream->loop_start_sample = msd.loop_start_sample;
vgmstream->loop_end_sample = msd.loop_end_sample;
//skip_samples = msd.skip_samples; //todo add skip samples
}
#endif
vgmstream->coding_type = coding;
vgmstream->meta_type = meta_TXTH;
if ( !vgmstream_open_stream(vgmstream,streamFile,txth.start_offset) )
goto fail;
if (streamText) close_streamfile(streamText);
return vgmstream;
fail:
if (streamText) close_streamfile(streamText);
close_vgmstream(vgmstream);
return NULL;
}
/* Simple text parser of "key = value" lines.
* The code is meh and error handling not exactly the best. */
static int parse_txth(STREAMFILE * streamFile, STREAMFILE * streamText, txth_header * txth) {
off_t off = 0;
off_t file_size = get_streamfile_size(streamText);
#ifndef LINE_MAX /* some platforms define this via limits.h */
#if defined(_MSC_VER) && (_MSC_VER < 1900)
enum { LINE_MAX = 0x2000 }; /* arbitrary max */
#else
const size_t LINE_MAX = 0x2000;
#endif
#endif
txth->data_size = get_streamfile_size(streamFile); /* for later use */
/* skip BOM if needed */
if (read_16bitLE(0x00, streamText) == 0xFFFE || read_16bitLE(0x00, streamText) == 0xFEFF)
off = 0x02;
/* read lines */
while (off < file_size) {
char line[LINE_MAX];
char key[LINE_MAX];
char val[LINE_MAX]; /* at least as big as a line to avoid overflows (I hope) */
int ok;
off_t line_start = off, line_end = 0;
line[0] = key[0] = val[0] = 0;
/* find line end */
while (line_end == 0 && off - line_start < LINE_MAX) {
char c = (char)read_8bit(off, streamText);
if (c == '\n')
line_end = off;
else if (off >= file_size)
line_end = off-1;
off++;
}
if (line_end == 0)
goto fail; /* bad file / line too long */
/* get key/val (ignores lead/trail spaces, stops at space/comment/separator) */
read_streamfile((uint8_t*)line,line_start,line_end, streamText);
line[line_end - line_start + 1] = '\0';
ok = sscanf(line, " %[^ \t#=] = %[^ \t#\r\n] ", key,val);
//VGM_LOG("TXTH: ok=%i, key=\"%s\", val=\"%s\" from 0x%lx to 0x%lx\n", ok, key, val, line_start, line_end);
if (ok != 2) /* ignore line if no key=val (comment or garbage) */
continue;
if (!parse_keyval(streamFile, streamText, txth, key, val)) /* read key/val */
goto fail;
}
if (!txth->loop_flag_set)
txth->loop_flag = txth->loop_end_sample && txth->loop_end_sample != 0xFFFFFFFF;
return 1;
fail:
return 0;
}
static int parse_keyval(STREAMFILE * streamFile, STREAMFILE * streamText, txth_header * txth, const char * key, const char * val) {
if (0==strcmp(key,"codec")) {
if (0==strcmp(val,"PSX")) txth->codec = PSX;
else if (0==strcmp(val,"XBOX")) txth->codec = XBOX;
else if (0==strcmp(val,"NGC_DTK")) txth->codec = NGC_DTK;
else if (0==strcmp(val,"PCM16BE")) txth->codec = PCM16BE;
else if (0==strcmp(val,"PCM16LE")) txth->codec = PCM16LE;
else if (0==strcmp(val,"PCM8")) txth->codec = PCM8;
else if (0==strcmp(val,"SDX2")) txth->codec = SDX2;
else if (0==strcmp(val,"DVI_IMA")) txth->codec = DVI_IMA;
else if (0==strcmp(val,"MPEG")) txth->codec = MPEG;
else if (0==strcmp(val,"IMA")) txth->codec = IMA;
else if (0==strcmp(val,"AICA")) txth->codec = AICA;
else if (0==strcmp(val,"MSADPCM")) txth->codec = MSADPCM;
else if (0==strcmp(val,"NGC_DSP")) txth->codec = NGC_DSP;
else if (0==strcmp(val,"PCM8_U_int")) txth->codec = PCM8_U_int;
else if (0==strcmp(val,"PSX_bf")) txth->codec = PSX_bf;
else if (0==strcmp(val,"MS_IMA")) txth->codec = MS_IMA;
else if (0==strcmp(val,"PCM8_U")) txth->codec = PCM8_U;
else if (0==strcmp(val,"APPLE_IMA4")) txth->codec = APPLE_IMA4;
else if (0==strcmp(val,"ATRAC3")) txth->codec = ATRAC3;
else if (0==strcmp(val,"ATRAC3PLUS")) txth->codec = ATRAC3PLUS;
else if (0==strcmp(val,"XMA1")) txth->codec = XMA1;
else if (0==strcmp(val,"XMA2")) txth->codec = XMA2;
else if (0==strcmp(val,"FFMPEG")) txth->codec = FFMPEG;
else goto fail;
}
else if (0==strcmp(key,"codec_mode")) {
if (!parse_num(streamFile,val, &txth->codec_mode)) goto fail;
}
else if (0==strcmp(key,"interleave")) {
if (!parse_num(streamFile,val, &txth->interleave)) goto fail;
}
else if (0==strcmp(key,"id_value")) {
if (!parse_num(streamFile,val, &txth->id_value)) goto fail;
}
else if (0==strcmp(key,"id_offset")) {
if (!parse_num(streamFile,val, &txth->id_offset)) goto fail;
if (txth->id_value != txth->id_offset) /* evaluate current ID */
goto fail;
}
else if (0==strcmp(key,"channels")) {
if (!parse_num(streamFile,val, &txth->channels)) goto fail;
}
else if (0==strcmp(key,"sample_rate")) {
if (!parse_num(streamFile,val, &txth->sample_rate)) goto fail;
}
else if (0==strcmp(key,"start_offset")) {
if (!parse_num(streamFile,val, &txth->start_offset)) goto fail;
if (!txth->data_size_set)
txth->data_size = get_streamfile_size(streamFile) - txth->start_offset; /* re-evaluate */
}
else if (0==strcmp(key,"data_size")) {
if (!parse_num(streamFile,val, &txth->data_size)) goto fail;
txth->data_size_set = 1;
}
else if (0==strcmp(key,"sample_type")) {
if (0==strcmp(val,"bytes")) txth->sample_type_bytes = 1;
else if (0==strcmp(val,"samples")) txth->sample_type_bytes = 0;
else goto fail;
}
else if (0==strcmp(key,"num_samples")) {
if (0==strcmp(val,"data_size")) {
txth->num_samples = get_bytes_to_samples(txth, txth->data_size);
}
else {
if (!parse_num(streamFile,val, &txth->num_samples)) goto fail;
if (txth->sample_type_bytes)
txth->num_samples = get_bytes_to_samples(txth, txth->num_samples);
}
}
else if (0==strcmp(key,"loop_start_sample")) {
if (!parse_num(streamFile,val, &txth->loop_start_sample)) goto fail;
if (txth->sample_type_bytes)
txth->loop_start_sample = get_bytes_to_samples(txth, txth->loop_start_sample);
if (txth->loop_adjust)
txth->loop_start_sample += txth->loop_adjust;
}
else if (0==strcmp(key,"loop_end_sample")) {
if (0==strcmp(val,"data_size")) {
txth->loop_end_sample = get_bytes_to_samples(txth, txth->data_size);
}
else {
if (!parse_num(streamFile,val, &txth->loop_end_sample)) goto fail;
if (txth->sample_type_bytes)
txth->loop_end_sample = get_bytes_to_samples(txth, txth->loop_end_sample);
}
if (txth->loop_adjust)
txth->loop_end_sample += txth->loop_adjust;
}
else if (0==strcmp(key,"skip_samples")) {
if (!parse_num(streamFile,val, &txth->skip_samples)) goto fail;
txth->skip_samples_set = 1;
if (txth->sample_type_bytes)
txth->skip_samples = get_bytes_to_samples(txth, txth->skip_samples);
}
else if (0==strcmp(key,"loop_adjust")) {
if (!parse_num(streamFile,val, &txth->loop_adjust)) goto fail;
if (txth->sample_type_bytes)
txth->loop_adjust = get_bytes_to_samples(txth, txth->loop_adjust);
}
else if (0==strcmp(key,"loop_flag")) {
if (!parse_num(streamFile,val, &txth->loop_flag)) goto fail;
txth->loop_flag_set = 1;
}
else if (0==strcmp(key,"coef_offset")) {
if (!parse_num(streamFile,val, &txth->coef_offset)) goto fail;
}
else if (0==strcmp(key,"coef_spacing")) {
if (!parse_num(streamFile,val, &txth->coef_spacing)) goto fail;
}
else if (0==strcmp(key,"coef_endianness")) {
if (val[0]=='B' && val[1]=='E')
txth->coef_big_endian = 1;
else if (val[0]=='L' && val[1]=='E')
txth->coef_big_endian = 0;
else if (!parse_num(streamFile,val, &txth->coef_big_endian)) goto fail;
}
else if (0==strcmp(key,"coef_mode")) {
if (!parse_num(streamFile,val, &txth->coef_mode)) goto fail;
}
else {
VGM_LOG("TXTH: unknown key=%s, val=%s\n", key,val);
goto fail;
}
return 1;
fail:
return 0;
}
static int parse_num(STREAMFILE * streamFile, const char * val, uint32_t * out_value) {
if (val[0] == '@') { /* offset */
uint32_t off = 0;
char ed1 = 'L', ed2 = 'E';
int size = 4;
int big_endian = 0;
int hex = (val[1]=='0' && val[2]=='x');
/* read exactly N fields in the expected format */
if (strchr(val,':') && strchr(val,'$')) {
if (sscanf(val, hex ? "@%x:%c%c$%i" : "@%u:%c%c$%i", &off, &ed1,&ed2, &size) != 4) goto fail;
} else if (strchr(val,':')) {
if (sscanf(val, hex ? "@%x:%c%c" : "@%u:%c%c", &off, &ed1,&ed2) != 3) goto fail;
} else if (strchr(val,'$')) {
if (sscanf(val, hex ? "@%x$%i" : "@%u$%i", &off, &size) != 2) goto fail;
} else {
if (sscanf(val, hex ? "@%x" : "@%u", &off) != 1) goto fail;
}
if (off < 0 || off > get_streamfile_size(streamFile))
goto fail;
if (ed1 == 'B' && ed2 == 'E')
big_endian = 1;
else if (!(ed1 == 'L' && ed2 == 'E'))
goto fail;
switch(size) {
case 1: *out_value = read_8bit(off,streamFile); break;
case 2: *out_value = big_endian ? (uint16_t)read_16bitBE(off,streamFile) : (uint16_t)read_16bitLE(off,streamFile); break;
case 3: *out_value = (big_endian ? (uint32_t)read_32bitBE(off,streamFile) : (uint32_t)read_32bitLE(off,streamFile)) & 0x00FFFFFF; break;
case 4: *out_value = big_endian ? (uint32_t)read_32bitBE(off,streamFile) : (uint32_t)read_32bitLE(off,streamFile); break;
default: goto fail;
}
}
else { /* constant */
int hex = (val[0]=='0' && val[1]=='x');
if (sscanf(val, hex ? "%x" : "%u", out_value)!=1) goto fail;
}
//VGM_LOG("TXTH: value=%s, read %u\n", val, *out_value);
return 1;
fail:
return 0;
}
static int get_bytes_to_samples(txth_header * txth, uint32_t bytes) {
switch(txth->codec) {
case MS_IMA:
return ms_ima_bytes_to_samples(bytes, txth->interleave, txth->channels);
case XBOX:
return ms_ima_bytes_to_samples(bytes, 0x24 * txth->channels, txth->channels);
case NGC_DSP:
return dsp_bytes_to_samples(bytes, txth->channels);
case PSX:
case PSX_bf:
return ps_bytes_to_samples(bytes, txth->channels);
case PCM16BE:
case PCM16LE:
return pcm_bytes_to_samples(bytes, txth->channels, 16);
case PCM8:
case PCM8_U_int:
case PCM8_U:
return pcm_bytes_to_samples(bytes, txth->channels, 8);
case MSADPCM:
return msadpcm_bytes_to_samples(bytes, txth->interleave, txth->channels);
case ATRAC3:
return atrac3_bytes_to_samples(bytes, txth->interleave);
case ATRAC3PLUS:
return atrac3plus_bytes_to_samples(bytes, txth->interleave);
/* XMA bytes-to-samples is done at the end as the value meanings are a bit different */
case XMA1:
case XMA2:
return bytes; /* preserve */
/* untested */
case IMA:
case DVI_IMA:
case SDX2:
return bytes;
case AICA:
return bytes * 2 / txth->channels;
case NGC_DTK:
return bytes / 32 * 28; /* always stereo? */
case APPLE_IMA4:
return (bytes / txth->interleave) * (txth->interleave - 2) * 2;
case MPEG: /* a bit complex */
case FFMPEG: /* too complex */
default:
return 0;
}
}

View File

@ -8,6 +8,7 @@ VGMSTREAM * init_vgmstream_xma(STREAMFILE *streamFile) {
size_t data_size, chunk_size;
int loop_flag, channel_count, sample_rate, is_xma2_old = 0, is_xma1 = 0;
int num_samples, loop_start_sample, loop_end_sample, loop_start_b = 0, loop_end_b = 0, loop_subframe = 0;
int fmt_be = 0;
/* check extension, case insensitive */
@ -34,13 +35,24 @@ VGMSTREAM * init_vgmstream_xma(STREAMFILE *streamFile) {
}
else if ( find_chunk_le(streamFile, 0x666d7420,first_offset,0, &chunk_offset,&chunk_size)) {
int format = read_16bitLE(chunk_offset,streamFile);
/* some Fable Heroes and Fable 3 XMA have a BE fmt chunk, but the rest of the file is still LE
* (incidentally they come with a "frsk" chunk) */
if (format == 0x6601) { /* new XMA2 but BE */
fmt_be = 1;
format = 0x0166;
}
if (format == 0x165) { /* XMA1 */
is_xma1 = 1;
xma1_parse_fmt_chunk(streamFile, chunk_offset, &channel_count,&sample_rate, &loop_flag, &loop_start_b, &loop_end_b, &loop_subframe, 0);
xma1_parse_fmt_chunk(streamFile, chunk_offset, &channel_count,&sample_rate, &loop_flag, &loop_start_b, &loop_end_b, &loop_subframe, fmt_be);
} else if (format == 0x166) { /* new XMA2 */
channel_count = read_16bitLE(chunk_offset+0x02,streamFile);
sample_rate = read_32bitLE(chunk_offset+0x04,streamFile);
xma2_parse_fmt_chunk_extra(streamFile, chunk_offset, &loop_flag, &num_samples, &loop_start_sample, &loop_end_sample, 0);
int32_t (*read_32bit)(off_t,STREAMFILE*) = fmt_be ? read_32bitBE : read_32bitLE;
int16_t (*read_16bit)(off_t,STREAMFILE*) = fmt_be ? read_16bitBE : read_16bitLE;
channel_count = read_16bit(chunk_offset+0x02,streamFile);
sample_rate = read_32bit(chunk_offset+0x04,streamFile);
xma2_parse_fmt_chunk_extra(streamFile, chunk_offset, &loop_flag, &num_samples, &loop_start_sample, &loop_end_sample, fmt_be);
} else {
goto fail;
}
@ -99,7 +111,7 @@ VGMSTREAM * init_vgmstream_xma(STREAMFILE *streamFile) {
if (is_xma2_old) {
bytes = ffmpeg_make_riff_xma2_from_xma2_chunk(buf,0x100, chunk_offset,chunk_size, data_size, streamFile);
} else {
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, chunk_offset,chunk_size, data_size, streamFile, 0);
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, chunk_offset,chunk_size, data_size, streamFile, fmt_be);
}
if (bytes <= 0) goto fail;

View File

@ -553,3 +553,29 @@ int find_chunk(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, in
return 0;
}
int get_streamfile_name(STREAMFILE *streamFile, char * buffer, size_t size) {
streamFile->get_name(streamFile,buffer,size);
return 1;
}
int get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size) {
const char *path;
streamFile->get_name(streamFile,buffer,size);
path = strrchr(buffer,DIR_SEPARATOR);
if (path!=NULL) path = path+1; /* includes "/" */
if (path) {
buffer[path - buffer] = '\0';
} else {
buffer[0] = '\0';
}
return 1;
}
int get_streamfile_ext(STREAMFILE *streamFile, char * filename, size_t size) {
streamFile->get_name(streamFile,filename,size);
strcpy(filename, filename_extension(filename));
return 1;
}

View File

@ -159,4 +159,8 @@ int check_extensions(STREAMFILE *streamFile, const char * cmp_exts);
int find_chunk_be(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size);
int find_chunk_le(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size);
int find_chunk(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int size_big_endian, int zero_size_end);
int get_streamfile_name(STREAMFILE *streamFile, char * buffer, size_t size);
int get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size);
int get_streamfile_ext(STREAMFILE *streamFile, char * filename, size_t size);
#endif

View File

@ -347,6 +347,10 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_dsp_adx,
init_vgmstream_akb_multi,
init_vgmstream_akb2_multi,
#ifdef VGM_USE_FFMPEG
init_vgmstream_mp4_aac_ffmpeg,
init_vgmstream_bik,
#endif
init_vgmstream_x360_ast,
init_vgmstream_wwise,
init_vgmstream_ubi_raki,
@ -364,11 +368,11 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_ngc_ulw,
init_vgmstream_pc_xa30,
init_vgmstream_wii_04sw,
init_vgmstream_ea_bnk,
init_vgmstream_ea_schl_fixed,
init_vgmstream_txth, /* should go at the end (lower priority) */
#ifdef VGM_USE_FFMPEG
init_vgmstream_mp4_aac_ffmpeg,
init_vgmstream_bik,
init_vgmstream_ffmpeg, /* should go at the end */
#endif
};
@ -940,6 +944,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
case layout_ps2_iab_blocked:
case layout_ps2_strlr_blocked:
case layout_rws_blocked:
case layout_hwas_blocked:
render_vgmstream_blocked(buffer,sample_count,vgmstream);
break;
case layout_interleave_byte:
@ -1045,9 +1050,10 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_FSB_IMA:
return 64;
case coding_EA_XA:
case coding_EA_XA_int:
case coding_EA_XA_V2:
return 28;
case coding_MAXIS_ADPCM:
case coding_EA_MT10:
case coding_MAXIS_XA:
return 14*vgmstream->channels;
case coding_WS:
/* only works if output sample size is 8 bit, which always is for WS ADPCM */
@ -1189,12 +1195,14 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_XBOX_int:
case coding_FSB_IMA:
return 36;
case coding_MAXIS_ADPCM:
return 15*vgmstream->channels;
case coding_EA_MT10:
return 30;
case coding_EA_XA:
return 1; // the frame is variant in size
return 0x1E;
case coding_EA_XA_int:
return 0x0F;
case coding_MAXIS_XA:
return 0x0F*vgmstream->channels;
case coding_EA_XA_V2:
return 1; /* the frame is variant in size (ADPCM frames of 0x0F or PCM frames) */
case coding_WS:
return vgmstream->current_block_size;
case coding_IMA_int:
@ -1394,7 +1402,7 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
break;
case coding_XBOX_int:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_int_xbox_ima(vgmstream,&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
decode_xbox_ima_int(vgmstream,&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do,chan);
}
@ -1490,16 +1498,23 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
samples_to_do,chan);
}
break;
case coding_EA_MT10:
case coding_EA_XA_int:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_ea_mt10(vgmstream,buffer+samples_written*vgmstream->channels+chan,
decode_ea_xa_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do,chan);
}
break;
case coding_MAXIS_ADPCM:
case coding_EA_XA_V2:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_maxis_adpcm(vgmstream,buffer+samples_written*vgmstream->channels+chan,
decode_ea_xa_v2(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do,chan);
}
break;
case coding_MAXIS_XA:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_maxis_xa(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do,chan);
}
@ -1849,6 +1864,7 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) {
if (vgmstream->meta_type == meta_DSP_STD ||
vgmstream->meta_type == meta_DSP_RS03 ||
vgmstream->meta_type == meta_DSP_CSTR ||
vgmstream->meta_type == meta_NDS_STRM_FFTA2 || /* clicks in some files otherwise */
vgmstream->coding_type == coding_PSX ||
vgmstream->coding_type == coding_PSX_bmdx ||
vgmstream->coding_type == coding_PSX_badflags) {

View File

@ -113,9 +113,10 @@ typedef enum {
coding_PSX_cfg, /* Sony PS ADPCM with configurable frame size (FF XI, SGXD type 5, Bizarre Creations) */
coding_HEVAG, /* Sony PSVita 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_EA_XA, /* Electronic Arts EA-XA ADPCM v1 (stereo) aka "EA ADPCM" */
coding_EA_XA_int, /* Electronic Arts EA-XA ADPCM v1 (mono/interleave) */
coding_EA_XA_V2, /* Electronic Arts EA-XA ADPCM v2 */
coding_MAXIS_XA, /* Maxis EA-XA ADPCM */
coding_XBOX, /* XBOX IMA ADPCM */
coding_XBOX_int, /* XBOX IMA ADPCM (interleaved) */
@ -143,7 +144,7 @@ typedef enum {
coding_L5_555, /* Level-5 0x555 ADPCM */
coding_SASSC, /* Activision EXAKT SASSC DPCM */
coding_LSF, /* lsf ADPCM (Fastlane Street Racing iPhone)*/
coding_MTAF, /* Konami MTAF ADPCM (IMA-derived) */
coding_MTAF, /* Konami MTAF ADPCM */
coding_MTA2, /* Konami MTA2 ADPCM */
coding_MC3, /* Paradigm MC3 3-bit ADPCM */
@ -245,6 +246,7 @@ typedef enum {
layout_ps2_iab_blocked,
layout_ps2_strlr_blocked,
layout_rws_blocked,
layout_hwas_blocked,
/* otherwise odd */
layout_acm, /* libacm layout */
@ -464,7 +466,9 @@ typedef enum {
meta_XBOX_XMU, /* XBOX XMU */
meta_XBOX_XVAS, /* XBOX VAS */
meta_EA_SCHL, /* Electronic Arts SCHl */
meta_EA_SCHL, /* Electronic Arts SCHl with variable header */
meta_EA_SCHL_fixed, /* Electronic Arts SCHl with fixed header */
meta_EA_BNK, /* Electronic Arts BNK */
meta_EACS_PC, /* Electronic Arts EACS PC */
meta_EACS_PSX, /* Electronic Arts EACS PSX */
meta_EACS_SAT, /* Electronic Arts EACS SATURN */
@ -626,6 +630,7 @@ typedef enum {
meta_NGC_ULW, /* Burnout 1 (GC only) */
meta_PC_XA30, /* Driver - Parallel Lines (PC) */
meta_WII_04SW, /* Driver - Parallel Lines (Wii) */
meta_TXTH, /* generic text header */
#ifdef VGM_USE_VORBIS
meta_OGG_VORBIS, /* Ogg Vorbis */