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