mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-19 08:07:23 +01:00
Fix multichannel Wwise Opus
This commit is contained in:
parent
450281dafd
commit
be8eeb22d4
@ -551,7 +551,7 @@ 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);
|
||||
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 table_offset, int table_count, off_t data_offset, size_t data_size, int channels, int skip);
|
||||
ffmpeg_codec_data* init_ffmpeg_wwise_opus(STREAMFILE* sf, off_t data_offset, size_t data_size, opus_config* cfg);
|
||||
|
||||
size_t switch_opus_get_samples(off_t offset, size_t stream_size, STREAMFILE* sf);
|
||||
|
||||
|
@ -490,11 +490,11 @@ static size_t make_opus_header(uint8_t* buf, int buf_size, opus_config *cfg) {
|
||||
if (mapping_family > 0) {
|
||||
int i;
|
||||
|
||||
/* internal mono/stereo streams (N mono/stereo streams form M channels) */
|
||||
/* internal mono/stereo streams (N mono/stereo streams that make M channels) */
|
||||
put_u8(buf+0x13, cfg->stream_count);
|
||||
/* joint stereo streams (rest would be mono, so 6ch can be 2ch+2ch+1ch+1ch = 2 coupled */
|
||||
/* joint stereo streams (rest would be mono, so 6ch can be 2ch+2ch+1ch+1ch = 2 coupled in 4 streams */
|
||||
put_u8(buf+0x14, cfg->coupled_count);
|
||||
/* mapping bits per channel? */
|
||||
/* mapping per channel (order of channels, ex: 0x000104050203) */
|
||||
for (i = 0; i < cfg->channels; i++) {
|
||||
put_u8(buf+0x15+i, cfg->channel_mapping[i]);
|
||||
}
|
||||
@ -753,8 +753,8 @@ ffmpeg_codec_data* init_ffmpeg_x_opus(STREAMFILE* sf, off_t table_offset, int ta
|
||||
ffmpeg_codec_data* init_ffmpeg_fsb_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_FSB);
|
||||
}
|
||||
ffmpeg_codec_data* init_ffmpeg_wwise_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_WWISE);
|
||||
ffmpeg_codec_data* init_ffmpeg_wwise_opus(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_WWISE);
|
||||
}
|
||||
|
||||
static opus_type_t get_ue4opus_version(STREAMFILE* sf, off_t offset) {
|
||||
|
@ -40,6 +40,7 @@ typedef struct {
|
||||
int block_align;
|
||||
int average_bps;
|
||||
int bits_per_sample;
|
||||
uint8_t channel_type;
|
||||
uint32_t channel_layout;
|
||||
size_t extra_size;
|
||||
|
||||
@ -462,7 +463,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
||||
break;
|
||||
}
|
||||
|
||||
case OPUS: { /* alt to Vorbis [Girl Cafe Gun (Mobile)] */
|
||||
case OPUS: { /* fully standard Ogg Opus [Girl Cafe Gun (Mobile)] */
|
||||
if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail;
|
||||
|
||||
/* extra: size 0x12 */
|
||||
@ -484,18 +485,26 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
||||
break;
|
||||
}
|
||||
|
||||
case OPUSWW: { /* updated Opus [Assassin's Creed Valhalla (PC)] */
|
||||
int skip, table_count;
|
||||
|
||||
case OPUSWW: { /* updated Opus [Assassin's Creed Valhalla (PC)] */
|
||||
int mapping;
|
||||
opus_config cfg = {0};
|
||||
|
||||
if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail;
|
||||
if (!ww.seek_offset) goto fail;
|
||||
|
||||
/* extra: size 0x10 */
|
||||
cfg.channels = ww.channels;
|
||||
cfg.table_offset = ww.seek_offset;
|
||||
|
||||
/* extra: size 0x10 (though last 2 fields are beyond, AK plz) */
|
||||
/* 0x12: samples per frame */
|
||||
vgmstream->num_samples = read_s32(ww.fmt_offset + 0x18, sf);
|
||||
table_count = read_u32(ww.fmt_offset + 0x1c, sf); /* same as seek size / 2 */
|
||||
skip = read_u16(ww.fmt_offset + 0x20, sf);
|
||||
/* 0x22: 1? (though extra size is declared as 0x10 so this is outsize, AK plz */
|
||||
cfg.table_count = read_u32(ww.fmt_offset + 0x1c, sf); /* same as seek size / 2 */
|
||||
cfg.skip = read_u16(ww.fmt_offset + 0x20, sf);
|
||||
/* 0x22: codec version */
|
||||
mapping = read_u8(ww.fmt_offset + 0x23, sf);
|
||||
|
||||
if (read_u8(ww.fmt_offset + 0x22, sf) != 1)
|
||||
goto fail;
|
||||
|
||||
/* OPUS is VBR so this is very approximate percent, meh */
|
||||
if (ww.truncated) {
|
||||
@ -504,8 +513,42 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
||||
ww.data_size = ww.file_size - start_offset;
|
||||
}
|
||||
|
||||
/* AK does some wonky implicit config for multichannel */
|
||||
if (mapping == 1 && ww.channel_type == 1) { /* only allowed values ATM, set when >2ch */
|
||||
static const int8_t mapping_matrix[8][8] = {
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, },
|
||||
{ 0, 1, 0, 0, 0, 0, 0, 0, },
|
||||
{ 0, 2, 1, 0, 0, 0, 0, 0, },
|
||||
{ 0, 1, 2, 3, 0, 0, 0, 0, },
|
||||
{ 0, 4, 1, 2, 3, 0, 0, 0, },
|
||||
{ 0, 4, 1, 2, 3, 5, 0, 0, },
|
||||
{ 0, 6, 1, 2, 3, 4, 5, 0, },
|
||||
{ 0, 6, 1, 2, 3, 4, 5, 7, },
|
||||
};
|
||||
int i;
|
||||
|
||||
/* find coupled OPUS streams (internal streams using 2ch) */
|
||||
switch(ww.channel_layout) {
|
||||
case mapping_7POINT1_surround: cfg.coupled_count = 3; break; /* 2ch+2ch+2ch+1ch+1ch, 5 streams */
|
||||
case mapping_5POINT1_surround: /* 2ch+2ch+1ch+1ch, 4 streams */
|
||||
case mapping_QUAD_side: cfg.coupled_count = 2; break; /* 2ch+2ch, 2 streams */
|
||||
case mapping_2POINT1_xiph: /* 2ch+1ch, 2 streams */
|
||||
case mapping_STEREO: cfg.coupled_count = 1; break; /* 2ch, 1 stream */
|
||||
default: cfg.coupled_count = 0; break; /* 1ch, 1 stream */
|
||||
//TODO: AK OPUS doesn't seem to handles others mappings, though AK's .h imply they exist (uses 0 coupleds?)
|
||||
}
|
||||
|
||||
/* total number internal OPUS streams (should be >0) */
|
||||
cfg.stream_count = ww.channels - cfg.coupled_count;
|
||||
|
||||
/* channel assignments */
|
||||
for (i = 0; i < ww.channels; i++) {
|
||||
cfg.channel_mapping[i] = mapping_matrix[ww.channels - 1][i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Wwise Opus saves all frame sizes in the seek table */
|
||||
vgmstream->codec_data = init_ffmpeg_wwise_opus(sf, ww.seek_offset, table_count, ww.data_offset, ww.data_size, ww.channels, skip);
|
||||
vgmstream->codec_data = init_ffmpeg_wwise_opus(sf, ww.data_offset, ww.data_size, &cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
@ -648,6 +691,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
|
||||
* - HEVAG: very off
|
||||
* - XMA2: exact file size
|
||||
* - some RIFX have LE size
|
||||
* Value is ignored by AK's parser (set to -1).
|
||||
* (later we'll validate "data" which fortunately is correct)
|
||||
*/
|
||||
if (read_u32(0x04,sf) + 0x04 + 0x04 != ww->file_size) {
|
||||
@ -743,6 +787,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
|
||||
* - 4b: eConfigType (0=none, 1=standard, 2=ambisonic)
|
||||
* - 19b: uChannelMask */
|
||||
if ((ww->channel_layout & 0xFF) == ww->channels) {
|
||||
ww->channel_type = (ww->channel_layout >> 8) & 0x0F;
|
||||
ww->channel_layout = (ww->channel_layout >> 12);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user