Merge pull request #83 from bnnm/adx-misc

ADX, old Worvis, misc
This commit is contained in:
Christopher Snowhill 2017-04-15 19:50:59 -07:00 committed by GitHub
commit e14eb7eecc
17 changed files with 210 additions and 292 deletions

View File

@ -26,7 +26,7 @@ CODING_OBJS=coding/adx_decoder.o \
coding/g719_decoder.o \
coding/hca_decoder.o \
coding/ffmpeg_decoder.o \
coding/ffmpeg_decoder_utils.o \
coding/coding_utils.o \
coding/fsb_vorbis_decoder.o \
coding/wwise_vorbis_decoder.o \
coding/wwise_vorbis_utils.o
@ -64,7 +64,7 @@ LAYOUT_OBJS=layout/ast_blocked.o \
layout/ps2_strlr_blocked.o \
layout/scd_int_layout.o
META_OBJS=meta/adx_header.o \
META_OBJS=meta/adx.o \
meta/afc_header.o \
meta/agsc.o \
meta/ast.o \

View File

@ -176,22 +176,22 @@ void decode_mp4_aac(mp4_aac_codec_data * data, sample * outbuf, int32_t samples_
void decode_at3plus(VGMSTREAM *vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel);
#endif
#ifdef VGM_USE_FFMPEG
/* ffmpeg_decoder */
#ifdef VGM_USE_FFMPEG
void decode_ffmpeg(VGMSTREAM *stream, sample * outbuf, int32_t samples_to_do, int channels);
void reset_ffmpeg(VGMSTREAM *vgmstream);
void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample);
void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples);
#endif
/* ffmpeg_decoder_utils */
/* coding_utils */
int ffmpeg_fmt_chunk_swap_endian(uint8_t * chunk, size_t chunk_size, uint16_t codec);
int ffmpeg_make_riff_atrac3(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int joint_stereo, int encoder_delay);
int ffmpeg_make_riff_atrac3plus(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int encoder_delay);
int ffmpeg_make_riff_xma1(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int stream_mode);
int ffmpeg_make_riff_xma2(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_count, int block_size);
int ffmpeg_make_riff_xma_from_fmt(uint8_t * buf, size_t buf_size, off_t fmt_offset, size_t fmt_size, size_t data_size, STREAMFILE *streamFile, int big_endian);
int ffmpeg_make_riff_xma_from_fmt_chunk(uint8_t * buf, size_t buf_size, off_t fmt_offset, size_t fmt_size, size_t data_size, STREAMFILE *streamFile, int big_endian);
int ffmpeg_make_riff_xma2_from_xma2_chunk(uint8_t * buf, size_t buf_size, off_t xma2_offset, size_t xma2_size, size_t data_size, STREAMFILE *streamFile);
int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t data_size, int channels, int sample_rate, int avg_bps, int block_align);
@ -215,9 +215,9 @@ typedef struct {
int32_t skip_samples;
int32_t loop_start_sample;
int32_t loop_end_sample;
} xma_sample_data; /* ms_sample_data */
void xma_get_samples(xma_sample_data * msd, STREAMFILE *streamFile);
void wmapro_get_samples(xma_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags);
} ms_sample_data;
void xma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile);
void wmapro_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags);
void xma1_parse_fmt_chunk(STREAMFILE *streamFile, 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 *streamFile, off_t chunk_offset, int * loop_flag, int32_t * num_samples, int32_t * loop_start_sample, int32_t * loop_end_sample, int be);
@ -226,6 +226,5 @@ void xma2_parse_xma2_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * cha
size_t atrac3_bytes_to_samples(size_t bytes, int full_block_align);
size_t atrac3plus_bytes_to_samples(size_t bytes, int full_block_align);
#endif
#endif /*_CODING_H*/

View File

