mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 08:20:54 +01:00
commit
eb643cf2c4
@ -495,7 +495,7 @@ id_check = @0x00 # 4ch only
|
||||
... #different settings for 4ch
|
||||
```
|
||||
|
||||
As an interesting side-effect, you can use this to force load `.txth` in other paths. For example it can be useful if you have files in subdirs and want to point to a base `.txtp` in root.
|
||||
As an interesting side-effect, you can use this to force load `.txth` in other paths. For example it can be useful if you have files in subdirs and want to point to a base `.txth` in root.
|
||||
```
|
||||
multi_txth = ../.main.txth
|
||||
```
|
||||
|
@ -595,6 +595,7 @@ ffmpeg_codec_data* init_ffmpeg_switch_opus_config(STREAMFILE* sf, off_t start_of
|
||||
ffmpeg_codec_data* init_ffmpeg_switch_opus(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
|
||||
ffmpeg_codec_data* init_ffmpeg_ue4_opus(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
|
||||
ffmpeg_codec_data* init_ffmpeg_ea_opus(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
|
||||
ffmpeg_codec_data* init_ffmpeg_ea_opusm(STREAMFILE* sf, off_t data_offset, size_t data_size, opus_config* cfg);
|
||||
ffmpeg_codec_data* init_ffmpeg_x_opus(STREAMFILE* sf, off_t table_offset, int table_count, off_t data_offset, size_t data_size, int channels, int skip);
|
||||
ffmpeg_codec_data* init_ffmpeg_fsb_opus(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
|
||||
ffmpeg_codec_data* init_ffmpeg_wwise_opus(STREAMFILE* sf, off_t data_offset, size_t data_size, opus_config* cfg);
|
||||
|
@ -17,7 +17,7 @@
|
||||
* https://github.com/hcs64/ww2ogg
|
||||
*/
|
||||
|
||||
typedef enum { OPUS_SWITCH, OPUS_UE4_v1, OPUS_UE4_v2, OPUS_EA, OPUS_X, OPUS_FSB, OPUS_WWISE, OPUS_FIXED } opus_type_t;
|
||||
typedef enum { OPUS_SWITCH, OPUS_UE4_v1, OPUS_UE4_v2, OPUS_EA, OPUS_EA_M, OPUS_X, OPUS_FSB, OPUS_WWISE, OPUS_FIXED } opus_type_t;
|
||||
|
||||
static size_t make_oggs_first(uint8_t *buf, int buf_size, opus_config *cfg);
|
||||
static size_t make_oggs_page(uint8_t *buf, int buf_size, size_t data_size, int page_sequence, int granule);
|
||||
@ -128,6 +128,17 @@ static size_t opus_io_read(STREAMFILE* sf, uint8_t *dest, off_t offset, size_t l
|
||||
data_size = read_u16be(data->physical_offset, sf);
|
||||
skip_size = 0x02;
|
||||
break;
|
||||
case OPUS_EA_M: {
|
||||
uint8_t flag = read_u8(data->physical_offset + 0x00, sf);
|
||||
if (flag == 0x48) { /* should start on 0x44 though */
|
||||
data->physical_offset += read_u16be(data->physical_offset + 0x02, sf);
|
||||
flag = read_u8(data->physical_offset + 0x00, sf);
|
||||
}
|
||||
data_size = read_u16be(data->physical_offset + 0x02, sf);
|
||||
skip_size = (flag == 0x45) ? data_size : 0x08;
|
||||
data_size -= skip_size;
|
||||
break;
|
||||
}
|
||||
case OPUS_X:
|
||||
case OPUS_WWISE:
|
||||
data_size = get_table_frame_size(data, data->sequence - 2);
|
||||
@ -195,7 +206,7 @@ static size_t opus_io_read(STREAMFILE* sf, uint8_t *dest, off_t offset, size_t l
|
||||
|
||||
|
||||
static size_t opus_io_size(STREAMFILE* sf, opus_io_data* data) {
|
||||
off_t physical_offset, max_physical_offset;
|
||||
off_t offset, max_offset;
|
||||
size_t logical_size = 0;
|
||||
int packet = 0;
|
||||
|
||||
@ -207,32 +218,43 @@ static size_t opus_io_size(STREAMFILE* sf, opus_io_data* data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
physical_offset = data->stream_offset;
|
||||
max_physical_offset = data->stream_offset + data->stream_size;
|
||||
offset = data->stream_offset;
|
||||
max_offset = data->stream_offset + data->stream_size;
|
||||
logical_size = data->head_size;
|
||||
|
||||
/* get size of the logical stream */
|
||||
while (physical_offset < max_physical_offset) {
|
||||
while (offset < max_offset) {
|
||||
size_t data_size, skip_size, oggs_size;
|
||||
|
||||
switch(data->type) {
|
||||
case OPUS_SWITCH:
|
||||
data_size = read_u32be(physical_offset, sf);
|
||||
data_size = read_u32be(offset, sf);
|
||||
skip_size = 0x08;
|
||||
break;
|
||||
case OPUS_UE4_v1:
|
||||
case OPUS_FSB:
|
||||
data_size = read_u16le(physical_offset, sf);
|
||||
data_size = read_u16le(offset, sf);
|
||||
skip_size = 0x02;
|
||||
break;
|
||||
case OPUS_UE4_v2:
|
||||
data_size = read_u16le(physical_offset, sf);
|
||||
data_size = read_u16le(offset, sf);
|
||||
skip_size = 0x02 + 0x02;
|
||||
break;
|
||||
case OPUS_EA:
|
||||
data_size = read_u16be(physical_offset, sf);
|
||||
data_size = read_u16be(offset, sf);
|
||||
skip_size = 0x02;
|
||||
break;
|
||||
case OPUS_EA_M: {
|
||||
uint8_t flag = read_u8(offset + 0x00, sf);
|
||||
if (flag == 0x48) {
|
||||
offset += read_u16be(offset + 0x02, sf);
|
||||
flag = read_u8(offset + 0x00, sf);
|
||||
}
|
||||
data_size = read_u16be(offset + 0x02, sf);
|
||||
skip_size = (flag == 0x45) ? data_size : 0x08;
|
||||
data_size -= skip_size;
|
||||
break;
|
||||
}
|
||||
case OPUS_X:
|
||||
case OPUS_WWISE:
|
||||
data_size = get_table_frame_size(data, packet);
|
||||
@ -247,24 +269,24 @@ static size_t opus_io_size(STREAMFILE* sf, opus_io_data* data) {
|
||||
}
|
||||
|
||||
/* FSB pads data after end (total size without frame headers is given but not too useful here) */
|
||||
if (data->type == OPUS_FSB && data_size == 0) {
|
||||
if ((data->type == OPUS_FSB || data->type == OPUS_EA_M) && data_size == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (data_size == 0) {
|
||||
VGM_LOG("OPUS: data_size is 0 at %x\n", (uint32_t)physical_offset);
|
||||
VGM_LOG("OPUS: data_size is 0 at %x\n", (uint32_t)offset);
|
||||
return 0; /* bad rip? or could 'break' and truck along */
|
||||
}
|
||||
|
||||
oggs_size = 0x1b + (int)(data_size / 0xFF + 1); /* OggS page: base size + lacing values */
|
||||
|
||||
physical_offset += data_size + skip_size;
|
||||
offset += data_size + skip_size;
|
||||
logical_size += oggs_size + data_size;
|
||||
packet++;
|
||||
}
|
||||
|
||||
/* logical size can be bigger though */
|
||||
if (physical_offset > get_streamfile_size(sf)) {
|
||||
if (offset > get_streamfile_size(sf)) {
|
||||
VGM_LOG("OPUS: wrong size\n");
|
||||
return 0;
|
||||
}
|
||||
@ -485,6 +507,11 @@ static size_t make_opus_header(uint8_t* buf, int buf_size, opus_config *cfg) {
|
||||
header_size += 0x01+0x01+cfg->channels;
|
||||
}
|
||||
|
||||
if (cfg->skip < 0) {
|
||||
VGM_LOG("OPUS: wrong skip %i\n", cfg->skip);
|
||||
cfg->skip = 0; /* ??? */
|
||||
}
|
||||
|
||||
if (header_size > buf_size) {
|
||||
VGM_LOG("OPUS: buffer can't hold header\n");
|
||||
goto fail;
|
||||
@ -623,6 +650,12 @@ static size_t custom_opus_get_samples(off_t offset, size_t stream_size, STREAMFI
|
||||
data_size = read_u16be(offset, sf);
|
||||
skip_size = 0x02;
|
||||
break;
|
||||
#if 0
|
||||
case OPUS_EA_M:
|
||||
/* num_samples should exist on header */
|
||||
...
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if 0 //needs data*, num_samples should exist on header
|
||||
case OPUS_X:
|
||||
@ -673,6 +706,15 @@ static size_t custom_opus_get_encoder_delay(off_t offset, STREAMFILE* sf, opus_t
|
||||
case OPUS_EA:
|
||||
skip_size = 0x02;
|
||||
break;
|
||||
case OPUS_EA_M: {
|
||||
uint8_t flag = read_u8(offset + 0x00, sf);
|
||||
if (flag == 0x48) {
|
||||
offset += read_u16be(offset + 0x02, sf);
|
||||
flag = read_u8(offset + 0x00, sf);
|
||||
}
|
||||
skip_size = read_u16be(offset + 0x02, sf);
|
||||
break;
|
||||
}
|
||||
case OPUS_X:
|
||||
case OPUS_WWISE:
|
||||
skip_size = 0x00;
|
||||
@ -768,6 +810,9 @@ ffmpeg_codec_data* init_ffmpeg_ue4_opus(STREAMFILE* sf, off_t start_offset, size
|
||||
ffmpeg_codec_data* init_ffmpeg_ea_opus(STREAMFILE* sf, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate) {
|
||||
return init_ffmpeg_custom_opus(sf, start_offset, data_size, channels, skip, sample_rate, OPUS_EA);
|
||||
}
|
||||
ffmpeg_codec_data* init_ffmpeg_ea_opusm(STREAMFILE* sf, off_t data_offset, size_t data_size, opus_config* cfg) {
|
||||
return init_ffmpeg_custom_opus_config(sf, data_offset, data_size, cfg, OPUS_EA_M);
|
||||
}
|
||||
ffmpeg_codec_data* init_ffmpeg_x_opus(STREAMFILE* sf, off_t table_offset, int table_count, off_t data_offset, size_t data_size, int channels, int skip) {
|
||||
return init_ffmpeg_custom_table_opus(sf, table_offset, table_count, data_offset, data_size, channels, skip, 0, OPUS_X);
|
||||
}
|
||||
|
@ -22,6 +22,9 @@
|
||||
#define EAAC_CODEC_EATRAX 0x0a
|
||||
#define EAAC_CODEC_EAMP3 0x0b
|
||||
#define EAAC_CODEC_EAOPUS 0x0c
|
||||
#define EAAC_CODEC_EAATRAC9 0x0d
|
||||
#define EAAC_CODEC_EAOPUSM 0x0e
|
||||
#define EAAC_CODEC_EAOPUSMU 0x0f
|
||||
|
||||
#define EAAC_TYPE_RAM 0x00
|
||||
#define EAAC_TYPE_STREAM 0x01
|
||||
@ -1294,6 +1297,23 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAM
|
||||
/* DSP coefs are read in the blocks */
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_SPEEX
|
||||
case EAAC_CODEC_EASPEEX: { /* "Esp0": EASpeex (libspeex variant, base versions vary: 1.0.5, 1.2beta3) [FIFA 14 (PS4), FIFA 2020 (Switch)] */
|
||||
/* EASpeex looks normal but simplify with custom IO to avoid worrying about blocks.
|
||||
* First block samples count frames' samples subtracting encoder delay. */
|
||||
|
||||
vgmstream->codec_data = init_speex_ea(eaac.channels);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
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);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VGM_USE_ATRAC9
|
||||
case EAAC_CODEC_EATRAX: { /* EATrax (unknown FourCC) [Need for Speed: Most Wanted (Vita)] */
|
||||
atrac9_config cfg = {0};
|
||||
@ -1320,7 +1340,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAM
|
||||
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
case EAAC_CODEC_EAMP3: { /* "EM30"?: EAMP3 [Need for Speed 2015 (PS4)] */
|
||||
case EAAC_CODEC_EAMP3: { /* "EM30": EA-MP3 [Need for Speed 2015 (PS4)] */
|
||||
mpeg_custom_config cfg = {0};
|
||||
|
||||
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
|
||||
@ -1335,7 +1355,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAM
|
||||
#endif
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case EAAC_CODEC_EAOPUS: { /* "Eop0"? : EAOpus [FIFA 17 (PC), FIFA 19 (Switch)]*/
|
||||
case EAAC_CODEC_EAOPUS: { /* "Eop0": EAOpus [FIFA 17 (PC), FIFA 19 (Switch)]*/
|
||||
vgmstream->layout_data = build_layered_eaaudiocore(sf, &eaac, 0x00);
|
||||
if (!vgmstream->layout_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
@ -1343,24 +1363,57 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAM
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
//case EAAC_CODEC_EAOPUSMU: /* "MSU0": Multi-Stream Opus Uncoupled (not seen) */
|
||||
case EAAC_CODEC_EAOPUSM: { /* "MSO0": Multi-Stream Opus */
|
||||
off_t offset = 0x00; // eaac.stream_offset;
|
||||
off_t data_size = get_streamfile_size(sf);
|
||||
opus_config cfg = {0};
|
||||
|
||||
#ifdef VGM_USE_SPEEX
|
||||
case EAAC_CODEC_EASPEEX: { /* "Esp0"?: EASpeex (libspeex variant, base versions vary: 1.0.5, 1.2beta3) [FIFA 14 (PS4), FIFA 2020 (Switch)] */
|
||||
/* EASpeex looks normal but simplify with custom IO to avoid worrying about blocks.
|
||||
* First block samples count frames' samples subtracting encoder delay. */
|
||||
cfg.channels = eaac.channels;
|
||||
{
|
||||
uint32_t block_size = read_u32be(offset + 0x00, sf) & 0x00FFFFFF;
|
||||
uint32_t curr_samples = read_u32be(offset + 0x04, sf);
|
||||
uint32_t next_samples = read_u32be(offset + block_size + 0x04, sf);
|
||||
|
||||
vgmstream->codec_data = init_speex_ea(eaac.channels);
|
||||
cfg.skip = next_samples - curr_samples;
|
||||
/* maybe should check if next block exists, but files of single packet? */
|
||||
}
|
||||
|
||||
/* find coupled OPUS streams (internal streams using 2ch) */
|
||||
if (eaac.codec == EAAC_CODEC_EAOPUSMU) {
|
||||
cfg.coupled_count = 0;
|
||||
}
|
||||
else {
|
||||
switch(eaac.channels) {
|
||||
//case 8: cfg.coupled_count = 3; break; /* 2ch+2ch+2ch+1ch+1ch, 5 streams */
|
||||
//case 6: /* 2ch+2ch+1ch+1ch, 4 streams */
|
||||
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 */
|
||||
default: goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* total number internal OPUS streams (should be >0) */
|
||||
cfg.stream_count = cfg.channels - cfg.coupled_count;
|
||||
|
||||
/* 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);
|
||||
//if (!temp_sf) goto fail;
|
||||
|
||||
vgmstream->codec_data = init_ffmpeg_ea_opusm(sf, offset, data_size, &cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_SPEEX;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case EAAC_CODEC_EAATRAC9: /* "AT90" (possibly ATRAC9 with a saner layout than EATRAX) */
|
||||
default:
|
||||
VGM_LOG("EA EAAC: unknown codec 0x%02x\n", eaac.codec);
|
||||
goto fail;
|
||||
|
@ -360,12 +360,12 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
}
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,sf) != 0x52494646) /* "RIFF" */
|
||||
if (!is_id32be(0x00,sf,"RIFF"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x08,sf) != 0x57415645) /* "WAVE" */
|
||||
if (!is_id32be(0x08,sf, "WAVE"))
|
||||
goto fail;
|
||||
|
||||
riff_size = read_32bitLE(0x04,sf);
|
||||
riff_size = read_u32le(0x04,sf);
|
||||
file_size = get_streamfile_size(sf);
|
||||
|
||||
/* some games have wonky sizes, selectively fix to catch bad rips and new mutations */
|
||||
@ -417,6 +417,9 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
else if (codec == 0xFFFE && riff_size + 0x08 + 0x30 == file_size)
|
||||
riff_size += 0x30; /* [E.X. Troopers (PS3)] (adds "ver /eBIT/tIME/mrkr" empty chunks but RIFF size wasn't updated) */
|
||||
|
||||
else if (codec == 0xFFFE && riff_size + 0x08 + 0x38 == file_size)
|
||||
riff_size += 0x38; /* [Sengoku Basara 4 (PS3)] (adds "ver /eBIT/tIME/mrkr" chunks but RIFF size wasn't updated) */
|
||||
|
||||
else if (codec == 0x0002 && riff_size + 0x08 + 0x1c == file_size)
|
||||
riff_size += 0x1c; /* [Mega Man X Legacy Collection (PC)] (adds "ver /tIME/ver " chunks but RIFF size wasn't updated) */
|
||||
}
|
||||
@ -986,12 +989,12 @@ VGMSTREAM* init_vgmstream_rifx(STREAMFILE* sf) {
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,sf) != 0x52494658) /* "RIFX" */
|
||||
if (!is_id32be(0x00,sf, "RIFX"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x08,sf) != 0x57415645) /* "WAVE" */
|
||||
if (!is_id32be(0x08,sf, "WAVE"))
|
||||
goto fail;
|
||||
|
||||
riff_size = read_32bitBE(0x04,sf);
|
||||
riff_size = read_u32be(0x04,sf);
|
||||
file_size = get_streamfile_size(sf);
|
||||
|
||||
/* check for truncated RIFF */
|
||||
|
Loading…
Reference in New Issue
Block a user