Fix 6ch .sps opus [EA Sports FC24 (PC)]

This commit is contained in:
bnnm 2024-04-13 20:23:14 +02:00
parent 3ac217fad9
commit 7f1641e820
2 changed files with 38 additions and 20 deletions

View File

@ -514,7 +514,7 @@ static size_t make_opus_header(uint8_t* buf, int buf_size, opus_config *cfg) {
/* set mapping family */ /* set mapping family */
if (cfg->channels > 2 || cfg->stream_count > 1) { if (cfg->channels > 2 || cfg->stream_count > 1) {
mapping_family = 1; //todo test 255 mapping_family = 1;
header_size += 0x01 + 0x01 + cfg->channels; /* table size */ header_size += 0x01 + 0x01 + cfg->channels; /* table size */
} }
@ -525,7 +525,7 @@ static size_t make_opus_header(uint8_t* buf, int buf_size, opus_config *cfg) {
if (header_size > buf_size) { if (header_size > buf_size) {
VGM_LOG("OPUS: buffer can't hold header\n"); VGM_LOG("OPUS: buffer can't hold header\n");
goto fail; return 0;
} }
put_u32be(buf+0x00, get_id32be("Opus")); put_u32be(buf+0x00, get_id32be("Opus"));
@ -539,21 +539,29 @@ static size_t make_opus_header(uint8_t* buf, int buf_size, opus_config *cfg) {
/* set mapping table */ /* set mapping table */
if (mapping_family > 0) { if (mapping_family > 0) {
int i; /* test if external mappings are correctly set, as incorrect values result in wrong output
* (ex. all 0s would mean "write channel L in every channel)")*/
bool mappings_set = false;
for (int i = 0; i < cfg->channels; i++) {
if (cfg->channel_mapping[i]) {
mappings_set = true;
break;
}
}
/* total streams (mono/stereo) */ /* total streams (mono/stereo) */
put_u8(buf+0x13, cfg->stream_count); put_u8(buf+0x13, cfg->stream_count);
/* stereo streams (6ch can be 2ch+2ch+1ch+1ch = 2 coupled in 4 streams) */ /* stereo streams (6ch can be 2ch+2ch+1ch+1ch = 2 coupled in 4 streams) */
put_u8(buf+0x14, cfg->coupled_count); put_u8(buf+0x14, cfg->coupled_count);
/* mapping per channel (order of channels, ex: 00 01 04 05 02 03) */ /* mapping per channel (order of channels, ex: 00 01 04 05 02 03) */
for (i = 0; i < cfg->channels; i++) { for (int i = 0; i < cfg->channels; i++) {
put_u8(buf+0x15+i, cfg->channel_mapping[i]); uint8_t mapping = (mappings_set) ? cfg->channel_mapping[i] : i;
put_u8(buf+0x15+i, mapping);
} }
} }
return header_size; return header_size;
fail:
return 0;
} }
static size_t make_opus_comment(uint8_t* buf, int buf_size) { static size_t make_opus_comment(uint8_t* buf, int buf_size) {
@ -568,11 +576,11 @@ static size_t make_opus_comment(uint8_t* buf, int buf_size) {
if (comment_size > buf_size) { if (comment_size > buf_size) {
VGM_LOG("OPUS: buffer can't hold comment\n"); VGM_LOG("OPUS: buffer can't hold comment\n");
goto fail; return 0;
} }
put_u32be(buf+0x00, 0x4F707573); /* "Opus" header magic */ put_u32be(buf+0x00, get_id32be("Opus"));
put_u32be(buf+0x04, 0x54616773); /* "Tags" header magic */ put_u32be(buf+0x04, get_id32be("Tags"));
put_u32le(buf+0x08, vendor_string_length); put_u32le(buf+0x08, vendor_string_length);
memcpy (buf+0x0c, vendor_string, vendor_string_length); memcpy (buf+0x0c, vendor_string, vendor_string_length);
put_u32le(buf+0x0c + vendor_string_length+0x00, 1); /* user_comment_list_length */ put_u32le(buf+0x0c + vendor_string_length+0x00, 1); /* user_comment_list_length */
@ -580,8 +588,6 @@ static size_t make_opus_comment(uint8_t* buf, int buf_size) {
memcpy (buf+0x0c + vendor_string_length+0x08, user_comment_0_string, user_comment_0_length); memcpy (buf+0x0c + vendor_string_length+0x08, user_comment_0_string, user_comment_0_length);
return comment_size; return comment_size;
fail:
return 0;
} }
static size_t make_oggs_first(uint8_t* buf, int buf_size, opus_config* cfg) { static size_t make_oggs_first(uint8_t* buf, int buf_size, opus_config* cfg) {

View File

@ -251,8 +251,8 @@ fail:
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE* sf_head, STREAMFILE* sf_data, eaac_header_t* eaac); static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE* sf_head, STREAMFILE* sf_data, eaac_header_t* eaac);
static layered_layout_data* build_layered_eaaudiocore(STREAMFILE* sf, eaac_header_t *eaac, off_t start_offset); static layered_layout_data* build_layered_eaaudiocore(STREAMFILE* sf, eaac_header_t *eaac, off_t start_offset);
static STREAMFILE *setup_eaac_streamfile(eaac_header_t *ea, STREAMFILE* sf_head, STREAMFILE* sf_data); static STREAMFILE* setup_eaac_streamfile(eaac_header_t* ea, STREAMFILE* sf_head, STREAMFILE* sf_data);
static size_t calculate_eaac_size(STREAMFILE* sf, eaac_header_t *ea, uint32_t num_samples, off_t start_offset, int is_ram); static size_t calculate_eaac_size(STREAMFILE* sf, eaac_header_t* ea, uint32_t num_samples, off_t start_offset, int is_ram);
static VGMSTREAM* init_vgmstream_eaaudiocore_main(eaac_header_t* eaac, STREAMFILE* sf_head, STREAMFILE* sf_data, off_t header_offset, off_t _start_offset, meta_t meta_type, bool standalone) { static VGMSTREAM* init_vgmstream_eaaudiocore_main(eaac_header_t* eaac, STREAMFILE* sf_head, STREAMFILE* sf_data, off_t header_offset, off_t _start_offset, meta_t meta_type, bool standalone) {
@ -469,18 +469,30 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_main(eaac_header_t* eaac, STREAMFIL
} }
else { else {
switch(eaac->channels) { switch(eaac->channels) {
//case 8: cfg.coupled_count = 3; break; /* 2ch+2ch+2ch+1ch+1ch, 5 streams */ //case 8: cfg.coupled_count = 3; break; /* 2ch+2ch+2ch+1ch+1ch, 5 streams */
//case 6: cfg.coupled_count = 2; break; /* 2ch+2ch+1ch+1ch, 4 streams */ case 6: cfg.coupled_count = 2; break; /* 2ch+2ch+1ch+1ch, 4 streams [FC24 (PC)] */
case 4: cfg.coupled_count = 2; break; /* 2ch+2ch, 2 streams */ case 4: cfg.coupled_count = 2; break; /* 2ch+2ch, 2 streams */
case 2: cfg.coupled_count = 1; break; /* 2ch, 1 stream */ case 2: cfg.coupled_count = 1; break; /* 2ch, 1 stream */
case 1: cfg.coupled_count = 0; break; /* 1ch, 1 stream [Madden 22 (PC)] */ case 1: cfg.coupled_count = 0; break; /* 1ch, 1 stream [Madden 22 (PC)] */
default: goto fail; /* possibly: streams = Nch / 2, coupled = Nch % 2 */ default:
VGM_LOG("EAAC: unknown coupled count for %i\n", eaac->channels);
goto fail; /* possibly: streams = Nch / 2, coupled = Nch % 2 */
} }
} }
/* total number internal OPUS streams (should be >0) */ /* total number internal OPUS streams (should be >0) */
cfg.stream_count = cfg.channels - cfg.coupled_count; cfg.stream_count = cfg.channels - cfg.coupled_count;
/* observed mapping, basically swaps BL<>LFE (4ch and below are fine with defaults)*/
if (eaac->channels == 6) { /* FL FR FC LFE BL BR */
cfg.channel_mapping[0] = 0;
cfg.channel_mapping[1] = 1;
cfg.channel_mapping[2] = 2;
cfg.channel_mapping[3] = 5;
cfg.channel_mapping[4] = 4;
cfg.channel_mapping[5] = 3;
}
/* We *don't* remove EA blocks b/c in Multi Opus 1 block = 1 Opus packet /* 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. * Regular EAOPUS uses layers to fake multichannel, this is normal multichannel Opus.
* This can be used for stereo too, so probably replaces EAOPUS. */ * This can be used for stereo too, so probably replaces EAOPUS. */