@ -2,7 +2,14 @@
#include "math.h"
#include "../vgmstream.h"
#ifdef VGM_USE_FFMPEG
/**
* Various utils for formats that aren't handled their own decoder or meta
*
* ffmpeg_make_riff_* utils don't depend on FFmpeg, but rather, they make headers that FFmpeg
* can use (it doesn't understand all valid RIFF headers, nor the utils make 100% correct headers).
*/
/* ******************************************** */
/* INTERNAL UTILS */
@ -254,7 +261,7 @@ int ffmpeg_make_riff_xma2(uint8_t * buf, size_t buf_size, size_t sample_count, s
/* Makes a XMA1/2 RIFF header for FFmpeg using a "fmt " chunk (XMAWAVEFORMAT or XMA2WAVEFORMATEX) as a base:
* Useful to preserve the stream layout */
int ffmpeg_make_riff_xma_from_fmt(uint8_t * buf, size_t buf_size, off_t fmt_offset, size_t fmt_size, size_t data_size, STREAMFILE *streamFile, int big_endian) {
int ffmpeg_make_riff_xma_from_fmt_chunk(uint8_t * buf, size_t buf_size, off_t fmt_offset, size_t fmt_size, size_t data_size, STREAMFILE *streamFile, int big_endian) {
size_t riff_size = 4+4+ 4 + 4+4+fmt_size + 4+4;
uint8_t chunk[0x100];
@ -425,7 +432,7 @@ fail:
* The stream is made of packets, each containing N small frames of X samples. Frames are further divided into subframes.
* XMA1/XMA2/WMAPRO only differ in the packet headers.
*/
static void ms_audio_get_samples(xma_sample_data * msd, STREAMFILE *streamFile, int bytes_per_packet, int samples_per_frame, int samples_per_subframe, int bits_frame_size) {
static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int bytes_per_packet, int samples_per_frame, int samples_per_subframe, int bits_frame_size) {
int frames = 0, samples = 0, loop_start_frame = 0, loop_end_frame = 0, skip_packets;
#if XMA_CHECK_SKIPS
int start_skip = 0, end_skip = 0, first_start_skip = 0, last_end_skip = 0;
@ -619,14 +626,14 @@ static void ms_audio_get_samples(xma_sample_data * msd, STREAMFILE *streamFile,
}
}
void xma_get_samples(xma_sample_data * msd, STREAMFILE *streamFile) {
void xma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile) {
const int bytes_per_packet = 2048;
const int samples_per_frame = 512;
const int samples_per_subframe = 128;
ms_audio_get_samples(msd, streamFile, bytes_per_packet, samples_per_frame, samples_per_subframe, 15);
}
void wmapro_get_samples(xma_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags) {
void wmapro_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags) {
int bytes_per_packet = block_align;
int samples_per_frame = 0;
int samples_per_subframe = 0;
@ -768,5 +775,3 @@ size_t atrac3plus_bytes_to_samples(size_t bytes, int full_block_align) {
* so (full_block_align / channels) DOESN'T give the size of a single channel (common in ATRAC3plus) */
return (bytes / full_block_align) * 2048;
}
#endif

View File

@ -1,12 +1,11 @@
#include "coding.h"
#include <math.h>
#ifdef VGM_USE_VORBIS
#include <vorbis/codec.h>
#define FSB_VORBIS_ON 1 //todo remove once battle-tested
#define FSB_VORBIS_USE_PRECOMPILED_FVS 1 /* if enabled vgmstream weights ~600kb more but doesn't need external .fvs packets */
#if FSB_VORBIS_ON
#if FSB_VORBIS_USE_PRECOMPILED_FVS
#include "fsb_vorbis_data.h"
#endif
@ -21,7 +20,6 @@ static int vorbis_make_header_setup(uint8_t * buf, size_t bufsize, uint32_t setu
static int load_fvs_file_single(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile);
static int load_fvs_file_multi(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile);
static int load_fvs_array(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile);
#endif
/**
* Inits a raw FSB vorbis stream.
@ -37,7 +35,6 @@ static int load_fvs_array(uint8_t * buf, size_t bufsize, uint32_t setup_id, STRE
* Also from the official docs (https://www.xiph.org/vorbis/doc/libvorbis/overview.html).
*/
vorbis_codec_data * init_fsb_vorbis_codec_data(STREAMFILE *streamfile, off_t start_offset, int channels, int sample_rate, uint32_t setup_id) {
#if FSB_VORBIS_ON
vorbis_codec_data * data = NULL;
/* init stuff */
@ -80,7 +77,6 @@ vorbis_codec_data * init_fsb_vorbis_codec_data(STREAMFILE *streamfile, off_t sta
fail:
free_fsb_vorbis(data);
#endif
return NULL;
}
@ -88,7 +84,6 @@ fail:
* Decodes raw FSB vorbis
*/
void decode_fsb_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels) {
#if FSB_VORBIS_ON
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0];
vorbis_codec_data * data = vgmstream->codec_data;
size_t stream_size = get_streamfile_size(stream->streamfile);
@ -177,10 +172,8 @@ void decode_fsb_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_t
decode_fail:
/* on error just put some 0 samples */
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample));
#endif
}
#if FSB_VORBIS_ON
static void pcm_convert_float_to_16(vorbis_codec_data * data, sample * outbuf, int samples_to_do, float ** pcm) {
/* mostly from Xiph's decoder_example.c */
@ -391,12 +384,9 @@ fail:
return 0;
}
#endif
/* ********************************************** */
void free_fsb_vorbis(vorbis_codec_data * data) {
#if FSB_VORBIS_ON
if (!data)
return;
@ -407,22 +397,18 @@ void free_fsb_vorbis(vorbis_codec_data * data) {
free(data->buffer);
free(data);
#endif
}
void reset_fsb_vorbis(VGMSTREAM *vgmstream) {
#if FSB_VORBIS_ON
vorbis_codec_data *data = vgmstream->codec_data;
/* Seeking is provided by the Ogg layer, so with raw vorbis we need seek tables instead.
* To avoid having to parse different formats we'll just discard until the expected sample */
vorbis_synthesis_restart(&data->vd);
data->samples_to_discard = 0;
#endif
}
void seek_fsb_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) {
#if FSB_VORBIS_ON
vorbis_codec_data *data = vgmstream->codec_data;
/* Seeking is provided by the Ogg layer, so with raw vorbis we need seek tables instead.
@ -431,7 +417,6 @@ void seek_fsb_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) {
data->samples_to_discard = num_sample;
if (vgmstream->loop_ch)
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset;
#endif
}
#endif

View File

@ -1,10 +1,10 @@
#include "coding.h"
#include <math.h>
#ifdef VGM_USE_VORBIS
#include <vorbis/codec.h>
#define WWISE_VORBIS_ON 1 //todo remove once battle-tested
#if WWISE_VORBIS_ON
#define WWISE_VORBIS_ON 0 //todo remove once battle-tested
#include "wwise_vorbis_utils.h"
@ -13,7 +13,6 @@
static void pcm_convert_float_to_16(vorbis_codec_data * data, sample * outbuf, int samples_to_do, float ** pcm);
static int vorbis_make_header_identification(uint8_t * buf, size_t bufsize, int channels, int sample_rate, int blocksize_short, int blocksize_long);
static int vorbis_make_header_comment(uint8_t * buf, size_t bufsize);
#endif
/**
* Inits a raw Wwise vorbis stream.
@ -31,7 +30,6 @@ static int vorbis_make_header_comment(uint8_t * buf, size_t bufsize);
*/
vorbis_codec_data * init_wwise_vorbis_codec_data(STREAMFILE *streamFile, off_t start_offset, int channels, int sample_rate, int blocksize_0_exp, int blocksize_1_exp,
wwise_setup_type setup_type, wwise_header_type header_type, wwise_packet_type packet_type, int big_endian) {
#if WWISE_VORBIS_ON
vorbis_codec_data * data = NULL;
size_t header_size, packet_size;
@ -62,20 +60,21 @@ vorbis_codec_data * init_wwise_vorbis_codec_data(STREAMFILE *streamFile, off_t s
/* normal identificacion packet */
header_size = wwise_vorbis_get_header(streamFile, offset, data->header_type, (int*)&data->op.granulepos, &packet_size, big_endian);
if (!header_size || packet_size > data->buffer_size) goto fail;
if (read_streamfile(data->buffer,offset+header_size,packet_size, streamFile)!=packet_size) goto fail;
data->op.bytes = read_streamfile(data->buffer,offset+header_size,packet_size, streamFile);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse identification header */
offset += header_size + packet_size;
/* normal comment packet */
header_size = wwise_vorbis_get_header(streamFile, offset, data->header_type, (int*)&data->op.granulepos, &packet_size, big_endian);
if (!header_size || packet_size > data->buffer_size) goto fail;
if (read_streamfile(data->buffer,offset+header_size,packet_size, streamFile)!=packet_size) goto fail;
data->op.bytes = read_streamfile(data->buffer,offset+header_size,packet_size, streamFile);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) !=0 ) goto fail; /* parse comment header */
offset += header_size + packet_size;
/* modified setup packet */ //todo doesn't seem needed, may be copied as -is
/* normal setup packet */
header_size = wwise_vorbis_get_header(streamFile, offset, data->header_type, (int*)&data->op.granulepos, &packet_size, big_endian);
data->op.bytes = wwise_vorbis_rebuild_setup(data->buffer, data->buffer_size, streamFile, offset, data, big_endian, channels);
if (!header_size || packet_size > data->buffer_size) goto fail;
data->op.bytes = read_streamfile(data->buffer,offset+header_size,packet_size, streamFile);
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse setup header */
offset += header_size + packet_size;
}
@ -110,7 +109,6 @@ vorbis_codec_data * init_wwise_vorbis_codec_data(STREAMFILE *streamFile, off_t s
fail:
free_wwise_vorbis(data);
#endif
return NULL;
}
@ -118,7 +116,6 @@ fail:
* Decodes raw Wwise Vorbis
*/
void decode_wwise_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels) {
#if WWISE_VORBIS_ON
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0];
vorbis_codec_data * data = vgmstream->codec_data;
size_t stream_size = get_streamfile_size(stream->streamfile);
@ -210,10 +207,9 @@ void decode_wwise_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples
decode_fail:
/* on error just put some 0 samples */
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample));
#endif
}
#if WWISE_VORBIS_ON
/* *************************************************** */
static void pcm_convert_float_to_16(vorbis_codec_data * data, sample * outbuf, int samples_to_do, float ** pcm) {
/* mostly from Xiph's decoder_example.c */
@ -235,8 +231,6 @@ static void pcm_convert_float_to_16(vorbis_codec_data * data, sample * outbuf, i
}
}
/* *************************************************** */
static int vorbis_make_header_identification(uint8_t * buf, size_t bufsize, int channels, int sample_rate, int blocksize_0_exp, int blocksize_1_exp) {
int bytes = 0x1e;
uint8_t blocksizes;
@ -274,12 +268,9 @@ static int vorbis_make_header_comment(uint8_t * buf, size_t bufsize) {
return bytes;
}
#endif
/* *************************************** */
void free_wwise_vorbis(vorbis_codec_data * data) {
#if WWISE_VORBIS_ON
if (!data)
return;
@ -290,22 +281,18 @@ void free_wwise_vorbis(vorbis_codec_data * data) {
free(data->buffer);
free(data);
#endif
}
void reset_wwise_vorbis(VGMSTREAM *vgmstream) {
#if WWISE_VORBIS_ON
vorbis_codec_data *data = vgmstream->codec_data;
/* Seeking is provided by the Ogg layer, so with raw vorbis we need seek tables instead.
* To avoid having to parse different formats we'll just discard until the expected sample */
vorbis_synthesis_restart(&data->vd);
data->samples_to_discard = 0;
#endif
}
void seek_wwise_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) {
#if WWISE_VORBIS_ON
vorbis_codec_data *data = vgmstream->codec_data;
/* Seeking is provided by the Ogg layer, so with raw vorbis we need seek tables instead.
@ -314,7 +301,6 @@ void seek_wwise_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) {
data->samples_to_discard = num_sample;
if (vgmstream->loop_ch) /* this func is only using for looping though */
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset;
#endif
}
#endif

View File

@ -20,7 +20,6 @@ typedef struct {
} ww_stream;
static int generate_vorbis_packet(ww_stream * ow, ww_stream * iw, STREAMFILE *streamFile, off_t offset, vorbis_codec_data * data, int big_endian);
static int generate_vorbis_setup_from_triad(ww_stream * ow, ww_stream * iw, vorbis_codec_data * data, int channels, size_t packet_size, STREAMFILE *streamFile);
static int generate_vorbis_setup(ww_stream * ow, ww_stream * iw, vorbis_codec_data * data, int channels, size_t packet_size, STREAMFILE *streamFile);
static int codebook_library_copy(ww_stream * ow, ww_stream * iw);
@ -136,11 +135,7 @@ int wwise_vorbis_rebuild_setup(uint8_t * obuf, size_t obufsize, STREAMFILE *stre
iw.bufsize = ibufsize;
iw.b_off = 0;
if (data->setup_type == HEADER_TRIAD) {
rc = generate_vorbis_setup_from_triad(&ow,&iw, data, channels, packet_size, streamFile);
} else {
rc = generate_vorbis_setup(&ow,&iw, data, channels, packet_size, streamFile);
}
rc = generate_vorbis_setup(&ow,&iw, data, channels, packet_size, streamFile);
if (!rc) goto fail;
if (ow.b_off % 8 != 0) {
@ -280,58 +275,6 @@ fail:
}
/* Parse a partially modified Wwise setup packet.
* (ref: https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-650004.2.4) */
static int generate_vorbis_setup_from_triad(ww_stream * ow, ww_stream * iw, vorbis_codec_data * data, int channels, size_t packet_size, STREAMFILE *streamFile) {
int i;
uint32_t c = 0;
/* other packets from the triad should be memcpy'ed externally as they are untouched */
/* type */
r_bits(iw, 8,&c);
w_bits(ow, 8, c);
/* 'vorbis' */
for (i = 0; i < 6; i++) {
r_bits(iw, 8,&c);
w_bits(iw, 8, c);
}
/* codebook count */
{
uint32_t codebook_count_less1 = 0, codebook_count = 0;
r_bits(iw, 8,&codebook_count_less1);
w_bits(iw, 8, codebook_count_less1);
codebook_count = codebook_count_less1 + 1;
/* rebuild codebooks */
for (i = 0; i < codebook_count; i++) {
if(!codebook_library_copy(ow, iw)) goto fail;
}
}
/* rest of setup is untouched, copy bits */
{
uint32_t bitly = 0;
uint32_t total_bits_read = iw->b_off;
uint32_t setup_packet_size_bits = packet_size*8;
while (total_bits_read < setup_packet_size_bits) {
r_bits(iw, 1,&bitly);
w_bits(ow, 1, bitly);
total_bits_read = iw->b_off;
}
}
return 1;
fail:
return 0;
}
/* Rebuild a Wwise setup (simplified with removed stuff), recreating all six setup parts.
* (ref: https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-650004.2.4) */
static int generate_vorbis_setup(ww_stream * ow, ww_stream * iw, vorbis_codec_data * data, int channels, size_t packet_size, STREAMFILE *streamFile) {

View File

@ -221,7 +221,7 @@
>
</File>
<File
RelativePath=".\meta\adx_header.c"
RelativePath=".\meta\adx.c"
>
</File>
<File
@ -1270,6 +1270,10 @@
RelativePath=".\coding\aica_decoder.c"
>
</File>
<File
RelativePath=".\coding\coding_utils.c"
>
</File>
<File
RelativePath=".\coding\eaxa_decoder.c"
>
@ -1278,10 +1282,6 @@
RelativePath=".\coding\ffmpeg_decoder.c"
>
</File>
<File
RelativePath=".\coding\ffmpeg_decoder_utils.c"
>
</File>
<File
RelativePath=".\coding\fsb_vorbis_decoder.c"
>

View File

@ -124,8 +124,8 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="coding\at3_decoder.c" />
<ClCompile Include="coding\coding_utils.c" />
<ClCompile Include="coding\ffmpeg_decoder.c" />
<ClCompile Include="coding\ffmpeg_decoder_utils.c" />
<ClCompile Include="coding\lsf_decoder.c" />
<ClCompile Include="coding\mp4_aac_decoder.c" />
<ClCompile Include="coding\mtaf_decoder.c" />
@ -178,7 +178,7 @@
<ClCompile Include="meta\aax.c" />
<ClCompile Include="meta\acm.c" />
<ClCompile Include="meta\ads.c" />
<ClCompile Include="meta\adx_header.c" />
<ClCompile Include="meta\adx.c" />
<ClCompile Include="meta\afc_header.c" />
<ClCompile Include="meta\agsc.c" />
<ClCompile Include="meta\ahx.c" />

View File

@ -112,7 +112,7 @@
<ClCompile Include="meta\ads.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\adx_header.c">
<ClCompile Include="meta\adx.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\afc_header.c">
@ -1039,7 +1039,7 @@
<ClCompile Include="coding\ffmpeg_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\ffmpeg_decoder_utils.c">
<ClCompile Include="coding\coding_utils.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\xma.c">

View File

@ -6,7 +6,7 @@ AM_MAKEFLAGS=-f Makefile.unix
libmeta_la_LDFLAGS =
libmeta_la_SOURCES =
libmeta_la_SOURCES += Cstr.c
libmeta_la_SOURCES += adx_header.c
libmeta_la_SOURCES += adx.c
libmeta_la_SOURCES += afc_header.c
libmeta_la_SOURCES += agsc.c
libmeta_la_SOURCES += ast.c

View File

@ -11,138 +11,146 @@
static int find_key(STREAMFILE *file, uint8_t type, uint16_t *xor_start, uint16_t *xor_mult, uint16_t *xor_add);
/* ADX - CRI Middleware format */
VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t stream_offset;
off_t start_offset, hist_offset = 0;
int loop_flag = 0, channel_count;
int32_t loop_start_sample = 0, loop_end_sample = 0;
uint16_t version_signature;
int loop_flag=0;
int channel_count;
int32_t loop_start_sample=0;
int32_t loop_end_sample=0;
meta_t header_type;
coding_t coding_type = coding_CRI_ADX;
int16_t coef1, coef2;
uint16_t cutoff;
char filename[PATH_LIMIT];
int coding_type = coding_CRI_ADX;
uint16_t xor_start=0,xor_mult=0,xor_add=0;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("adx",filename_extension(filename))) goto fail;
if (!check_extensions(streamFile,"adx")) goto fail;
/* check first 2 bytes */
if ((uint16_t)read_16bitBE(0,streamFile)!=0x8000) goto fail;
if ((uint16_t)read_16bitBE(0x00,streamFile)!=0x8000) goto fail;
/* get stream offset, check for CRI signature just before */
stream_offset = (uint16_t)read_16bitBE(2,streamFile) + 4;
if ((uint16_t)read_16bitBE(stream_offset-6,streamFile)!=0x2863 ||/* "(c" */
(uint32_t)read_32bitBE(stream_offset-4,streamFile)!=0x29435249 /* ")CRI" */
start_offset = (uint16_t)read_16bitBE(0x02,streamFile) + 4;
if ((uint16_t)read_16bitBE(start_offset-6,streamFile)!=0x2863 || /* "(c" */
(uint32_t)read_32bitBE(start_offset-4,streamFile)!=0x29435249 /* ")CRI" */
) goto fail;
/* check for encoding type */
/* 2 is for some unknown fixed filter, 3 is standard ADX, 4 is
* ADX with exponential scale, 0x11 is AHX */
if (read_8bit(4,streamFile) != 3) goto fail;
/* 0x02 is for some unknown fixed filter, 0x03 is standard ADX, 0x04 is
* ADX with exponential scale, 0x10 is AHX for DC, 0x11 is AHX */
if (read_8bit(0x04,streamFile) != 3) goto fail;
/* check for frame size (only 18 is supported at the moment) */
if (read_8bit(5,streamFile) != 18) goto fail;
if (read_8bit(0x05,streamFile) != 18) goto fail;
/* check for bits per sample? (only 4 makes sense for ADX) */
if (read_8bit(6,streamFile) != 4) goto fail;
if (read_8bit(0x06,streamFile) != 4) goto fail;
/* older ADX (adxencd) up to 2ch, newer ADX (criatomencd) up to 8 */
channel_count = read_8bit(0x07,streamFile);
/* check version signature, read loop info */
version_signature = read_16bitBE(0x12,streamFile);
/* encryption */
if (version_signature == 0x0408) {
if (find_key(streamFile, 8, &xor_start, &xor_mult, &xor_add))
{
if (find_key(streamFile, 8, &xor_start, &xor_mult, &xor_add)) {
coding_type = coding_CRI_ADX_enc_8;
version_signature = 0x0400;
}
}
else if (version_signature == 0x0409) {
if (find_key(streamFile, 9, &xor_start, &xor_mult, &xor_add))
{
if (find_key(streamFile, 9, &xor_start, &xor_mult, &xor_add)) {
coding_type = coding_CRI_ADX_enc_9;
version_signature = 0x0400;
}
}
if (version_signature == 0x0300) { /* type 03 */
/* version + extra data */
if (version_signature == 0x0300) { /* early ADX (~2004?) */
size_t base_size = 0x14, loops_size = 0x18;
header_type = meta_ADX_03;
if (stream_offset-6 >= 0x2c) { /* enough space for loop info? */
loop_flag = (read_32bitBE(0x18,streamFile) != 0);
loop_start_sample = read_32bitBE(0x1c,streamFile);
//loop_start_offset = read_32bitBE(0x20,streamFile);
loop_end_sample = read_32bitBE(0x24,streamFile);
//loop_end_offset = read_32bitBE(0x28,streamFile);
/* no sample history */
if (start_offset - 6 >= base_size + loops_size) { /* enough space for loop info? */
off_t loops_offset = base_size;
/* off+0x00 (2): initial loop padding (the encoder adds a few blank samples so loop start is block-aligned; max 31)
* ex. loop_start=12: enc_start=32, padding=20 (32-20=12); loop_start=35: enc_start=64, padding=29 (64-29=35)
* off+0x02 (2): loop sample(?) flag (always 1) */
loop_flag = read_32bitBE(loops_offset+0x04,streamFile) != 0; /* loop offset(?) flag (always 1) */
loop_start_sample = read_32bitBE(loops_offset+0x08,streamFile);
//loop_start_offset = read_32bitBE(loops_offset+0x0c,streamFile);
loop_end_sample = read_32bitBE(loops_offset+0x10,streamFile);
//loop_end_offset = read_32bitBE(loops_offset+0x14,streamFile);
}
} else if (version_signature == 0x0400) {
off_t ainf_info_length=0;
if((uint32_t)read_32bitBE(0x24,streamFile)==0x41494E46) /* AINF Header */
ainf_info_length = (off_t)read_32bitBE(0x28,streamFile);
}
else if (version_signature == 0x0400) { /* common */
size_t base_size = 0x18, hist_size, ainf_size = 0, loops_size = 0x18;
off_t ainf_offset;
header_type = meta_ADX_04;
if (stream_offset-ainf_info_length-6 >= 0x38) { /* enough space for loop info? */
if (read_32bitBE(0x24,streamFile) == 0xFFFEFFFE)
loop_flag = 0;
else
loop_flag = (read_32bitBE(0x24,streamFile) != 0);
loop_start_sample = read_32bitBE(0x28,streamFile);
//loop_start_offset = read_32bitBE(0x2c,streamFile);
loop_end_sample = read_32bitBE(0x30,streamFile);
//loop_end_offset = read_32bitBE(0x34,streamFile);
hist_offset = base_size; /* always present but often blank */
hist_size = (channel_count > 1 ? 4*channel_count : 4+4); /* min is 8, even in 1ch files */
ainf_offset = base_size + hist_size + 0x4; /* not seen with >2ch though */
if ((uint32_t)read_32bitBE(ainf_offset+0x00,streamFile) == 0x41494E46) /* "AINF" */
ainf_size = read_32bitBE(ainf_offset+0x04,streamFile);
if (start_offset - ainf_size - 6 >= hist_offset + hist_size + loops_size) { /* enough space for loop info? */
off_t loops_offset = base_size + hist_size;
/* off+0x00 (2): initial loop padding (the encoder adds a few blank samples so loop start is block-aligned; max 31)
* ex. loop_start=12: enc_start=32, padding=20 (32-20=12); loop_start=35: enc_start=64, padding=29 (64-29=35)
* off+0x02 (2): loop sample(?) flag (always 1) */
loop_flag = read_32bitBE(loops_offset+0x04,streamFile) != 0; /* loop offset(?) flag (always 1) */
loop_start_sample = read_32bitBE(loops_offset+0x08,streamFile);
//loop_start_offset = read_32bitBE(loops_offset+0x0c,streamFile);
loop_end_sample = read_32bitBE(loops_offset+0x10,streamFile);
//loop_end_offset = read_32bitBE(loops_offset+0x14,streamFile);
}
/* AINF header can also start after the loop points
* (may be inserted by CRI's tools but is rarely used) */
/* ainf_magic = read_32bitBE(0x38,streamFile); */ /* 0x41494E46 */
/* ainf_length = read_32bitBE(0x3c,streamFile); */
/* ainf_str_id = read_string(0x40,streamFile); */ /* max size 0x10 */
/* ainf_volume = read_16bitBE(0x50,streamFile); */ /* 0=base/max?, negative=reduce */
/* ainf_pan_l = read_16bitBE(0x54,streamFile); */ /* 0=base, max +-128 */
/* ainf_pan_r = read_16bitBE(0x56,streamFile); */
} else if (version_signature == 0x0500) { /* found in some SFD : Buggy Heat, appears to have no loop */
/* AINF header info (may be inserted by CRI's tools but is rarely used)
* Can also start right after the loop points (base_size + hist_size + loops_size)
* 0x00 (4): "AINF"; 0x04 (4): size; 0x08 (10): str_id
* 0x18 (2): volume (0=base/max?, negative=reduce)
* 0x1c (2): pan l; 0x1e (2): pan r (0=base, max +-128) */
}
else if (version_signature == 0x0500) { /* found in some SFD: Buggy Heat, appears to have no loop */
header_type = meta_ADX_05;
} else goto fail; /* not a known/supported version signature */
/* At this point we almost certainly have an ADX file,
* so let's build the VGMSTREAM. */
/* high-pass cutoff frequency, always 500 that I've seen */
cutoff = (uint16_t)read_16bitBE(0x10,streamFile);
if (loop_start_sample == 0 && loop_end_sample == 0) {
loop_flag = 0;
}
else { /* not a known/supported version signature */
goto fail;
}
channel_count = read_8bit(7,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->num_samples = read_32bitBE(0xc,streamFile);
vgmstream->sample_rate = read_32bitBE(8,streamFile);
/* channels and loop flag are set by allocate_vgmstream */
vgmstream->sample_rate = read_32bitBE(0x8,streamFile);
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->coding_type = coding_type;
if (channel_count==1)
vgmstream->layout_type = layout_none;
else
vgmstream->layout_type = layout_interleave;
vgmstream->layout_type = channel_count==1 ? layout_none : layout_interleave;
vgmstream->interleave_block_size = 18;
vgmstream->meta_type = header_type;
vgmstream->interleave_block_size=18;
/* calculate filter coefficients */
{
double x,y,z,a,b,c;
/* high-pass cutoff frequency, always 500 that I've seen */
uint16_t cutoff = (uint16_t)read_16bitBE(0x10,streamFile);
x = cutoff;
y = vgmstream->sample_rate;
@ -156,27 +164,22 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
coef2 = floor(c*c*-4096);
}
/* init decoder */
{
int i;
STREAMFILE * chstreamfile;
/* ADX is so tightly interleaved that having two buffers is silly */
chstreamfile = streamFile->open(streamFile,filename,18*0x400);
if (!chstreamfile) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = chstreamfile;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=
stream_offset+18*i;
vgmstream->ch[i].adpcm_coef[0] = coef1;
vgmstream->ch[i].adpcm_coef[1] = coef2;
if (coding_type == coding_CRI_ADX_enc_8 ||
coding_type == coding_CRI_ADX_enc_9)
{
/* 2 hist shorts per ch, corresponding to the very first original sample repeated (verified with CRI's encoders).
* Not vital as their effect is small, after a few samples they don't matter, and most songs start in silence. */
if (hist_offset) {
vgmstream->ch[i].adpcm_history1_32 = read_16bitBE(hist_offset + i*4 + 0x00,streamFile);
vgmstream->ch[i].adpcm_history2_32 = read_16bitBE(hist_offset + i*4 + 0x02,streamFile);
}
if (coding_type == coding_CRI_ADX_enc_8 || coding_type == coding_CRI_ADX_enc_9) {
int j;
vgmstream->ch[i].adx_channels = channel_count;
vgmstream->ch[i].adx_xor = xor_start;
@ -189,11 +192,13 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
}
}
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
goto fail;
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}
@ -426,7 +431,7 @@ static struct {
};
/* type 9 keys */
/* type 9 keys (may not be autodetected correctly) */
static struct {
uint16_t start,mult,add;
} keys_9[] = {
@ -442,6 +447,10 @@ static struct {
* guessed with degod */
{0x0005,0x0bcd,0x1add},
/* Raramagi [Android]
* found in 2ch */
{0x0000,0x0b99,0x1e33},
};
static const int keys_8_count = sizeof(keys_8)/sizeof(keys_8[0]);

View File

@ -113,7 +113,7 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) {
if (!find_chunk_be(streamFileGSP, 0x584D4558,first_offset,1, &chunk_offset,NULL)) goto fail; /*"XMEX"*/
/* 0x00: fmt0x166 header (BE), 0x34: seek table */
bytes = ffmpeg_make_riff_xma_from_fmt(buf,200, chunk_offset,0x34, datasize, streamFileGSP, 1);
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, chunk_offset,0x34, datasize, streamFileGSP, 1);
if (bytes <= 0) goto fail;
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,datasize);

View File

@ -358,7 +358,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
/* post_meta_offset+0x00: fmt0x166 header (BE), post_meta_offset+0x34: seek table */
bytes = ffmpeg_make_riff_xma_from_fmt(buf,200, post_meta_offset,0x34, stream_size, streamFile, 1);
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, post_meta_offset,0x34, stream_size, streamFile, 1);
if (bytes <= 0) goto fail;
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,stream_size);

View File

@ -137,7 +137,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
case 0x0001: ww.codec = PCM; break; /* older Wwise */
case 0x0002: ww.codec = IMA; break; /* newer Wwise (conflicts with MSADPCM, probably means "platform's ADPCM") */
//case 0x0011: ww.codec = IMA; break; /* older Wwise (used?) */
case 0x0069: ww.codec = IMA; break; /* older Wwise (Spiderman Web of Shadows X360) */
case 0x0069: ww.codec = IMA; break; /* older Wwise (Spiderman Web of Shadows X360, LotR Conquest PC) */
case 0x0161: ww.codec = XWMA; break;
case 0x0162: ww.codec = XWMA; break;
case 0x0165: ww.codec = XMA2; break; /* always with the "XMA2" chunk, Wwise doesn't use XMA1 */
@ -146,7 +146,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
case 0xFFF0: ww.codec = DSP; break;
case 0xFFFB: ww.codec = HEVAG; break;
case 0xFFFC: ww.codec = ATRAC9; break;
case 0xFFFE: ww.codec = PCM; break; /* newer Wwise ("PCM for Wwise Authoring") (conflicts with WAVEFORMATEXTENSIBLE) */
case 0xFFFE: ww.codec = PCM; break; /* "PCM for Wwise Authoring" */
case 0xFFFF: ww.codec = VORBIS; break;
default:
VGM_LOG("WWISE: unknown codec 0x%x \n", ww.format);
@ -162,7 +162,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
* We'll add basic support to avoid complaints of this or that .wem not playing */
if (ww.data_size > ww.file_size) {
//VGM_LOG("WWISE: truncated data size (prefetch): (real=0x%x > riff=0x%x)\n", ww.data_size, ww.file_size);
if (ww.codec == IMA || ww.codec == VORBIS) /* only seen in those, probably other exist */
if (ww.codec == IMA || ww.codec == VORBIS) /* only seen those, probably others exist */
ww.truncated = 1;
else
goto fail;
@ -227,9 +227,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
/* older Wwise (~<2012) */
switch(vorb_size) {
#if 0
case 0x28: /* early (~2009), some Divinity II files? */
case 0x2C: /* early (~2009), some EVE Online Apocrypha files? */
//case 0x2C: /* early (~2009), some EVE Online Apocrypha files? */
case 0x28: /* early (~2009), ex. The Lord of the Rings: Conquest PC */
data_offsets = 0x18;
block_offsets = 0; /* no need, full headers are present */
header_type = TYPE_8;
@ -237,16 +236,15 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
setup_type = HEADER_TRIAD;
break;
case 0x32: /* ? */
#endif
//case 0x32: /* ? */
case 0x34: /* common (2010~2011) */
data_offsets = 0x18;
block_offsets = 0x30;
header_type = TYPE_6;
packet_type = STANDARD;
/* setup_type: autodetect later */
setup_type = EXTERNAL_CODEBOOKS; /* setup_type will be corrected later */
break;
case 0x2a: /* infamous 2 (mid 2011) */
case 0x2a: /* uncommon (mid 2011), ex. infamous 2 PS3 */
data_offsets = 0x10;
block_offsets = 0x28;
header_type = TYPE_2;
@ -282,9 +280,6 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
else if (setup_size > 0x200) { /* an external setup it's ~0x100 max + some threshold */
setup_type = INLINE_CODEBOOKS;
}
else {
setup_type = EXTERNAL_CODEBOOKS;
}
}
vgmstream->codec_data = init_wwise_vorbis_codec_data(streamFile, start_offset + setup_offset, ww.channels, ww.sample_rate, blocksize_0_exp,blocksize_1_exp,
@ -302,16 +297,16 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
block_offsets = 0x28;
header_type = TYPE_2;
packet_type = MODIFIED;
//packet_type = STANDARD;
/* setup not detectable by header, so we'll try both; hopefully libvorbis will reject wrong codebooks
* - standard: early (<2012), ex. The King of Fighters XIII X360 (2011/11), .ogg
* - standard: early (<2012), ex. The King of Fighters XIII X360 (2011/11), .ogg (cbs are from aoTuV, too)
* - aoTuV603: later (>2012), ex. Sonic & All-Stars Racing Transformed PC (2012/11), .wem */
setup_type = is_wem ? AOTUV603_CODEBOOKS : EXTERNAL_CODEBOOKS; /* aoTuV came along .wem */
break;
//case 0x2a: /* Rocksmith 2011 X360? */
//non mod packets? TYPE_06? (possibly detectable by checking setup's granule, should be 0)
default:
//todo apparently some 0x2a + non mod_packets exist
//todo TYPE_06 possibly detectable by checking setup's granule (should be 0)
VGM_LOG("WWISE: unknown extra size 0x%x\n", vorb_size);
goto fail;
}
@ -404,7 +399,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
if (find_chunk(streamFile, 0x584D4132,first_offset,0, &xma2_offset,&xma2_size, ww.big_endian, 0)) { /*"XMA2"*/ /* older Wwise */
bytes = ffmpeg_make_riff_xma2_from_xma2_chunk(buf,0x100, xma2_offset, xma2_size, ww.data_size, streamFile);
} else { /* newer Wwise */
bytes = ffmpeg_make_riff_xma_from_fmt(buf,0x100, ww.fmt_offset, ww.fmt_size, ww.data_size, streamFile, ww.big_endian);
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, ww.fmt_offset, ww.fmt_size, ww.data_size, streamFile, ww.big_endian);
}
if (bytes <= 0) goto fail;
@ -441,8 +436,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
/* manually find total samples, why don't they put this in the header is beyond me */
if (ww.format == 0x0162) { /* WMAPRO */
xma_sample_data msd;
memset(&msd,0,sizeof(xma_sample_data));
ms_sample_data msd;
memset(&msd,0,sizeof(ms_sample_data));
msd.channels = ww.channels;
msd.data_offset = ww.data_offset;
@ -535,7 +530,7 @@ fail:
0x31 (1): blocksize_0_exp (large)
0x32 (2): empty
"vorb" size 0x2a
"vorb" size 0x28 / 0x2a
0x00 (4): num_samples
0x04 (4): loop offset after seek table+setup (offset after setup if file doesn't loop)
0x08 (4): data size without seek table (setup+packets)
@ -547,8 +542,8 @@ fail:
0x1c (4): ? (mid, 0~0x5000)
0x20 (4): ? (mid, 0~0x5000)
0x24 (4): parent bank/event id? (shared by several .wem a game, but not all need to share it)
0x28 (1): blocksize_1_exp (small)
0x29 (1): blocksize_0_exp (large)
0x28 (1): blocksize_1_exp (small) [removed when size is 0x28]
0x29 (1): blocksize_0_exp (large) [removed when size is 0x28]
- new format:

View File

@ -37,29 +37,29 @@ VGMSTREAM * init_vgmstream_x360_ast(STREAMFILE *streamFile) {
vgmstream->sample_rate = read_32bitBE(0x40,streamFile);
vgmstream->meta_type = meta_X360_AST;
#ifdef VGM_USE_FFMPEG
{
/* manually find sample offsets (XMA1 nonsense again) */
xma_sample_data xma_sd;
memset(&xma_sd,0,sizeof(xma_sample_data));
ms_sample_data msd;
memset(&msd,0,sizeof(ms_sample_data));
xma_sd.xma_version = 1;
xma_sd.channels = channel_count;
xma_sd.data_offset = start_offset;
xma_sd.data_size = data_size;
xma_sd.loop_flag = loop_flag;
xma_sd.loop_start_b = read_32bitBE(0x44,streamFile);
xma_sd.loop_end_b = read_32bitBE(0x48,streamFile);
xma_sd.loop_start_subframe = read_8bit(0x4c,streamFile) & 0xF; /* lower 4b: subframe where the loop starts, 0..4 */
xma_sd.loop_end_subframe = read_8bit(0x4c,streamFile) >> 4; /* upper 4b: subframe where the loop ends, 0..3 */
msd.xma_version = 1;
msd.channels = channel_count;
msd.data_offset = start_offset;
msd.data_size = data_size;
msd.loop_flag = loop_flag;
msd.loop_start_b = read_32bitBE(0x44,streamFile);
msd.loop_end_b = read_32bitBE(0x48,streamFile);
msd.loop_start_subframe = read_8bit(0x4c,streamFile) & 0xF; /* lower 4b: subframe where the loop starts, 0..4 */
msd.loop_end_subframe = read_8bit(0x4c,streamFile) >> 4; /* upper 4b: subframe where the loop ends, 0..3 */
xma_get_samples(&xma_sd, streamFile);
vgmstream->num_samples = xma_sd.num_samples;
vgmstream->loop_start_sample = xma_sd.loop_start_sample;
vgmstream->loop_end_sample = xma_sd.loop_end_sample;
//skip_samples = xma_sd.skip_samples; //todo add skip samples
xma_get_samples(&msd, streamFile);
vgmstream->num_samples = msd.num_samples;
vgmstream->loop_start_sample = msd.loop_start_sample;
vgmstream->loop_end_sample = msd.loop_end_sample;
//skip_samples = msd.skip_samples; //todo add skip samples
}
#ifdef VGM_USE_FFMPEG
{
uint8_t buf[100];
size_t bytes;
@ -68,7 +68,7 @@ VGMSTREAM * init_vgmstream_x360_ast(STREAMFILE *streamFile) {
size_t fmt_size = 0x0c + xma_streams * 0x14;
/* XMA1 "fmt" chunk @ 0x20 (BE, unlike the usual LE) */
bytes = ffmpeg_make_riff_xma_from_fmt(buf,100, fmt_offset,fmt_size, data_size, streamFile, 1);
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,100, fmt_offset,fmt_size, data_size, streamFile, 1);
if (bytes <= 0) goto fail;
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);

View File

@ -286,7 +286,7 @@ fail:
static void fix_samples(xma_header_data * xma, STREAMFILE *streamFile) {
xma_sample_data xma_sd;
ms_sample_data msd;
/* for now only XMA1 is fixed, but xmaencode.exe doesn't seem to use
* XMA2 sample values in the headers, and the exact number of samples may not be exact.
@ -296,26 +296,26 @@ static void fix_samples(xma_header_data * xma, STREAMFILE *streamFile) {
return;
}
memset(&xma_sd,0,sizeof(xma_sample_data));
memset(&msd,0,sizeof(ms_sample_data));
/* call xma parser (copy to its own struct, a bit clunky but oh well...) */
xma_sd.xma_version = xma->fmt_codec==0x165 ? 1 : 2;
xma_sd.channels = xma->channels;
xma_sd.data_offset = xma->data_offset;
xma_sd.data_size = xma->data_size;
xma_sd.loop_flag = xma->loop_flag;
xma_sd.loop_start_b = xma->loop_start_b;
xma_sd.loop_end_b = xma->loop_end_b;
xma_sd.loop_start_subframe = xma->loop_subframe & 0xF; /* lower 4b: subframe where the loop starts, 0..4 */
xma_sd.loop_end_subframe = xma->loop_subframe >> 4; /* upper 4b: subframe where the loop ends, 0..3 */
msd.xma_version = xma->fmt_codec==0x165 ? 1 : 2;
msd.channels = xma->channels;
msd.data_offset = xma->data_offset;
msd.data_size = xma->data_size;
msd.loop_flag = xma->loop_flag;
msd.loop_start_b = xma->loop_start_b;
msd.loop_end_b = xma->loop_end_b;
msd.loop_start_subframe = xma->loop_subframe & 0xF; /* lower 4b: subframe where the loop starts, 0..4 */
msd.loop_end_subframe = xma->loop_subframe >> 4; /* upper 4b: subframe where the loop ends, 0..3 */
xma_get_samples(&xma_sd, streamFile);
xma_get_samples(&msd, streamFile);
/* and recieve results */
xma->num_samples = xma_sd.num_samples;
xma->skip_samples = xma_sd.skip_samples;
xma->loop_start_sample = xma_sd.loop_start_sample;
xma->loop_end_sample = xma_sd.loop_end_sample;
xma->num_samples = msd.num_samples;
xma->skip_samples = msd.skip_samples;
xma->loop_start_sample = msd.loop_start_sample;
xma->loop_end_sample = msd.loop_end_sample;
/* XMA2 loop/num_samples don't seem to skip_samples */
}

View File

@ -255,25 +255,24 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
}
else if (xwb.xact == 2 && xwb.version <= 38 /* v38: byte offset, v40+: sample offset, v39: ? */
&& (xwb.codec == XMA1 || xwb.codec == XMA2) && xwb.loop_flag) {
#ifdef VGM_USE_FFMPEG
/* need to manually find sample offsets, thanks to Microsoft dumb headers */
xma_sample_data xma_sd;
memset(&xma_sd,0,sizeof(xma_sample_data));
ms_sample_data msd;
memset(&msd,0,sizeof(ms_sample_data));
xma_sd.xma_version = xwb.codec == XMA1 ? 1 : 2;
xma_sd.channels = xwb.channels;
xma_sd.data_offset = xwb.stream_offset;
xma_sd.data_size = xwb.stream_size;
xma_sd.loop_flag = xwb.loop_flag;
xma_sd.loop_start_b = xwb.loop_start; /* bit offset in the stream */
xma_sd.loop_end_b = (xwb.loop_end >> 4); /*28b */
msd.xma_version = xwb.codec == XMA1 ? 1 : 2;
msd.channels = xwb.channels;
msd.data_offset = xwb.stream_offset;
msd.data_size = xwb.stream_size;
msd.loop_flag = xwb.loop_flag;
msd.loop_start_b = xwb.loop_start; /* bit offset in the stream */
msd.loop_end_b = (xwb.loop_end >> 4); /*28b */
/* XACT adds +1 to the subframe, but this means 0 can't be used? */
xma_sd.loop_end_subframe = ((xwb.loop_end >> 2) & 0x3) + 1; /* 2b */
xma_sd.loop_start_subframe = ((xwb.loop_end >> 0) & 0x3) + 1; /* 2b */
msd.loop_end_subframe = ((xwb.loop_end >> 2) & 0x3) + 1; /* 2b */
msd.loop_start_subframe = ((xwb.loop_end >> 0) & 0x3) + 1; /* 2b */
xma_get_samples(&xma_sd, streamFile);
xwb.loop_start_sample = xma_sd.loop_start_sample;
xwb.loop_end_sample = xma_sd.loop_end_sample;
xma_get_samples(&msd, streamFile);
xwb.loop_start_sample = msd.loop_start_sample;
xwb.loop_end_sample = msd.loop_end_sample;
// todo fix properly (XWB loop_start/end seem to count padding samples while XMA1 RIFF doesn't)
//this doesn't seem ok because can fall within 0 to 512 (ie.- first frame)
@ -283,9 +282,6 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
//add padding back until it's fixed (affects looping)
// (in rare cases this causes a glitch in FFmpeg since it has a bug where it's missing some samples)
xwb.num_samples += 64 + 512;
#else
goto fail;
#endif
}