mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 16:30:54 +01:00
Tweak some XWMA total samples
This commit is contained in:
parent
227ea3db5e
commit
58b6b16e3a
@ -592,7 +592,7 @@ STREAMFILE* ffmpeg_get_streamfile(ffmpeg_codec_data* data);
|
|||||||
ffmpeg_codec_data* init_ffmpeg_atrac3_raw(STREAMFILE* sf, off_t offset, size_t data_size, int sample_count, int channels, int sample_rate, int block_align, int encoder_delay);
|
ffmpeg_codec_data* init_ffmpeg_atrac3_raw(STREAMFILE* sf, off_t offset, size_t data_size, int sample_count, int channels, int sample_rate, int block_align, int encoder_delay);
|
||||||
ffmpeg_codec_data* init_ffmpeg_atrac3_riff(STREAMFILE* sf, off_t offset, int* out_samples);
|
ffmpeg_codec_data* init_ffmpeg_atrac3_riff(STREAMFILE* sf, off_t offset, int* out_samples);
|
||||||
ffmpeg_codec_data* init_ffmpeg_aac(STREAMFILE* sf, off_t offset, size_t size, int skip_samples);
|
ffmpeg_codec_data* init_ffmpeg_aac(STREAMFILE* sf, off_t offset, size_t size, int skip_samples);
|
||||||
|
ffmpeg_codec_data* init_ffmpeg_xwma(STREAMFILE* sf, uint32_t data_offset, uint32_t data_size, int format, int channels, int sample_rate, int avg_bitrate, int block_size);
|
||||||
|
|
||||||
/* ffmpeg_decoder_custom_opus.c (helper-things) */
|
/* ffmpeg_decoder_custom_opus.c (helper-things) */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -663,6 +663,8 @@ typedef struct {
|
|||||||
void xma_get_samples(ms_sample_data* msd, STREAMFILE* sf);
|
void xma_get_samples(ms_sample_data* msd, STREAMFILE* sf);
|
||||||
void wmapro_get_samples(ms_sample_data* msd, STREAMFILE* sf, int block_align, int sample_rate, uint32_t decode_flags);
|
void wmapro_get_samples(ms_sample_data* msd, STREAMFILE* sf, int block_align, int sample_rate, uint32_t decode_flags);
|
||||||
void wma_get_samples(ms_sample_data* msd, STREAMFILE* sf, int block_align, int sample_rate, uint32_t decode_flags);
|
void wma_get_samples(ms_sample_data* msd, STREAMFILE* sf, int block_align, int sample_rate, uint32_t decode_flags);
|
||||||
|
int32_t xwma_get_samples(STREAMFILE* sf, uint32_t data_offset, uint32_t data_size, int format, int channels, int sample_rate, int block_size);
|
||||||
|
int32_t xwma_dpds_get_samples(STREAMFILE* sf, uint32_t dpds_offset, uint32_t dpds_size, int channels, int be);
|
||||||
|
|
||||||
void xma1_parse_fmt_chunk(STREAMFILE* sf, off_t chunk_offset, int* channels, int* sample_rate, int* loop_flag, int32_t* loop_start_b, int32_t* loop_end_b, int32_t* loop_subframe, int be);
|
void xma1_parse_fmt_chunk(STREAMFILE* sf, off_t chunk_offset, int* channels, int* sample_rate, int* loop_flag, int32_t* loop_start_b, int32_t* loop_end_b, int32_t* loop_subframe, int be);
|
||||||
void xma2_parse_fmt_chunk_extra(STREAMFILE* sf, off_t chunk_offset, int* loop_flag, int32_t* out_num_samples, int32_t* out_loop_start_sample, int32_t* out_loop_end_sample, int be);
|
void xma2_parse_fmt_chunk_extra(STREAMFILE* sf, off_t chunk_offset, int* loop_flag, int32_t* out_num_samples, int32_t* out_loop_start_sample, int32_t* out_loop_end_sample, int be);
|
||||||
|
@ -760,6 +760,34 @@ void wma_get_samples(ms_sample_data* msd, STREAMFILE* sf, int block_align, int s
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t xwma_get_samples(STREAMFILE* sf, uint32_t data_offset, uint32_t data_size, int format, int channels, int sample_rate, int block_size) {
|
||||||
|
/* manually find total samples, why don't they put this in the header is beyond me */
|
||||||
|
ms_sample_data msd = {0};
|
||||||
|
|
||||||
|
msd.channels = channels;
|
||||||
|
msd.data_offset = data_offset;
|
||||||
|
msd.data_size = data_size;
|
||||||
|
|
||||||
|
if (format == 0x0162)
|
||||||
|
wmapro_get_samples(&msd, sf, block_size, sample_rate, 0x00E0);
|
||||||
|
else
|
||||||
|
wma_get_samples(&msd, sf, block_size, sample_rate, 0x001F);
|
||||||
|
|
||||||
|
return msd.num_samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t xwma_dpds_get_samples(STREAMFILE* sf, uint32_t dpds_offset, uint32_t dpds_size, int channels, int be) {
|
||||||
|
int32_t (*read_s32)(off_t,STREAMFILE*) = be ? read_s32be : read_s32le;
|
||||||
|
uint32_t offset;
|
||||||
|
if (!dpds_offset || !dpds_size || !channels)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
offset = dpds_offset + (dpds_size - 0x04); /* last entry */
|
||||||
|
/* XWMA's seek table ("dpds") contains max decoded bytes (after encoder delay), checked vs xWMAEncode.
|
||||||
|
* WMAPRO usually encodes a few more tail samples though (see xwma_get_samples). */
|
||||||
|
return read_s32(offset, sf) / channels / sizeof(int16_t); /* in PCM16 bytes */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* XMA hell for precise looping and gapless support, fixes raw sample values from headers
|
/* XMA hell for precise looping and gapless support, fixes raw sample values from headers
|
||||||
* that don't count XMA's final subframe/encoder delay/encoder padding, and FFmpeg stuff.
|
* that don't count XMA's final subframe/encoder delay/encoder padding, and FFmpeg stuff.
|
||||||
|
@ -203,4 +203,39 @@ fail:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: make init_ffmpeg_xwma_fmt(be) too to pass fmt chunk
|
||||||
|
|
||||||
|
ffmpeg_codec_data* init_ffmpeg_xwma(STREAMFILE* sf, uint32_t data_offset, uint32_t data_size, int format, int channels, int sample_rate, int avg_bitrate, int block_size) {
|
||||||
|
ffmpeg_codec_data* data = NULL;
|
||||||
|
uint8_t buf[0x100];
|
||||||
|
int bytes;
|
||||||
|
|
||||||
|
bytes = ffmpeg_make_riff_xwma(buf, sizeof(buf), format, data_size, channels, sample_rate, avg_bitrate, block_size);
|
||||||
|
data = init_ffmpeg_header_offset(sf, buf,bytes, data_offset, data_size);
|
||||||
|
if (!data) goto fail;
|
||||||
|
|
||||||
|
if (format == 0x161) {
|
||||||
|
int skip_samples = 0;
|
||||||
|
|
||||||
|
/* Skip WMA encoder delay, not specified in the flags or containers (ASF/XWMA),
|
||||||
|
* but verified compared to Microsoft's output. Seems to match frame_samples * 2 */
|
||||||
|
if (sample_rate >= 32000)
|
||||||
|
skip_samples = 4096;
|
||||||
|
else if (sample_rate >= 22050)
|
||||||
|
skip_samples = 2048;
|
||||||
|
else if (sample_rate >= 8000)
|
||||||
|
skip_samples = 1024;
|
||||||
|
|
||||||
|
ffmpeg_set_skip_samples(data, skip_samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO WMAPro uses variable skips and is more complex
|
||||||
|
//TODO ffmpeg's WMA doesn't properly output trailing samples (ignored patch...)
|
||||||
|
|
||||||
|
return data;
|
||||||
|
fail:
|
||||||
|
free_ffmpeg(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -454,17 +454,15 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
|
|||||||
|
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
case 0x0E: { /* FMOD_SOUND_FORMAT_XWMA [from fsbankex tests, no known games] */
|
case 0x0E: { /* FMOD_SOUND_FORMAT_XWMA [from fsbankex tests, no known games] */
|
||||||
uint8_t buf[0x100];
|
int format,avg_bitrate, block_size;
|
||||||
int bytes, format, average_bps, block_align;
|
|
||||||
|
|
||||||
format = read_u16be(fsb5.extradata_offset+0x00,sf);
|
format = read_u16be(fsb5.extradata_offset+0x00,sf);
|
||||||
block_align = read_u16be(fsb5.extradata_offset+0x02,sf);
|
block_size = read_u16be(fsb5.extradata_offset+0x02,sf);
|
||||||
average_bps = read_u32be(fsb5.extradata_offset+0x04,sf);
|
avg_bitrate = read_u32be(fsb5.extradata_offset+0x04,sf);
|
||||||
/* rest: seek entries + mini seek table? */
|
/* rest: seek entries + mini seek table? */
|
||||||
/* XWMA encoder only does up to 6ch (doesn't use FSB multistreams for more) */
|
/* XWMA encoder only does up to 6ch (doesn't use FSB multistreams for more) */
|
||||||
|
|
||||||
bytes = ffmpeg_make_riff_xwma(buf,0x100, format, fsb5.stream_size, vgmstream->channels, vgmstream->sample_rate, average_bps, block_align);
|
vgmstream->codec_data = init_ffmpeg_xwma(sf, fsb5.stream_offset, fsb5.stream_size, format, fsb5.channels, fsb5.sample_rate, avg_bitrate, block_size);
|
||||||
vgmstream->codec_data = init_ffmpeg_header_offset(sb, buf,bytes, fsb5.stream_offset, fsb5.stream_size);
|
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
vgmstream->coding_type = coding_FFmpeg;
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
@ -38,8 +38,8 @@ typedef struct {
|
|||||||
int format;
|
int format;
|
||||||
int channels;
|
int channels;
|
||||||
int sample_rate;
|
int sample_rate;
|
||||||
int block_align;
|
int block_size;
|
||||||
int average_bps;
|
int avg_bitrate;
|
||||||
int bits_per_sample;
|
int bits_per_sample;
|
||||||
uint8_t channel_type;
|
uint8_t channel_type;
|
||||||
uint32_t channel_layout;
|
uint32_t channel_layout;
|
||||||
@ -121,11 +121,11 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
|||||||
|
|
||||||
if (ww.fmt_size != 0x14 && ww.fmt_size != 0x28 && ww.fmt_size != 0x18) goto fail; /* oldest, old, new */
|
if (ww.fmt_size != 0x14 && ww.fmt_size != 0x28 && ww.fmt_size != 0x18) goto fail; /* oldest, old, new */
|
||||||
if (ww.bits_per_sample != 4) goto fail;
|
if (ww.bits_per_sample != 4) goto fail;
|
||||||
if (ww.block_align != 0x24 * ww.channels) goto fail;
|
if (ww.block_size != 0x24 * ww.channels) goto fail;
|
||||||
|
|
||||||
vgmstream->coding_type = coding_WWISE_IMA;
|
vgmstream->coding_type = coding_WWISE_IMA;
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = ww.block_align / ww.channels;
|
vgmstream->interleave_block_size = ww.block_size / ww.channels;
|
||||||
vgmstream->codec_endian = ww.big_endian;
|
vgmstream->codec_endian = ww.big_endian;
|
||||||
|
|
||||||
/* oldest version uses regular XBOX IMA with stereo mode [Shadowrun (PC)] */
|
/* oldest version uses regular XBOX IMA with stereo mode [Shadowrun (PC)] */
|
||||||
@ -155,7 +155,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
|||||||
cfg.sample_rate = ww.sample_rate;
|
cfg.sample_rate = ww.sample_rate;
|
||||||
cfg.big_endian = ww.big_endian;
|
cfg.big_endian = ww.big_endian;
|
||||||
|
|
||||||
if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail; /* always 0 for Worbis */
|
if (ww.block_size != 0 || ww.bits_per_sample != 0) goto fail; /* always 0 for Worbis */
|
||||||
|
|
||||||
/* autodetect format (fields are mostly common, see the end of the file) */
|
/* autodetect format (fields are mostly common, see the end of the file) */
|
||||||
if (ww.vorb_offset) {
|
if (ww.vorb_offset) {
|
||||||
@ -305,7 +305,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
|||||||
|
|
||||||
vgmstream->coding_type = coding_NGC_DSP;
|
vgmstream->coding_type = coding_NGC_DSP;
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = 0x08; /* ww.block_align = 0x8 in older Wwise, samples per block in newer Wwise */
|
vgmstream->interleave_block_size = 0x08; /* ww.block_size = 0x8 in older Wwise, samples per block in newer Wwise */
|
||||||
|
|
||||||
/* find coef position */
|
/* find coef position */
|
||||||
if (ww.wiih_offset) { /* older */
|
if (ww.wiih_offset) { /* older */
|
||||||
@ -382,40 +382,18 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case XWMA: { /* X360 */
|
case XWMA: { /* X360 */
|
||||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
|
||||||
uint8_t buf[0x100];
|
|
||||||
int bytes;
|
|
||||||
|
|
||||||
if (ww.fmt_size != 0x18) goto fail;
|
if (ww.fmt_size != 0x18) goto fail;
|
||||||
if (!ww.big_endian) goto fail; /* must be from Wwise X360 (PC LE XWMA is parsed elsewhere) */
|
if (!ww.big_endian) goto fail; /* must be from Wwise X360 (PC LE XWMA is parsed elsewhere) */
|
||||||
|
|
||||||
bytes = ffmpeg_make_riff_xwma(buf, sizeof(buf), ww.format, ww.data_size, ww.channels, ww.sample_rate, ww.average_bps, ww.block_align);
|
vgmstream->codec_data = init_ffmpeg_xwma(sf, ww.data_offset, ww.data_size, ww.format, ww.channels, ww.sample_rate, ww.avg_bitrate, ww.block_size);
|
||||||
ffmpeg_data = init_ffmpeg_header_offset(sf, buf,bytes, ww.data_offset, ww.data_size);
|
if (!vgmstream->codec_data) goto fail;
|
||||||
if ( !ffmpeg_data ) goto fail;
|
|
||||||
vgmstream->codec_data = ffmpeg_data;
|
|
||||||
vgmstream->coding_type = coding_FFmpeg;
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
|
/* seek table seems BE dpds */
|
||||||
/* manually find total samples, why don't they put this in the header is beyond me */
|
vgmstream->num_samples = xwma_dpds_get_samples(sf, ww.seek_offset, ww.seek_size, ww.channels, ww.big_endian);
|
||||||
{
|
|
||||||
ms_sample_data msd = {0};
|
|
||||||
|
|
||||||
msd.channels = ww.channels;
|
|
||||||
msd.data_offset = ww.data_offset;
|
|
||||||
msd.data_size = ww.data_size;
|
|
||||||
|
|
||||||
if (ww.format == 0x0162)
|
|
||||||
wmapro_get_samples(&msd, sf, ww.block_align, ww.sample_rate, 0x00E0);
|
|
||||||
else
|
|
||||||
wma_get_samples(&msd, sf, ww.block_align, ww.sample_rate, 0x001F);
|
|
||||||
|
|
||||||
vgmstream->num_samples = msd.num_samples;
|
|
||||||
if (!vgmstream->num_samples)
|
if (!vgmstream->num_samples)
|
||||||
vgmstream->num_samples = ffmpeg_get_samples(ffmpeg_data); /* very wrong, from avg-br */
|
vgmstream->num_samples = xwma_get_samples(sf, ww.data_offset, ww.data_size, ww.format, ww.channels, ww.sample_rate, ww.block_size);
|
||||||
//num_samples seem to be found in the last "seek" table entry too, as: entry / channels / 2
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,7 +401,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
|||||||
ffmpeg_codec_data * ffmpeg_data = NULL;
|
ffmpeg_codec_data * ffmpeg_data = NULL;
|
||||||
|
|
||||||
if (ww.fmt_size != 0x24) goto fail;
|
if (ww.fmt_size != 0x24) goto fail;
|
||||||
if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail;
|
if (ww.block_size != 0 || ww.bits_per_sample != 0) goto fail;
|
||||||
|
|
||||||
/* extra: size 0x12, unknown values */
|
/* extra: size 0x12, unknown values */
|
||||||
|
|
||||||
@ -442,7 +420,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
|||||||
size_t seek_size;
|
size_t seek_size;
|
||||||
|
|
||||||
if (ww.fmt_size != 0x28) goto fail;
|
if (ww.fmt_size != 0x28) goto fail;
|
||||||
/* values up to 0x14 seem fixed and similar to HEVAG's (block_align 0x02/04, bits_per_sample 0x10) */
|
/* values up to 0x14 seem fixed and similar to HEVAG's (block_size 0x02/04, bits_per_sample 0x10) */
|
||||||
|
|
||||||
vgmstream->num_samples = read_s32(ww.fmt_offset + 0x18, sf);
|
vgmstream->num_samples = read_s32(ww.fmt_offset + 0x18, sf);
|
||||||
/* 0x1c: null?
|
/* 0x1c: null?
|
||||||
@ -476,7 +454,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case OPUS: { /* fully standard Ogg Opus [Girl Cafe Gun (Mobile), Gears 5 (PC)] */
|
case OPUS: { /* fully standard Ogg Opus [Girl Cafe Gun (Mobile), Gears 5 (PC)] */
|
||||||
if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail;
|
if (ww.block_size != 0 || ww.bits_per_sample != 0) goto fail;
|
||||||
|
|
||||||
/* extra: size 0x12 */
|
/* extra: size 0x12 */
|
||||||
vgmstream->num_samples = read_s32(ww.fmt_offset + 0x18, sf);
|
vgmstream->num_samples = read_s32(ww.fmt_offset + 0x18, sf);
|
||||||
@ -526,7 +504,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
|||||||
int mapping;
|
int mapping;
|
||||||
opus_config cfg = {0};
|
opus_config cfg = {0};
|
||||||
|
|
||||||
if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail;
|
if (ww.block_size != 0 || ww.bits_per_sample != 0) goto fail;
|
||||||
if (!ww.seek_offset) goto fail;
|
if (!ww.seek_offset) goto fail;
|
||||||
if (ww.channels > 8) goto fail; /* mapping not defined */
|
if (ww.channels > 8) goto fail; /* mapping not defined */
|
||||||
|
|
||||||
@ -596,7 +574,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
|||||||
|
|
||||||
case HEVAG: /* PSV */
|
case HEVAG: /* PSV */
|
||||||
/* changed values, another bizarre Wwise quirk */
|
/* changed values, another bizarre Wwise quirk */
|
||||||
//ww.block_align /* unknown (1ch=2, 2ch=4) */
|
//ww.block_size /* unknown (1ch=2, 2ch=4) */
|
||||||
//ww.bits_per_sample; /* unknown (0x10) */
|
//ww.bits_per_sample; /* unknown (0x10) */
|
||||||
//if (ww.bits_per_sample != 4) goto fail;
|
//if (ww.bits_per_sample != 4) goto fail;
|
||||||
|
|
||||||
@ -647,11 +625,11 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
|||||||
|
|
||||||
case PTADPCM: /* newer ADPCM [Bayonetta 2 (Switch), Genshin Impact (PC)] */
|
case PTADPCM: /* newer ADPCM [Bayonetta 2 (Switch), Genshin Impact (PC)] */
|
||||||
if (ww.bits_per_sample != 4) goto fail;
|
if (ww.bits_per_sample != 4) goto fail;
|
||||||
if (ww.block_align != 0x24 * ww.channels && ww.block_align != 0x104 * ww.channels) goto fail;
|
if (ww.block_size != 0x24 * ww.channels && ww.block_size != 0x104 * ww.channels) goto fail;
|
||||||
|
|
||||||
vgmstream->coding_type = coding_PTADPCM;
|
vgmstream->coding_type = coding_PTADPCM;
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = ww.block_align / ww.channels;
|
vgmstream->interleave_block_size = ww.block_size / ww.channels;
|
||||||
//vgmstream->codec_endian = ww.big_endian; //?
|
//vgmstream->codec_endian = ww.big_endian; //?
|
||||||
|
|
||||||
if (ww.truncated) {
|
if (ww.truncated) {
|
||||||
@ -827,8 +805,8 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
|
|||||||
ww->format = read_u16(ww->fmt_offset + 0x00,sf);
|
ww->format = read_u16(ww->fmt_offset + 0x00,sf);
|
||||||
ww->channels = read_u16(ww->fmt_offset + 0x02,sf);
|
ww->channels = read_u16(ww->fmt_offset + 0x02,sf);
|
||||||
ww->sample_rate = read_u32(ww->fmt_offset + 0x04,sf);
|
ww->sample_rate = read_u32(ww->fmt_offset + 0x04,sf);
|
||||||
ww->average_bps = read_u32(ww->fmt_offset + 0x08,sf);
|
ww->avg_bitrate = read_u32(ww->fmt_offset + 0x08,sf);
|
||||||
ww->block_align = read_u16(ww->fmt_offset + 0x0c,sf);
|
ww->block_size = read_u16(ww->fmt_offset + 0x0c,sf);
|
||||||
ww->bits_per_sample = read_u16(ww->fmt_offset + 0x0e,sf);
|
ww->bits_per_sample = read_u16(ww->fmt_offset + 0x0e,sf);
|
||||||
if (ww->fmt_size > 0x10 && ww->format != 0x0165 && ww->format != 0x0166) /* ignore XMAWAVEFORMAT */
|
if (ww->fmt_size > 0x10 && ww->format != 0x0165 && ww->format != 0x0166) /* ignore XMAWAVEFORMAT */
|
||||||
ww->extra_size = read_u16(ww->fmt_offset + 0x10,sf);
|
ww->extra_size = read_u16(ww->fmt_offset + 0x10,sf);
|
||||||
@ -900,7 +878,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
|
|||||||
/* few older Wwise DSP with num_samples in extra_size [Tony Hawk: Shred (Wii)] */
|
/* few older Wwise DSP with num_samples in extra_size [Tony Hawk: Shred (Wii)] */
|
||||||
ww->codec = DSP;
|
ww->codec = DSP;
|
||||||
}
|
}
|
||||||
else if (ww->block_align == 0x104 * ww->channels) {
|
else if (ww->block_size == 0x104 * ww->channels) {
|
||||||
/* Bayonetta 2 (Switch) */
|
/* Bayonetta 2 (Switch) */
|
||||||
ww->codec = PTADPCM;
|
ww->codec = PTADPCM;
|
||||||
}
|
}
|
||||||
|
116
src/meta/xwma.c
116
src/meta/xwma.c
@ -1,79 +1,101 @@
|
|||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
|
#include "../util/chunks.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t data_offset;
|
||||||
|
uint32_t data_size;
|
||||||
|
uint32_t dpds_offset;
|
||||||
|
uint32_t dpds_size;
|
||||||
|
|
||||||
|
int loop_flag;
|
||||||
|
|
||||||
|
int format;
|
||||||
|
int channels;
|
||||||
|
int sample_rate;
|
||||||
|
int bytes;
|
||||||
|
int avg_bitrate;
|
||||||
|
int block_size;
|
||||||
|
} xwma_header_t;
|
||||||
|
|
||||||
|
|
||||||
/* XWMA - Microsoft WMA container [The Elder Scrolls: Skyrim (PC/X360), Hydrophobia (PC)] */
|
/* XWMA - Microsoft WMA container [The Elder Scrolls: Skyrim (PC/X360), Hydrophobia (PC)] */
|
||||||
VGMSTREAM * init_vgmstream_xwma(STREAMFILE *streamFile) {
|
VGMSTREAM* init_vgmstream_xwma(STREAMFILE* sf) {
|
||||||
VGMSTREAM* vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
off_t fmt_offset, data_offset, first_offset = 0xc;
|
xwma_header_t xwma = {0};
|
||||||
size_t fmt_size, data_size;
|
|
||||||
int loop_flag, channel_count;
|
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
|
if (!is_id32be(0x00,sf, "RIFF"))
|
||||||
|
goto fail;
|
||||||
|
if (!is_id32be(0x08,sf, "XWMA"))
|
||||||
|
goto fail;
|
||||||
/* .xwma: standard
|
/* .xwma: standard
|
||||||
* .xwm: The Elder Scrolls: Skyrim (PC), Blade Arcus from Shining (PC) */
|
* .xwm: The Elder Scrolls: Skyrim (PC), Blade Arcus from Shining (PC) */
|
||||||
if (!check_extensions(streamFile, "xwma,xwm"))
|
if (!check_extensions(sf, "xwma,xwm"))
|
||||||
goto fail;
|
|
||||||
if (read_32bitBE(0x00,streamFile) != 0x52494646) /* "RIFF" */
|
|
||||||
goto fail;
|
|
||||||
if (read_32bitBE(0x08,streamFile) != 0x58574D41) /* "XWMA" */
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if ( !find_chunk_le(streamFile, 0x666d7420,first_offset,0, &fmt_offset,&fmt_size) ) /* "fmt "*/
|
{
|
||||||
goto fail;
|
enum {
|
||||||
if ( !find_chunk_le(streamFile, 0x64617461,first_offset,0, &data_offset,&data_size) ) /* "data"*/
|
CHUNK_fmt = 0x666d7420, /* "fmt " */
|
||||||
goto fail;
|
CHUNK_data = 0x64617461, /* "data" */
|
||||||
|
CHUNK_dpds = 0x64706473, /* "dpds" */
|
||||||
|
};
|
||||||
|
chunk_t rc = {0};
|
||||||
|
|
||||||
channel_count = read_16bitLE(fmt_offset+0x02,streamFile);
|
rc.current = 0x0c;
|
||||||
loop_flag = 0;
|
while (next_chunk(&rc, sf)) {
|
||||||
|
switch(rc.type) {
|
||||||
|
case CHUNK_fmt:
|
||||||
|
xwma.format = read_u16le(rc.offset+0x00, sf);
|
||||||
|
xwma.channels = read_u16le(rc.offset+0x02, sf);
|
||||||
|
xwma.sample_rate = read_u32le(rc.offset+0x04, sf);
|
||||||
|
xwma.avg_bitrate = read_u32le(rc.offset+0x08, sf);
|
||||||
|
xwma.block_size = read_u16le(rc.offset+0x0c, sf);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHUNK_data:
|
||||||
|
xwma.data_offset = rc.offset;
|
||||||
|
xwma.data_size = rc.size;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHUNK_dpds:
|
||||||
|
xwma.dpds_offset = rc.offset;
|
||||||
|
xwma.dpds_size = rc.size;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!xwma.format || !xwma.data_offset)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
vgmstream = allocate_vgmstream(xwma.channels, xwma.loop_flag);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
vgmstream->sample_rate = read_32bitLE(fmt_offset+0x04, streamFile);
|
|
||||||
vgmstream->meta_type = meta_XWMA;
|
vgmstream->meta_type = meta_XWMA;
|
||||||
|
vgmstream->sample_rate = xwma.sample_rate;
|
||||||
|
|
||||||
/* the main purpose of this meta is redoing the XWMA header to:
|
/* the main purpose of this meta is redoing the XWMA header to:
|
||||||
* - redo header to fix XWMA with buggy bit rates so FFmpeg can play them ok
|
* - fix XWMA with buggy bit rates so FFmpeg can play them ok
|
||||||
* - skip seek table to fix FFmpeg buggy XWMA seeking (see init_seek)
|
* - remove seek table to fix FFmpeg buggy XWMA seeking (see init_seek)
|
||||||
* - read num_samples correctly
|
* - read num_samples correctly
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
{
|
{
|
||||||
uint8_t buf[0x100];
|
vgmstream->codec_data = init_ffmpeg_xwma(sf, xwma.data_offset, xwma.data_size, xwma.format, xwma.channels, xwma.sample_rate, xwma.avg_bitrate, xwma.block_size);
|
||||||
int bytes, avg_bps, block_align, wma_codec;
|
|
||||||
|
|
||||||
avg_bps = read_32bitLE(fmt_offset+0x08, streamFile);
|
|
||||||
block_align = (uint16_t)read_16bitLE(fmt_offset+0x0c, streamFile);
|
|
||||||
wma_codec = (uint16_t)read_16bitLE(fmt_offset+0x00, streamFile);
|
|
||||||
|
|
||||||
bytes = ffmpeg_make_riff_xwma(buf,0x100, wma_codec, data_size, vgmstream->channels, vgmstream->sample_rate, avg_bps, block_align);
|
|
||||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, data_offset,data_size);
|
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
vgmstream->coding_type = coding_FFmpeg;
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
/* manually find total samples, why don't they put this in the header is beyond me */
|
/* try from (optional) seek table, or (less accurate) manual count */
|
||||||
{
|
vgmstream->num_samples = xwma_dpds_get_samples(sf, xwma.dpds_offset, xwma.dpds_size, xwma.channels, 0);
|
||||||
ms_sample_data msd = {0};
|
if (!vgmstream->num_samples)
|
||||||
|
vgmstream->num_samples = xwma_get_samples(sf, xwma.data_offset, xwma.data_size, xwma.format, xwma.channels, xwma.sample_rate, xwma.block_size);
|
||||||
msd.channels = vgmstream->channels;
|
|
||||||
msd.data_offset = data_offset;
|
|
||||||
msd.data_size = data_size;
|
|
||||||
|
|
||||||
if (wma_codec == 0x0162)
|
|
||||||
wmapro_get_samples(&msd, streamFile, block_align, vgmstream->sample_rate,0x00E0);
|
|
||||||
else
|
|
||||||
wma_get_samples(&msd, streamFile, block_align, vgmstream->sample_rate,0x001F);
|
|
||||||
|
|
||||||
vgmstream->num_samples = msd.num_samples;
|
|
||||||
if (vgmstream->num_samples == 0)
|
|
||||||
vgmstream->num_samples = ffmpeg_get_samples(vgmstream->codec_data); /* from avg-br */
|
|
||||||
//num_samples seem to be found in the last "seek" table entry too, as: entry / channels / 2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
goto fail;
|
goto fail;
|
||||||
|
Loading…
Reference in New Issue
Block a user