mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-18 07:44:43 +01:00
commit
b2e31d8222
@ -24,7 +24,7 @@ void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
/* At 0x00(1): block flag
|
||||
* - in SNS: 0x00=normal block, 0x80=last block (not mandatory)
|
||||
* - in SPS: 0x48=header, 0x44=normal block, 0x45=last block (empty) */
|
||||
block_id = (block_size & 0x00FFFFFF) >> 24;
|
||||
block_id = (block_size & 0xFF000000) >> 24;
|
||||
block_size &= 0x00FFFFFF;
|
||||
|
||||
if (block_id == 0x00 || block_id == 0x80 || block_id == 0x44) {
|
||||
|
@ -25,8 +25,7 @@
|
||||
|
||||
#define EAAC_TYPE_RAM 0x00
|
||||
#define EAAC_TYPE_STREAM 0x01
|
||||
|
||||
#define EAAC_LOOP_SET 0x01
|
||||
#define EAAC_TYPE_GIGASAMPLE 0x02
|
||||
|
||||
#define EAAC_BLOCKID0_DATA 0x00
|
||||
#define EAAC_BLOCKID0_END 0x80 /* maybe meant to be a bitflag? */
|
||||
@ -35,64 +34,32 @@
|
||||
#define EAAC_BLOCKID1_DATA 0x44 /* 'D' */
|
||||
#define EAAC_BLOCKID1_END 0x45 /* 'E' */
|
||||
|
||||
static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, STREAMFILE * streamData, off_t header_offset, off_t start_offset, meta_t meta_type);
|
||||
static size_t get_snr_size(STREAMFILE *streamFile, off_t offset);
|
||||
static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, STREAMFILE * streamData, off_t header_offset, off_t start_offset, meta_t meta_type, int standalone);
|
||||
static VGMSTREAM *parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint16_t target_index, off_t ast_offset);
|
||||
VGMSTREAM * init_vgmstream_gin_header(STREAMFILE *streamFile, off_t offset);
|
||||
|
||||
|
||||
/* .SNR+SNS - from EA latest games (~2008-2013), v0 header */
|
||||
VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE * streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamData = NULL;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if (!check_extensions(streamFile,"snr"))
|
||||
goto fail;
|
||||
|
||||
/* SNR headers normally need an external SNS file, but some have data [Burnout Paradise, NFL2013 (iOS)] */
|
||||
if (get_streamfile_size(streamFile) > 0x10) {
|
||||
off_t start_offset = get_snr_size(streamFile, 0x00);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, 0x00, start_offset, meta_EA_SNR_SNS);
|
||||
if (!vgmstream) goto fail;
|
||||
}
|
||||
else {
|
||||
streamData = open_streamfile_by_ext(streamFile,"sns");
|
||||
if (!streamData) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamData, 0x00, 0x00, meta_EA_SNR_SNS);
|
||||
if (!vgmstream) goto fail;
|
||||
}
|
||||
|
||||
close_streamfile(streamData);
|
||||
return vgmstream;
|
||||
return init_vgmstream_eaaudiocore_header(streamFile, NULL, 0x00, 0x00, meta_EA_SNR_SNS, 1);
|
||||
|
||||
fail:
|
||||
close_streamfile(streamData);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* .SPS - from EA latest games (~2014), v1 header */
|
||||
VGMSTREAM * init_vgmstream_ea_sps(STREAMFILE * streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if (!check_extensions(streamFile,"sps"))
|
||||
goto fail;
|
||||
|
||||
/* SPS block start: 0x00(1): block flag (header=0x48); 0x01(3): block size (usually 0x0c-0x14) */
|
||||
if (read_8bit(0x00, streamFile) != EAAC_BLOCKID1_HEADER)
|
||||
goto fail;
|
||||
start_offset = read_32bitBE(0x00, streamFile) & 0x00FFFFFF;
|
||||
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, 0x04, start_offset, meta_EA_SPS);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
return vgmstream;
|
||||
return init_vgmstream_eaaudiocore_header(streamFile, NULL, 0x00, 0x00, meta_EA_SPS, 1);
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -125,7 +92,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) {
|
||||
header_offset = 0x10; /* SNR header */
|
||||
start_offset = read_32bit(0x08,streamFile); /* SNS blocks */
|
||||
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, header_offset, start_offset, meta_EA_SNU);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, header_offset, start_offset, meta_EA_SNU, 0);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
return vgmstream;
|
||||
@ -259,9 +226,9 @@ fail:
|
||||
}
|
||||
|
||||
/* EA S10A header - seen inside new ABK files. Putting it here in case it's encountered stand-alone. */
|
||||
static VGMSTREAM * parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint16_t target_index, off_t ast_offset) {
|
||||
static VGMSTREAM * parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint16_t target_index, off_t sns_offset) {
|
||||
uint32_t num_sounds;
|
||||
off_t snr_offset, sns_offset;
|
||||
off_t snr_offset;
|
||||
STREAMFILE *astFile = NULL;
|
||||
VGMSTREAM *vgmstream;
|
||||
|
||||
@ -279,11 +246,10 @@ static VGMSTREAM * parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint1
|
||||
|
||||
snr_offset = offset + read_32bitBE(offset + 0x0C + 0x04 * target_index, streamFile);
|
||||
|
||||
if (ast_offset == 0xFFFFFFFF) {
|
||||
if (sns_offset == 0xFFFFFFFF) {
|
||||
/* RAM asset */
|
||||
sns_offset = snr_offset + get_snr_size(streamFile, snr_offset);
|
||||
//;VGM_LOG("EA S10A: RAM at sns=%lx, sns=%lx\n", snr_offset, sns_offset);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
|
||||
//;VGM_LOG("EA S10A: RAM at snr=%lx", snr_offset);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, NULL, snr_offset, 0x00, meta_EA_SNR_SNS, 0);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
} else {
|
||||
@ -295,9 +261,8 @@ static VGMSTREAM * parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint1
|
||||
if (read_32bitBE(0x00, astFile) != 0x53313053) /* "S10S" */
|
||||
goto fail;
|
||||
|
||||
sns_offset = ast_offset;
|
||||
//;VGM_LOG("EA S10A: stream at sns=%lx, sns=%lx\n", snr_offset, sns_offset);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, astFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
|
||||
//;VGM_LOG("EA S10A: stream at snr=%lx, sns=%lx\n", snr_offset, sns_offset);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, astFile, snr_offset, sns_offset, meta_EA_SNR_SNS, 0);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
@ -373,16 +338,12 @@ VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE *streamFile) {
|
||||
if (read_32bitBE(0x00, sbsFile) != 0x53424B53) /* "SBKS" */
|
||||
goto fail;
|
||||
|
||||
snr_offset = sns_offset;
|
||||
sns_offset = snr_offset + (read_32bitBE(snr_offset, sbsFile) & 0x00FFFFFF);
|
||||
snr_offset += 0x04;
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(sbsFile, sbsFile, snr_offset, sns_offset, meta_EA_SPS);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(sbsFile, NULL, sns_offset, 0x00, meta_EA_SPS, 0);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
} else if (sns_offset == 0) {
|
||||
/* RAM asset */
|
||||
sns_offset = snr_offset + get_snr_size(streamFile, snr_offset);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, NULL, snr_offset, 0x00, meta_EA_SNR_SNS, 0);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
} else {
|
||||
@ -394,7 +355,7 @@ VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE *streamFile) {
|
||||
if (read_32bitBE(0x00, sbsFile) != 0x53424B53) /* "SBKS" */
|
||||
goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, sbsFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, sbsFile, snr_offset, sns_offset, meta_EA_SNR_SNS, 0);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
}
|
||||
@ -428,6 +389,9 @@ VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) {
|
||||
/* 0x0C: zero */
|
||||
/* 0x10: table start */
|
||||
|
||||
if (!check_extensions(streamFile, "hdr"))
|
||||
goto fail;
|
||||
|
||||
if (read_8bit(0x09, streamFile) != 0)
|
||||
goto fail;
|
||||
|
||||
@ -520,7 +484,7 @@ VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) {
|
||||
if (block_id != EAAC_BLOCKID0_DATA && block_id != EAAC_BLOCKID0_END)
|
||||
goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(sthFile, datFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(sthFile, datFile, snr_offset, sns_offset, meta_EA_SNR_SNS, 0);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
@ -632,7 +596,7 @@ static STREAMFILE *open_mapfile_pair(STREAMFILE *streamFile, int track, int num_
|
||||
/* EA MPF/MUS combo - used in older 7th gen games for storing interactive music */
|
||||
VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) {
|
||||
uint32_t num_tracks, track_start, track_hash, mus_sounds, mus_stream = 0;
|
||||
uint8_t version, sub_version, block_id;
|
||||
uint8_t version, sub_version;
|
||||
off_t tracks_table, samples_table, eof_offset, table_offset, entry_offset, snr_offset, sns_offset;
|
||||
int32_t(*read_32bit)(off_t, STREAMFILE*);
|
||||
STREAMFILE *musFile = NULL;
|
||||
@ -716,12 +680,7 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) {
|
||||
table_offset = 0x08;
|
||||
entry_offset = table_offset + mus_stream * 0x0c;
|
||||
snr_offset = read_32bit(entry_offset + 0x04, musFile);
|
||||
|
||||
if (is_ram) {
|
||||
sns_offset = snr_offset + get_snr_size(musFile, snr_offset);
|
||||
} else {
|
||||
sns_offset = read_32bit(entry_offset + 0x08, musFile);
|
||||
}
|
||||
} else if (sub_version == 3) {
|
||||
/* number of files is always little endian */
|
||||
mus_sounds = read_32bitLE(0x04, musFile);
|
||||
@ -752,11 +711,7 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
block_id = read_8bit(sns_offset, musFile);
|
||||
if (block_id != EAAC_BLOCKID0_DATA && block_id != EAAC_BLOCKID0_END)
|
||||
goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(musFile, musFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(musFile, musFile, snr_offset, sns_offset, meta_EA_SNR_SNS, 0);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
@ -773,7 +728,7 @@ fail:
|
||||
/* EA TMX - used for engine sounds in NFS games (2007-present) */
|
||||
VGMSTREAM * init_vgmstream_ea_tmx(STREAMFILE *streamFile) {
|
||||
uint32_t num_sounds, sound_type;
|
||||
off_t table_offset, data_offset, entry_offset, sound_offset, sns_offset;
|
||||
off_t table_offset, data_offset, entry_offset, sound_offset;
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
int target_stream = streamFile->stream_index;
|
||||
|
||||
@ -798,13 +753,11 @@ VGMSTREAM * init_vgmstream_ea_tmx(STREAMFILE *streamFile) {
|
||||
|
||||
switch (sound_type) {
|
||||
case 0x47494E20: /* "GIN " */
|
||||
/* FIXME: need to get GIN size somehow */
|
||||
vgmstream = init_vgmstream_gin_header(streamFile, sound_offset);
|
||||
if (!vgmstream) goto fail;
|
||||
break;
|
||||
case 0x534E5220: /* "SNR " */
|
||||
sns_offset = sound_offset + get_snr_size(streamFile, sound_offset);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, sound_offset, sns_offset, meta_EA_SNR_SNS);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, NULL, sound_offset, 0x00, meta_EA_SNR_SNS, 0);
|
||||
if (!vgmstream) goto fail;
|
||||
break;
|
||||
default:
|
||||
@ -823,7 +776,7 @@ VGMSTREAM * init_vgmstream_ea_sbr_harmony(STREAMFILE *streamFile) {
|
||||
uint32_t num_dsets, set_sounds, chunk_id;
|
||||
uint32_t i;
|
||||
uint8_t set_type, flag, offset_size;
|
||||
off_t data_offset, table_offset, dset_offset, base_offset, sound_table_offset, sound_offset, header_offset, start_offset;
|
||||
off_t data_offset, table_offset, dset_offset, base_offset, sound_table_offset, sound_offset;
|
||||
STREAMFILE *sbsFile = NULL, *streamData = NULL;
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
int target_stream = streamFile->stream_index, total_sounds, local_target, is_streamed = 0;
|
||||
@ -973,12 +926,7 @@ VGMSTREAM * init_vgmstream_ea_sbr_harmony(STREAMFILE *streamFile) {
|
||||
}
|
||||
}
|
||||
|
||||
if (read_8bit(sound_offset, streamData) != EAAC_BLOCKID1_HEADER)
|
||||
goto fail;
|
||||
|
||||
header_offset = sound_offset + 0x04;
|
||||
start_offset = sound_offset + (read_32bitBE(sound_offset, streamData) & 0x00FFFFFF);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamData, streamData, header_offset, start_offset, meta_EA_SNR_SNS);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamData, NULL, sound_offset, 0x00, meta_EA_SPS, 0);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
@ -999,7 +947,6 @@ typedef struct {
|
||||
int channel_config;
|
||||
int sample_rate;
|
||||
int type;
|
||||
int loop;
|
||||
|
||||
int streamed;
|
||||
int channels;
|
||||
@ -1008,25 +955,37 @@ typedef struct {
|
||||
int loop_start;
|
||||
int loop_end;
|
||||
int loop_flag;
|
||||
int prefetch_samples;
|
||||
|
||||
off_t stream_offset;
|
||||
off_t loop_offset;
|
||||
off_t prefetch_offset;
|
||||
} eaac_header;
|
||||
|
||||
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf_data, eaac_header *eaac);
|
||||
static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *streamFile, eaac_header *eaac);
|
||||
static size_t calculate_eaac_size(VGMSTREAM *vgmstream, STREAMFILE *streamFile, eaac_header *eaac, off_t start_offset);
|
||||
static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *streamFile, eaac_header *eaac, off_t start_offset);
|
||||
static STREAMFILE *setup_eaac_streamfile(eaac_header *ea, STREAMFILE *streamHead, STREAMFILE *streamData);
|
||||
static size_t calculate_eaac_size(STREAMFILE *streamFile, uint32_t version, uint32_t num_samples, off_t start_offset);
|
||||
|
||||
/* EA newest header from RwAudioCore (RenderWare?) / EAAudioCore library (still generated by sx.exe).
|
||||
* Audio "assets" come in separate RAM headers (.SNR/SPH) and raw blocked streams (.SNS/SPS),
|
||||
* or together in pseudoformats (.SNU, .SBR+.SBS banks, .AEMS, .MUS, etc).
|
||||
* Some .SNR include stream data, while .SPS have headers so .SPH is optional. */
|
||||
static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, STREAMFILE * streamData, off_t header_offset, off_t start_offset, meta_t meta_type) {
|
||||
static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, STREAMFILE * streamData, off_t header_offset, off_t start_offset, meta_t meta_type, int standalone) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE* temp_streamFile = NULL;
|
||||
uint32_t header1, header2;
|
||||
STREAMFILE* temp_streamFile = NULL, *streamFile = NULL;
|
||||
uint32_t header1, header2, header_block_size, header_size;
|
||||
uint8_t header_block_id;
|
||||
eaac_header eaac = {0};
|
||||
|
||||
if (meta_type == meta_EA_SPS) {
|
||||
header_block_id = read_8bit(header_offset, streamHead);
|
||||
header_block_size = read_32bitBE(header_offset, streamHead) & 0x00FFFFFF;
|
||||
if (header_block_id != EAAC_BLOCKID1_HEADER)
|
||||
goto fail;
|
||||
|
||||
header_offset += 0x04;
|
||||
}
|
||||
|
||||
/* EA SNR/SPH header */
|
||||
header1 = (uint32_t)read_32bitBE(header_offset + 0x00, streamHead);
|
||||
@ -1036,10 +995,9 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
eaac.channel_config = (header1 >> 18) & 0x3F; /* 6 bits */
|
||||
eaac.sample_rate = (header1 >> 0) & 0x03FFFF; /* 18 bits */
|
||||
eaac.type = (header2 >> 30) & 0x03; /* 2 bits */
|
||||
eaac.loop = (header2 >> 29) & 0x01; /* 1 bits */
|
||||
eaac.loop_flag = (header2 >> 29) & 0x01; /* 1 bits */
|
||||
eaac.num_samples = (header2 >> 0) & 0x1FFFFFFF; /* 29 bits */
|
||||
/* rest is optional, depends on used flags and codec (handled below) */
|
||||
eaac.stream_offset = start_offset;
|
||||
|
||||
/* common channel configs are mono/stereo/quad/5.1/7.1 (from debug strings), while others are quite rare
|
||||
* [Battlefield 4 (X360)-EAXMA: 3/5/7ch, Army of Two: The Devil's Cartel (PS3)-EALayer3v2P: 11ch] */
|
||||
@ -1057,53 +1015,33 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* catch unknown values (0x02: "gigasample"? some kind of memory+stream thing?) */
|
||||
if (eaac.type != EAAC_TYPE_RAM && eaac.type != EAAC_TYPE_STREAM) {
|
||||
/* catch unknown values */
|
||||
if (eaac.type != EAAC_TYPE_RAM && eaac.type != EAAC_TYPE_STREAM && eaac.type != EAAC_TYPE_GIGASAMPLE) {
|
||||
VGM_LOG("EA EAAC: unknown type 0x%02x\n", eaac.type);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Non-streamed sounds are stored as a single block (may not set block end flags) */
|
||||
eaac.streamed = (eaac.type == EAAC_TYPE_STREAM);
|
||||
eaac.streamed = (eaac.type != EAAC_TYPE_RAM);
|
||||
|
||||
/* get loops (fairly involved due to the multiple layouts and mutant streamfiles)
|
||||
* full loops aren't too uncommon [Dead Space (PC) stream sfx/ambiance, FIFA 98 (PS3) RAM sfx],
|
||||
* while actual looping is very rare [Need for Speed: World (PC)-EAL3, The Simpsons Game (X360)-EAXMA] */
|
||||
if (eaac.loop == EAAC_LOOP_SET) {
|
||||
eaac.loop_flag = 1;
|
||||
eaac.loop_start = read_32bitBE(header_offset+0x08, streamHead);
|
||||
|
||||
/* get optional header values */
|
||||
header_size = 0x08;
|
||||
if (eaac.loop_flag) {
|
||||
header_size += 0x04;
|
||||
eaac.loop_start = read_32bitBE(header_offset + 0x08, streamHead);
|
||||
eaac.loop_end = eaac.num_samples;
|
||||
|
||||
if (eaac.streamed) {
|
||||
eaac.loop_offset = read_32bitBE(header_offset+0x0c, streamHead);
|
||||
|
||||
if (eaac.version == EAAC_VERSION_V0) {
|
||||
/* SNR+SNS are separate so offsets are relative to the data start
|
||||
* (first .SNS block, or extra data before the .SNS block in case of .SNU) */
|
||||
eaac.loop_offset = eaac.stream_offset + eaac.loop_offset;
|
||||
} else {
|
||||
/* SPS have headers+data together so offsets are relative to the file start [ex. FIFA 18 (PC)] */
|
||||
eaac.loop_offset = header_offset - 0x04 + eaac.loop_offset;
|
||||
}
|
||||
}
|
||||
else if (eaac.loop_start > 0) {
|
||||
/* RAM assets have two blocks in case of actual loops */
|
||||
/* find the second block by getting the first block size */
|
||||
eaac.loop_offset = read_32bitBE(eaac.stream_offset, streamData) & 0x00FFFFF;
|
||||
eaac.loop_offset = eaac.stream_offset + eaac.loop_offset;
|
||||
}
|
||||
else {
|
||||
/* RAM assets have only one block in case of full loops */
|
||||
eaac.loop_offset = eaac.stream_offset; /* implicit */
|
||||
}
|
||||
|
||||
//todo EATrax has extra values in header, which would coexist with loop values
|
||||
/* TODO: EATrax has extra values in header, which would coexist with loop values */
|
||||
if (eaac.codec == EAAC_CODEC_EATRAX) {
|
||||
VGM_LOG("EA EAAC: unknown loop header for EATrax\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
//todo need more cases to test how layout/streamfiles react
|
||||
/* TODO: need more cases to test how layout/streamfiles react */
|
||||
if (eaac.loop_start > 0 && !(
|
||||
eaac.codec == EAAC_CODEC_EALAYER3_V1 ||
|
||||
eaac.codec == EAAC_CODEC_EALAYER3_V2_PCM ||
|
||||
@ -1115,9 +1053,73 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
}
|
||||
}
|
||||
|
||||
/* if type is gigasample there seems to be a field with number of "gigasamples in ram",
|
||||
* that goes after loop_start but before streamed/gigasamples' eaac.loop_offset) */
|
||||
switch (eaac.type) {
|
||||
case EAAC_TYPE_RAM:
|
||||
break;
|
||||
case EAAC_TYPE_STREAM:
|
||||
if (eaac.loop_flag) {
|
||||
header_size += 0x04;
|
||||
eaac.loop_offset = read_32bitBE(header_offset + 0x0c, streamHead);
|
||||
}
|
||||
break;
|
||||
case EAAC_TYPE_GIGASAMPLE: /* rarely seen [Def Jam Icon (X360)] */
|
||||
if (eaac.loop_flag) {
|
||||
VGM_LOG("EAAC: Looped gigasample found.\n");
|
||||
goto fail;
|
||||
}
|
||||
header_size += 0x04;
|
||||
eaac.prefetch_samples = read_32bitBE(header_offset + 0x08, streamHead);
|
||||
break;
|
||||
}
|
||||
|
||||
/* get data offsets */
|
||||
if (eaac.version == EAAC_VERSION_V0) {
|
||||
switch (eaac.type) {
|
||||
case EAAC_TYPE_RAM:
|
||||
eaac.stream_offset = header_offset + header_size;
|
||||
break;
|
||||
case EAAC_TYPE_STREAM:
|
||||
eaac.stream_offset = start_offset;
|
||||
break;
|
||||
case EAAC_TYPE_GIGASAMPLE:
|
||||
eaac.prefetch_offset = header_offset + header_size;
|
||||
eaac.stream_offset = start_offset;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
eaac.stream_offset = header_offset - 0x04 + header_block_size;
|
||||
}
|
||||
|
||||
/* correct loop offsets */
|
||||
if (eaac.loop_flag) {
|
||||
if (eaac.streamed) {
|
||||
/* SNR+SNS are separate so offsets are relative to the data start
|
||||
* (first .SNS block, or extra data before the .SNS block in case of .SNU)
|
||||
* SPS have headers+data together so offsets are relative to the file start [ex. FIFA 18 (PC)] */
|
||||
if (eaac.version == EAAC_VERSION_V1) {
|
||||
eaac.loop_offset -= header_block_size;
|
||||
}
|
||||
} else if (eaac.loop_start > 0) {
|
||||
/* RAM assets have two blocks in case of actual loops */
|
||||
/* find the second block by getting the first block size */
|
||||
eaac.loop_offset = read_32bitBE(eaac.stream_offset, streamHead) & 0x00FFFFFF;
|
||||
} else {
|
||||
/* RAM assets have only one block in case of full loops */
|
||||
eaac.loop_offset = 0x00; /* implicit */
|
||||
}
|
||||
}
|
||||
|
||||
if (eaac.version == EAAC_VERSION_V0 && eaac.streamed) {
|
||||
/* open SNS file if needed */
|
||||
if (standalone) {
|
||||
streamData = open_streamfile_by_ext(streamHead, "sns");
|
||||
}
|
||||
if (!streamData) goto fail;
|
||||
}
|
||||
|
||||
/* build streamfile with audio data */
|
||||
streamFile = setup_eaac_streamfile(&eaac, streamHead, streamData);
|
||||
if (!streamFile) goto fail;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(eaac.channels,eaac.loop_flag);
|
||||
@ -1128,6 +1130,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
vgmstream->loop_start_sample = eaac.loop_start;
|
||||
vgmstream->loop_end_sample = eaac.loop_end;
|
||||
vgmstream->meta_type = meta_type;
|
||||
vgmstream->stream_size = get_streamfile_size(streamFile);
|
||||
|
||||
/* EA decoder list and known internal FourCCs */
|
||||
switch(eaac.codec) {
|
||||
@ -1143,14 +1146,14 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
|
||||
/* special (if hacky) loop handling, see comments */
|
||||
if (eaac.loop_start > 0) {
|
||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamData, &eaac);
|
||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamFile, &eaac);
|
||||
if (!data) goto fail;
|
||||
vgmstream->layout_data = data;
|
||||
vgmstream->coding_type = data->segments[0]->coding_type;
|
||||
vgmstream->layout_type = layout_segmented;
|
||||
}
|
||||
else {
|
||||
vgmstream->layout_data = build_layered_eaaudiocore(streamData, &eaac);
|
||||
vgmstream->layout_data = build_layered_eaaudiocore(streamFile, &eaac, 0x00);
|
||||
if (!vgmstream->layout_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_layered;
|
||||
@ -1164,7 +1167,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
|
||||
/* special (if hacky) loop handling, see comments */
|
||||
if (eaac.loop_start > 0) {
|
||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamData, &eaac);
|
||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamFile, &eaac);
|
||||
if (!data) goto fail;
|
||||
vgmstream->layout_data = data;
|
||||
vgmstream->coding_type = data->segments[0]->coding_type;
|
||||
@ -1187,21 +1190,19 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
* and to properly apply discard modes (see ealayer3 decoder)
|
||||
* (otherwise, and after removing discard code, it'd work with layout_blocked_ea_sns) */
|
||||
|
||||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||
|
||||
/* special (if hacky) loop handling, see comments */
|
||||
if (eaac.loop_start > 0) {
|
||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamData, &eaac);
|
||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(streamFile, &eaac);
|
||||
if (!data) goto fail;
|
||||
vgmstream->layout_data = data;
|
||||
vgmstream->coding_type = data->segments[0]->coding_type;
|
||||
vgmstream->layout_type = layout_segmented;
|
||||
}
|
||||
else {
|
||||
temp_streamFile = setup_eaac_streamfile(streamData, eaac.version, eaac.codec, eaac.streamed,0,0, eaac.stream_offset);
|
||||
temp_streamFile = setup_eaac_audio_streamfile(streamFile, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
vgmstream->codec_data = init_mpeg_custom(temp_streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, type, &cfg);
|
||||
vgmstream->codec_data = init_mpeg_custom(temp_streamFile, 0x00, &vgmstream->coding_type, vgmstream->channels, type, &cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->layout_type = layout_none;
|
||||
}
|
||||
@ -1222,8 +1223,6 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
|
||||
/* EATrax is "buffered" ATRAC9, uses custom IO since it's kind of complex to add to the decoder */
|
||||
|
||||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||
|
||||
cfg.channels = eaac.channels;
|
||||
cfg.config_data = read_32bitBE(header_offset + 0x08,streamHead);
|
||||
/* 0x10: frame size? (same as config data?) */
|
||||
@ -1235,7 +1234,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
vgmstream->coding_type = coding_ATRAC9;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
temp_streamFile = setup_eaac_streamfile(streamData, eaac.version, eaac.codec, eaac.streamed,0,0, eaac.stream_offset);
|
||||
temp_streamFile = setup_eaac_audio_streamfile(streamFile, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
break;
|
||||
@ -1247,12 +1246,10 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
case EAAC_CODEC_EAMP3: { /* "EM30"?: EAMP3 [Need for Speed 2015 (PS4)] */
|
||||
mpeg_custom_config cfg = {0};
|
||||
|
||||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||
|
||||
temp_streamFile = setup_eaac_streamfile(streamData, eaac.version, eaac.codec, eaac.streamed,0,0, eaac.stream_offset);
|
||||
temp_streamFile = setup_eaac_audio_streamfile(streamFile, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
vgmstream->codec_data = init_mpeg_custom(temp_streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_EAMP3, &cfg);
|
||||
vgmstream->codec_data = init_mpeg_custom(temp_streamFile, 0x00, &vgmstream->coding_type, vgmstream->channels, MPEG_EAMP3, &cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
@ -1263,7 +1260,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case EAAC_CODEC_EAOPUS: { /* EAOpus (unknown FourCC) [FIFA 17 (PC), FIFA 19 (Switch)]*/
|
||||
vgmstream->layout_data = build_layered_eaaudiocore(streamData, &eaac);
|
||||
vgmstream->layout_data = build_layered_eaaudiocore(streamFile, &eaac, 0x00);
|
||||
if (!vgmstream->layout_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_layered;
|
||||
@ -1277,74 +1274,154 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, temp_streamFile ? temp_streamFile : streamData, start_offset))
|
||||
if (!vgmstream_open_stream(vgmstream, temp_streamFile ? temp_streamFile : streamFile, 0x00))
|
||||
goto fail;
|
||||
|
||||
if (eaac.loop_start == 0) {
|
||||
vgmstream->stream_size = calculate_eaac_size(vgmstream, temp_streamFile ? temp_streamFile : streamData, &eaac, start_offset);
|
||||
}
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(streamFile);
|
||||
close_streamfile(temp_streamFile);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t get_snr_size(STREAMFILE *streamFile, off_t offset) {
|
||||
//const int EAAC_FLAG_LOOPED = 0x02;
|
||||
//const int EAAC_FLAG_STREAMED = 0x04;
|
||||
switch (read_8bit(offset + 0x04, streamFile) >> 4 & 0x0F) { /* flags */ //todo improve
|
||||
case 0x02 | 0x04: return 0x10;
|
||||
case 0x02: return 0x0C;
|
||||
default: return 0x08;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t calculate_eaac_size(VGMSTREAM *vgmstream, STREAMFILE *streamFile, eaac_header *eaac, off_t start_offset) {
|
||||
uint32_t total_samples;
|
||||
static size_t calculate_eaac_size(STREAMFILE *streamFile, uint32_t version, uint32_t num_samples, off_t start_offset) {
|
||||
uint32_t samples_parsed, block_size, block_samples;
|
||||
uint8_t block_id;
|
||||
size_t stream_size, file_size;
|
||||
off_t block_offset;
|
||||
|
||||
if (streamFile == NULL)
|
||||
return 0;
|
||||
|
||||
switch (eaac->codec) {
|
||||
case EAAC_CODEC_EAXMA:
|
||||
case EAAC_CODEC_EALAYER3_V1:
|
||||
case EAAC_CODEC_EALAYER3_V2_PCM:
|
||||
case EAAC_CODEC_EALAYER3_V2_SPIKE:
|
||||
case EAAC_CODEC_EATRAX:
|
||||
case EAAC_CODEC_EAMP3:
|
||||
case EAAC_CODEC_EAOPUS:
|
||||
stream_size = get_streamfile_size(streamFile);
|
||||
break;
|
||||
default:
|
||||
stream_size = 0;
|
||||
total_samples = 0;
|
||||
file_size = get_streamfile_size(streamFile);
|
||||
vgmstream->next_block_offset = start_offset;
|
||||
block_offset = start_offset;
|
||||
stream_size = 0, samples_parsed = 0;
|
||||
|
||||
while (vgmstream->next_block_offset < file_size && total_samples != vgmstream->num_samples) {
|
||||
block_update_ea_sns(vgmstream->next_block_offset, vgmstream);
|
||||
if (vgmstream->current_block_samples == 0)
|
||||
continue;
|
||||
while (block_offset < file_size && samples_parsed < num_samples) {
|
||||
block_id = read_8bit(block_offset, streamFile);
|
||||
block_size = read_32bitBE(block_offset, streamFile) & 0x00FFFFFF;
|
||||
|
||||
/* stream size is almost never provided in bank files so we have to calc it manually */
|
||||
stream_size += vgmstream->next_block_offset - vgmstream->ch[0].offset;
|
||||
total_samples += vgmstream->current_block_samples;
|
||||
if (version == EAAC_VERSION_V0) {
|
||||
if (block_id != EAAC_BLOCKID0_DATA && block_id != EAAC_BLOCKID0_END)
|
||||
goto fail;
|
||||
} else {
|
||||
if (block_id != EAAC_BLOCKID1_DATA)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* reset once we're done */
|
||||
block_update(start_offset, vgmstream);
|
||||
break;
|
||||
block_samples = read_32bitBE(block_offset + 0x04, streamFile);
|
||||
|
||||
stream_size += block_size;
|
||||
samples_parsed += block_samples;
|
||||
block_offset += block_size;
|
||||
}
|
||||
|
||||
if (samples_parsed != num_samples)
|
||||
goto fail;
|
||||
|
||||
return stream_size;
|
||||
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static STREAMFILE *setup_eaac_streamfile(eaac_header *ea, STREAMFILE *streamHead, STREAMFILE *streamData) {
|
||||
size_t data_size;
|
||||
STREAMFILE *new_streamFile = NULL;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
STREAMFILE *stream_segments[2] = { 0 };
|
||||
|
||||
if (ea->version == EAAC_VERSION_V0) {
|
||||
switch (ea->type) {
|
||||
case EAAC_TYPE_RAM:
|
||||
/* both header and data in SNR */
|
||||
data_size = calculate_eaac_size(streamHead, ea->version, ea->num_samples, ea->stream_offset);
|
||||
if (data_size == 0) goto fail;
|
||||
|
||||
new_streamFile = open_wrap_streamfile(streamHead);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_clamp_streamfile(temp_streamFile, ea->stream_offset, data_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
break;
|
||||
case EAAC_TYPE_STREAM:
|
||||
/* header in SNR, data in SNS */
|
||||
data_size = calculate_eaac_size(streamData, ea->version, ea->num_samples, ea->stream_offset);
|
||||
if (data_size == 0) goto fail;
|
||||
|
||||
new_streamFile = open_wrap_streamfile(streamData);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_clamp_streamfile(temp_streamFile, ea->stream_offset, data_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
break;
|
||||
case EAAC_TYPE_GIGASAMPLE:
|
||||
/* header and prefetched data in SNR, rest of data in SNS */
|
||||
/* open prefetched data */
|
||||
data_size = calculate_eaac_size(streamHead, ea->version, ea->prefetch_samples, ea->prefetch_offset);
|
||||
if (data_size == 0) goto fail;
|
||||
|
||||
new_streamFile = open_wrap_streamfile(streamHead);
|
||||
if (!new_streamFile) goto fail;
|
||||
stream_segments[0] = new_streamFile;
|
||||
|
||||
new_streamFile = open_clamp_streamfile(stream_segments[0], ea->prefetch_offset, data_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
stream_segments[0] = new_streamFile;
|
||||
|
||||
/* open main data */
|
||||
data_size = calculate_eaac_size(streamData, ea->version, ea->num_samples - ea->prefetch_samples, ea->stream_offset);
|
||||
if (data_size == 0) goto fail;
|
||||
|
||||
new_streamFile = open_wrap_streamfile(streamData);
|
||||
if (!new_streamFile) goto fail;
|
||||
stream_segments[1] = new_streamFile;
|
||||
|
||||
new_streamFile = open_clamp_streamfile(stream_segments[1], ea->stream_offset, data_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
stream_segments[1] = new_streamFile;
|
||||
|
||||
new_streamFile = open_multifile_streamfile(stream_segments, 2);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
stream_segments[0] = NULL;
|
||||
stream_segments[1] = NULL;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (ea->type == EAAC_TYPE_GIGASAMPLE) {
|
||||
/* not seen so far, need samples */
|
||||
VGM_LOG("EAAC: Found SPS gigasample\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
data_size = calculate_eaac_size(streamHead, ea->version, ea->num_samples, ea->stream_offset);
|
||||
if (data_size == 0) goto fail;
|
||||
|
||||
new_streamFile = open_wrap_streamfile(streamHead);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_clamp_streamfile(temp_streamFile, ea->stream_offset, data_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
}
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(stream_segments[0]);
|
||||
close_streamfile(stream_segments[1]);
|
||||
close_streamfile(temp_streamFile);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Actual looping uses 2 block sections, separated by a block end flag *and* padded.
|
||||
*
|
||||
* We use the segmented layout, since the eaac_streamfile doesn't handle padding,
|
||||
@ -1353,7 +1430,7 @@ static size_t calculate_eaac_size(VGMSTREAM *vgmstream, STREAMFILE *streamFile,
|
||||
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf_data, eaac_header *eaac) {
|
||||
segmented_layout_data *data = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
off_t offsets[2] = { eaac->stream_offset, eaac->loop_offset };
|
||||
off_t offsets[2] = { 0x00, eaac->loop_offset };
|
||||
off_t start_offset;
|
||||
int num_samples[2] = { eaac->loop_start, eaac->num_samples - eaac->loop_start};
|
||||
int segment_count = 2; /* intro/loop */
|
||||
@ -1377,12 +1454,11 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf
|
||||
eaac_header temp_eaac = *eaac; /* equivalent to memcpy... I think */
|
||||
temp_eaac.loop_flag = 0;
|
||||
temp_eaac.num_samples = num_samples[i];
|
||||
temp_eaac.stream_offset = offsets[i];
|
||||
|
||||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||
|
||||
/* layers inside segments, how trippy */
|
||||
data->segments[i]->layout_data = build_layered_eaaudiocore(sf_data, &temp_eaac);
|
||||
data->segments[i]->layout_data = build_layered_eaaudiocore(sf_data, &temp_eaac, offsets[i]);
|
||||
if (!data->segments[i]->layout_data) goto fail;
|
||||
data->segments[i]->coding_type = coding_FFmpeg;
|
||||
data->segments[i]->layout_type = layout_layered;
|
||||
@ -1407,7 +1483,7 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf
|
||||
|
||||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||
|
||||
temp_sf = setup_eaac_streamfile(sf_data, eaac->version,eaac->codec,eaac->streamed,0,0, offsets[i]);
|
||||
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version,eaac->codec,eaac->streamed,0,0, offsets[i]);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
data->segments[i]->codec_data = init_mpeg_custom(temp_sf, 0x00, &data->segments[i]->coding_type, eaac->channels, type, &cfg);
|
||||
@ -1425,9 +1501,6 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf
|
||||
|
||||
close_streamfile(temp_sf);
|
||||
temp_sf = NULL;
|
||||
|
||||
//todo temp_streamFile doesn't contain EAXMA's streamfile
|
||||
data->segments[i]->stream_size = calculate_eaac_size(data->segments[i], temp_sf, eaac, start_offset);
|
||||
}
|
||||
|
||||
if (!setup_layout_segmented(data))
|
||||
@ -1440,7 +1513,7 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_header *eaac) {
|
||||
static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_header *eaac, off_t start_offset) {
|
||||
layered_layout_data* data = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
int i, layers = (eaac->channels+1) / 2;
|
||||
@ -1472,7 +1545,7 @@ static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_
|
||||
int bytes, block_size, block_count;
|
||||
size_t stream_size;
|
||||
|
||||
temp_sf = setup_eaac_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, eaac->stream_offset);
|
||||
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, start_offset);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
stream_size = get_streamfile_size(temp_sf);
|
||||
@ -1497,7 +1570,7 @@ static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_
|
||||
size_t data_size;
|
||||
|
||||
/* We'll remove EA blocks and pass raw data to FFmpeg Opus decoder */
|
||||
temp_sf = setup_eaac_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, eaac->stream_offset);
|
||||
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, start_offset);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
skip = ea_opus_get_encoder_delay(0x00, temp_sf);
|
||||
|
@ -245,7 +245,7 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
|
||||
* - EATrax: ATRAC9 frames can be split between blooks
|
||||
* - EAOpus: multiple Opus packets of frame size + Opus data per block
|
||||
*/
|
||||
static STREAMFILE* setup_eaac_streamfile(STREAMFILE *sf, int version, int codec, int streamed, int stream_number, int stream_count, off_t stream_offset) {
|
||||
static STREAMFILE* setup_eaac_audio_streamfile(STREAMFILE *sf, int version, int codec, int streamed, int stream_number, int stream_count, off_t stream_offset) {
|
||||
STREAMFILE *new_sf = NULL;
|
||||
eaac_io_data io_data = {0};
|
||||
|
||||
|
@ -5,16 +5,10 @@ VGMSTREAM * init_vgmstream_gin_header(STREAMFILE *streamFile, off_t offset);
|
||||
|
||||
/* .gin - EA engine sounds [Need for Speed: Most Wanted (multi)] */
|
||||
VGMSTREAM * init_vgmstream_gin(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
|
||||
if (!check_extensions(streamFile, "gin"))
|
||||
goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_gin_header(streamFile, 0x00);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
return init_vgmstream_gin_header(streamFile, 0x00);
|
||||
|
||||
fail:
|
||||
return NULL;
|
||||
|
@ -1525,7 +1525,7 @@ static int parse_stream_codec(ubi_sb_header * sb) {
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("Unknown stream_type %02x for version %08x\n", sb->stream_type, sb->version);
|
||||
VGM_LOG("UBI SB: Unknown stream_type %02x for version %08x\n", sb->stream_type, sb->version);
|
||||
goto fail;
|
||||
}
|
||||
} else if (sb->version < 0x000A0000) {
|
||||
@ -1539,7 +1539,7 @@ static int parse_stream_codec(ubi_sb_header * sb) {
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("Unknown stream_type %02x for version %08x\n", sb->stream_type, sb->version);
|
||||
VGM_LOG("UBI SB: Unknown stream_type %02x for version %08x\n", sb->stream_type, sb->version);
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
@ -1555,7 +1555,7 @@ static int parse_stream_codec(ubi_sb_header * sb) {
|
||||
break;
|
||||
case UBI_PSP:
|
||||
/* TODO: IMA using Ubisoft ADPCM frame layout [Splinter Cell: Essentials (PSP)] */
|
||||
VGM_LOG("Unimplemented custom IMA codec.\n");
|
||||
VGM_LOG("UBI SB: Unimplemented custom IMA codec.\n");
|
||||
goto fail;
|
||||
default:
|
||||
sb->codec = UBI_ADPCM;
|
||||
@ -1581,7 +1581,7 @@ static int parse_stream_codec(ubi_sb_header * sb) {
|
||||
sb->codec = FMT_AT3;
|
||||
break;
|
||||
default:
|
||||
VGM_LOG("UBI SB: unknown codec for stream_type %x\n", sb->stream_type);
|
||||
VGM_LOG("UBI SB: unknown codec for stream_type %02x\n", sb->stream_type);
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
@ -1599,7 +1599,7 @@ static int parse_stream_codec(ubi_sb_header * sb) {
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("Unknown stream_type %02x\n", sb->stream_type);
|
||||
VGM_LOG("UBI SB: Unknown stream_type %02x\n", sb->stream_type);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@ -2364,7 +2364,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Rainbow Six 3 (2003)(PC)-bank 0x0000000B */
|
||||
/* Tom Clancy's Rainbow Six 3: Raven Shield + addons (2003)(PC)-bank 0x0000000B */
|
||||
if (sb->version == 0x0000000B && sb->platform == UBI_PC) {
|
||||
config_sb_entry(sb, 0x5c, 0x7c);
|
||||
|
||||
@ -2519,7 +2519,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
||||
|
||||
/* Batman: Rise of Sin Tzu (2003)(GC)-map 0x000A0002 */
|
||||
/* Prince of Persia: The Sands of Time (2003)(GC)-bank 0x000A0004 / 0x000A0002 (POP1 port) */
|
||||
/* Tom Clancy's Rainbow Six 3 (2003)(Xbox)-bank 0x000A0007 */
|
||||
/* Tom Clancy's Rainbow Six 3 (2003)(GC)-bank 0x000A0007 */
|
||||
if ((sb->version == 0x000A0002 && sb->platform == UBI_GC) ||
|
||||
(sb->version == 0x000A0004 && sb->platform == UBI_GC) ||
|
||||
(sb->version == 0x000A0007 && sb->platform == UBI_GC)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user