mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-12-01 09:37:21 +01:00
Fix some .sps [Madden 13 (Vita), Madden 22 (PC)]
This commit is contained in:
parent
cbe3165f69
commit
484908c57e
@ -1050,7 +1050,7 @@ typedef struct {
|
||||
off_t prefetch_offset;
|
||||
} eaac_header;
|
||||
|
||||
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf_data, eaac_header *eaac);
|
||||
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE* sf_head, STREAMFILE* sf_data, eaac_header* eaac);
|
||||
static layered_layout_data* build_layered_eaaudiocore(STREAMFILE* sf, eaac_header *eaac, off_t start_offset);
|
||||
static STREAMFILE *setup_eaac_streamfile(eaac_header *ea, STREAMFILE* sf_head, STREAMFILE* sf_data);
|
||||
static size_t calculate_eaac_size(STREAMFILE* sf, eaac_header *ea, uint32_t num_samples, off_t start_offset, int is_ram);
|
||||
@ -1137,8 +1137,9 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||
eaac.codec == EAAC_CODEC_EALAYER3_V2_PCM ||
|
||||
eaac.codec == EAAC_CODEC_EALAYER3_V2_SPIKE ||
|
||||
eaac.codec == EAAC_CODEC_EAXMA ||
|
||||
eaac.codec == EAAC_CODEC_XAS1)) {
|
||||
VGM_LOG("EA EAAC: unknown actual looping for codec %x\n", eaac.codec);
|
||||
eaac.codec == EAAC_CODEC_XAS1 ||
|
||||
eaac.codec == EAAC_CODEC_EATRAX)) {
|
||||
VGM_LOG("EA EAAC: unknown actual looping %i for codec %x\n", eaac.loop_start, eaac.codec);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@ -1220,7 +1221,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||
if (eaac.version == EAAC_VERSION_V0 && eaac.streamed) {
|
||||
/* open SNS file if needed */
|
||||
if (standalone) {
|
||||
snsFile = open_streamfile_by_ext(sf_head, "sns");
|
||||
snsFile = open_streamfile_by_ext(sf_head, "sns"); //todo clean
|
||||
sf_data = snsFile;
|
||||
}
|
||||
if (!sf_data) goto fail;
|
||||
@ -1255,7 +1256,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||
|
||||
/* special (if hacky) loop handling, see comments */
|
||||
if (eaac.loop_start > 0) {
|
||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf, &eaac);
|
||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf, sf, &eaac);
|
||||
if (!data) goto fail;
|
||||
vgmstream->layout_data = data;
|
||||
vgmstream->coding_type = data->segments[0]->coding_type;
|
||||
@ -1276,7 +1277,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||
|
||||
/* special (if hacky) loop handling, see comments */
|
||||
if (eaac.loop_start > 0) {
|
||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf, &eaac);
|
||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf, sf, &eaac);
|
||||
if (!data) goto fail;
|
||||
vgmstream->layout_data = data;
|
||||
vgmstream->coding_type = data->segments[0]->coding_type;
|
||||
@ -1301,14 +1302,14 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||
|
||||
/* special (if hacky) loop handling, see comments */
|
||||
if (eaac.loop_start > 0) {
|
||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf, &eaac);
|
||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf, sf, &eaac);
|
||||
if (!data) goto fail;
|
||||
vgmstream->layout_data = data;
|
||||
vgmstream->coding_type = data->segments[0]->coding_type;
|
||||
vgmstream->layout_type = layout_segmented;
|
||||
}
|
||||
else {
|
||||
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
|
||||
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00, 0);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
vgmstream->codec_data = init_mpeg_custom(temp_sf, 0x00, &vgmstream->coding_type, vgmstream->channels, type, &cfg);
|
||||
@ -1336,7 +1337,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||
vgmstream->coding_type = coding_SPEEX;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
|
||||
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00, 0);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
break;
|
||||
@ -1349,9 +1350,21 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||
|
||||
/* EATrax is "buffered" ATRAC9, uses custom IO since it's kind of complex to add to the decoder */
|
||||
|
||||
#if 0
|
||||
/* For looped EATRAX, since we are using a deblocker SF no need to make segmented looping, though it works [Madden NFL 13 Demo (Vita)]
|
||||
* An issue with segmented is that AT9 state is probably not reset between loops, which segmented can't simulate */
|
||||
if (eaac.loop_start > 0) {
|
||||
segmented_layout_data *data = build_segmented_eaaudiocore_looping(sf_head, sf, &eaac);
|
||||
if (!data) goto fail;
|
||||
vgmstream->layout_data = data;
|
||||
vgmstream->coding_type = data->segments[0]->coding_type;
|
||||
vgmstream->layout_type = layout_segmented;
|
||||
}
|
||||
#endif
|
||||
|
||||
cfg.channels = eaac.channels;
|
||||
/* sub-header after normal header */
|
||||
cfg.config_data = read_32bitBE(header_offset + header_size + 0x00,sf_head);
|
||||
cfg.config_data = read_u32be(header_offset + header_size + 0x00,sf_head);
|
||||
/* 0x04: data size without blocks, LE b/c why make sense (but don't use it in case of truncated files) */
|
||||
/* 0x08: 16b frame size (same as config data) */
|
||||
|
||||
@ -1360,7 +1373,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||
vgmstream->coding_type = coding_ATRAC9;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
|
||||
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00, 0);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
break;
|
||||
@ -1372,7 +1385,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||
case EAAC_CODEC_EAMP3: { /* "EM30": EA-MP3 [Need for Speed 2015 (PS4), FIFA 2021 (PC)] */
|
||||
mpeg_custom_config cfg = {0};
|
||||
|
||||
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
|
||||
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00, 0);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
vgmstream->codec_data = init_mpeg_custom(temp_sf, 0x00, &vgmstream->coding_type, vgmstream->channels, MPEG_EAMP3, &cfg);
|
||||
@ -1420,7 +1433,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||
case 4: cfg.coupled_count = 2; break; /* 2ch+2ch, 2 streams */
|
||||
//case 3: /* 2ch+1ch, 2 streams */
|
||||
case 2: cfg.coupled_count = 1; break; /* 2ch, 1 stream */
|
||||
//case 1: cfg.coupled_count = 0; break; /* 1ch, 1 stream */
|
||||
case 1: cfg.coupled_count = 0; break; /* 1ch, 1 stream [Madden 22 (PC)] */
|
||||
default: goto fail;
|
||||
}
|
||||
}
|
||||
@ -1431,7 +1444,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||
/* We *don't* remove EA blocks b/c in Multi Opus 1 block = 1 Opus packet
|
||||
* Regular EAOPUS uses layers to fake multichannel, this is normal multichannel Opus.
|
||||
* This can be used for stereo too, so probably replaces EAOPUS. */
|
||||
//temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,0,0, 0x00);
|
||||
//temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,0,0, 0x00, 0);
|
||||
//if (!temp_sf) goto fail;
|
||||
|
||||
vgmstream->codec_data = init_ffmpeg_ea_opusm(sf, offset, data_size, &cfg);
|
||||
@ -1613,10 +1626,12 @@ fail:
|
||||
* We use the segmented layout, since the eaac_streamfile doesn't handle padding,
|
||||
* and the segments seem fully separate (so even skipping would probably decode wrong). */
|
||||
// todo reorganize code for more standard init
|
||||
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf_data, eaac_header *eaac) {
|
||||
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf_head, STREAMFILE *sf_data, eaac_header *eaac) {
|
||||
segmented_layout_data *data = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
uint32_t data_size = get_streamfile_size(sf_data);
|
||||
off_t offsets[2] = { 0x00, eaac->loop_offset };
|
||||
uint32_t sizes[2] = { eaac->loop_offset, data_size - 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 */
|
||||
@ -1628,8 +1643,11 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf
|
||||
if (!data) goto fail;
|
||||
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
data->segments[i] = allocate_vgmstream(eaac->channels, 0);
|
||||
if (!data->segments[i]) goto fail;
|
||||
VGMSTREAM* vgmstream = allocate_vgmstream(eaac->channels, 0);
|
||||
|
||||
if (!vgmstream) goto fail;
|
||||
data->segments[i] = vgmstream;
|
||||
|
||||
data->segments[i]->sample_rate = eaac->sample_rate;
|
||||
data->segments[i]->num_samples = num_samples[i];
|
||||
//data->segments[i]->meta_type = eaac->meta_type; /* bleh */
|
||||
@ -1669,7 +1687,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_audio_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], sizes[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);
|
||||
@ -1678,6 +1696,32 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef VGM_USE_ATRAC9
|
||||
case EAAC_CODEC_EATRAX: { /* EATrax (unknown FourCC) [Need for Speed: Most Wanted (Vita)] */
|
||||
atrac9_config cfg = {0};
|
||||
|
||||
/* EATrax is "buffered" ATRAC9, uses custom IO since it's kind of complex to add to the decoder */
|
||||
|
||||
cfg.channels = eaac->channels;
|
||||
/* sub-header after normal header */
|
||||
cfg.config_data = read_u32be(0x14 + 0x00, sf_head); //todo pass header offset
|
||||
/* 0x04: data size without blocks, LE b/c why make sense (but don't use it in case of truncated files) */
|
||||
/* 0x08: 16b frame size (same as config data) */
|
||||
|
||||
vgmstream->codec_data = init_atrac9(&cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_ATRAC9;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||
|
||||
//todo should make sizes
|
||||
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,0,0, offsets[i], sizes[i]);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
@ -1732,7 +1776,7 @@ static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_
|
||||
size_t stream_size;
|
||||
int is_xma1;
|
||||
|
||||
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, start_offset);
|
||||
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, start_offset, 0);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
stream_size = get_streamfile_size(temp_sf);
|
||||
@ -1764,7 +1808,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_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, start_offset);
|
||||
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, start_offset, 0);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
skip = ea_opus_get_encoder_delay(0x00, temp_sf);
|
||||
|
@ -13,6 +13,7 @@ typedef struct {
|
||||
int stream_number;
|
||||
int stream_count;
|
||||
off_t stream_offset;
|
||||
uint32_t stream_size;
|
||||
|
||||
/* state */
|
||||
off_t logical_offset; /* offset that corresponds to physical_offset */
|
||||
@ -30,7 +31,7 @@ typedef struct {
|
||||
|
||||
/* Reads skipping EA's block headers, so the resulting data is smaller or larger than physical data.
|
||||
* physical/logical_offset will be at the start of a block and only advance when a block is done */
|
||||
static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, eaac_io_data* data) {
|
||||
static size_t eaac_io_read(STREAMFILE* sf, uint8_t *dest, off_t offset, size_t length, eaac_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
/* ignore bad reads */
|
||||
@ -58,8 +59,8 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
|
||||
|
||||
/* process new block */
|
||||
if (data->data_size == 0) {
|
||||
data->block_flag = (uint8_t)read_8bit(data->physical_offset+0x00,streamfile);
|
||||
data->block_size = read_32bitBE(data->physical_offset+0x00,streamfile) & 0x00FFFFFF;
|
||||
data->block_flag = (uint8_t)read_8bit(data->physical_offset+0x00,sf);
|
||||
data->block_size = read_32bitBE(data->physical_offset+0x00,sf) & 0x00FFFFFF;
|
||||
|
||||
/* ignore header block */
|
||||
if (data->version == 1 && data->block_flag == 0x48) {
|
||||
@ -74,9 +75,9 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
|
||||
|
||||
data->skip_size = 0x04 + 0x04;
|
||||
for (i = 0; i < data->stream_number; i++) {
|
||||
data->skip_size += read_32bitBE(data->physical_offset+data->skip_size, streamfile) / 4;
|
||||
data->skip_size += read_32bitBE(data->physical_offset+data->skip_size, sf) / 4;
|
||||
}
|
||||
data->data_size = read_32bitBE(data->physical_offset+data->skip_size, streamfile) / 4; /* why size*4...? */
|
||||
data->data_size = read_32bitBE(data->physical_offset+data->skip_size, sf) / 4; /* why size*4...? */
|
||||
data->skip_size += 0x04; /* skip mini header */
|
||||
data->data_size -= 0x04; /* remove mini header */
|
||||
if (data->data_size % XMA_FRAME_SIZE)
|
||||
@ -96,7 +97,7 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
|
||||
|
||||
case 0x0a: /* EATrax */
|
||||
data->skip_size = 0x08;
|
||||
data->data_size = read_32bitBE(data->physical_offset+0x04,streamfile); /* also block_size - 0x08 */
|
||||
data->data_size = read_32bitBE(data->physical_offset+0x04,sf); /* also block_size - 0x08 */
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -125,7 +126,7 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
|
||||
to_read = data->data_size - bytes_consumed;
|
||||
if (to_read > length)
|
||||
to_read = length;
|
||||
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
|
||||
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, sf);
|
||||
}
|
||||
else { /* offset falls within logical padded data */
|
||||
to_read = data->data_size + data->extra_size - bytes_consumed;
|
||||
@ -141,7 +142,7 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
|
||||
to_read = data->data_size - bytes_consumed;
|
||||
if (to_read > length)
|
||||
to_read = length;
|
||||
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
|
||||
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, sf);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -168,7 +169,7 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
|
||||
return data->logical_size;
|
||||
|
||||
physical_offset = data->stream_offset;
|
||||
max_physical_offset = get_streamfile_size(streamfile);
|
||||
max_physical_offset = physical_offset + data->stream_size;
|
||||
|
||||
/* get size of the logical stream */
|
||||
while (physical_offset < max_physical_offset) {
|
||||
@ -231,7 +232,7 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
|
||||
}
|
||||
|
||||
/* logical size can be bigger in EA-XMA though */
|
||||
if (physical_offset > get_streamfile_size(streamfile)) {
|
||||
if (physical_offset > max_physical_offset) {
|
||||
VGM_LOG("EA EAAC: wrong size\n");
|
||||
return 0;
|
||||
}
|
||||
@ -247,10 +248,13 @@ 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_audio_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, uint32_t stream_offset, uint32_t stream_size) {
|
||||
STREAMFILE *new_sf = NULL;
|
||||
eaac_io_data io_data = {0};
|
||||
|
||||
if (!stream_size)
|
||||
stream_size = get_streamfile_size(sf) - stream_offset;
|
||||
|
||||
io_data.version = version;
|
||||
io_data.codec = codec;
|
||||
io_data.streamed = streamed;
|
||||
@ -258,6 +262,7 @@ static STREAMFILE* setup_eaac_audio_streamfile(STREAMFILE *sf, int version, int
|
||||
io_data.stream_count = stream_count;
|
||||
io_data.stream_offset = stream_offset;
|
||||
io_data.physical_offset = stream_offset;
|
||||
io_data.stream_size = stream_size;
|
||||
io_data.logical_size = eaac_io_size(sf, &io_data); /* force init */
|
||||
|
||||
/* setup subfile */
|
||||
|
Loading…
Reference in New Issue
Block a user