From 242c0b94764518b9dc092ecb0bbc31f48eb97cac Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Sun, 20 Oct 2019 17:24:44 -0700 Subject: [PATCH] Updated VGMStream to r1050-2574-g246222dd --- .../libvgmstream.xcodeproj/project.pbxproj | 4 + .../vgmstream/vgmstream/src/coding/coding.h | 10 +- .../vgmstream/src/coding/coding_utils.c | 21 +- .../vgmstream/src/coding/ffmpeg_decoder.c | 51 ++- .../src/coding/ffmpeg_decoder_custom_opus.c | 114 ++++-- .../vgmstream/src/coding/msadpcm_decoder.c | 30 +- .../vgmstream/src/coding/ogg_vorbis_decoder.c | 243 ++++++++++++- .../vgmstream/src/layout/blocked_xa.c | 35 +- .../vgmstream/vgmstream/src/meta/2dx9.c | 74 ++-- Frameworks/vgmstream/vgmstream/src/meta/acb.c | 21 +- Frameworks/vgmstream/vgmstream/src/meta/aix.c | 16 +- .../vgmstream/src/meta/aix_streamfile.h | 32 +- Frameworks/vgmstream/vgmstream/src/meta/akb.c | 4 +- .../vgmstream/vgmstream/src/meta/bwav.c | 44 ++- Frameworks/vgmstream/vgmstream/src/meta/ck.c | 2 +- Frameworks/vgmstream/vgmstream/src/meta/dec.c | 8 +- .../vgmstream/vgmstream/src/meta/genh.c | 6 +- .../vgmstream/vgmstream/src/meta/meta.h | 2 +- .../vgmstream/vgmstream/src/meta/mus_acm.c | 34 +- .../vgmstream/vgmstream/src/meta/mzrt.c | 15 +- Frameworks/vgmstream/vgmstream/src/meta/nub.c | 90 ++--- .../vgmstream/vgmstream/src/meta/ogg_vorbis.c | 339 ++++++------------ .../vgmstream/vgmstream/src/meta/riff.c | 230 ++++++------ .../vgmstream/src/meta/riff_ogg_streamfile.h | 130 +++++++ Frameworks/vgmstream/vgmstream/src/meta/sd9.c | 20 +- .../vgmstream/vgmstream/src/meta/sgxd.c | 8 + Frameworks/vgmstream/vgmstream/src/meta/sli.c | 20 +- Frameworks/vgmstream/vgmstream/src/meta/smp.c | 5 +- .../vgmstream/vgmstream/src/meta/spt_spd.c | 165 ++++----- .../vgmstream/vgmstream/src/meta/sqex_scd.c | 43 +-- .../vgmstream/vgmstream/src/meta/sqex_sead.c | 4 +- .../vgmstream/vgmstream/src/meta/txth.c | 22 +- .../vgmstream/vgmstream/src/meta/txtp.c | 8 +- .../vgmstream/vgmstream/src/meta/ubi_bao.c | 17 +- .../vgmstream/vgmstream/src/meta/ubi_hx.c | 6 +- .../vgmstream/vgmstream/src/meta/ubi_jade.c | 14 +- .../vgmstream/vgmstream/src/meta/ubi_raki.c | 7 +- .../vgmstream/vgmstream/src/meta/ubi_sb.c | 12 +- Frameworks/vgmstream/vgmstream/src/meta/vxn.c | 28 +- Frameworks/vgmstream/vgmstream/src/meta/waf.c | 14 +- Frameworks/vgmstream/vgmstream/src/meta/xa.c | 116 +++++- Frameworks/vgmstream/vgmstream/src/meta/xnb.c | 9 +- Frameworks/vgmstream/vgmstream/src/meta/xwb.c | 11 +- Frameworks/vgmstream/vgmstream/src/meta/xwc.c | 7 +- Frameworks/vgmstream/vgmstream/src/plugins.c | 8 +- .../vgmstream/vgmstream/src/streamfile.c | 303 +++++++++------- .../vgmstream/vgmstream/src/streamfile.h | 66 ++-- .../vgmstream/vgmstream/src/streamtypes.h | 13 +- Frameworks/vgmstream/vgmstream/src/util.h | 16 + .../vgmstream/vgmstream/src/vgmstream.c | 25 +- .../vgmstream/vgmstream/src/vgmstream.h | 14 +- 51 files changed, 1482 insertions(+), 1054 deletions(-) create mode 100644 Frameworks/vgmstream/vgmstream/src/meta/riff_ogg_streamfile.h diff --git a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj index 419a80798..37ded1057 100644 --- a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj +++ b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj @@ -564,6 +564,7 @@ 83F0AA6021E2028C004BBC04 /* vsv_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F0AA5D21E2028B004BBC04 /* vsv_streamfile.h */; }; 83F0AA6121E2028C004BBC04 /* vsv.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F0AA5E21E2028C004BBC04 /* vsv.c */; }; 83F5F8831908D0A400C8E65F /* fsb5.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F5F8821908D0A400C8E65F /* fsb5.c */; }; + 83FBD506235D31F800D35BCD /* riff_ogg_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83FBD502235D31F700D35BCD /* riff_ogg_streamfile.h */; }; 83FF0EBC1E93282100C58054 /* wwise.c in Sources */ = {isa = PBXBuildFile; fileRef = 83FF0EBB1E93282100C58054 /* wwise.c */; }; /* End PBXBuildFile section */ @@ -1247,6 +1248,7 @@ 83F0AA5E21E2028C004BBC04 /* vsv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vsv.c; sourceTree = ""; }; 83F412871E932F9A002E37D0 /* Vorbis.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Vorbis.xcodeproj; path = ../Vorbis/macosx/Vorbis.xcodeproj; sourceTree = ""; }; 83F5F8821908D0A400C8E65F /* fsb5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fsb5.c; sourceTree = ""; }; + 83FBD502235D31F700D35BCD /* riff_ogg_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = riff_ogg_streamfile.h; sourceTree = ""; }; 83FF0EBB1E93282100C58054 /* wwise.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wwise.c; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1804,6 +1806,7 @@ 837CEAE723487F2B00E62A4A /* raw_wavm.c */, 836F6EE218BDC2190095E648 /* redspark.c */, 834FE0D9215C79EA000A5D3D /* rfrm.c */, + 83FBD502235D31F700D35BCD /* riff_ogg_streamfile.h */, 836F6EE318BDC2190095E648 /* riff.c */, 836F6EE418BDC2190095E648 /* rkv.c */, 836F6EE518BDC2190095E648 /* rs03.c */, @@ -2013,6 +2016,7 @@ 834FE103215C79ED000A5D3D /* ea_schl_streamfile.h in Headers */, 83C7282722BC8C1500678B4A /* plugins.h in Headers */, 83F0AA6021E2028C004BBC04 /* vsv_streamfile.h in Headers */, + 83FBD506235D31F800D35BCD /* riff_ogg_streamfile.h in Headers */, 48C2650F1A5D420800A0A3D6 /* vorbisfile.h in Headers */, 836F705718BDC2190095E648 /* util.h in Headers */, 836F6F9A18BDC2190095E648 /* meta.h in Headers */, diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding.h b/Frameworks/vgmstream/vgmstream/src/coding/coding.h index c56a28c2d..70b4735b5 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/coding.h +++ b/Frameworks/vgmstream/vgmstream/src/coding/coding.h @@ -128,6 +128,7 @@ void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t fir void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_msadpcm_ck(VGMSTREAM * vgmstream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); long msadpcm_bytes_to_samples(long bytes, int block_size, int channels); +int msadpcm_check_coefs(STREAMFILE *sf, off_t offset); /* yamaha_decoder */ void decode_aica(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo); @@ -212,11 +213,18 @@ int test_hca_key(hca_codec_data * data, unsigned long long keycode); #ifdef VGM_USE_VORBIS /* ogg_vorbis_decoder */ -void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample_t * outbuf, int32_t samples_to_do, int channels); +ogg_vorbis_codec_data* init_ogg_vorbis(STREAMFILE *sf, off_t start, off_t size, ogg_vorbis_io *io); +void decode_ogg_vorbis(ogg_vorbis_codec_data *data, sample_t *outbuf, int32_t samples_to_do, int channels); void reset_ogg_vorbis(VGMSTREAM *vgmstream); void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample); void free_ogg_vorbis(ogg_vorbis_codec_data *data); +int ogg_vorbis_get_comment(ogg_vorbis_codec_data *data, const char **comment); +void ogg_vorbis_get_info(ogg_vorbis_codec_data *data, int *p_channels, int *p_sample_rate); +void ogg_vorbis_get_samples(ogg_vorbis_codec_data *data, int *p_samples); +void ogg_vorbis_set_disable_reordering(ogg_vorbis_codec_data *data, int set); +STREAMFILE* ogg_vorbis_get_streamfile(ogg_vorbis_codec_data *data); + /* vorbis_custom_decoder */ vorbis_custom_codec_data *init_vorbis_custom(STREAMFILE *streamfile, off_t start_offset, vorbis_custom_t type, vorbis_custom_config * config); void decode_vorbis_custom(VGMSTREAM * vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels); diff --git a/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c b/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c index fbb6db35e..fa83dbd85 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c @@ -1160,25 +1160,12 @@ int w_bits(vgm_bitstream * ob, int num_bits, uint32_t value) { /* ******************************************** */ STREAMFILE* setup_subfile_streamfile(STREAMFILE *sf, off_t subfile_offset, size_t subfile_size, const char* extension) { - STREAMFILE *temp_sf = NULL, *new_sf = NULL; + STREAMFILE *new_sf = NULL; new_sf = open_wrap_streamfile(sf); - if (!new_sf) goto fail; - temp_sf = new_sf; - - new_sf = open_clamp_streamfile(temp_sf, subfile_offset, subfile_size); - if (!new_sf) goto fail; - temp_sf = new_sf; - + new_sf = open_clamp_streamfile_f(new_sf, subfile_offset, subfile_size); if (extension) { - new_sf = open_fakename_streamfile(temp_sf, NULL, extension); - if (!new_sf) goto fail; - temp_sf = new_sf; + new_sf = open_fakename_streamfile_f(new_sf, NULL, extension); } - - return temp_sf; - -fail: - close_streamfile(temp_sf); - return NULL; + return new_sf; } diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c index 465ff7305..046d91a7c 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c @@ -1,3 +1,4 @@ +#include #include "coding.h" #ifdef VGM_USE_FFMPEG @@ -540,6 +541,38 @@ fail: } +/* When casting float to int value is simply truncated: + * - 0.0000518798828125 * 32768.0f = 1.7f, (int)1.7 = 1, (int)-1.7 = -1 + * (instead of 1.7 = 2, -1.7 = -2) + * + * Alts for more accurate rounding could be: + * - (int)floor(f32 * 32768.0) //not quite ok negatives + * - (int)floor(f32 * 32768.0f + 0.5f) //Xiph Vorbis style + * - (int)(f32 < 0 ? f32 - 0.5f : f + 0.5f) + * - (((int) (f1 + 32768.5)) - 32768) + * - etc + * but since +-1 isn't really audible we'll just cast as it's the fastest. + * + * Regular C float-to-int casting ("int i = (int)f") is somewhat slow due to IEEE + * float requirements, but C99 adds some faster-but-less-precise casting functions + * we try to use (returning "long", though). They work ok without "fast float math" compiler + * flags, but probably should be enabled anyway to ensure no extra IEEE checks are needed. + */ +static inline int float_to_int(float val) { +#if defined(_MSC_VER) && (_MSC_VER < 1900) /* VS2015 */ + return (int)val; +#else + return lrintf(val); +#endif +} +static inline int double_to_int(double val) { +#if defined(_MSC_VER) && (_MSC_VER < 1900) /* VS2015 */ + return (int)val; +#else + return lrint(val); /* returns long tho */ +#endif +} + /* sample copy helpers, using different functions to minimize branches. * * in theory, small optimizations like *outbuf++ vs outbuf[i] or alt clamping @@ -556,16 +589,6 @@ fail: * int s16 = (int)(f32 * 32768.0f); * if ((unsigned)(s16 + 0x8000) & 0xFFFF0000) * s16 = (s16 >> 31) ^ 0x7FFF; - * - * when casting float to int, value is simply truncated: - * - 0.0000518798828125 * 32768.0f = 1.7f, (int)1.7 = 1, (int)-1.7 = -1 - * alts for more accurate rounding could be: - * - (int)floor(f32 * 32768.0) //not quite ok negatives - * - (int)floor(f32 * 32768.0f + 0.5f) //Xiph Vorbis style - * - (int)(f32 < 0 ? f32 - 0.5f : f + 0.5f) - * - (((int) (f1 + 32768.5)) - 32768) - * - etc - * but since +-1 isn't really audible we'll just cast as it's the fastest */ static void samples_silence_s16(sample_t* obuf, int ochs, int samples) { @@ -621,7 +644,7 @@ static void samples_flt_to_s16(sample_t* obuf, float* ibuf, int ichs, int sample int s, total_samples = samples * ichs; float scale = invert ? -32768.0f : 32768.0f; for (s = 0; s < total_samples; s++) { - obuf[s] = clamp16(ibuf[skip*ichs + s] * scale); + obuf[s] = clamp16(float_to_int(ibuf[skip*ichs + s] * scale)); } } static void samples_fltp_to_s16(sample_t* obuf, float** ibuf, int ichs, int samples, int skip, int invert) { @@ -629,21 +652,21 @@ static void samples_fltp_to_s16(sample_t* obuf, float** ibuf, int ichs, int samp float scale = invert ? -32768.0f : 32768.0f; for (ch = 0; ch < ichs; ch++) { for (s = 0; s < samples; s++) { - obuf[s*ichs + ch] = clamp16(ibuf[ch][skip + s] * scale); + obuf[s*ichs + ch] = clamp16(float_to_int(ibuf[ch][skip + s] * scale)); } } } static void samples_dbl_to_s16(sample_t* obuf, double* ibuf, int ichs, int samples, int skip) { int s, total_samples = samples * ichs; for (s = 0; s < total_samples; s++) { - obuf[s] = clamp16(ibuf[skip*ichs + s] * 32768.0); + obuf[s] = clamp16(double_to_int(ibuf[skip*ichs + s] * 32768.0)); } } static void samples_dblp_to_s16(sample_t* obuf, double** inbuf, int ichs, int samples, int skip) { int s, ch; for (ch = 0; ch < ichs; ch++) { for (s = 0; s < samples; s++) { - obuf[s*ichs + ch] = clamp16(inbuf[ch][skip + s] * 32768.0); + obuf[s*ichs + ch] = clamp16(double_to_int(inbuf[ch][skip + s] * 32768.0)); } } } diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c index ed5b57b92..624055774 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c @@ -17,12 +17,15 @@ * https://github.com/hcs64/ww2ogg */ -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); -static size_t opus_get_packet_samples(const uint8_t * buf, int len); -static size_t get_xopus_packet_size(int packet, STREAMFILE * streamfile); +typedef enum { OPUS_SWITCH, OPUS_UE4_v1, OPUS_UE4_v2, OPUS_EA, OPUS_X } 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); +static size_t opus_get_packet_samples(const uint8_t *buf, int len); +static size_t opus_get_packet_samples_sf(STREAMFILE *sf, off_t offset); +static size_t get_xopus_packet_size(int packet, STREAMFILE *streamfile); +static opus_type_t get_ue4opus_version(STREAMFILE *sf, off_t offset); -typedef enum { OPUS_SWITCH, OPUS_UE4, OPUS_EA, OPUS_X } opus_type_t; typedef struct { /* config */ opus_type_t type; @@ -94,19 +97,24 @@ static size_t opus_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, /* process new block */ if (data->page_size == 0) { - size_t data_size, skip_size, oggs_size; + size_t data_size, skip_size, oggs_size, packet_samples = 0; switch(data->type) { case OPUS_SWITCH: /* format seem to come from opus_test and not Nintendo-specific */ - data_size = read_32bitBE(data->physical_offset, streamfile); + data_size = read_u32be(data->physical_offset, streamfile); skip_size = 0x08; /* size + Opus state(?) */ break; - case OPUS_UE4: - data_size = (uint16_t)read_16bitLE(data->physical_offset, streamfile); + case OPUS_UE4_v1: + data_size = read_u16le(data->physical_offset, streamfile); skip_size = 0x02; break; + case OPUS_UE4_v2: + data_size = read_u16le(data->physical_offset + 0x00, streamfile); + packet_samples = read_u16le(data->physical_offset + 0x02, streamfile); + skip_size = 0x02 + 0x02; + break; case OPUS_EA: - data_size = (uint16_t)read_16bitBE(data->physical_offset, streamfile); + data_size = read_u16be(data->physical_offset, streamfile); skip_size = 0x02; break; case OPUS_X: @@ -130,8 +138,10 @@ static size_t opus_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, /* create fake OggS page (full page for checksums) */ read_streamfile(data->page_buffer+oggs_size, data->physical_offset + skip_size, data_size, streamfile); /* store page data */ - data->samples_done += opus_get_packet_samples(data->page_buffer+oggs_size, data_size); - make_oggs_page(data->page_buffer,sizeof(data->page_buffer), data_size, data->sequence, data->samples_done); + if (packet_samples == 0) + packet_samples = opus_get_packet_samples(data->page_buffer + oggs_size, data_size); + data->samples_done += packet_samples; + make_oggs_page(data->page_buffer, sizeof(data->page_buffer), data_size, data->sequence, data->samples_done); data->sequence++; } @@ -191,15 +201,19 @@ static size_t opus_io_size(STREAMFILE *streamfile, opus_io_data* data) { switch(data->type) { case OPUS_SWITCH: - data_size = read_32bitBE(physical_offset, streamfile); + data_size = read_u32be(physical_offset, streamfile); skip_size = 0x08; break; - case OPUS_UE4: - data_size = (uint16_t)read_16bitLE(physical_offset, streamfile); + case OPUS_UE4_v1: + data_size = read_u16le(physical_offset, streamfile); skip_size = 0x02; break; + case OPUS_UE4_v2: + data_size = read_u16le(physical_offset, streamfile); + skip_size = 0x02 + 0x02; + break; case OPUS_EA: - data_size = (uint16_t)read_16bitBE(physical_offset, streamfile); + data_size = read_u16be(physical_offset, streamfile); skip_size = 0x02; break; case OPUS_X: @@ -505,6 +519,11 @@ fail: static size_t opus_get_packet_samples(const uint8_t * buf, int len) { return opus_packet_get_nb_frames(buf, len) * opus_packet_get_samples_per_frame(buf, 48000); } +static size_t opus_get_packet_samples_sf(STREAMFILE *sf, off_t offset) { + uint8_t buf[0x04]; /* at least 0x02 */ + read_streamfile(buf, offset, sizeof(buf), sf); + return opus_get_packet_samples(buf, sizeof(buf)); +} /************************** */ @@ -512,48 +531,53 @@ static size_t get_xopus_packet_size(int packet, STREAMFILE * streamfile) { /* XOPUS has a packet size table at the beginning, get size from there. * Maybe should copy the table during setup to avoid IO, but all XOPUS are * quite small so it isn't very noticeable. */ - return (uint16_t)read_16bitLE(0x20 + packet*0x02, streamfile); + return read_u16le(0x20 + packet*0x02, streamfile); } -static size_t custom_opus_get_samples(off_t offset, size_t stream_size, STREAMFILE *streamFile, opus_type_t type) { +static size_t custom_opus_get_samples(off_t offset, size_t stream_size, STREAMFILE *sf, opus_type_t type) { size_t num_samples = 0; off_t end_offset = offset + stream_size; int packet = 0; - if (end_offset > get_streamfile_size(streamFile)) { + if (end_offset > get_streamfile_size(sf)) { VGM_LOG("OPUS: wrong end offset found\n"); - end_offset = get_streamfile_size(streamFile); + end_offset = get_streamfile_size(sf); } /* count by reading all frames */ while (offset < end_offset) { - uint8_t buf[4]; - size_t data_size, skip_size; + size_t data_size, skip_size, packet_samples = 0; switch(type) { case OPUS_SWITCH: - data_size = read_32bitBE(offset, streamFile); + data_size = read_u32be(offset, sf); skip_size = 0x08; break; - case OPUS_UE4: - data_size = (uint16_t)read_16bitLE(offset, streamFile); + case OPUS_UE4_v1: + data_size = read_u16le(offset, sf); skip_size = 0x02; break; + case OPUS_UE4_v2: + data_size = read_u16le(offset + 0x00, sf); + packet_samples = read_u16le(offset + 0x02, sf); + skip_size = 0x02 + 0x02; + break; case OPUS_EA: - data_size = (uint16_t)read_16bitBE(offset, streamFile); + data_size = read_u16be(offset, sf); skip_size = 0x02; break; case OPUS_X: - data_size = get_xopus_packet_size(packet, streamFile); + data_size = get_xopus_packet_size(packet, sf); skip_size = 0x00; break; default: return 0; } - read_streamfile(buf, offset+skip_size, 0x04, streamFile); /* at least 0x02 */ - num_samples += opus_get_packet_samples(buf, 0x04); + if (packet_samples == 0) + packet_samples = opus_get_packet_samples_sf(sf, offset + skip_size); + num_samples += packet_samples; offset += skip_size + data_size; packet++; @@ -567,17 +591,20 @@ size_t switch_opus_get_samples(off_t offset, size_t stream_size, STREAMFILE *str } -static size_t custom_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile, opus_type_t type) { - uint8_t buf[4]; - size_t skip_size; +static size_t custom_opus_get_encoder_delay(off_t offset, STREAMFILE *sf, opus_type_t type) { + size_t skip_size, packet_samples = 0; switch(type) { case OPUS_SWITCH: skip_size = 0x08; break; - case OPUS_UE4: + case OPUS_UE4_v1: skip_size = 0x02; break; + case OPUS_UE4_v2: + packet_samples = read_u16le(offset + 0x02, sf); + skip_size = 0x02 + 0x02; + break; case OPUS_EA: skip_size = 0x02; break; @@ -588,15 +615,16 @@ static size_t custom_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile return 0; } + if (packet_samples == 0) + packet_samples = opus_get_packet_samples_sf(sf, offset + skip_size); /* encoder delay seems fixed to 1/8 of samples per frame, but may need more testing */ - read_streamfile(buf, offset+skip_size, 0x04, streamFile); /* at least 0x02 */ - return opus_get_packet_samples(buf, 0x04) / 8; + return packet_samples / 8; } size_t switch_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile) { return custom_opus_get_encoder_delay(offset, streamFile, OPUS_SWITCH); } size_t ue4_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile) { - return custom_opus_get_encoder_delay(offset, streamFile, OPUS_UE4); + return custom_opus_get_encoder_delay(offset, streamFile, get_ue4opus_version(streamFile, offset)); } size_t ea_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile) { return custom_opus_get_encoder_delay(offset, streamFile, OPUS_EA); @@ -648,7 +676,7 @@ ffmpeg_codec_data * init_ffmpeg_switch_opus(STREAMFILE *streamFile, off_t start_ return init_ffmpeg_custom_opus(streamFile, start_offset, data_size, channels, skip, sample_rate, OPUS_SWITCH); } ffmpeg_codec_data * init_ffmpeg_ue4_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate) { - return init_ffmpeg_custom_opus(streamFile, start_offset, data_size, channels, skip, sample_rate, OPUS_UE4); + return init_ffmpeg_custom_opus(streamFile, start_offset, data_size, channels, skip, sample_rate, get_ue4opus_version(streamFile, start_offset)); } ffmpeg_codec_data * init_ffmpeg_ea_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate) { return init_ffmpeg_custom_opus(streamFile, start_offset, data_size, channels, skip, sample_rate, OPUS_EA); @@ -657,4 +685,16 @@ ffmpeg_codec_data * init_ffmpeg_x_opus(STREAMFILE *streamFile, off_t start_offse return init_ffmpeg_custom_opus(streamFile, start_offset, data_size, channels, skip, sample_rate, OPUS_X); } +static opus_type_t get_ue4opus_version(STREAMFILE *sf, off_t offset) { + int read_samples, calc_samples; + + /* UE4OPUS v2 has packet samples right after packet size, check if data follows this */ + read_samples = read_u16le(offset + 0x02, sf); + calc_samples = opus_get_packet_samples_sf(sf, offset + 0x04); + if (read_samples > 0 && read_samples == calc_samples) + return OPUS_UE4_v2; + else + return OPUS_UE4_v1; +} + #endif diff --git a/Frameworks/vgmstream/vgmstream/src/coding/msadpcm_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/msadpcm_decoder.c index 1f48830ab..f76f2d0d3 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/msadpcm_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/msadpcm_decoder.c @@ -2,14 +2,14 @@ #include "coding.h" -static const int msadpcm_steps[16] = { +static const int16_t msadpcm_steps[16] = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 }; -static const int msadpcm_coefs[7][2] = { +static const int16_t msadpcm_coefs[7][2] = { { 256, 0 }, { 512, -256 }, { 0, 0 }, @@ -226,3 +226,29 @@ long msadpcm_bytes_to_samples(long bytes, int block_size, int channels) { return (bytes / block_size) * (block_size - (7-1)*channels) * 2 / channels + ((bytes % block_size) ? ((bytes % block_size) - (7-1)*channels) * 2 / channels : 0); } + +/* test if MSADPCM coefs were re-defined (possible in theory but not used in practice) */ +int msadpcm_check_coefs(STREAMFILE *sf, off_t offset) { + int i; + int count = read_16bitLE(offset, sf); + if (count != 7) { + VGM_LOG("MSADPCM: bad count %i at %lx\n", count, offset); + goto fail; + } + + offset += 0x02; + for (i = 0; i < 7; i++) { + int16_t coef1 = read_16bitLE(offset + 0x00, sf); + int16_t coef2 = read_16bitLE(offset + 0x02, sf); + + if (coef1 != msadpcm_coefs[i][0] || coef2 != msadpcm_coefs[i][1]) { + VGM_LOG("MSADPCM: bad coef %i/%i vs %i/%i\n", coef1, coef2, msadpcm_coefs[i][0], msadpcm_coefs[i][1]); + goto fail; + } + offset += 0x02 + 0x02; + } + + return 1; +fail: + return 0; +} diff --git a/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c index 198d14aa6..83566456d 100644 --- a/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c +++ b/Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c @@ -5,21 +5,183 @@ #ifdef VGM_USE_VORBIS #include +#define OGG_DEFAULT_BITSTREAM 0 -static void pcm_convert_float_to_16(int channels, sample_t * outbuf, int samples_to_do, float ** pcm, int disable_ordering); +/* opaque struct */ +struct ogg_vorbis_codec_data { + OggVorbis_File ogg_vorbis_file; + int ovf_init; + int bitstream; + int disable_reordering; /* Xiph Ogg must reorder channels on output, but some pre-ordered games don't need it */ + + ogg_vorbis_io io; + vorbis_comment *comment; + int comment_number; + vorbis_info *info; +}; -void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample_t * outbuf, int32_t samples_to_do, int channels) { +static void pcm_convert_float_to_16(int channels, sample_t *outbuf, int samples_to_do, float **pcm, int disable_ordering); + +static size_t ov_read_func(void *ptr, size_t size, size_t nmemb, void *datasource); +static int ov_seek_func(void *datasource, ogg_int64_t offset, int whence); +static long ov_tell_func(void *datasource); +static int ov_close_func(void *datasource); + + +ogg_vorbis_codec_data* init_ogg_vorbis(STREAMFILE *sf, off_t start, off_t size, ogg_vorbis_io *io) { + ogg_vorbis_codec_data *data = NULL; + ov_callbacks callbacks = {0}; + + //todo clean up + + callbacks.read_func = ov_read_func; + callbacks.seek_func = ov_seek_func; + callbacks.close_func = ov_close_func; + callbacks.tell_func = ov_tell_func; + + /* test if this is a proper Ogg Vorbis file, with the current (from init_x) STREAMFILE + * (quick test without having to malloc first, though if one invoked this it'll probably success) */ + { + OggVorbis_File temp_ovf = {0}; + ogg_vorbis_io temp_io = {0}; + + temp_io.streamfile = sf; + + temp_io.start = start; + temp_io.offset = 0; + temp_io.size = size; + + if (io != NULL) { + temp_io.decryption_callback = io->decryption_callback; + temp_io.scd_xor = io->scd_xor; + temp_io.scd_xor_length = io->scd_xor_length; + temp_io.xor_value = io->xor_value; + } + + /* open the ogg vorbis file for testing */ + if (ov_test_callbacks(&temp_io, &temp_ovf, NULL, 0, callbacks)) + goto fail; + + /* we have to close this as it has the init_vgmstream meta-reading STREAMFILE */ + ov_clear(&temp_ovf); + } + + /* proceed to init codec_data and reopen a STREAMFILE for this codec */ + { + data = calloc(1,sizeof(ogg_vorbis_codec_data)); + if (!data) goto fail; + + data->io.streamfile = reopen_streamfile(sf, 0); + if (!data->io.streamfile) goto fail; + + data->io.start = start; + data->io.offset = 0; + data->io.size = size; + + if (io != NULL) { + data->io.decryption_callback = io->decryption_callback; + data->io.scd_xor = io->scd_xor; + data->io.scd_xor_length = io->scd_xor_length; + data->io.xor_value = io->xor_value; + } + + /* open the ogg vorbis file for real */ + if (ov_open_callbacks(&data->io, &data->ogg_vorbis_file, NULL, 0, callbacks)) + goto fail; + data->ovf_init = 1; + } + + //todo could set bitstreams as subsongs? + /* get info from bitstream */ + data->bitstream = OGG_DEFAULT_BITSTREAM; + + data->comment = ov_comment(&data->ogg_vorbis_file, data->bitstream); + data->info = ov_info(&data->ogg_vorbis_file, data->bitstream); + + return data; +fail: + free_ogg_vorbis(data); + return NULL; +} + +static size_t ov_read_func(void *ptr, size_t size, size_t nmemb, void *datasource) { + ogg_vorbis_io *io = datasource; + size_t bytes_read, items_read; + + off_t real_offset = io->start + io->offset; + size_t max_bytes = size * nmemb; + + /* clamp for virtual filesize */ + if (max_bytes > io->size - io->offset) + max_bytes = io->size - io->offset; + + bytes_read = read_streamfile(ptr, real_offset, max_bytes, io->streamfile); + items_read = bytes_read / size; + + /* may be encrypted */ + if (io->decryption_callback) { + io->decryption_callback(ptr, size, items_read, io); + } + + io->offset += items_read * size; + + return items_read; +} + +static int ov_seek_func(void *datasource, ogg_int64_t offset, int whence) { + ogg_vorbis_io *io = datasource; + ogg_int64_t base_offset, new_offset; + + switch (whence) { + case SEEK_SET: + base_offset = 0; + break; + case SEEK_CUR: + base_offset = io->offset; + break; + case SEEK_END: + base_offset = io->size; + break; + default: + return -1; + break; + } + + + new_offset = base_offset + offset; + if (new_offset < 0 || new_offset > io->size) { + return -1; /* *must* return -1 if stream is unseekable */ + } else { + io->offset = new_offset; + return 0; + } +} + +static long ov_tell_func(void *datasource) { + ogg_vorbis_io *io = datasource; + return io->offset; +} + +static int ov_close_func(void *datasource) { + /* needed as setting ov_close_func in ov_callbacks to NULL doesn't seem to work + * (closing the streamfile is done in free_ogg_vorbis) */ + return 0; +} + +/* ********************************************** */ + +void decode_ogg_vorbis(ogg_vorbis_codec_data *data, sample_t *outbuf, int32_t samples_to_do, int channels) { int samples_done = 0; long rc; float **pcm_channels; /* pointer to Xiph's double array buffer */ while (samples_done < samples_to_do) { rc = ov_read_float( - &data->ogg_vorbis_file, /* context */ - &pcm_channels, /* buffer pointer */ - (samples_to_do - samples_done), /* samples to produce */ - &data->bitstream); /* bitstream*/ + &data->ogg_vorbis_file, /* context */ + &pcm_channels, /* buffer pointer */ + (samples_to_do - samples_done), /* samples to produce */ + &data->bitstream); /* bitstream */ if (rc <= 0) goto fail; /* rc is samples done */ pcm_convert_float_to_16(channels, outbuf, rc, pcm_channels, data->disable_reordering); @@ -32,13 +194,13 @@ void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample_t * outbuf, int32_t /* we use ov_read_float as to reuse the xiph's buffer for easier remapping, * but seems ov_read is slightly faster due to optimized (asm) float-to-int. */ rc = ov_read( - &data->ogg_vorbis_file, /* context */ - (char *)(outbuf), /* buffer */ + &data->ogg_vorbis_file, /* context */ + (char *)(outbuf), /* buffer */ (samples_to_do - samples_done) * sizeof(sample_t) * channels, /* length in bytes */ - 0, /* pcm endianness */ - sizeof(sample), /* pcm size */ - 1, /* pcm signedness */ - &data->bitstream); /* bitstream */ + 0, /* pcm endianness */ + sizeof(sample), /* pcm size */ + 1, /* pcm signedness */ + &data->bitstream); /* bitstream */ if (rc <= 0) goto fail; /* rc is bytes done (for all channels) */ swap_samples_le(outbuf, rc / sizeof(sample_t)); /* endianness is a bit weird with ov_read though */ @@ -56,7 +218,7 @@ fail: /* vorbis encodes channels in non-standard order, so we remap during conversion to fix this oddity. * (feels a bit weird as one would think you could leave as-is and set the player's output - * order, but that isn't possible and remapping is what FFmpeg and every other plugin do). */ + * order, but that isn't possible and remapping is what FFmpeg and every other plugin does). */ static const int xiph_channel_map[8][8] = { { 0 }, /* 1ch: FC > same */ { 0, 1 }, /* 2ch: FL FR > same */ @@ -115,10 +277,61 @@ void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) { void free_ogg_vorbis(ogg_vorbis_codec_data *data) { if (!data) return; - ov_clear(&data->ogg_vorbis_file); + if (data->ovf_init) + ov_clear(&data->ogg_vorbis_file); - close_streamfile(data->ov_streamfile.streamfile); + close_streamfile(data->io.streamfile); free(data); } +/* ********************************************** */ + +int ogg_vorbis_get_comment(ogg_vorbis_codec_data *data, const char **comment) { + if (!data) return 0; + + /* dumb reset */ + if (comment == NULL) { + data->comment_number = 0; + return 1; + } + + if (data->comment_number >= data->comment->comments) + return 0; + + *comment = data->comment->user_comments[data->comment_number]; + data->comment_number++; + return 1; +} + +void ogg_vorbis_get_info(ogg_vorbis_codec_data *data, int *p_channels, int *p_sample_rate) { + if (!data) { + if (p_channels) *p_channels = 0; + if (p_sample_rate) *p_sample_rate = 0; + return; + } + + if (p_channels) *p_channels = data->info->channels; + if (p_sample_rate) *p_sample_rate = (int)data->info->rate; +} + +void ogg_vorbis_get_samples(ogg_vorbis_codec_data *data, int *p_samples) { + if (!data) { + if (p_samples) *p_samples = 0; + return; + } + + if (p_samples) *p_samples = ov_pcm_total(&data->ogg_vorbis_file,-1); +} + +void ogg_vorbis_set_disable_reordering(ogg_vorbis_codec_data *data, int set) { + if (!data) return; + + data->disable_reordering = set; +} + +STREAMFILE* ogg_vorbis_get_streamfile(ogg_vorbis_codec_data *data) { + if (!data) return NULL; + return data->io.streamfile; +} + #endif diff --git a/Frameworks/vgmstream/vgmstream/src/layout/blocked_xa.c b/Frameworks/vgmstream/vgmstream/src/layout/blocked_xa.c index 8ab45fdc1..87340b622 100644 --- a/Frameworks/vgmstream/vgmstream/src/layout/blocked_xa.c +++ b/Frameworks/vgmstream/vgmstream/src/layout/blocked_xa.c @@ -5,31 +5,36 @@ /* parse a CD-XA raw mode2/form2 sector */ void block_update_xa(off_t block_offset, VGMSTREAM * vgmstream) { STREAMFILE* streamFile = vgmstream->ch[0].streamfile; - int i; + int i, is_audio; size_t block_samples; - uint8_t xa_submode; + uint8_t xa_target, xa_submode, config_target; /* XA mode2/form2 sector, size 0x930 * 0x00: sync word * 0x0c: header = minute, second, sector, mode (always 0x02) - * 0x10: subheader = file, channel (substream marker), submode flags, xa header + * 0x10: subheader = file, channel, submode flags, xa header * 0x14: subheader again (for error correction) * 0x18: data * 0x918: unused * 0x92c: EDC/checksum or null * 0x930: end + * Sectors with no data may exist near other with data */ + xa_target = (uint8_t)read_16bitBE(block_offset + 0x10, streamFile); + config_target = vgmstream->codec_config; + + /* Sector subheader's file+channel markers are used to interleave streams (music/sfx/voices) + * by reading one target file+channel while ignoring the rest. This is needed to adjust + * CD drive spinning <> decoding speed (data is read faster otherwise, so can't have 2 + * sectors of the same channel), Normally N channels = N streams (usually 8/16/32 depending + * on sample rate/stereo), though channels can be empty or contain video (like 7 or 15 video + * sectors + 1 audio frame). Normally interleaved channels use with the same file ID, but some + * games change ID too. Extractors deinterleave and split .xa using file + channel + EOF flags. */ - /* channel markers supposedly could be used to interleave streams, ex. audio languages within video - * (extractors may split .XA using channels?) */ - VGM_ASSERT(block_offset + 0x930 < get_streamfile_size(streamFile) && - (uint8_t)read_8bit(block_offset + 0x000 + 0x11,streamFile) != - (uint8_t)read_8bit(block_offset + 0x930 + 0x11,streamFile), - "XA block: subchannel change at %x\n", (uint32_t)block_offset); /* submode flag bits (typical audio value = 0x64 01100100) - * - 7 (0x80 10000000): end of file + * - 7 (0x80 10000000): end of file (usually at data end, not per subheader's file) * - 6 (0x40 01000000): real time mode * - 5 (0x20 00100000): sector form (0=form1, 1=form2) * - 4 (0x10 00010000): trigger (for application) @@ -37,11 +42,19 @@ void block_update_xa(off_t block_offset, VGMSTREAM * vgmstream) { * - 2 (0x04 00000100): audio sector * - 1 (0x02 00000010): video sector * - 0 (0x01 00000001): end of audio + * Empty sectors with no flags may exist interleaved with other with audio/data. */ xa_submode = (uint8_t)read_8bit(block_offset + 0x12,streamFile); /* audio sector must set/not set certain flags, as per spec */ - if (!(xa_submode & 0x08) && (xa_submode & 0x04) && !(xa_submode & 0x02)) { + is_audio = !(xa_submode & 0x08) && (xa_submode & 0x04) && !(xa_submode & 0x02); + + + if (xa_target != config_target) { + //;VGM_LOG("XA block: ignored block at %x\n", (uint32_t)block_offset); + block_samples = 0; /* not a target sector */ + } + else if (is_audio) { if (xa_submode & 0x20) { /* form2 audio: size 0x900, 18 frames of size 0x80 with 8 subframes of 28 samples */ block_samples = (28*8 / vgmstream->channels) * 18; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/2dx9.c b/Frameworks/vgmstream/vgmstream/src/meta/2dx9.c index 14912d71a..911b6f6ac 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/2dx9.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/2dx9.c @@ -1,69 +1,51 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* 2DX9 (found in beatmaniaIIDX16 - EMPRESS (Arcade) */ +/* 2DX9 - from Konami arcade games [beatmaniaIIDX16: EMPRESS (AC), BeatStream (AC), REFLEC BEAT (AC)] */ VGMSTREAM * init_vgmstream_2dx9(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; off_t start_offset; + int channel_count, loop_flag; - int loop_flag; - int channel_count; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("2dx9",filename_extension(filename))) goto fail; + /* checks */ + if (!check_extensions(streamFile, "2dx9")) + goto fail; /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x32445839) /* 2DX9 */ - goto fail; - if (read_32bitBE(0x18,streamFile) != 0x52494646) /* RIFF */ - goto fail; - if (read_32bitBE(0x20,streamFile) != 0x57415645) /* WAVE */ - goto fail; - if (read_32bitBE(0x24,streamFile) != 0x666D7420) /* fmt */ - goto fail; + if (read_32bitBE(0x00,streamFile) != 0x32445839) /* 2DX9 */ + goto fail; + if (read_32bitBE(0x18,streamFile) != 0x52494646) /* RIFF */ + goto fail; + if (read_32bitBE(0x20,streamFile) != 0x57415645) /* WAVE */ + goto fail; + if (read_32bitBE(0x24,streamFile) != 0x666D7420) /* fmt */ + goto fail; if (read_32bitBE(0x6a,streamFile) != 0x64617461) /* data */ - goto fail; + goto fail; loop_flag = 0; channel_count = read_16bitLE(0x2e,streamFile); + start_offset = 0x72; - /* build the VGMSTREAM */ + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = 0x72; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x30,streamFile); - vgmstream->coding_type = coding_MSADPCM; - vgmstream->num_samples = read_32bitLE(0x66,streamFile); - vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = read_16bitLE(0x38,streamFile); vgmstream->meta_type = meta_2DX9; + vgmstream->sample_rate = read_32bitLE(0x30,streamFile); + vgmstream->num_samples = read_32bitLE(0x66,streamFile); + vgmstream->coding_type = coding_MSADPCM; + vgmstream->layout_type = layout_none; + vgmstream->frame_size = read_16bitLE(0x38,streamFile); + if (!msadpcm_check_coefs(streamFile, 0x40)) + goto fail; - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - - return vgmstream; + if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) + goto fail; + return vgmstream; fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/acb.c b/Frameworks/vgmstream/vgmstream/src/meta/acb.c index f25ed1d0c..bfe06d884 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/acb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/acb.c @@ -70,24 +70,15 @@ fail: /* ************************************** */ +//todo maybe use reopen sf? since internal buffer is going to be read #define ACB_TABLE_BUFFER_SIZE 0x4000 -STREAMFILE* setup_acb_streamfile(STREAMFILE *streamFile, size_t buffer_size) { - STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL; +STREAMFILE* setup_acb_streamfile(STREAMFILE *sf, size_t buffer_size) { + STREAMFILE *new_sf = NULL; - new_streamFile = open_wrap_streamfile(streamFile); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; - - new_streamFile = open_buffer_streamfile(temp_streamFile, buffer_size); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; - - return temp_streamFile; - -fail: - close_streamfile(temp_streamFile); - return NULL; + new_sf = open_wrap_streamfile(sf); + new_sf = open_buffer_streamfile_f(new_sf, buffer_size); + return new_sf; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/aix.c b/Frameworks/vgmstream/vgmstream/src/meta/aix.c index 93ab5dc46..41ce11454 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/aix.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/aix.c @@ -110,7 +110,7 @@ static VGMSTREAM *build_layered_vgmstream(STREAMFILE *streamFile, off_t segment_ VGMSTREAM *vgmstream = NULL; layered_layout_data* data = NULL; int i; - STREAMFILE* temp_streamFile = NULL; + STREAMFILE* temp_sf = NULL; /* build layers */ @@ -119,17 +119,17 @@ static VGMSTREAM *build_layered_vgmstream(STREAMFILE *streamFile, off_t segment_ for (i = 0; i < layer_count; i++) { /* build the layer STREAMFILE */ - temp_streamFile = setup_aix_streamfile(streamFile, segment_offset, segment_size, i, "adx"); - if (!temp_streamFile) goto fail; + temp_sf = setup_aix_streamfile(streamFile, segment_offset, segment_size, i, "adx"); + if (!temp_sf) goto fail; /* build the sub-VGMSTREAM */ - data->layers[i] = init_vgmstream_adx(temp_streamFile); + data->layers[i] = init_vgmstream_adx(temp_sf); if (!data->layers[i]) goto fail; - data->layers[i]->stream_size = get_streamfile_size(temp_streamFile); + data->layers[i]->stream_size = get_streamfile_size(temp_sf); - close_streamfile(temp_streamFile); - temp_streamFile = NULL; + close_streamfile(temp_sf); + temp_sf = NULL; } if (!setup_layout_layered(data)) @@ -145,7 +145,7 @@ static VGMSTREAM *build_layered_vgmstream(STREAMFILE *streamFile, off_t segment_ fail: if (!vgmstream) free_layout_layered(data); close_vgmstream(vgmstream); - close_streamfile(temp_streamFile); + close_streamfile(temp_sf); return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/aix_streamfile.h b/Frameworks/vgmstream/vgmstream/src/meta/aix_streamfile.h index e60537a87..cf560f182 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/aix_streamfile.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/aix_streamfile.h @@ -112,40 +112,22 @@ static size_t aix_io_size(STREAMFILE *streamfile, aix_io_data* data) { } /* Handles deinterleaving of AIX blocked layer streams */ -static STREAMFILE* setup_aix_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t stream_size, int layer_number, const char* extension) { - STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL; +static STREAMFILE* setup_aix_streamfile(STREAMFILE *sf, off_t stream_offset, size_t stream_size, int layer_number, const char* extension) { + STREAMFILE *new_sf = NULL; aix_io_data io_data = {0}; - size_t io_data_size = sizeof(aix_io_data); io_data.stream_offset = stream_offset; io_data.stream_size = stream_size; io_data.layer_number = layer_number; io_data.logical_offset = -1; /* force reset */ - /* setup subfile */ - new_streamFile = open_wrap_streamfile(streamFile); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; - - new_streamFile = open_io_streamfile(new_streamFile, &io_data,io_data_size, aix_io_read,aix_io_size); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; - - new_streamFile = open_buffer_streamfile(new_streamFile,0); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; - + new_sf = open_wrap_streamfile(sf); + new_sf = open_io_streamfile_f(new_sf, &io_data, sizeof(aix_io_data), aix_io_read, aix_io_size); + new_sf = open_buffer_streamfile_f(new_sf, 0); if (extension) { - new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,extension); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; + new_sf = open_fakename_streamfile_f(new_sf, NULL, extension); } - - return temp_streamFile; - -fail: - close_streamfile(temp_streamFile); - return NULL; + return new_sf; } #endif /* _AIX_STREAMFILE_H_ */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/akb.c b/Frameworks/vgmstream/vgmstream/src/meta/akb.c index ab19920d8..422a5676f 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/akb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/akb.c @@ -91,7 +91,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) { case 0x02: { /* MSADPCM [Dragon Quest II (iOS) sfx] */ vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = read_16bitLE(extradata_offset + 0x02,streamFile); + vgmstream->frame_size = read_16bitLE(extradata_offset + 0x02,streamFile); /* adjusted samples; bigger or smaller than base samples, akb lib uses these fields instead * (base samples may have more than possible and read over file size otherwise, very strange) @@ -277,7 +277,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) { case 0x02: { /* MSADPCM [The Irregular at Magic High School Lost Zero (Android)] */ vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = read_16bitLE(extradata_offset + 0x02, streamFile); + vgmstream->frame_size = read_16bitLE(extradata_offset + 0x02, streamFile); /* adjusted samples; bigger or smaller than base samples, akb lib uses these fields instead * (base samples may have more than possible and read over file size otherwise, very strange) diff --git a/Frameworks/vgmstream/vgmstream/src/meta/bwav.c b/Frameworks/vgmstream/vgmstream/src/meta/bwav.c index 5ee7fc299..2d6ced0ce 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/bwav.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/bwav.c @@ -5,20 +5,32 @@ VGMSTREAM * init_vgmstream_bwav(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; - int channel_count, loop_flag; - int32_t coef_start_offset, coef_spacing; + int channel_count, loop_flag, codec; + size_t interleave = 0; + /* checks */ if (!check_extensions(streamFile, "bwav")) goto fail; - /* BWAV header */ if (read_32bitBE(0x00, streamFile) != 0x42574156) /* "BWAV" */ goto fail; + /* 0x04: BOM */ + /* 0x06: version? */ + /* 0x08: ??? */ + /* 0x0c: null? */ channel_count = read_16bitLE(0x0E, streamFile); + + /* - per channel (size 0x4c) */ + codec = read_16bitLE(0x10, streamFile); + /* see below */ start_offset = read_32bitLE(0x40, streamFile); - loop_flag = read_32bitLE(0x4C, streamFile); + loop_flag = read_32bitLE(0x4C, streamFile) != -1; + if (channel_count > 1) + interleave = read_32bitLE(0x8C, streamFile) - start_offset; + //TODO should make sure channels match and offsets make a proper interleave (see bfwav) + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count, loop_flag); @@ -29,14 +41,24 @@ VGMSTREAM * init_vgmstream_bwav(STREAMFILE *streamFile) { vgmstream->loop_start_sample = read_32bitLE(0x50, streamFile); vgmstream->loop_end_sample = read_32bitLE(0x4C, streamFile); vgmstream->meta_type = meta_BWAV; - vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0x8C, streamFile) - start_offset; - vgmstream->coding_type = coding_NGC_DSP; - - coef_start_offset = 0x20; - coef_spacing = 0x4C; - dsp_read_coefs_le(vgmstream, streamFile, coef_start_offset, coef_spacing); + switch(codec) { + case 0x0000: + vgmstream->coding_type = coding_PCM16LE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + break; + + case 0x0001: + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + dsp_read_coefs_le(vgmstream, streamFile, 0x20, 0x4C); + break; + + default: + goto fail; + } if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ck.c b/Frameworks/vgmstream/vgmstream/src/meta/ck.c index d01f62a42..51637f768 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ck.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ck.c @@ -56,7 +56,7 @@ VGMSTREAM * init_vgmstream_cks(STREAMFILE *streamFile) { break; case 0x02: /* adpcm [Part Time UFO (Android), Mega Man 1-6 (Android)] */ vgmstream->coding_type = coding_MSADPCM_ck; - /* frame_size is always 0x18 */ + vgmstream->frame_size = block_size / channel_count; /* always 0x18 */ break; default: goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/dec.c b/Frameworks/vgmstream/vgmstream/src/meta/dec.c index 69247e150..77ac6cd21 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/dec.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/dec.c @@ -76,7 +76,7 @@ VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile) { vgmstream->loop_end_sample = loop_end; vgmstream->coding_type = coding_MSADPCM; - vgmstream->interleave_block_size = 0x800; + vgmstream->frame_size = 0x800; vgmstream->layout_type = layout_blocked_dec; if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) @@ -122,10 +122,10 @@ static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int * while (txt_offset < get_streamfile_size(streamText)) { char line[TXT_LINE_MAX]; char name[TXT_LINE_MAX]; - int ok, line_done, loop, bytes_read; + int ok, line_ok, loop, bytes_read; - bytes_read = get_streamfile_text_line(TXT_LINE_MAX,line, txt_offset,streamText, &line_done); - if (!line_done) goto end; + bytes_read = read_line(line, TXT_LINE_MAX, txt_offset, streamText, &line_ok); + if (!line_ok) goto end; txt_offset += bytes_read; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/genh.c b/Frameworks/vgmstream/vgmstream/src/meta/genh.c index eedba22ed..20a74194e 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/genh.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/genh.c @@ -225,13 +225,15 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { vgmstream->interleave_block_size = genh.interleave; vgmstream->layout_type = layout_none; break; + case coding_MSADPCM: if (vgmstream->channels > 2) goto fail; - if (!genh.interleave) goto fail; /* creates garbage */ + if (!genh.interleave) goto fail; - vgmstream->interleave_block_size = genh.interleave; + vgmstream->frame_size = genh.interleave; vgmstream->layout_type = layout_none; break; + case coding_XBOX_IMA: if (genh.codec_mode == 1) { /* mono interleave */ coding = coding_XBOX_IMA_int; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/meta.h b/Frameworks/vgmstream/vgmstream/src/meta/meta.h index edf0eefcd..87b24c54b 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h @@ -128,7 +128,7 @@ typedef struct { } ogg_vorbis_meta_info_t; -VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callbacks *callbacks, off_t other_header_bytes, const ogg_vorbis_meta_info_t *ovmi); +VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callbacks *callbacks, off_t start, const ogg_vorbis_meta_info_t *ovmi); #endif VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile); diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mus_acm.c b/Frameworks/vgmstream/vgmstream/src/meta/mus_acm.c index f0a77278f..88b02a1a1 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/mus_acm.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/mus_acm.c @@ -188,15 +188,15 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo char** names = NULL; char filename[NAME_LENGTH]; - char line_buffer[NAME_LENGTH]; + char line[NAME_LENGTH]; char * end_ptr; char name_base[NAME_LENGTH]; char dir_name[NAME_LENGTH]; char subdir_name[NAME_LENGTH]; int file_count; - size_t line_bytes; - int whole_line_read = 0; + size_t bytes_read; + int line_ok = 0; off_t mus_offset = 0; int i; @@ -204,10 +204,10 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo /* read file name base */ - line_bytes = get_streamfile_text_line(sizeof(line_buffer),line_buffer, mus_offset, streamFile, &whole_line_read); - if (!whole_line_read) goto fail; - mus_offset += line_bytes; - memcpy(name_base,line_buffer,sizeof(name_base)); + bytes_read = read_line(line, sizeof(line), mus_offset, streamFile, &line_ok); + if (!line_ok) goto fail; + mus_offset += bytes_read; + memcpy(name_base,line,sizeof(name_base)); /* uppercase name_base */ { @@ -217,11 +217,11 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo } /* read track entry count */ - line_bytes = get_streamfile_text_line(sizeof(line_buffer),line_buffer, mus_offset, streamFile, &whole_line_read); - if (!whole_line_read) goto fail; - if (line_buffer[0] == '\0') goto fail; - mus_offset += line_bytes; - file_count = strtol(line_buffer,&end_ptr,10); + bytes_read = read_line(line, sizeof(line), mus_offset, streamFile, &line_ok); + if (!line_ok) goto fail; + if (line[0] == '\0') goto fail; + mus_offset += bytes_read; + file_count = strtol(line,&end_ptr,10); /* didn't parse whole line as an integer (optional opening whitespace) */ if (*end_ptr != '\0') goto fail; @@ -262,13 +262,11 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo for (i = 0; i < file_count; i++) { int fields_matched; - line_bytes = - get_streamfile_text_line(sizeof(line_buffer),line_buffer, - mus_offset, streamFile, &whole_line_read); - if (!whole_line_read) goto fail; - mus_offset += line_bytes; + bytes_read = read_line(line,sizeof(line), mus_offset, streamFile, &line_ok); + if (!line_ok) goto fail; + mus_offset += bytes_read; - fields_matched = sscanf(line_buffer,"%s %s %s",name, + fields_matched = sscanf(line,"%s %s %s",name, loop_name_base_temp,loop_name_temp); if (fields_matched < 1) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/mzrt.c b/Frameworks/vgmstream/vgmstream/src/meta/mzrt.c index 6acb62500..9692c0d37 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/mzrt.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/mzrt.c @@ -45,15 +45,22 @@ VGMSTREAM * init_vgmstream_mzrt(STREAMFILE *streamFile) { goto fail; } - /* skip fmt-extra data */ - if (codec == 0x0002 || codec == 0x0166) { + /* skip MSADPCM data */ + if (codec == 0x0002) { + if (!msadpcm_check_coefs(streamFile, start_offset + 0x02 + 0x02)) + goto fail; + + start_offset += 0x02 + read_16bitLE(start_offset, streamFile); + } + + /* skip extra data */ + if (codec == 0x0166) { start_offset += 0x02 + read_16bitLE(start_offset, streamFile); } /* skip unknown table */ if (codec == 0x0000) { start_offset += 0x04 + read_32bitBE(start_offset, streamFile) * 0x04; - } /* skip unknown table */ @@ -95,7 +102,7 @@ VGMSTREAM * init_vgmstream_mzrt(STREAMFILE *streamFile) { if (bps != 4) goto fail; vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = block_size; + vgmstream->frame_size = block_size; break; #ifdef VGM_USE_FFMPEG diff --git a/Frameworks/vgmstream/vgmstream/src/meta/nub.c b/Frameworks/vgmstream/vgmstream/src/meta/nub.c index 96e738177..cc5b39f90 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/nub.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/nub.c @@ -2,12 +2,12 @@ #include "../coding/coding.h" -static STREAMFILE* make_nub_streamfile(STREAMFILE* streamFile, off_t header_offset, size_t header_size, off_t stream_offset, size_t stream_size, const char* fake_ext); +static STREAMFILE* setup_nub_streamfile(STREAMFILE *sf, off_t header_offset, size_t header_size, off_t stream_offset, size_t stream_size, const char *fake_ext); /* .nub - Namco's nu Sound v2 audio container */ VGMSTREAM * init_vgmstream_nub(STREAMFILE *streamFile) { VGMSTREAM *vgmstream = NULL; - STREAMFILE *temp_streamFile = NULL; + STREAMFILE *temp_sf = NULL; off_t name_offset = 0; size_t name_size = 0; int total_subsongs, target_subsong = streamFile->stream_index; @@ -133,8 +133,8 @@ VGMSTREAM * init_vgmstream_nub(STREAMFILE *streamFile) { //;VGM_LOG("NUB: subfile header=%lx + %x, offset=%lx + %x\n", header_offset, header_size, stream_offset, stream_size); - temp_streamFile = make_nub_streamfile(streamFile, header_offset, header_size, stream_offset, stream_size, fake_ext); - if (!temp_streamFile) goto fail; + temp_sf = setup_nub_streamfile(streamFile, header_offset, header_size, stream_offset, stream_size, fake_ext); + if (!temp_sf) goto fail; } /* get names */ @@ -166,66 +166,36 @@ VGMSTREAM * init_vgmstream_nub(STREAMFILE *streamFile) { } /* init the VGMSTREAM */ - vgmstream = init_vgmstream_function(temp_streamFile); + vgmstream = init_vgmstream_function(temp_sf); if (!vgmstream) goto fail; - vgmstream->stream_size = get_streamfile_size(temp_streamFile); + vgmstream->stream_size = get_streamfile_size(temp_sf); vgmstream->num_streams = total_subsongs; if (name[0] != '\0') strcpy(vgmstream->stream_name, name); - close_streamfile(temp_streamFile); + close_streamfile(temp_sf); return vgmstream; fail: - close_streamfile(temp_streamFile); + close_streamfile(temp_sf); close_vgmstream(vgmstream); return NULL; } /* *********************************************************** */ -static STREAMFILE* make_nub_streamfile(STREAMFILE* streamFile, off_t header_offset, size_t header_size, off_t stream_offset, size_t stream_size, const char* fake_ext) { - STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL; - STREAMFILE *segment_streamFiles[2] = {0}; - int i; +static STREAMFILE* setup_nub_streamfile(STREAMFILE *sf, off_t header_offset, size_t header_size, off_t stream_offset, size_t stream_size, const char *fake_ext) { + STREAMFILE *new_sf = NULL; + STREAMFILE *multi_sf[2] = {0}; - - new_streamFile = open_wrap_streamfile(streamFile); - if (!new_streamFile) goto fail; - segment_streamFiles[0] = new_streamFile; - - new_streamFile = open_wrap_streamfile(streamFile); - if (!new_streamFile) goto fail; - segment_streamFiles[1] = new_streamFile; - - new_streamFile = open_clamp_streamfile(segment_streamFiles[0], header_offset,header_size); - if (!new_streamFile) goto fail; - segment_streamFiles[0] = new_streamFile; - - new_streamFile = open_clamp_streamfile(segment_streamFiles[1], stream_offset,stream_size); - if (!new_streamFile) goto fail; - segment_streamFiles[1] = new_streamFile; - - new_streamFile = open_multifile_streamfile(segment_streamFiles, 2); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; - - new_streamFile = open_fakename_streamfile(temp_streamFile, NULL, fake_ext); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; - - return temp_streamFile; - -fail: - if (!temp_streamFile) { - for (i = 0; i < 2; i++) { - close_streamfile(segment_streamFiles[i]); - } - } else { - close_streamfile(temp_streamFile); /* closes all segments */ - } - return NULL; + multi_sf[0] = open_wrap_streamfile(sf); + multi_sf[0] = open_clamp_streamfile_f(multi_sf[0], header_offset, header_size); + multi_sf[1] = open_wrap_streamfile(sf); + multi_sf[1] = open_clamp_streamfile_f(multi_sf[1], stream_offset, stream_size); + new_sf = open_multifile_streamfile_f(multi_sf, 2); + new_sf = open_fakename_streamfile_f(new_sf, NULL, fake_ext); + return new_sf; } /* *********************************************************** */ @@ -318,7 +288,7 @@ fail: /* .nub at3 - from Namco NUB archives [Ridge Racer 7 (PS3), Katamari Forever (PS3)] */ VGMSTREAM * init_vgmstream_nub_at3(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - STREAMFILE *temp_streamFile = NULL; + STREAMFILE *temp_sf = NULL; off_t subfile_offset = 0; size_t subfile_size = 0; @@ -333,16 +303,16 @@ VGMSTREAM * init_vgmstream_nub_at3(STREAMFILE *streamFile) { subfile_offset = 0x100; subfile_size = read_32bitLE(subfile_offset + 0x04, streamFile) + 0x08; /* RIFF size */ - temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL); - if (!temp_streamFile) goto fail; + temp_sf = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL); + if (!temp_sf) goto fail; - vgmstream = init_vgmstream_riff(temp_streamFile); + vgmstream = init_vgmstream_riff(temp_sf); if (!vgmstream) goto fail; - close_streamfile(temp_streamFile); + close_streamfile(temp_sf); return vgmstream; fail: - close_streamfile(temp_streamFile); + close_streamfile(temp_sf); close_vgmstream(vgmstream); return NULL; } @@ -512,7 +482,7 @@ fail: /* .nub is14 - from Namco NUB archives [Tales of Vesperia (PS3)] */ VGMSTREAM * init_vgmstream_nub_is14(STREAMFILE *streamFile) { VGMSTREAM *vgmstream = NULL; - STREAMFILE *temp_streamFile = NULL; + STREAMFILE *temp_sf = NULL; off_t header_offset, stream_offset; size_t header_size, stream_size, sdat_size; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; @@ -542,16 +512,16 @@ VGMSTREAM * init_vgmstream_nub_is14(STREAMFILE *streamFile) { stream_size = sdat_size; - temp_streamFile = make_nub_streamfile(streamFile, header_offset, header_size, stream_offset, stream_size, "bnsf"); - if (!temp_streamFile) goto fail; + temp_sf = setup_nub_streamfile(streamFile, header_offset, header_size, stream_offset, stream_size, "bnsf"); + if (!temp_sf) goto fail; - vgmstream = init_vgmstream_bnsf(temp_streamFile); + vgmstream = init_vgmstream_bnsf(temp_sf); if (!vgmstream) goto fail; - close_streamfile(temp_streamFile); + close_streamfile(temp_sf); return vgmstream; fail: - close_streamfile(temp_streamFile); + close_streamfile(temp_sf); close_vgmstream(vgmstream); return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c b/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c index 7f90b1798..d1ed10f44 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c @@ -1,123 +1,60 @@ -#include "../vgmstream.h" - #ifdef VGM_USE_VORBIS #include #include -#include #include "meta.h" +#include "../coding/coding.h" #include "ogg_vorbis_streamfile.h" -#define OGG_DEFAULT_BITSTREAM 0 - -static size_t ov_read_func(void *ptr, size_t size, size_t nmemb, void * datasource) { - ogg_vorbis_streamfile * const ov_streamfile = datasource; - size_t bytes_read, items_read; - - off_t real_offset = ov_streamfile->start + ov_streamfile->offset; - size_t max_bytes = size * nmemb; - - /* clamp for virtual filesize */ - if (max_bytes > ov_streamfile->size - ov_streamfile->offset) - max_bytes = ov_streamfile->size - ov_streamfile->offset; - - bytes_read = read_streamfile(ptr, real_offset, max_bytes, ov_streamfile->streamfile); - items_read = bytes_read / size; - - /* may be encrypted */ - if (ov_streamfile->decryption_callback) { - ov_streamfile->decryption_callback(ptr, size, items_read, ov_streamfile); - } - - ov_streamfile->offset += items_read * size; - - return items_read; -} - -static int ov_seek_func(void *datasource, ogg_int64_t offset, int whence) { - ogg_vorbis_streamfile * const ov_streamfile = datasource; - ogg_int64_t base_offset, new_offset; - - switch (whence) { - case SEEK_SET: - base_offset = 0; - break; - case SEEK_CUR: - base_offset = ov_streamfile->offset; - break; - case SEEK_END: - base_offset = ov_streamfile->size; - break; - default: - return -1; - break; - } - - - new_offset = base_offset + offset; - if (new_offset < 0 || new_offset > ov_streamfile->size) { - return -1; /* *must* return -1 if stream is unseekable */ - } else { - ov_streamfile->offset = new_offset; - return 0; - } -} - -static long ov_tell_func(void * datasource) { - ogg_vorbis_streamfile * const ov_streamfile = datasource; - return ov_streamfile->offset; -} - -static int ov_close_func(void * datasource) { - /* needed as setting ov_close_func in ov_callbacks to NULL doesn't seem to work - * (closing the streamfile is done in free_ogg_vorbis) */ - return 0; -} - static void um3_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) { - size_t bytes_read = size*nmemb; - ogg_vorbis_streamfile * const ov_streamfile = datasource; + uint8_t *ptr8 = ptr; + size_t bytes_read = size * nmemb; + ogg_vorbis_io *io = datasource; int i; /* first 0x800 bytes are xor'd */ - if (ov_streamfile->offset < 0x800) { - int num_crypt = 0x800 - ov_streamfile->offset; + if (io->offset < 0x800) { + int num_crypt = 0x800 - io->offset; if (num_crypt > bytes_read) num_crypt = bytes_read; for (i = 0; i < num_crypt; i++) - ((uint8_t*)ptr)[i] ^= 0xff; + ptr8[i] ^= 0xff; } } static void kovs_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) { - size_t bytes_read = size*nmemb; - ogg_vorbis_streamfile * const ov_streamfile = datasource; + uint8_t *ptr8 = ptr; + size_t bytes_read = size * nmemb; + ogg_vorbis_io *io = datasource; int i; /* first 0x100 bytes are xor'd */ - if (ov_streamfile->offset < 0x100) { - int max_offset = ov_streamfile->offset + bytes_read; + if (io->offset < 0x100) { + int max_offset = io->offset + bytes_read; if (max_offset > 0x100) max_offset = 0x100; - for (i = ov_streamfile->offset; i < max_offset; i++) { - ((uint8_t*)ptr)[i-ov_streamfile->offset] ^= i; + for (i = io->offset; i < max_offset; i++) { + ptr8[i-io->offset] ^= i; } } } static void psychic_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) { - ogg_vorbis_streamfile * const ov_streamfile = datasource; - size_t bytes_read = size*nmemb; - uint8_t key[6] = { 0x23,0x31,0x20,0x2e,0x2e,0x28 }; + static const uint8_t key[6] = { + 0x23,0x31,0x20,0x2e,0x2e,0x28 + }; + uint8_t *ptr8 = ptr; + size_t bytes_read = size * nmemb; + ogg_vorbis_io *io = datasource; int i; //todo incorrect, picked value changes (fixed order for all files), or key is bigger /* bytes add key that changes every 0x64 bytes */ for (i = 0; i < bytes_read; i++) { - int pos = (ov_streamfile->offset + i) / 0x64; - ((uint8_t*)ptr)[i] += key[pos % sizeof(key)]; + int pos = (io->offset + i) / 0x64; + ptr8[i] += key[pos % sizeof(key)]; } } @@ -125,21 +62,22 @@ static void rpgmvo_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, static const uint8_t header[16] = { /* OggS, packet type, granule, stream id(empty) */ 0x4F,0x67,0x67,0x53,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; + uint8_t *ptr8 = ptr; size_t bytes_read = size*nmemb; - ogg_vorbis_streamfile * const ov_streamfile = datasource; + ogg_vorbis_io *io = datasource; int i; /* first 0x10 are xor'd, but header can be easily reconstructed * (key is also in (game)/www/data/System.json "encryptionKey") */ for (i = 0; i < bytes_read; i++) { - if (ov_streamfile->offset+i < 0x10) { - ((uint8_t*)ptr)[i] = header[(ov_streamfile->offset + i) % 16]; + if (io->offset+i < 0x10) { + ptr8[i] = header[(io->offset + i) % 16]; /* last two bytes are the stream id, get from next OggS */ - if (ov_streamfile->offset+i == 0x0e) - ((uint8_t*)ptr)[i] = read_8bit(0x58, ov_streamfile->streamfile); - if (ov_streamfile->offset+i == 0x0f) - ((uint8_t*)ptr)[i] = read_8bit(0x59, ov_streamfile->streamfile); + if (io->offset+i == 0x0e) + ptr8[i] = read_8bit(0x58, io->streamfile); + if (io->offset+i == 0x0f) + ptr8[i] = read_8bit(0x59, io->streamfile); } } } @@ -158,7 +96,7 @@ static const uint32_t xiph_mappings[] = { }; -/* Ogg Vorbis, by way of libvorbisfile; may contain loop comments */ +/* Ogg Vorbis, may contain loop comments */ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; STREAMFILE *temp_streamFile = NULL; @@ -181,7 +119,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { /* check extension */ /* .ogg: standard/various, .logg: renamed for plugins - * .adx: KID [Remember11 (PC)] + * .adx: KID games [Remember11 (PC)] * .rof: The Rhythm of Fighters (Mobile) * .acm: Planescape Torment Enhanced Edition (PC) * .sod: Zone 4 (PC) @@ -190,7 +128,8 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { is_ogg = 1; } else if (check_extensions(streamFile,"um3")) { is_um3 = 1; - } else if (check_extensions(streamFile,"kvs,kovs")) { /* .kvs: Atelier Sophie (PC), kovs: header id only? */ + } else if (check_extensions(streamFile,"kvs,kovs")) { + /* .kvs: Atelier Sophie (PC), kovs: header id only? */ is_kovs = 1; } else if (check_extensions(streamFile,"sngw")) { /* .sngw: Capcom [Devil May Cry 4 SE (PC), Biohazard 6 (PC)] */ is_sngw = 1; @@ -228,11 +167,11 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { } else if (read_32bitBE(0x00,streamFile) == 0x00000000 && /* null instead of "OggS" [Yuppie Psycho (PC)] */ - read_32bitBE(0x3a,streamFile) == 0x4F676753) { + read_32bitBE(0x3a,streamFile) == 0x4F676753) { /* "OggS" in next page */ cfg.is_header_swap = 1; cfg.is_encrypted = 1; } - else if (read_32bitBE(0x00,streamFile) == 0x4f676753) { /* "OggS" (standard) */ + else if (read_32bitBE(0x00,streamFile) == 0x4F676753) { /* "OggS" (standard) */ ; } else { @@ -382,7 +321,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { if (is_eno) { /* [Metronomicon (PC)] */ /* first byte probably derives into key, but this works too */ - cfg.key[0] = (uint8_t)read_8bit(0x05,streamFile); /* regular ogg have a zero at this offset = easy key */; + cfg.key[0] = (uint8_t)read_8bit(0x05,streamFile); /* regular ogg have a zero at this offset = easy key */ cfg.key_len = 1; cfg.is_encrypted = 1; start_offset = 0x01; /* "OggS" starts after key-thing */ @@ -394,7 +333,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { cfg.is_encrypted = 1; } - if (is_mus) { /* [Redux - Dark Matters (PC)] */ + if (is_mus) { /* [Redux: Dark Matters (PC)] */ static const uint8_t mus_key[16] = { 0x21,0x4D,0x6F,0x01,0x20,0x4C,0x6E,0x02,0x1F,0x4B,0x6D,0x03,0x20,0x4C,0x6E,0x02 }; @@ -464,12 +403,12 @@ fail: return NULL; } -VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callbacks *callbacks_p, off_t start, const ogg_vorbis_meta_info_t *ovmi) { +VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callbacks *callbacks, off_t start, const ogg_vorbis_meta_info_t *ovmi) { VGMSTREAM * vgmstream = NULL; - ogg_vorbis_codec_data * data = NULL; - OggVorbis_File *ovf = NULL; - vorbis_info *vi; + ogg_vorbis_codec_data* data = NULL; + ogg_vorbis_io io = {0}; char name[STREAM_NAME_SIZE] = {0}; + int channels, sample_rate, num_samples; int loop_flag = ovmi->loop_flag; int32_t loop_start = ovmi->loop_start; @@ -480,156 +419,96 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb size_t stream_size = ovmi->stream_size ? ovmi->stream_size : get_streamfile_size(streamFile) - start; - - ov_callbacks default_callbacks; - - if (!callbacks_p) { - default_callbacks.read_func = ov_read_func; - default_callbacks.seek_func = ov_seek_func; - default_callbacks.close_func = ov_close_func; - default_callbacks.tell_func = ov_tell_func; - - callbacks_p = &default_callbacks; - } - - /* test if this is a proper Ogg Vorbis file, with the current (from init_x) STREAMFILE */ - { - OggVorbis_File temp_ovf = {0}; - ogg_vorbis_streamfile temp_streamfile = {0}; - - temp_streamfile.streamfile = streamFile; - - temp_streamfile.start = start; - temp_streamfile.offset = 0; - temp_streamfile.size = stream_size; - - temp_streamfile.decryption_callback = ovmi->decryption_callback; - temp_streamfile.scd_xor = ovmi->scd_xor; - temp_streamfile.scd_xor_length = ovmi->scd_xor_length; - temp_streamfile.xor_value = ovmi->xor_value; - - /* open the ogg vorbis file for testing */ - if (ov_test_callbacks(&temp_streamfile, &temp_ovf, NULL, 0, *callbacks_p)) - goto fail; - - /* we have to close this as it has the init_vgmstream meta-reading STREAMFILE */ - ov_clear(&temp_ovf); - } + int disable_reordering = ovmi->disable_reordering; - /* proceed to init codec_data and reopen a STREAMFILE for this stream */ - { - char filename[PATH_LIMIT]; + //todo improve how to pass config + io.decryption_callback = ovmi->decryption_callback; + io.scd_xor = ovmi->scd_xor; + io.scd_xor_length = ovmi->scd_xor_length; + io.xor_value = ovmi->xor_value; - data = calloc(1,sizeof(ogg_vorbis_codec_data)); - if (!data) goto fail; - - streamFile->get_name(streamFile,filename,sizeof(filename)); - data->ov_streamfile.streamfile = streamFile->open(streamFile,filename, STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!data->ov_streamfile.streamfile) goto fail; - - data->ov_streamfile.start = start; - data->ov_streamfile.offset = 0; - data->ov_streamfile.size = stream_size; - - data->ov_streamfile.decryption_callback = ovmi->decryption_callback; - data->ov_streamfile.scd_xor = ovmi->scd_xor; - data->ov_streamfile.scd_xor_length = ovmi->scd_xor_length; - data->ov_streamfile.xor_value = ovmi->xor_value; - - /* open the ogg vorbis file for real */ - if (ov_open_callbacks(&data->ov_streamfile, &data->ogg_vorbis_file, NULL, 0, *callbacks_p)) - goto fail; - ovf = &data->ogg_vorbis_file; - } - - //todo could set bitstreams as subsongs? - /* get info from bitstream 0 */ - data->bitstream = OGG_DEFAULT_BITSTREAM; - vi = ov_info(ovf,OGG_DEFAULT_BITSTREAM); - - /* other settings */ - data->disable_reordering = ovmi->disable_reordering; + data = init_ogg_vorbis(streamFile, start, stream_size, &io); + if (!data) goto fail; /* search for loop comments */ {//todo ignore if loop flag already set? - int i; - vorbis_comment *comment = ov_comment(ovf,OGG_DEFAULT_BITSTREAM); + const char * comment = NULL; - for (i = 0; i < comment->comments; i++) { - const char * user_comment = comment->user_comments[i]; - if (strstr(user_comment,"loop_start=")==user_comment || /* PSO4 */ - strstr(user_comment,"LOOP_START=")==user_comment || /* PSO4 */ - strstr(user_comment,"COMMENT=LOOPPOINT=")==user_comment || - strstr(user_comment,"LOOPSTART=")==user_comment || - strstr(user_comment,"um3.stream.looppoint.start=")==user_comment || - strstr(user_comment,"LOOP_BEGIN=")==user_comment || /* Hatsune Miku: Project Diva F (PS3) */ - strstr(user_comment,"LoopStart=")==user_comment || /* Devil May Cry 4 (PC) */ - strstr(user_comment,"XIPH_CUE_LOOPSTART=")==user_comment) { /* Super Mario Run (Android) */ - loop_start = atol(strrchr(user_comment,'=')+1); + while (ogg_vorbis_get_comment(data, &comment)) { + + if (strstr(comment,"loop_start=") == comment || /* PSO4 */ + strstr(comment,"LOOP_START=") == comment || /* PSO4 */ + strstr(comment,"COMMENT=LOOPPOINT=") == comment || + strstr(comment,"LOOPSTART=") == comment || + strstr(comment,"um3.stream.looppoint.start=") == comment || + strstr(comment,"LOOP_BEGIN=") == comment || /* Hatsune Miku: Project Diva F (PS3) */ + strstr(comment,"LoopStart=") == comment || /* Devil May Cry 4 (PC) */ + strstr(comment,"XIPH_CUE_LOOPSTART=") == comment) { /* Super Mario Run (Android) */ + loop_start = atol(strrchr(comment,'=')+1); loop_flag = (loop_start >= 0); } - else if (strstr(user_comment,"LOOPLENGTH=")==user_comment) {/* (LOOPSTART pair) */ - loop_length = atol(strrchr(user_comment,'=')+1); + else if (strstr(comment,"LOOPLENGTH=") == comment) {/* (LOOPSTART pair) */ + loop_length = atol(strrchr(comment,'=')+1); loop_length_found = 1; } - else if (strstr(user_comment,"title=-lps")==user_comment) { /* KID [Memories Off #5 (PC), Remember11 (PC)] */ - loop_start = atol(user_comment+10); + else if (strstr(comment,"title=-lps") == comment) { /* KID [Memories Off #5 (PC), Remember11 (PC)] */ + loop_start = atol(comment+10); loop_flag = (loop_start >= 0); } - else if (strstr(user_comment,"album=-lpe")==user_comment) { /* (title=-lps pair) */ - loop_end = atol(user_comment+10); + else if (strstr(comment,"album=-lpe") == comment) { /* (title=-lps pair) */ + loop_end = atol(comment+10); loop_flag = 1; loop_end_found = 1; } - else if (strstr(user_comment,"LoopEnd=")==user_comment) { /* (LoopStart pair) */ + else if (strstr(comment,"LoopEnd=") == comment) { /* (LoopStart pair) */ if(loop_flag) { - loop_length = atol(strrchr(user_comment,'=')+1)-loop_start; + loop_length = atol(strrchr(comment,'=')+1)-loop_start; loop_length_found = 1; } } - else if (strstr(user_comment,"LOOP_END=")==user_comment) { /* (LOOP_BEGIN pair) */ + else if (strstr(comment,"LOOP_END=") == comment) { /* (LOOP_BEGIN pair) */ if(loop_flag) { - loop_length = atol(strrchr(user_comment,'=')+1)-loop_start; + loop_length = atol(strrchr(comment,'=')+1)-loop_start; loop_length_found = 1; } } - else if (strstr(user_comment,"lp=")==user_comment) { - sscanf(strrchr(user_comment,'=')+1,"%d,%d", &loop_start,&loop_end); + else if (strstr(comment,"lp=") == comment) { + sscanf(strrchr(comment,'=')+1,"%d,%d", &loop_start,&loop_end); loop_flag = 1; loop_end_found = 1; } - else if (strstr(user_comment,"LOOPDEFS=")==user_comment) { /* Fairy Fencer F: Advent Dark Force */ - sscanf(strrchr(user_comment,'=')+1,"%d,%d", &loop_start,&loop_end); + else if (strstr(comment,"LOOPDEFS=") == comment) { /* Fairy Fencer F: Advent Dark Force */ + sscanf(strrchr(comment,'=')+1,"%d,%d", &loop_start,&loop_end); loop_flag = 1; loop_end_found = 1; } - else if (strstr(user_comment,"COMMENT=loop(")==user_comment) { /* Zero Time Dilemma (PC) */ - sscanf(strrchr(user_comment,'(')+1,"%d,%d", &loop_start,&loop_end); + else if (strstr(comment,"COMMENT=loop(") == comment) { /* Zero Time Dilemma (PC) */ + sscanf(strrchr(comment,'(')+1,"%d,%d", &loop_start,&loop_end); loop_flag = 1; loop_end_found = 1; } - else if (strstr(user_comment, "XIPH_CUE_LOOPEND=") == user_comment) { /* XIPH_CUE_LOOPSTART pair */ + else if (strstr(comment, "XIPH_CUE_LOOPEND=") == comment) { /* (XIPH_CUE_LOOPSTART pair) */ if (loop_flag) { - loop_length = atol(strrchr(user_comment, '=') + 1) - loop_start; + loop_length = atol(strrchr(comment, '=') + 1) - loop_start; loop_length_found = 1; } } - else if (strstr(user_comment, "omment=") == user_comment) { /* Air (Android) */ - sscanf(strstr(user_comment, "=LOOPSTART=") + 11, "%d,LOOPEND=%d", &loop_start, &loop_end); + else if (strstr(comment, "omment=") == comment) { /* Air (Android) */ + sscanf(strstr(comment, "=LOOPSTART=") + 11, "%d,LOOPEND=%d", &loop_start, &loop_end); loop_flag = 1; loop_end_found = 1; } - else if (strstr(user_comment,"MarkerNum=0002")==user_comment) { /* Megaman X Legacy Collection: MMX1/2/3 (PC) flag */ + else if (strstr(comment,"MarkerNum=0002") == comment) { /* Megaman X Legacy Collection: MMX1/2/3 (PC) flag */ /* uses LoopStart=-1 LoopEnd=-1, then 3 secuential comments: "MarkerNum" + "M=7F(start)" + "M=7F(end)" */ loop_flag = 1; } - else if (strstr(user_comment,"M=7F")==user_comment) { /* Megaman X Legacy Collection: MMX1/2/3 (PC) start/end */ + else if (strstr(comment,"M=7F") == comment) { /* Megaman X Legacy Collection: MMX1/2/3 (PC) start/end */ if (loop_flag && loop_start < 0) { /* LoopStart should set as -1 before */ - sscanf(user_comment,"M=7F%x", &loop_start); + sscanf(comment,"M=7F%x", &loop_start); } else if (loop_flag && loop_start >= 0) { - sscanf(user_comment,"M=7F%x", &loop_end); + sscanf(comment,"M=7F%x", &loop_end); loop_end_found = 1; } } @@ -637,26 +516,33 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb /* Hatsune Miku Project DIVA games, though only 'Arcade Future Tone' has >4ch files * ENCODER tag is common but ogg_vorbis_encode looks unique enough * (arcade ends with "2010-11-26" while consoles have "2011-02-07" */ - if (strstr(user_comment, "ENCODER=ogg_vorbis_encode/") == user_comment) { - data->disable_reordering = 1; + if (strstr(comment, "ENCODER=ogg_vorbis_encode/") == comment) { + disable_reordering = 1; } - if (strstr(user_comment, "TITLE=") == user_comment) { - strncpy(name, user_comment + 6, sizeof(name) - 1); + if (strstr(comment, "TITLE=") == comment) { + strncpy(name, comment + 6, sizeof(name) - 1); } - ;VGM_LOG("OGG: user_comment=%s\n", user_comment); + ;VGM_LOG("OGG: user_comment=%s\n", comment); } } + ogg_vorbis_set_disable_reordering(data, disable_reordering); + ogg_vorbis_get_info(data, &channels, &sample_rate); + ogg_vorbis_get_samples(data, &num_samples); /* let libvorbisfile find total samples */ + /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(vi->channels,loop_flag); + vgmstream = allocate_vgmstream(channels,loop_flag); if (!vgmstream) goto fail; - vgmstream->codec_data = data; /* store our fun extra datas */ - vgmstream->channels = vi->channels; - vgmstream->sample_rate = vi->rate; + vgmstream->codec_data = data; + vgmstream->coding_type = coding_OGG_VORBIS; + vgmstream->layout_type = layout_none; + vgmstream->meta_type = ovmi->meta_type; + + vgmstream->sample_rate = sample_rate; vgmstream->stream_size = stream_size; if (ovmi->total_subsongs) /* not setting it has some effect when showing stream names */ @@ -665,11 +551,11 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb if (name[0] != '\0') strcpy(vgmstream->stream_name, name); - vgmstream->num_samples = ov_pcm_total(ovf,-1); /* let libvorbisfile find total samples */ + vgmstream->num_samples = num_samples; if (loop_flag) { vgmstream->loop_start_sample = loop_start; if (loop_length_found) - vgmstream->loop_end_sample = loop_start+loop_length; + vgmstream->loop_end_sample = loop_start + loop_length; else if (loop_end_found) vgmstream->loop_end_sample = loop_end; else @@ -679,10 +565,6 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb vgmstream->loop_end_sample = vgmstream->num_samples; } - vgmstream->coding_type = coding_OGG_VORBIS; - vgmstream->layout_type = layout_none; - vgmstream->meta_type = ovmi->meta_type; - if (vgmstream->channels <= 8) { vgmstream->channel_layout = xiph_mappings[vgmstream->channels]; } @@ -690,18 +572,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb return vgmstream; fail: - /* clean up anything we may have opened */ - if (data) { - if (ovf) - ov_clear(&data->ogg_vorbis_file);//same as ovf - if (data->ov_streamfile.streamfile) - close_streamfile(data->ov_streamfile.streamfile); - free(data); - } - if (vgmstream) { - vgmstream->codec_data = NULL; - close_vgmstream(vgmstream); - } + close_vgmstream(vgmstream); return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/riff.c b/Frameworks/vgmstream/vgmstream/src/meta/riff.c index aad822b84..b07483bbe 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/riff.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/riff.c @@ -1,15 +1,12 @@ +#include #include "meta.h" #include "../coding/coding.h" #include "../layout/layout.h" #include "../util.h" -#include +#include "riff_ogg_streamfile.h" /* RIFF - Resource Interchange File Format, standard container used in many games */ -#ifdef VGM_USE_VORBIS -static VGMSTREAM *parse_riff_ogg(STREAMFILE * streamFile, off_t start_offset, size_t data_size); -#endif - /* return milliseconds */ static long parse_adtl_marker(unsigned char * marker) { @@ -160,6 +157,8 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk case 0x02: /* MSADPCM */ if (fmt->bps == 4) { fmt->coding_type = coding_MSADPCM; + if (!msadpcm_check_coefs(streamFile, fmt->offset + 0x08 + 0x14)) + goto fail; } else if (fmt->bps == 16 && fmt->block_size == 0x02 * fmt->channel_count && fmt->size == 0x14) { fmt->coding_type = coding_IMA; /* MX vs ATV Unleashed (PC) codec hijack */ @@ -286,6 +285,7 @@ fail: } static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* streamFile, riff_fmt_chunk* fmt, int fact_sample_count, off_t start_offset); +static size_t get_ue4_msadpcm_interleave(STREAMFILE *sf, riff_fmt_chunk *fmt, off_t start, size_t size); VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { @@ -448,7 +448,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { break; case 0x66616374: /* "fact" */ - if (chunk_size == 0x04) { /* standard, usually found with ADPCM */ + if (chunk_size == 0x04) { /* standard (usually for ADPCM, MS recommends to set for non-PCM codecs) */ fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile); } else if (chunk_size == 0x10 && read_32bitBE(current_chunk+0x08+0x04, streamFile) == 0x4C794E20) { /* "LyN " */ @@ -537,13 +537,6 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { goto fail; } -#ifdef VGM_USE_VORBIS - /* special case using init_vgmstream_ogg_vorbis */ - if (fmt.coding_type == coding_OGG_VORBIS) { - return parse_riff_ogg(streamFile, start_offset, data_size); - } -#endif - /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(fmt.channel_count,loop_flag); @@ -555,7 +548,6 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { /* coding, layout, interleave */ vgmstream->coding_type = fmt.coding_type; switch (fmt.coding_type) { - case coding_MSADPCM: case coding_MS_IMA: case coding_AICA: case coding_XBOX_IMA: @@ -568,10 +560,19 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { #endif #ifdef VGM_USE_ATRAC9 case coding_ATRAC9: +#endif +#ifdef VGM_USE_VORBIS + case coding_OGG_VORBIS: #endif vgmstream->layout_type = layout_none; vgmstream->interleave_block_size = fmt.block_size; break; + + case coding_MSADPCM: + vgmstream->layout_type = layout_none; + vgmstream->frame_size = fmt.block_size; + break; + default: vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = fmt.interleave; @@ -694,10 +695,35 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { break; } #endif +#ifdef VGM_USE_VORBIS + case coding_OGG_VORBIS: { + /* special handling of Liar-soft's buggy RIFF+Ogg made with Soundforge [Shikkoku no Sharnoth (PC)] */ + STREAMFILE *temp_sf = setup_riff_ogg_streamfile(streamFile, start_offset, data_size); + if (!temp_sf) goto fail; + + vgmstream->codec_data = init_ogg_vorbis(temp_sf, 0x00, get_streamfile_size(temp_sf), NULL); + if (!vgmstream->codec_data) goto fail; + + /* Soundforge includes fact_samples and should be equal to Ogg samples */ + vgmstream->num_samples = fact_sample_count; + break; + } +#endif + default: goto fail; } + /* UE4 uses interleaved mono MSADPCM, try to autodetect without breaking normal MSADPCM */ + if (fmt.coding_type == coding_MSADPCM && is_ue4_msadpcm(vgmstream, streamFile, &fmt, fact_sample_count, start_offset)) { + vgmstream->coding_type = coding_MSADPCM_int; + vgmstream->frame_size = fmt.block_size; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = get_ue4_msadpcm_interleave(streamFile, &fmt, start_offset, data_size); + if (fmt.size == 0x36) + vgmstream->num_samples = read_s32le(fmt.offset+0x08+0x32, streamFile); + } + /* Dynasty Warriors 5 (Xbox) 6ch interleaves stereo frames, probably not official */ if (vgmstream->coding_type == coding_XBOX_IMA && vgmstream->channels > 2) { vgmstream->layout_type = layout_interleave; @@ -742,23 +768,9 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { vgmstream->meta_type = meta_RIFF_WAVE_MWV; } - if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) ) + if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) goto fail; - /* UE4 uses half-interleave mono MSADPCM, try to autodetect without breaking normal MSADPCM */ - if (fmt.coding_type == coding_MSADPCM && is_ue4_msadpcm(vgmstream, streamFile, &fmt, fact_sample_count, start_offset)) { - int ch; - size_t half_interleave = data_size / vgmstream->channels; - - vgmstream->coding_type = coding_MSADPCM_int; - - /* only works with half-interleave as frame_size and interleave are merged ATM */ - for (ch = 0; ch < vgmstream->channels; ch++) { - vgmstream->ch[ch].channel_start_offset = - vgmstream->ch[ch].offset = start_offset + half_interleave*ch; - } - } - return vgmstream; fail: @@ -767,10 +779,10 @@ fail: } /* UE4 MSADPCM is quite normal but has a few minor quirks we can use to detect it */ -static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* streamFile, riff_fmt_chunk* fmt, int fact_sample_count, off_t start_offset) { +static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* streamFile, riff_fmt_chunk* fmt, int fact_sample_count, off_t start) { - /* stereo only */ - if (fmt->channel_count != 2) + /* multichannel ok */ + if (fmt->channel_count < 2) goto fail; /* UE4 class is "ADPCM", assume it's the extension too */ @@ -785,13 +797,13 @@ static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* streamFile, riff_fmt if (fmt->block_size != 0x200) goto fail; - /* later UE4 versions use 0x36 (at 0x32 may be fact_samples?) */ + /* later UE4 versions use 0x36 */ if (fmt->size != 0x32 && fmt->size != 0x36) goto fail; /* size 0x32 in older UE4 matches standard MSADPCM, so add extra detection */ if (fmt->size == 0x32) { - off_t offset = start_offset; + off_t offset = start; off_t max_offset = 5 * fmt->block_size; /* try N blocks */ if (max_offset > get_streamfile_size(streamFile)) max_offset = get_streamfile_size(streamFile); @@ -810,6 +822,64 @@ fail: return 0; } +/* for maximum annoyance later UE4 versions (~v4.2x?) interleave single frames instead of + * half interleave, but don't have flags to detect so we need some heuristics */ +static size_t get_ue4_msadpcm_interleave(STREAMFILE *sf, riff_fmt_chunk *fmt, off_t start, size_t size) { + size_t v1_interleave = size / fmt->channel_count; + size_t v2_interleave = fmt->block_size; + uint8_t nibbles1[0x08] = {0}; + uint8_t nibbles2[0x08] = {0}; + + + /* old versions */ + if (fmt->size == 0x32) + return v1_interleave; + + /* 6ch only observed in later versions [Fortnite (PC)], not padded */ + if (fmt->channel_count > 2) + return v2_interleave; + + read_streamfile(nibbles1, start + size - 0x08, sizeof(nibbles2), sf); + read_streamfile(nibbles2, start + v1_interleave - 0x08, sizeof(nibbles2), sf); + + /* last frame is almost always padded, so should at half interleave */ + if (get_u64be(nibbles1) == 0 && get_u64be(nibbles2) == 0) + return v1_interleave; + + /* last frame is silent-ish, so should at half interleave (TSA's SML_DarknessLoop_01, TSA_CAD_YAKATA) + * this doesn't work too well b/c num_samples at 0x36 uses all data, may need adjustment */ + { + + int i; + int empty_nibbles1 = 1, empty_nibbles2 = 1; + + for (i = 0; i < sizeof(nibbles1); i++) { + uint8_t n1 = ((nibbles1[i] >> 0) & 0x0f); + uint8_t n2 = ((nibbles1[i] >> 4) & 0x0f); + if ((n1 != 0x0 && n1 != 0xf && n1 != 0x1) || (n2 != 0x0 && n2 != 0xf && n2 != 0x1)) { + empty_nibbles1 = 0; + break; + } + } + + for (i = 0; i < sizeof(nibbles2); i++) { + uint8_t n1 = ((nibbles2[i] >> 0) & 0x0f); + uint8_t n2 = ((nibbles2[i] >> 4) & 0x0f); + if ((n1 != 0x0 && n1 != 0xf && n1 != 0x1) || (n2 != 0x0 && n2 != 0xf && n2 != 0x1)) { + empty_nibbles2 = 0; + break; + } + } + + if (empty_nibbles1 && empty_nibbles2) + return v1_interleave; + } + + /* other tests? */ + + return v2_interleave; /* favor newer games */ +} + VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; riff_fmt_chunk fmt = {0}; @@ -940,95 +1010,3 @@ fail: close_vgmstream(vgmstream); return NULL; } - - -#ifdef VGM_USE_VORBIS -typedef struct { - off_t patch_offset; -} riff_ogg_io_data; - -static size_t riff_ogg_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, riff_ogg_io_data* data) { - size_t bytes_read = streamfile->read(streamfile, dest, offset, length); - - /* has garbage init Oggs pages, patch bad flag */ - if (data->patch_offset && data->patch_offset >= offset && data->patch_offset < offset + bytes_read) { - VGM_ASSERT(dest[data->patch_offset - offset] != 0x02, "RIFF Ogg: bad patch offset\n"); - dest[data->patch_offset - offset] = 0x00; - } - - return bytes_read; -} - -/* special handling of Liar-soft's buggy RIFF+Ogg made with Soundforge [Shikkoku no Sharnoth (PC)] */ -static VGMSTREAM *parse_riff_ogg(STREAMFILE * streamFile, off_t start_offset, size_t data_size) { - off_t patch_offset = 0; - size_t real_size = data_size; - - /* initial page flag is repeated and causes glitches in decoders, find bad offset */ - { - off_t offset = start_offset + 0x04+0x02; - off_t offset_limit = start_offset + data_size; /* usually in the first 0x3000 but can be +0x100000 */ - - while (offset < offset_limit) { - if (read_32bitBE(offset+0x00, streamFile) == 0x4f676753 && /* "OggS" */ - read_16bitBE(offset+0x04, streamFile) == 0x0002) { /* start page flag */ - - //todo callback should patch on-the-fly by analyzing all "OggS", but is problematic due to arbitrary offsets - if (patch_offset) { - VGM_LOG("RIFF Ogg: found multiple repeated start pages\n"); - return NULL; - } - - patch_offset = offset /*- start_offset*/ + 0x04+0x01; - } - offset++; //todo could be optimized to do OggS page sizes - } - } - - /* last pages don't have the proper flag and confuse decoders, find actual end */ - { - size_t max_size = data_size; - off_t offset_limit = start_offset + data_size - 0x1000; /* not worth checking more, let decoder try */ - off_t offset = start_offset + data_size - 0x1a; - - while (offset > offset_limit) { - if (read_32bitBE(offset+0x00, streamFile) == 0x4f676753) { /* "OggS" */ - if (read_16bitBE(offset+0x04, streamFile) == 0x0004) { /* last page flag */ - real_size = max_size; - break; - } else { - max_size = offset - start_offset; /* ignore bad pages */ - } - } - offset--; - } - } - - /* Soundforge includes fact_samples but should be equal to Ogg samples */ - - /* actual Ogg init with custom callback to patch weirdness */ - { - VGMSTREAM *vgmstream = NULL; - STREAMFILE *custom_streamFile = NULL; - ogg_vorbis_meta_info_t ovmi = {0}; - riff_ogg_io_data io_data = {0}; - size_t io_data_size = sizeof(riff_ogg_io_data); - - - ovmi.meta_type = meta_RIFF_WAVE; - ovmi.stream_size = real_size; - //inf.loop_flag = 0; /* not observed */ - - io_data.patch_offset = patch_offset; - - custom_streamFile = open_io_streamfile(open_wrap_streamfile(streamFile), &io_data,io_data_size, riff_ogg_io_read,NULL); - if (!custom_streamFile) return NULL; - - vgmstream = init_vgmstream_ogg_vorbis_callbacks(custom_streamFile, NULL, start_offset, &ovmi); - - close_streamfile(custom_streamFile); - - return vgmstream; - } -} -#endif diff --git a/Frameworks/vgmstream/vgmstream/src/meta/riff_ogg_streamfile.h b/Frameworks/vgmstream/vgmstream/src/meta/riff_ogg_streamfile.h new file mode 100644 index 000000000..6c7c599de --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/riff_ogg_streamfile.h @@ -0,0 +1,130 @@ +#ifndef _RIFF_OGG_STREAMFILE_H_ +#define _RIFF_OGG_STREAMFILE_H_ +#include "../streamfile.h" + +#ifdef VGM_USE_VORBIS +typedef struct { + off_t patch_offset; +} riff_ogg_io_data; + +static size_t riff_ogg_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, riff_ogg_io_data* data) { + size_t bytes_read = streamfile->read(streamfile, dest, offset, length); + + /* has garbage init Oggs pages, patch bad flag */ + if (data->patch_offset && data->patch_offset >= offset && data->patch_offset < offset + bytes_read) { + VGM_ASSERT(dest[data->patch_offset - offset] != 0x02, "RIFF Ogg: bad patch offset at %lx\n", data->patch_offset); + dest[data->patch_offset - offset] = 0x00; + } + + return bytes_read; +} + +static size_t ogg_get_page(uint8_t *buf, size_t bufsize, off_t offset, STREAMFILE *sf) { + size_t segments, bytes, page_size; + int i; + + if (0x1b > bufsize) goto fail; + bytes = read_streamfile(buf, offset, 0x1b, sf); + if (bytes != 0x1b) goto fail; + + segments = get_u8(buf + 0x1a); + if (0x1b + segments > bufsize) goto fail; + + bytes = read_streamfile(buf + 0x1b, offset + 0x1b, segments, sf); + if (bytes != segments) goto fail; + + page_size = 0x1b + segments; + for (i = 0; i < segments; i++) { + page_size += get_u8(buf + 0x1b + i); + } + + return page_size; +fail: + return 0; +} + +/* patches Oggs with weirdness */ +static STREAMFILE* setup_riff_ogg_streamfile(STREAMFILE *sf, off_t start, size_t size) { + off_t patch_offset = 0; + size_t real_size = size; + uint8_t buf[0x1000]; + + + /* initial page flag is repeated and causes glitches in decoders, find bad offset */ + //todo callback could patch on-the-fly by analyzing all "OggS", but is problematic due to arbitrary offsets + { + off_t offset = start; + size_t page_size; + off_t offset_limit = start + size; /* usually in the first 0x3000 but can be +0x100000 */ + //todo this doesn't seem to help much + STREAMFILE *temp_sf = reopen_streamfile(sf, 0x100); /* use small-ish sf to avoid reading the whole thing */ + + /* first page is ok */ + page_size = ogg_get_page(buf, sizeof(buf), offset, temp_sf); + offset += page_size; + + while (offset < offset_limit) { + page_size = ogg_get_page(buf, sizeof(buf), offset, temp_sf); + if (page_size == 0) break; + + if (get_u32be(buf + 0x00) != 0x4f676753) /* "OggS" */ + break; + + if (get_u16be(buf + 0x04) == 0x0002) { /* start page flag */ + //;VGM_ASSERT(patch_offset > 0, "RIFF Ogg: found multiple repeated start pages\n"); + patch_offset = (offset - start) + 0x04 + 0x01; /* clamp'ed */ + break; + } + + offset += page_size; + } + + close_streamfile(temp_sf); + + if (patch_offset == 0) + return NULL; + } + + /* has a bunch of padding(?) pages at the end with no data nor flag that confuse decoders, find actual end */ + { + size_t chunk_size = sizeof(buf); /* not worth testing more */ + size_t max_size = size; + size_t pos; + off_t read_offset = start + size - chunk_size; + + pos = read_streamfile(buf, read_offset, chunk_size, sf); + if (read_offset < 0 || pos <= 0x1a) return NULL; + + pos -= 0x1a; /* at least one OggS page */ + while (pos > 0) { + if (get_u32be(buf + pos + 0x00) == 0x4f676753) { /* "OggS" */ + + if (get_u16be(buf + pos + 0x04) == 0x0004) { /* last page flag is ok */ + real_size = max_size; + break; + } + else { /* last page flag is wrong */ + max_size = size - (chunk_size - pos); /* update size up to this page */ + } + } + pos--; + } + } + + /* actual custom streamfile init */ + { + STREAMFILE *new_sf = NULL; + riff_ogg_io_data io_data = {0}; + + io_data.patch_offset = patch_offset; + + new_sf = open_wrap_streamfile(sf); + new_sf = open_clamp_streamfile_f(new_sf, start, real_size); + new_sf = open_io_streamfile_f(new_sf, &io_data, sizeof(riff_ogg_io_data), riff_ogg_io_read, NULL); + return new_sf; + } +} + +#endif /* VGM_USE_VORBIS */ + +#endif /* _RIFF_OGG_STREAMFILE_H_ */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sd9.c b/Frameworks/vgmstream/vgmstream/src/meta/sd9.c index 9c373bf86..dbe9d264a 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sd9.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sd9.c @@ -1,17 +1,16 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* SD9 (found in beatmania IIDX Arcade games) */ +/* SD9 - from Konami arcade games [beatmania IIDX series (AC), BeatStream (AC)] */ VGMSTREAM * init_vgmstream_sd9(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; int loop_flag, channel_count; - /* check extension */ + /* checks */ if (!check_extensions(streamFile, "sd9")) goto fail; - /* check header */ if (read_32bitBE(0x0, streamFile) != 0x53443900) /* SD9 */ goto fail; if (read_32bitBE(0x20, streamFile) != 0x52494646) /* RIFF */ @@ -30,27 +29,26 @@ VGMSTREAM * init_vgmstream_sd9(STREAMFILE *streamFile) { //loop_flag = (read_16bitLE(0x0e,streamFile)==0x1); loop_flag = read_32bitLE(0x18, streamFile); // use loop end channel_count = read_16bitLE(0x36, streamFile); + start_offset = 0x7a; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count, loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = 0x7a; - vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(0x38, streamFile); - vgmstream->coding_type = coding_MSADPCM; vgmstream->num_samples = read_32bitLE(0x6e, streamFile); if (loop_flag) { vgmstream->loop_start_sample = read_32bitLE(0x14, streamFile) / 2 / channel_count; vgmstream->loop_end_sample = read_32bitLE(0x18, streamFile) / 2 / channel_count; } + vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = read_16bitLE(0x40, streamFile); + vgmstream->frame_size = read_16bitLE(0x40, streamFile); vgmstream->meta_type = meta_SD9; + if (!msadpcm_check_coefs(streamFile, 0x48)) + goto fail; - /* open the file for reading */ if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) goto fail; return vgmstream; @@ -58,4 +56,4 @@ VGMSTREAM * init_vgmstream_sd9(STREAMFILE *streamFile) { fail: close_vgmstream(vgmstream); return NULL; -} \ No newline at end of file +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c b/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c index f05bb748f..cc9c0f36c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sgxd.c @@ -112,6 +112,14 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) { read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamHeader); switch (type) { +#ifdef VGM_USE_FFMPEG + case 0x02: /* Ogg Vorbis [Ni no Kuni: Wrath of the White Witch Remastered (PC)] (codec hijack?) */ + vgmstream->codec_data = init_ogg_vorbis(streamFile, start_offset, stream_size, NULL); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_OGG_VORBIS; + vgmstream->layout_type = layout_none; + break; +#endif case 0x03: /* PS-ADPCM [Genji (PS3), Ape Escape Move (PS3)]*/ vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_interleave; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sli.c b/Frameworks/vgmstream/vgmstream/src/meta/sli.c index 2ecf5427e..41554ed1a 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sli.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sli.c @@ -53,39 +53,39 @@ VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE *streamFile) { /* find loop text */ { - char linebuffer[PATH_LIMIT]; + char line[PATH_LIMIT]; size_t bytes_read; off_t sli_offset; - int done; + int line_ok; sli_offset = 0; while ((loop_start == -1 || loop_length == -1) && sli_offset < get_streamfile_size(streamFile)) { char *endptr, *foundptr; - bytes_read = get_streamfile_text_line(sizeof(linebuffer),linebuffer,sli_offset,streamFile,&done); - if (!done) goto fail; + bytes_read = read_line(line, sizeof(line), sli_offset, streamFile, &line_ok); + if (!line_ok) goto fail; - if (memcmp("LoopStart=",linebuffer,10)==0 && linebuffer[10] != '\0') { - loop_start = strtol(linebuffer+10,&endptr,10); + if (memcmp("LoopStart=",line,10)==0 && line[10] != '\0') { + loop_start = strtol(line+10,&endptr,10); if (*endptr != '\0') { loop_start = -1; /* if it didn't parse cleanly */ } } - else if (memcmp("LoopLength=",linebuffer,11)==0 && linebuffer[11] != '\0') { - loop_length = strtol(linebuffer+11,&endptr,10); + else if (memcmp("LoopLength=",line,11)==0 && line[11] != '\0') { + loop_length = strtol(line+11,&endptr,10); if (*endptr != '\0') { loop_length = -1; /* if it didn't parse cleanly */ } } /* a completely different format (2.0?), also with .sli extension and can be handled similarly */ - if ((foundptr = strstr(linebuffer,"To=")) != NULL && isdigit(foundptr[3])) { + if ((foundptr = strstr(line,"To=")) != NULL && isdigit(foundptr[3])) { loop_to = strtol(foundptr+3,&endptr,10); if (*endptr != ';') { loop_to = -1; } } - if ((foundptr = strstr(linebuffer,"From=")) != NULL && isdigit(foundptr[5])) { + if ((foundptr = strstr(line,"From=")) != NULL && isdigit(foundptr[5])) { loop_from = strtol(foundptr+5,&endptr,10); if (*endptr != ';') { loop_from = -1; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/smp.c b/Frameworks/vgmstream/vgmstream/src/meta/smp.c index 8549b6787..c7025e4ae 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/smp.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/smp.c @@ -74,11 +74,12 @@ VGMSTREAM * init_vgmstream_smp(STREAMFILE *streamFile) { case 0x04: if (bps != 4) goto fail; - /* 0x34: standard MSADPCM coef table */ + if (!msadpcm_check_coefs(streamFile, 0x36)) + goto fail; vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = 0x86*channel_count; + vgmstream->frame_size = 0x86*channel_count; break; case 0x06: diff --git a/Frameworks/vgmstream/vgmstream/src/meta/spt_spd.c b/Frameworks/vgmstream/vgmstream/src/meta/spt_spd.c index 5535a74b4..f21322a08 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/spt_spd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/spt_spd.c @@ -1,109 +1,110 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* SPT+SPT - - 2008-11-27 - manakoAT : First try for splitted files... -*/ +/* SPD+SPT - Nintendo bank (bgm or sfx) format [Bloodrayne (GC), 4x4 EVO 2 (GC), Table Tennis (Wii)] */ VGMSTREAM * init_vgmstream_spt_spd(STREAMFILE *streamFile) { - - VGMSTREAM * vgmstream = NULL; - STREAMFILE * streamFileSPT = NULL; - char filename[PATH_LIMIT]; - char filenameSPT[PATH_LIMIT]; - int channel_count; - int loop_flag; - int i; + VGMSTREAM *vgmstream = NULL; + STREAMFILE *sf_h = NULL; + int channel_count, loop_flag, sample_rate; + off_t header_offset, extra_offset, start_offset; + int32_t loop_start, loop_end, stream_start, stream_end; + size_t stream_size; + uint32_t flags; + int total_subsongs, target_subsong = streamFile->stream_index; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("spd",filename_extension(filename))) goto fail; - strcpy(filenameSPT,filename); - strcpy(filenameSPT+strlen(filenameSPT)-3,"spt"); - - streamFileSPT = streamFile->open(streamFile,filenameSPT,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!streamFileSPT) + /* checks */ + if (!check_extensions(streamFile, "spd")) goto fail; - - if (read_32bitBE(0x0,streamFileSPT) != 0x1) // make sure that it's not a container + sf_h = open_streamfile_by_ext(streamFile, "spt"); + if (!sf_h) goto fail; + + /* ignore alt .spt+spd [Spyro: Enter the Dragonfly (GC)] */ + if (read_u16be(0x00, sf_h) != 0) /* always 0xA20C? */ goto fail; - channel_count = 1; - loop_flag = (read_32bitBE(0x0C,streamFileSPT) == 0x2); + total_subsongs = read_s32be(0x00, sf_h); + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; + + header_offset = 0x04 + 0x1c * (target_subsong-1); + extra_offset = 0x04 + 0x1c * total_subsongs + 0x2e * (target_subsong-1); + + flags = read_u32be(header_offset + 0x00, sf_h); + sample_rate = read_s32be(header_offset + 0x04, sf_h); + loop_start = read_s32be(header_offset + 0x08, sf_h); + loop_end = read_s32be(header_offset + 0x0c, sf_h); + stream_end = read_s32be(header_offset + 0x10, sf_h); + stream_start = read_s32be(header_offset + 0x14, sf_h); + /* 0x18: null */ + + channel_count = 1; + loop_flag = (flags & 1); + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitBE(0x08,streamFileSPT); - - switch ((read_32bitBE(0x4,streamFileSPT))) { - case 0: - case 1: - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->num_samples=read_32bitBE(0x14,streamFileSPT)*14/16/channel_count; - if(loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = read_32bitBE(0x14,streamFileSPT)*14/16/channel_count; - } - break; - case 2: - vgmstream->coding_type = coding_PCM16BE; - vgmstream->num_samples=read_32bitBE(0x14,streamFileSPT)/channel_count; - if(loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = read_32bitBE(0x14,streamFileSPT)/channel_count; - } - break; - default: - goto fail; - } - - if (channel_count == 1) { - vgmstream->layout_type = layout_none; - } else if (channel_count == 2) { - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size=(read_32bitBE(0x34,streamFileSPT)*channel_count)/2; - } - vgmstream->meta_type = meta_SPT_SPD; vgmstream->allow_dual_stereo = 1; + vgmstream->sample_rate = sample_rate; + vgmstream->layout_type = layout_none; - /* open the file for reading */ - { - for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - vgmstream->ch[i].offset = 0; - if (!vgmstream->ch[i].streamfile) goto fail; - } - } + vgmstream->num_streams = total_subsongs; - - - if (vgmstream->coding_type == coding_NGC_DSP) { - int i; - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x20+i*2,streamFileSPT); - } - if (vgmstream->channels == 2) { - for (i=0;i<16;i++) { - vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x40+i*2,streamFileSPT); + switch(flags & (~1)) { /* bitflags */ + case 0: /* common */ + /* values in file nibbles? */ + start_offset = (stream_start / 2 - 1); + stream_size = (stream_end / 2 + 1) - (stream_start / 2 - 1); + if (loop_flag) { + loop_start = (loop_start / 2 - 1) - start_offset; + loop_end = (loop_end / 2 + 1) - start_offset; } - } + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->num_samples = dsp_bytes_to_samples(stream_size, channel_count); + if (loop_flag) { + vgmstream->loop_start_sample = dsp_bytes_to_samples(loop_start, channel_count); + vgmstream->loop_end_sample = dsp_bytes_to_samples(loop_end, channel_count); + } + dsp_read_coefs_be(vgmstream, sf_h, extra_offset + 0x00, 0x00); + dsp_read_hist_be (vgmstream, sf_h, extra_offset + 0x24, 0x00); + break; + + case 2: /* rare [Monster Jam: Maximum Destruction (GC)] */ + /* values in samples? */ + start_offset = (stream_start * 2); + stream_size = (stream_end * 2) - (stream_start * 2); + if (loop_flag) { + loop_start = (loop_start * 2) - start_offset; + loop_end = (loop_end * 2) - start_offset; + } + + vgmstream->coding_type = coding_PCM16BE; + vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16); + if (loop_flag) { + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; + } + break; + + case 4: /* supposedly PCM8 */ + default: + goto fail; } + vgmstream->stream_size = stream_size; - close_streamfile(streamFileSPT); streamFileSPT=NULL; + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + close_streamfile(sf_h); return vgmstream; - /* clean up anything we may have opened */ fail: - if (streamFileSPT) close_streamfile(streamFileSPT); - if (vgmstream) close_vgmstream(vgmstream); + close_streamfile(sf_h); + close_vgmstream(vgmstream); return NULL; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c b/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c index e17e803de..286a5f9d4 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c @@ -270,13 +270,15 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) { case 0x0C: /* MS ADPCM [Final Fantasy XIV (PC) sfx] */ vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = read_16bit(extradata_offset+0x0c,streamFile); - /* in extradata_offset is a WAVEFORMATEX (including coefs and all) */ + vgmstream->frame_size = read_16bit(extradata_offset + 0x0c, streamFile); + /* WAVEFORMATEX in extradata_offset */ + if (!msadpcm_check_coefs(streamFile, extradata_offset + 0x14)) + goto fail; - vgmstream->num_samples = msadpcm_bytes_to_samples(stream_size, vgmstream->interleave_block_size, vgmstream->channels); + vgmstream->num_samples = msadpcm_bytes_to_samples(stream_size, vgmstream->frame_size, vgmstream->channels); if (loop_flag) { - vgmstream->loop_start_sample = msadpcm_bytes_to_samples(loop_start, vgmstream->interleave_block_size, vgmstream->channels); - vgmstream->loop_end_sample = msadpcm_bytes_to_samples(loop_end, vgmstream->interleave_block_size, vgmstream->channels); + vgmstream->loop_start_sample = msadpcm_bytes_to_samples(loop_start, vgmstream->frame_size, vgmstream->channels); + vgmstream->loop_end_sample = msadpcm_bytes_to_samples(loop_end, vgmstream->frame_size, vgmstream->channels); } break; @@ -416,23 +418,24 @@ fail: #ifdef VGM_USE_VORBIS static void scd_ogg_v2_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) { - size_t bytes_read = size*nmemb; - ogg_vorbis_streamfile * ov_streamfile = (ogg_vorbis_streamfile*)datasource; + uint8_t *ptr8 = ptr; + size_t bytes_read = size * nmemb; + ogg_vorbis_io *io = datasource; /* no encryption, sometimes happens */ - if (ov_streamfile->scd_xor == 0x00) + if (io->scd_xor == 0x00) return; /* header is XOR'd with a constant byte */ - if (ov_streamfile->offset < ov_streamfile->scd_xor_length) { + if (io->offset < io->scd_xor_length) { int i, num_crypt; - num_crypt = ov_streamfile->scd_xor_length - ov_streamfile->offset; + num_crypt = io->scd_xor_length - io->offset; if (num_crypt > bytes_read) num_crypt = bytes_read; for (i = 0; i < num_crypt; i++) { - ((uint8_t*)ptr)[i] ^= (uint8_t)ov_streamfile->scd_xor; + ptr8[i] ^= (uint8_t)io->scd_xor; } } } @@ -457,25 +460,25 @@ static void scd_ogg_v3_decryption_callback(void *ptr, size_t size, size_t nmemb, 0xE2, 0xA2, 0x67, 0x32, 0x32, 0x12, 0x32, 0xB2, 0x32, 0x32, 0x32, 0x32, 0x75, 0xA3, 0x26, 0x7B, // E0-EF 0x83, 0x26, 0xF9, 0x83, 0x2E, 0xFF, 0xE3, 0x16, 0x7D, 0xC0, 0x1E, 0x63, 0x21, 0x07, 0xE3, 0x01, // F0-FF }; - - size_t bytes_read = size*nmemb; - ogg_vorbis_streamfile *ov_streamfile = (ogg_vorbis_streamfile*)datasource; + uint8_t *ptr8 = ptr; + size_t bytes_read = size * nmemb; + ogg_vorbis_io *io = datasource; /* file is XOR'd with a table (algorithm and table by Ioncannon) */ - { //if (ov_streamfile->offset < ov_streamfile->scd_xor_length) + { //if (io->offset < io->scd_xor_length) int i, num_crypt; uint8_t byte1, byte2, xor_byte; num_crypt = bytes_read; - byte1 = ov_streamfile->scd_xor & 0x7F; - byte2 = ov_streamfile->scd_xor & 0x3F; + byte1 = io->scd_xor & 0x7F; + byte2 = io->scd_xor & 0x3F; for (i = 0; i < num_crypt; i++) { - xor_byte = scd_ogg_v3_lookuptable[(byte2 + ov_streamfile->offset + i) & 0xFF]; + xor_byte = scd_ogg_v3_lookuptable[(byte2 + io->offset + i) & 0xFF]; xor_byte &= 0xFF; - xor_byte ^= ((uint8_t*)ptr)[i]; + xor_byte ^= ptr8[i]; xor_byte ^= byte1; - ((uint8_t*)ptr)[i] = (uint8_t)xor_byte; + ptr8[i] = xor_byte; } } } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/sqex_sead.c b/Frameworks/vgmstream/vgmstream/src/meta/sqex_sead.c index 66c3f4e56..524c4b29d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/sqex_sead.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/sqex_sead.c @@ -125,11 +125,11 @@ VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile) { /* 0x00 (2): null?, 0x02(2): entry size? */ vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = read_16bit(sead.extradata_offset+0x04,streamFile); + vgmstream->frame_size = read_16bit(sead.extradata_offset+0x04,streamFile); /* much like AKBs, there are slightly different loop values here, probably more accurate * (if no loop, loop_end doubles as num_samples) */ - vgmstream->num_samples = msadpcm_bytes_to_samples(sead.stream_size, vgmstream->interleave_block_size, vgmstream->channels); + vgmstream->num_samples = msadpcm_bytes_to_samples(sead.stream_size, vgmstream->frame_size, vgmstream->channels); vgmstream->loop_start_sample = read_32bit(sead.extradata_offset+0x08, streamFile); //loop_start vgmstream->loop_end_sample = read_32bit(sead.extradata_offset+0x0c, streamFile); //loop_end break; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/txth.c b/Frameworks/vgmstream/vgmstream/src/meta/txth.c index 6b0d0ae62..eb307fad5 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/txth.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/txth.c @@ -337,13 +337,15 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) { vgmstream->interleave_block_size = txth.interleave; vgmstream->layout_type = layout_none; break; + case coding_MSADPCM: if (vgmstream->channels > 2) goto fail; - if (!txth.interleave) goto fail; /* creates garbage */ + if (!txth.interleave) goto fail; - vgmstream->interleave_block_size = txth.interleave; + vgmstream->frame_size = txth.interleave; vgmstream->layout_type = layout_none; break; + case coding_XBOX_IMA: if (txth.codec_mode == 1) { /* mono interleave */ coding = coding_XBOX_IMA_int; @@ -772,12 +774,12 @@ static int parse_txth(txth_header * txth) { /* read lines */ while (txt_offset < file_size) { - char line[TXT_LINE_MAX] = {0}; + char line[TXT_LINE_MAX]; char key[TXT_LINE_MAX] = {0}, val[TXT_LINE_MAX] = {0}; /* at least as big as a line to avoid overflows (I hope) */ - int ok, bytes_read, line_done; + int ok, bytes_read, line_ok; - bytes_read = get_streamfile_text_line(TXT_LINE_MAX,line, txt_offset,txth->streamText, &line_done); - if (!line_done) goto fail; + bytes_read = read_line(line, sizeof(line), txt_offset, txth->streamText, &line_ok); + if (!line_ok) goto fail; //;VGM_LOG("TXTH: line=%s\n",line); txt_offset += bytes_read; @@ -1441,12 +1443,12 @@ static int parse_name_table(txth_header * txth, char * name_list) { /* read lines and find target filename, format is (filename): value1, ... valueN */ while (txt_offset < file_size) { - char line[TXT_LINE_MAX] = {0}; + char line[TXT_LINE_MAX]; char key[TXT_LINE_MAX] = {0}, val[TXT_LINE_MAX] = {0}; - int ok, bytes_read, line_done; + int ok, bytes_read, line_ok; - bytes_read = get_streamfile_text_line(TXT_LINE_MAX,line, txt_offset,nameFile, &line_done); - if (!line_done) goto fail; + bytes_read = read_line(line, sizeof(line), txt_offset, nameFile, &line_ok); + if (!line_ok) goto fail; //;VGM_LOG("TXTH: line=%s\n",line); txt_offset += bytes_read; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/txtp.c b/Frameworks/vgmstream/vgmstream/src/meta/txtp.c index 976d30c27..c9102e93f 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/txtp.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/txtp.c @@ -1434,13 +1434,13 @@ static txtp_header* parse_txtp(STREAMFILE* streamFile) { /* read and parse lines */ while (txt_offset < file_size) { - char line[TXTP_LINE_MAX] = {0}; + char line[TXTP_LINE_MAX]; char key[TXTP_LINE_MAX] = {0}, val[TXTP_LINE_MAX] = {0}; /* at least as big as a line to avoid overflows (I hope) */ char filename[TXTP_LINE_MAX] = {0}; - int ok, bytes_read, line_done; + int ok, bytes_read, line_ok; - bytes_read = get_streamfile_text_line(TXTP_LINE_MAX,line, txt_offset,streamFile, &line_done); - if (!line_done) goto fail; + bytes_read = read_line(line, sizeof(line), txt_offset, streamFile, &line_ok); + if (!line_ok) goto fail; txt_offset += bytes_read; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c index dd719cfb5..c6309982c 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c @@ -379,22 +379,17 @@ static VGMSTREAM * init_vgmstream_ubi_bao_base(ubi_bao_header * bao, STREAMFILE vgmstream->layout_type = layout_none; break; } - +#endif +#ifdef VGM_USE_VORBIS case FMT_OGG: { - ffmpeg_codec_data *ffmpeg_data; - - ffmpeg_data = init_ffmpeg_offset(streamData, start_offset, bao->stream_size); - if (!ffmpeg_data) goto fail; - vgmstream->codec_data = ffmpeg_data; - vgmstream->coding_type = coding_FFmpeg; + vgmstream->codec_data = init_ogg_vorbis(streamData, start_offset, bao->stream_size, NULL); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_OGG_VORBIS; vgmstream->layout_type = layout_none; - vgmstream->num_samples = bao->num_samples; /* ffmpeg_data->totalSamples */ - VGM_ASSERT(bao->num_samples != ffmpeg_data->totalSamples, - "UBI BAO: header samples %i vs ffmpeg %i differ\n", bao->num_samples, (uint32_t)ffmpeg_data->totalSamples); + vgmstream->num_samples = bao->num_samples; /* same as Ogg samples */ break; } - #endif default: goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c index 48020a1c8..454f8c85b 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c @@ -107,10 +107,10 @@ static int parse_name_bnh(ubi_hx_header * hx, STREAMFILE *sf, uint32_t cuuid1, u /* each .bnh line has a cuuid, a bunch of repeated fields and name (sometimes name is filename or "bad name") */ while (txt_offset < get_streamfile_size(sf)) { - int line_read, bytes_read; + int line_ok, bytes_read; - bytes_read = get_streamfile_text_line(TXT_LINE_MAX,line, txt_offset,sf_t, &line_read); - if (!line_read) break; + bytes_read = read_line(line, sizeof(line), txt_offset, sf_t, &line_ok); + if (!line_ok) break; txt_offset += bytes_read; if (strncmp(line,cuuid,31) != 0) diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_jade.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_jade.c index 35f44bfb9..0d9f17ff4 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_jade.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_jade.c @@ -209,9 +209,9 @@ VGMSTREAM * init_vgmstream_ubi_jade(STREAMFILE *streamFile) { vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = 0x24*channel_count; + vgmstream->frame_size = block_size; - vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, vgmstream->interleave_block_size, channel_count); + vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, vgmstream->frame_size, channel_count); if (!is_jade_v2) { vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = vgmstream->num_samples; @@ -221,7 +221,7 @@ VGMSTREAM * init_vgmstream_ubi_jade(STREAMFILE *streamFile) { case 0x0001: { /* PS3 */ VGMSTREAM *temp_vgmstream = NULL; - STREAMFILE *temp_streamFile = NULL; + STREAMFILE *temp_sf = NULL; if (fmt_size != 0x10) goto fail; if (block_size != 0x02*channel_count) goto fail; @@ -230,11 +230,11 @@ VGMSTREAM * init_vgmstream_ubi_jade(STREAMFILE *streamFile) { if (read_32bitBE(start_offset, streamFile) != 0x4D534643) /* "MSF\43" */ goto fail; - temp_streamFile = setup_subfile_streamfile(streamFile, start_offset, data_size, "msf"); - if (!temp_streamFile) goto fail; + temp_sf = setup_subfile_streamfile(streamFile, start_offset, data_size, "msf"); + if (!temp_sf) goto fail; - temp_vgmstream = init_vgmstream_msf(temp_streamFile); - close_streamfile(temp_streamFile); + temp_vgmstream = init_vgmstream_msf(temp_sf); + close_streamfile(temp_sf); if (!temp_vgmstream) goto fail; temp_vgmstream->meta_type = vgmstream->meta_type; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_raki.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_raki.c index 403900b21..c039d649b 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_raki.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_raki.c @@ -94,9 +94,12 @@ VGMSTREAM * init_vgmstream_ubi_raki(STREAMFILE *streamFile) { /* chunks: "data" */ vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = block_align; + vgmstream->frame_size = block_align; - vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, vgmstream->interleave_block_size, channel_count); + vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, vgmstream->frame_size, channel_count); + + if (!msadpcm_check_coefs(streamFile, fmt_offset + 0x14)) + goto fail; break; case 0x5769692061647063: /* "Wii adpc" */ diff --git a/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c b/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c index b1528ee22..fe3cb3cc1 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c @@ -661,14 +661,12 @@ static VGMSTREAM * init_vgmstream_ubi_sb_base(ubi_sb_header *sb, STREAMFILE *str xma_fix_raw_samples_ch(vgmstream, streamData, start_offset, sb->stream_size, sb->channels, 0, 0); break; } - +#endif +#ifdef VGM_USE_VORBIS case FMT_OGG: { - ffmpeg_codec_data *ffmpeg_data; - - ffmpeg_data = init_ffmpeg_offset(streamData, start_offset, sb->stream_size); - if ( !ffmpeg_data ) goto fail; - vgmstream->codec_data = ffmpeg_data; - vgmstream->coding_type = coding_FFmpeg; + vgmstream->codec_data = init_ogg_vorbis(streamData, start_offset, sb->stream_size, NULL); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_OGG_VORBIS; vgmstream->layout_type = layout_none; break; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/vxn.c b/Frameworks/vgmstream/vgmstream/src/meta/vxn.c index 27aacce09..252999411 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/vxn.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/vxn.c @@ -9,23 +9,23 @@ VGMSTREAM * init_vgmstream_vxn(STREAMFILE *streamFile) { size_t stream_size; int total_subsongs, target_subsong = streamFile->stream_index; - /* check extensions */ + /* checks */ if (!check_extensions(streamFile,"vxn")) goto fail; - /* check header/version chunk (RIFF-like format with many custom chunks) */ if (read_32bitBE(0x00,streamFile) != 0x566F784E) /* "VoxN" */ goto fail; if (read_32bitLE(0x10,streamFile) != get_streamfile_size(streamFile) ) goto fail; + /* header is RIFF-like with many custom chunks */ if (!find_chunk_le(streamFile, 0x41666D74,first_offset,0, &chunk_offset,NULL)) /* "Afmt" */ goto fail; codec = (uint16_t)read_16bitLE(chunk_offset+0x00, streamFile); channel_count = (uint16_t)read_16bitLE(chunk_offset+0x02, streamFile); sample_rate = read_32bitLE(chunk_offset+0x04, streamFile); block_align = (uint16_t)read_16bitLE(chunk_offset+0x08, streamFile); - bits = (uint16_t)read_16bitLE(chunk_offset+0x0a, streamFile); + bits = read_16bitLE(chunk_offset+0x0a, streamFile); /* files are divided into segment subsongs, often a leadout and loop in that order * (the "Plst" and "Rule" chunks may have order info) */ @@ -67,8 +67,13 @@ VGMSTREAM * init_vgmstream_vxn(STREAMFILE *streamFile) { if (bits != 4) goto fail; vgmstream->coding_type = coding_MSADPCM; - vgmstream->interleave_block_size = block_align; + vgmstream->frame_size = block_align; vgmstream->layout_type = layout_none; + + if (find_chunk_le(streamFile, 0x4D736165,first_offset,0, &chunk_offset,NULL)) { /* "Msae" */ + if (!msadpcm_check_coefs(streamFile, chunk_offset + 0x02)) + goto fail; + } break; case 0x0011: /* MS-IMA (ex. Asphalt 6) */ @@ -80,17 +85,17 @@ VGMSTREAM * init_vgmstream_vxn(STREAMFILE *streamFile) { break; #ifdef VGM_USE_FFMPEG - case 0x0800: { /* Musepack (ex. Asphalt Xtreme) */ - ffmpeg_codec_data * ffmpeg_data = NULL; - if (bits != 0xFFFF) goto fail; + case 0x0800: /* Musepack (ex. Asphalt Xtreme) */ + if (bits != -1) goto fail; - ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size); - if (!ffmpeg_data) goto fail; - vgmstream->codec_data = ffmpeg_data; + vgmstream->codec_data = init_ffmpeg_offset(streamFile, start_offset,stream_size); + if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; + + /* unlike standard .mpc, .vxn has no seek table so no need to fix */ + //ffmpeg_set_force_seek(vgmstream->codec_data); break; - } #endif default: @@ -98,7 +103,6 @@ VGMSTREAM * init_vgmstream_vxn(STREAMFILE *streamFile) { goto fail; } - /* open the file for reading */ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; return vgmstream; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/waf.c b/Frameworks/vgmstream/vgmstream/src/meta/waf.c index dbb944eda..ba73d1430 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/waf.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/waf.c @@ -12,7 +12,7 @@ VGMSTREAM * init_vgmstream_waf(STREAMFILE *streamFile) { if (!check_extensions(streamFile, "waf")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x57414600) /* "WAF\0" "*/ + if (read_32bitBE(0x00,streamFile) != 0x57414600) /* "WAF\0" */ goto fail; if (read_32bitLE(0x34,streamFile) + 0x38 != get_streamfile_size(streamFile)) goto fail; @@ -25,13 +25,17 @@ VGMSTREAM * init_vgmstream_waf(STREAMFILE *streamFile) { vgmstream = allocate_vgmstream(channel_count, loop_flag); if (!vgmstream) goto fail; - vgmstream->sample_rate = read_32bitLE(0x08, streamFile); vgmstream->meta_type = meta_WAF; + vgmstream->sample_rate = read_32bitLE(0x08, streamFile); + vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = read_16bitLE(0x10, streamFile); - vgmstream->num_samples = msadpcm_bytes_to_samples(read_32bitLE(0x34,streamFile), vgmstream->interleave_block_size, channel_count); - /* 0x04: null?, 0x0c: avg br, 0x12: bps, 0x14: s_p_f, 0x16~34: count + standard MSADPCM coefs (a modified RIFF fmt) */ + vgmstream->frame_size = read_16bitLE(0x10, streamFile); + /* 0x04: null?, 0x0c: avg br, 0x12: bps, 0x14: s_p_f, 0x16~34: coefs (a modified RIFF fmt) */ + if (!msadpcm_check_coefs(streamFile, 0x16)) + goto fail; + + vgmstream->num_samples = msadpcm_bytes_to_samples(read_32bitLE(0x34,streamFile), vgmstream->frame_size, channel_count); if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xa.c b/Frameworks/vgmstream/vgmstream/src/meta/xa.c index 5c919dacf..79c12ea6d 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xa.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xa.c @@ -2,21 +2,26 @@ #include "../layout/layout.h" #include "../coding/coding.h" -/* CD-XA - from Sony PS1 and Philips CD-i CD audio */ +/* CD-XA - from Sony PS1 and Philips CD-i CD audio, also Saturn streams */ VGMSTREAM * init_vgmstream_xa(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; int loop_flag = 0, channel_count, sample_rate; - int is_blocked; - size_t file_size = get_streamfile_size(streamFile); + int is_riff = 0, is_blocked = 0; + size_t file_size, stream_size; + int total_subsongs, /*target_subsong = streamFile->stream_index,*/ target_config; /* checks - * .xa: common, .str: sometimes (mainly videos) + * .xa: common + * .str: often (but not always) videos * .adp: Phantasy Star Collection (SAT) raw XA */ if ( !check_extensions(streamFile,"xa,str,adp") ) goto fail; + + file_size = get_streamfile_size(streamFile); + /* Proper XA comes in raw (BIN 2352 mode2/form2) CD sectors, that contain XA subheaders. * This also has minimal support for headerless (ISO 2048 mode1/data) mode. */ @@ -25,6 +30,7 @@ VGMSTREAM * init_vgmstream_xa(STREAMFILE *streamFile) { read_32bitBE(0x08,streamFile) == 0x43445841 && /* "CDXA" */ read_32bitBE(0x0C,streamFile) == 0x666D7420) { /* "fmt " */ is_blocked = 1; + is_riff = 1; start_offset = 0x2c; /* after "data" (chunk size tends to be a bit off) */ } else { @@ -36,22 +42,34 @@ VGMSTREAM * init_vgmstream_xa(STREAMFILE *streamFile) { start_offset = 0x00; } else { /* headerless and possibly incorrectly ripped */ - is_blocked = 0; start_offset = 0x00; } } /* test some blocks (except when RIFF) since other .XA/STR may start blank */ - if (start_offset == 0) { - int i, j, block; + if (!is_riff) { + int i, j, block = 0, miss = 0; off_t test_offset = start_offset; - size_t sector_size = (is_blocked ? 0x900 : 0x800); - size_t block_size = 0x80; + const size_t sector_size = (is_blocked ? 0x900 : 0x800); + const size_t block_size = 0x80; + const int block_max = 3; + const int miss_max = 25; + + while (block < block_max) { + uint8_t xa_submode = read_u8(test_offset + 0x12, streamFile); + int is_audio = !(xa_submode & 0x08) && (xa_submode & 0x04) && !(xa_submode & 0x02); + + if (is_blocked && !is_audio) { + miss++; + if (block == 0 && miss > miss_max) /* no a single audio block found */ + goto fail; + test_offset += sector_size + (is_blocked ? 0x18 + 0x18 : 0); + continue; + } - for (block = 0; block < 3; block++) { test_offset += (is_blocked ? 0x18 : 0x00); /* header */ - for (i = 0; i < (sector_size/block_size); i++) { + for (i = 0; i < (sector_size / block_size); i++) { /* XA headers checks: filter indexes should be 0..3, and shifts 0..C */ for (j = 0; j < 16; j++) { uint8_t header = (uint8_t)read_8bit(test_offset + j, streamFile); @@ -75,13 +93,72 @@ VGMSTREAM * init_vgmstream_xa(STREAMFILE *streamFile) { } test_offset += (is_blocked ? 0x18 : 0x00); /* footer */ + block++; + } + } + + /* find subsongs as XA can interleave sectors using 'file' and 'channel' makers (see blocked_xa.c) */ + if (is_blocked) { + off_t offset; + STREAMFILE *sf_test = NULL; + + /* mini buffer to speed up by reading headers only (not sure if O.S. has buffer though */ + sf_test = reopen_streamfile(streamFile, 0x10); + if (!sf_test) goto fail; + + //TODO add subsongs (optimized for giant xa) + // - only do if first sector and next sector have different channels? + // N sectors of the same channel then N sectors of another should't happen, but + // we need to read all sectors to count samples anyway. + // - read all sectors + // - skip non-audio sectors + // - find first actual stream start + // - detect file+channel change + register new subsong (or detect file end flags too) + // - save total sectors subsong_sectors[subsong] = N for quick sample calcs + stream size + // (block_update is much slower since it buffers all data) + total_subsongs = 0; + + target_config = -1; + + offset = start_offset; + while (offset < file_size) { + uint16_t xa_subheader = read_u16be(offset + 0x10, sf_test); + uint8_t xa_submode = read_u8 (offset + 0x12, sf_test); + int is_audio = !(xa_submode & 0x08) && (xa_submode & 0x04) && !(xa_submode & 0x02); + + if (!is_audio) { + offset += 0x900 + 0x18 + 0x18; + continue; + } + + + //if target_subsong .. + //total_subsongs++ + //... + target_config = xa_subheader; + start_offset = offset; //stream_offset + break; + } + + close_streamfile(sf_test); + + stream_size = file_size; + //stream_size = ...; + + //if (target_subsong == 0) target_subsong = 1; + //if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; + + /* file has no audio */ + if (target_config < 0) { + VGM_LOG("XA: no audio found"); + goto fail; } } /* data is ok: parse header */ if (is_blocked) { - /* parse 0x18 sector header (also see xa_blocked.c) */ + /* parse 0x18 sector header (also see blocked_xa.c) */ uint8_t xa_header = (uint8_t)read_8bit(start_offset + 0x13,streamFile); switch((xa_header >> 0) & 3) { /* 0..1: mono/stereo */ @@ -94,9 +171,9 @@ VGMSTREAM * init_vgmstream_xa(STREAMFILE *streamFile) { case 1: sample_rate = 18900; break; default: goto fail; } - switch((xa_header >> 4) & 3) { /* 4..5: bits per sample (0=4, 1=8) */ + switch((xa_header >> 4) & 3) { /* 4..5: bits per sample (0=4-bit ADPCM, 1=8-bit ADPCM) */ case 0: break; - default: /* PS1 games only do 4b */ + default: /* PS1 games only do 4-bit */ VGM_LOG("XA: unknown bits per sample found\n"); goto fail; } @@ -150,11 +227,16 @@ VGMSTREAM * init_vgmstream_xa(STREAMFILE *streamFile) { vgmstream->coding_type = coding_XA; vgmstream->layout_type = is_blocked ? layout_blocked_xa : layout_none; - /* open the file for reading */ + if (is_blocked) { + vgmstream->codec_config = target_config; + vgmstream->num_streams = total_subsongs; + vgmstream->stream_size = stream_size; + } + + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; - if (is_blocked) { /* calc num_samples as blocks may be empty or smaller than usual depending on flags */ vgmstream->next_block_offset = start_offset; @@ -162,7 +244,7 @@ VGMSTREAM * init_vgmstream_xa(STREAMFILE *streamFile) { block_update(vgmstream->next_block_offset,vgmstream); vgmstream->num_samples += vgmstream->current_block_samples; } - while (vgmstream->next_block_offset < get_streamfile_size(streamFile)); + while (vgmstream->next_block_offset < file_size); block_update(start_offset,vgmstream); } else { diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xnb.c b/Frameworks/vgmstream/vgmstream/src/meta/xnb.c index 961c25c75..930cc6cf7 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xnb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xnb.c @@ -79,7 +79,12 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) { block_align = read_16bit(current_offset+0x0c, streamFile); bps = read_16bit(current_offset+0x0e, streamFile); - if (codec == 0x166) { + if (codec == 0x0002) { + if (!msadpcm_check_coefs(streamFile, current_offset + 0x14)) + goto fail; + } + + if (codec == 0x0166) { xma2_parse_fmt_chunk_extra(streamFile, current_offset, &loop_flag, &num_samples, &loop_start, &loop_end, big_endian); xma_chunk_offset = current_offset; } @@ -122,7 +127,7 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) { if (!block_align) goto fail; vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = block_align; + vgmstream->frame_size = block_align; vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, block_align, channel_count); break; diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xwb.c b/Frameworks/vgmstream/vgmstream/src/meta/xwb.c index 244218609..5fe169e31 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xwb.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xwb.c @@ -449,7 +449,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) { case MS_ADPCM: /* Persona 4 Ultimax (AC) */ vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = (xwb.block_align + 22) * xwb.channels; /*22=CONVERSION_OFFSET (?)*/ + vgmstream->frame_size = (xwb.block_align + 22) * xwb.channels; /*22=CONVERSION_OFFSET (?)*/ break; #ifdef VGM_USE_FFMPEG @@ -540,11 +540,12 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) { vgmstream->layout_type = layout_none; break; } - +#endif +#ifdef VGM_USE_VORBIS case OGG: { /* Oddworld: Strangers Wrath (iOS/Android) extension */ - vgmstream->codec_data = init_ffmpeg_offset(streamFile, xwb.stream_offset, xwb.stream_size); - if ( !vgmstream->codec_data ) goto fail; - vgmstream->coding_type = coding_FFmpeg; + vgmstream->codec_data = init_ogg_vorbis(streamFile, xwb.stream_offset, xwb.stream_size, NULL); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_OGG_VORBIS; vgmstream->layout_type = layout_none; break; } diff --git a/Frameworks/vgmstream/vgmstream/src/meta/xwc.c b/Frameworks/vgmstream/vgmstream/src/meta/xwc.c index fec7a6219..dcd1e4fa3 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/xwc.c +++ b/Frameworks/vgmstream/vgmstream/src/meta/xwc.c @@ -97,14 +97,15 @@ VGMSTREAM * init_vgmstream_xwc(STREAMFILE *streamFile) { xma_fix_raw_samples(vgmstream, streamFile, start_offset,data_size, 0, 0,0); /* samples are ok, fix delay */ break; } - +#endif +#ifdef VGM_USE_VORBIS case 0x564F5242: { /* "VORB" (PC) */ start_offset = 0x30; data_size = data_size - start_offset; - vgmstream->codec_data = init_ffmpeg_offset(streamFile, start_offset,data_size); + vgmstream->codec_data = init_ogg_vorbis(streamFile, start_offset, data_size, NULL); if ( !vgmstream->codec_data ) goto fail; - vgmstream->coding_type = coding_FFmpeg; + vgmstream->coding_type = coding_OGG_VORBIS; vgmstream->layout_type = layout_none; vgmstream->sample_rate = read_32bitLE(start_offset + 0x28, streamFile); diff --git a/Frameworks/vgmstream/vgmstream/src/plugins.c b/Frameworks/vgmstream/vgmstream/src/plugins.c index 524132632..71ed37fb0 100644 --- a/Frameworks/vgmstream/vgmstream/src/plugins.c +++ b/Frameworks/vgmstream/vgmstream/src/plugins.c @@ -138,8 +138,8 @@ void vgmstream_tags_close(VGMSTREAM_TAGS *tags) { int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tags, STREAMFILE* tagfile) { off_t file_size = get_streamfile_size(tagfile); char currentname[VGMSTREAM_TAGS_LINE_MAX] = {0}; - char line[VGMSTREAM_TAGS_LINE_MAX] = {0}; - int ok, bytes_read, line_done, n1,n2; + char line[VGMSTREAM_TAGS_LINE_MAX]; + int ok, bytes_read, line_ok, n1,n2; if (!tags) return 0; @@ -193,8 +193,8 @@ int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tags, STREAMFILE* tagfile) { goto fail; } - bytes_read = get_streamfile_text_line(VGMSTREAM_TAGS_LINE_MAX,line, tags->offset,tagfile, &line_done); - if (!line_done || bytes_read == 0) goto fail; + bytes_read = read_line(line, sizeof(line), tags->offset, tagfile, &line_ok); + if (!line_ok || bytes_read == 0) goto fail; tags->offset += bytes_read; diff --git a/Frameworks/vgmstream/vgmstream/src/streamfile.c b/Frameworks/vgmstream/vgmstream/src/streamfile.c index bdbb2412d..6323e5276 100644 --- a/Frameworks/vgmstream/vgmstream/src/streamfile.c +++ b/Frameworks/vgmstream/vgmstream/src/streamfile.c @@ -20,13 +20,13 @@ typedef struct { size_t filesize; /* buffered file size */ } STDIO_STREAMFILE; -static STREAMFILE * open_stdio_streamfile_buffer(const char * const filename, size_t buffersize); -static STREAMFILE * open_stdio_streamfile_buffer_by_file(FILE *infile,const char * const filename, size_t buffersize); +static STREAMFILE* open_stdio_streamfile_buffer(const char * const filename, size_t buffersize); +static STREAMFILE* open_stdio_streamfile_buffer_by_file(FILE *infile, const char * const filename, size_t buffersize); -static size_t read_stdio(STDIO_STREAMFILE *streamfile,uint8_t * dest, off_t offset, size_t length) { +static size_t read_stdio(STDIO_STREAMFILE *streamfile, uint8_t *dst, off_t offset, size_t length) { size_t length_read_total = 0; - if (!streamfile->infile || !dest || length <= 0 || offset < 0) + if (!streamfile->infile || !dst || length <= 0 || offset < 0) return 0; /* is the part of the requested length in the buffer? */ @@ -38,11 +38,11 @@ static size_t read_stdio(STDIO_STREAMFILE *streamfile,uint8_t * dest, off_t offs if (length_to_read > length) length_to_read = length; - memcpy(dest,streamfile->buffer + offset_into_buffer,length_to_read); + memcpy(dst, streamfile->buffer + offset_into_buffer, length_to_read); length_read_total += length_to_read; length -= length_to_read; offset += length_to_read; - dest += length_to_read; + dst += length_to_read; } #ifdef VGM_DEBUG_OUTPUT @@ -77,7 +77,7 @@ static size_t read_stdio(STDIO_STREAMFILE *streamfile,uint8_t * dest, off_t offs /* fill the buffer (offset now is beyond buffer_offset) */ streamfile->buffer_offset = offset; - streamfile->validsize = fread(streamfile->buffer,sizeof(uint8_t),streamfile->buffersize,streamfile->infile); + streamfile->validsize = fread(streamfile->buffer, sizeof(uint8_t), streamfile->buffersize, streamfile->infile); /* decide how much must be read this time */ if (length > streamfile->buffersize) @@ -87,55 +87,55 @@ static size_t read_stdio(STDIO_STREAMFILE *streamfile,uint8_t * dest, off_t offs /* give up on partial reads (EOF) */ if (streamfile->validsize < length_to_read) { - memcpy(dest,streamfile->buffer,streamfile->validsize); + memcpy(dst, streamfile->buffer, streamfile->validsize); offset += streamfile->validsize; length_read_total += streamfile->validsize; break; } /* use the new buffer */ - memcpy(dest,streamfile->buffer,length_to_read); + memcpy(dst, streamfile->buffer, length_to_read); offset += length_to_read; length_read_total += length_to_read; length -= length_to_read; - dest += length_to_read; + dst += length_to_read; } streamfile->offset = offset; /* last fread offset */ return length_read_total; } -static size_t get_size_stdio(STDIO_STREAMFILE * streamfile) { +static size_t get_size_stdio(STDIO_STREAMFILE *streamfile) { return streamfile->filesize; } static off_t get_offset_stdio(STDIO_STREAMFILE *streamfile) { return streamfile->offset; } -static void get_name_stdio(STDIO_STREAMFILE *streamfile,char *buffer,size_t length) { - strncpy(buffer,streamfile->name,length); +static void get_name_stdio(STDIO_STREAMFILE *streamfile, char *buffer, size_t length) { + strncpy(buffer, streamfile->name, length); buffer[length-1]='\0'; } -static void close_stdio(STDIO_STREAMFILE * streamfile) { +static void close_stdio(STDIO_STREAMFILE *streamfile) { if (streamfile->infile) fclose(streamfile->infile); free(streamfile->buffer); free(streamfile); } -static STREAMFILE *open_stdio(STDIO_STREAMFILE *streamFile,const char * const filename,size_t buffersize) { +static STREAMFILE* open_stdio(STDIO_STREAMFILE *streamfile, const char * const filename, size_t buffersize) { if (!filename) return NULL; #if !defined (__ANDROID__) // if same name, duplicate the file pointer we already have open - if (streamFile->infile && !strcmp(streamFile->name,filename)) { + if (streamfile->infile && !strcmp(streamfile->name,filename)) { int newfd; FILE *newfile; - STREAMFILE *newstreamFile; + STREAMFILE *new_sf; - if ( ((newfd = dup(fileno(streamFile->infile))) >= 0) && (newfile = fdopen( newfd, "rb")) ) { - newstreamFile = open_stdio_streamfile_buffer_by_file(newfile,filename,buffersize); - if (newstreamFile) { - return newstreamFile; + if ( ((newfd = dup(fileno(streamfile->infile))) >= 0) && (newfile = fdopen(newfd, "rb")) ) { + new_sf = open_stdio_streamfile_buffer_by_file(newfile, filename, buffersize); + if (new_sf) { + return new_sf; } // failure, close it and try the default path (which will probably fail a second time) fclose(newfile); @@ -143,12 +143,12 @@ static STREAMFILE *open_stdio(STDIO_STREAMFILE *streamFile,const char * const fi } #endif // a normal open, open a new file - return open_stdio_streamfile_buffer(filename,buffersize); + return open_stdio_streamfile_buffer(filename, buffersize); } -static STREAMFILE * open_stdio_streamfile_buffer_by_file(FILE *infile, const char * const filename, size_t buffersize) { - uint8_t * buffer = NULL; - STDIO_STREAMFILE * streamfile = NULL; +static STREAMFILE* open_stdio_streamfile_buffer_by_file(FILE *infile, const char * const filename, size_t buffersize) { + uint8_t *buffer = NULL; + STDIO_STREAMFILE *streamfile = NULL; buffer = calloc(buffersize,1); if (!buffer) goto fail; @@ -167,7 +167,7 @@ static STREAMFILE * open_stdio_streamfile_buffer_by_file(FILE *infile, const cha streamfile->buffersize = buffersize; streamfile->buffer = buffer; - strncpy(streamfile->name,filename,sizeof(streamfile->name)); + strncpy(streamfile->name, filename, sizeof(streamfile->name)); streamfile->name[sizeof(streamfile->name)-1] = '\0'; /* cache filesize */ @@ -195,9 +195,9 @@ fail: return NULL; } -static STREAMFILE * open_stdio_streamfile_buffer(const char * const filename, size_t buffersize) { - FILE * infile; - STREAMFILE *streamFile; +static STREAMFILE* open_stdio_streamfile_buffer(const char * const filename, size_t bufsize) { + FILE *infile = NULL; + STREAMFILE *streamfile = NULL; infile = fopen(filename,"rb"); if (!infile) { @@ -206,21 +206,20 @@ static STREAMFILE * open_stdio_streamfile_buffer(const char * const filename, si return NULL; } - streamFile = open_stdio_streamfile_buffer_by_file(infile,filename,buffersize); - if (!streamFile) { + streamfile = open_stdio_streamfile_buffer_by_file(infile, filename, bufsize); + if (!streamfile) { if (infile) fclose(infile); } - return streamFile; + return streamfile; } - -STREAMFILE * open_stdio_streamfile(const char * filename) { - return open_stdio_streamfile_buffer(filename,STREAMFILE_DEFAULT_BUFFER_SIZE); +STREAMFILE* open_stdio_streamfile(const char *filename) { + return open_stdio_streamfile_buffer(filename, STREAMFILE_DEFAULT_BUFFER_SIZE); } -STREAMFILE * open_stdio_streamfile_by_file(FILE * file, const char * filename) { - return open_stdio_streamfile_buffer_by_file(file,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); +STREAMFILE* open_stdio_streamfile_by_file(FILE *file, const char *filename) { + return open_stdio_streamfile_buffer_by_file(file, filename, STREAMFILE_DEFAULT_BUFFER_SIZE); } /* **************************************************** */ @@ -238,10 +237,10 @@ typedef struct { } BUFFER_STREAMFILE; -static size_t buffer_read(BUFFER_STREAMFILE *streamfile, uint8_t * dest, off_t offset, size_t length) { +static size_t buffer_read(BUFFER_STREAMFILE *streamfile, uint8_t *dst, off_t offset, size_t length) { size_t length_read_total = 0; - if (!dest || length <= 0 || offset < 0) + if (!dst || length <= 0 || offset < 0) return 0; /* is the part of the requested length in the buffer? */ @@ -253,11 +252,11 @@ static size_t buffer_read(BUFFER_STREAMFILE *streamfile, uint8_t * dest, off_t o if (length_to_read > length) length_to_read = length; - memcpy(dest,streamfile->buffer + offset_into_buffer,length_to_read); + memcpy(dst, streamfile->buffer + offset_into_buffer, length_to_read); length_read_total += length_to_read; length -= length_to_read; offset += length_to_read; - dest += length_to_read; + dst += length_to_read; } #ifdef VGM_DEBUG_OUTPUT @@ -289,27 +288,27 @@ static size_t buffer_read(BUFFER_STREAMFILE *streamfile, uint8_t * dest, off_t o /* give up on partial reads (EOF) */ if (streamfile->validsize < length_to_read) { - memcpy(dest,streamfile->buffer,streamfile->validsize); + memcpy(dst, streamfile->buffer, streamfile->validsize); offset += streamfile->validsize; length_read_total += streamfile->validsize; break; } /* use the new buffer */ - memcpy(dest,streamfile->buffer,length_to_read); + memcpy(dst, streamfile->buffer, length_to_read); offset += length_to_read; length_read_total += length_to_read; length -= length_to_read; - dest += length_to_read; + dst += length_to_read; } streamfile->offset = offset; /* last fread offset */ return length_read_total; } -static size_t buffer_get_size(BUFFER_STREAMFILE * streamfile) { +static size_t buffer_get_size(BUFFER_STREAMFILE *streamfile) { return streamfile->filesize; /* cache */ } -static size_t buffer_get_offset(BUFFER_STREAMFILE * streamfile) { +static size_t buffer_get_offset(BUFFER_STREAMFILE *streamfile) { return streamfile->offset; /* cache */ } static void buffer_get_name(BUFFER_STREAMFILE *streamfile, char *buffer, size_t length) { @@ -325,12 +324,12 @@ static void buffer_close(BUFFER_STREAMFILE *streamfile) { free(streamfile); } -STREAMFILE *open_buffer_streamfile(STREAMFILE *streamfile, size_t buffer_size) { +STREAMFILE* open_buffer_streamfile(STREAMFILE *streamfile, size_t buffer_size) { BUFFER_STREAMFILE *this_sf = NULL; if (!streamfile) goto fail; - this_sf = calloc(1,sizeof(BUFFER_STREAMFILE)); + this_sf = calloc(1, sizeof(BUFFER_STREAMFILE)); if (!this_sf) goto fail; this_sf->buffersize = buffer_size; @@ -360,6 +359,12 @@ fail: free(this_sf); return NULL; } +STREAMFILE* open_buffer_streamfile_f(STREAMFILE *streamfile, size_t buffer_size) { + STREAMFILE *new_sf = open_buffer_streamfile(streamfile, buffer_size); + if (!new_sf) + close_streamfile(streamfile); + return new_sf; +} /* **************************************************** */ @@ -373,13 +378,13 @@ typedef struct { STREAMFILE *inner_sf; } WRAP_STREAMFILE; -static size_t wrap_read(WRAP_STREAMFILE *streamfile, uint8_t * dest, off_t offset, size_t length) { - return streamfile->inner_sf->read(streamfile->inner_sf, dest, offset, length); /* default */ +static size_t wrap_read(WRAP_STREAMFILE *streamfile, uint8_t *dst, off_t offset, size_t length) { + return streamfile->inner_sf->read(streamfile->inner_sf, dst, offset, length); /* default */ } -static size_t wrap_get_size(WRAP_STREAMFILE * streamfile) { +static size_t wrap_get_size(WRAP_STREAMFILE *streamfile) { return streamfile->inner_sf->get_size(streamfile->inner_sf); /* default */ } -static size_t wrap_get_offset(WRAP_STREAMFILE * streamfile) { +static size_t wrap_get_offset(WRAP_STREAMFILE *streamfile) { return streamfile->inner_sf->get_offset(streamfile->inner_sf); /* default */ } static void wrap_get_name(WRAP_STREAMFILE *streamfile, char *buffer, size_t length) { @@ -393,8 +398,8 @@ static void wrap_close(WRAP_STREAMFILE *streamfile) { free(streamfile); } -STREAMFILE *open_wrap_streamfile(STREAMFILE *streamfile) { - WRAP_STREAMFILE *this_sf; +STREAMFILE* open_wrap_streamfile(STREAMFILE *streamfile) { + WRAP_STREAMFILE *this_sf = NULL; if (!streamfile) return NULL; @@ -414,6 +419,12 @@ STREAMFILE *open_wrap_streamfile(STREAMFILE *streamfile) { return &this_sf->sf; } +STREAMFILE* open_wrap_streamfile_f(STREAMFILE *streamfile) { + STREAMFILE *new_sf = open_wrap_streamfile(streamfile); + if (!new_sf) + close_streamfile(streamfile); + return new_sf; +} /* **************************************************** */ @@ -425,10 +436,10 @@ typedef struct { size_t size; } CLAMP_STREAMFILE; -static size_t clamp_read(CLAMP_STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length) { +static size_t clamp_read(CLAMP_STREAMFILE *streamfile, uint8_t *dst, off_t offset, size_t length) { off_t inner_offset = streamfile->start + offset; size_t clamp_length = length > (streamfile->size - offset) ? (streamfile->size - offset) : length; - return streamfile->inner_sf->read(streamfile->inner_sf, dest, inner_offset, clamp_length); + return streamfile->inner_sf->read(streamfile->inner_sf, dst, inner_offset, clamp_length); } static size_t clamp_get_size(CLAMP_STREAMFILE *streamfile) { return streamfile->size; @@ -441,7 +452,7 @@ static void clamp_get_name(CLAMP_STREAMFILE *streamfile, char *buffer, size_t le } static STREAMFILE *clamp_open(CLAMP_STREAMFILE *streamfile, const char * const filename, size_t buffersize) { char original_filename[PATH_LIMIT]; - STREAMFILE *new_inner_sf; + STREAMFILE *new_inner_sf = NULL; new_inner_sf = streamfile->inner_sf->open(streamfile->inner_sf,filename,buffersize); streamfile->inner_sf->get_name(streamfile->inner_sf, original_filename, PATH_LIMIT); @@ -450,7 +461,7 @@ static STREAMFILE *clamp_open(CLAMP_STREAMFILE *streamfile, const char * const f if (strcmp(filename, original_filename) == 0) { return open_clamp_streamfile(new_inner_sf, streamfile->start, streamfile->size); /* clamp again */ } else { - return new_inner_sf; /**/ + return new_inner_sf; } } static void clamp_close(CLAMP_STREAMFILE *streamfile) { @@ -458,10 +469,10 @@ static void clamp_close(CLAMP_STREAMFILE *streamfile) { free(streamfile); } -STREAMFILE *open_clamp_streamfile(STREAMFILE *streamfile, off_t start, size_t size) { - CLAMP_STREAMFILE *this_sf; +STREAMFILE* open_clamp_streamfile(STREAMFILE *streamfile, off_t start, size_t size) { + CLAMP_STREAMFILE *this_sf = NULL; - if (!streamfile || !size) return NULL; + if (!streamfile || size == 0) return NULL; if (start + size > get_streamfile_size(streamfile)) return NULL; this_sf = calloc(1,sizeof(CLAMP_STREAMFILE)); @@ -482,6 +493,12 @@ STREAMFILE *open_clamp_streamfile(STREAMFILE *streamfile, off_t start, size_t si return &this_sf->sf; } +STREAMFILE* open_clamp_streamfile_f(STREAMFILE *streamfile, off_t start, size_t size) { + STREAMFILE *new_sf = open_clamp_streamfile(streamfile, start, size); + if (!new_sf) + close_streamfile(streamfile); + return new_sf; +} /* **************************************************** */ @@ -497,8 +514,8 @@ typedef struct { //size_t (*close_data_callback)(STREAMFILE *, void*); /* called during close, allows to free stuff in data */ } IO_STREAMFILE; -static size_t io_read(IO_STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length) { - return streamfile->read_callback(streamfile->inner_sf, dest, offset, length, streamfile->data); +static size_t io_read(IO_STREAMFILE *streamfile, uint8_t *dst, off_t offset, size_t length) { + return streamfile->read_callback(streamfile->inner_sf, dst, offset, length, streamfile->data); } static size_t io_get_size(IO_STREAMFILE *streamfile) { if (streamfile->size_callback) @@ -512,7 +529,7 @@ static off_t io_get_offset(IO_STREAMFILE *streamfile) { static void io_get_name(IO_STREAMFILE *streamfile, char *buffer, size_t length) { streamfile->inner_sf->get_name(streamfile->inner_sf, buffer, length); /* default */ } -static STREAMFILE *io_open(IO_STREAMFILE *streamfile, const char * const filename, size_t buffersize) { +static STREAMFILE* io_open(IO_STREAMFILE *streamfile, const char * const filename, size_t buffersize) { //todo should have some flag to decide if opening other files with IO STREAMFILE *new_inner_sf = streamfile->inner_sf->open(streamfile->inner_sf,filename,buffersize); return open_io_streamfile(new_inner_sf, streamfile->data, streamfile->data_size, streamfile->read_callback, streamfile->size_callback); @@ -523,8 +540,8 @@ static void io_close(IO_STREAMFILE *streamfile) { free(streamfile); } -STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_size, void* read_callback, void* size_callback) { - IO_STREAMFILE *this_sf; +STREAMFILE* open_io_streamfile(STREAMFILE *streamfile, void *data, size_t data_size, void *read_callback, void *size_callback) { + IO_STREAMFILE *this_sf = NULL; if (!streamfile) return NULL; if ((data && !data_size) || (!data && data_size)) return NULL; @@ -556,6 +573,12 @@ STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_s return &this_sf->sf; } +STREAMFILE* open_io_streamfile_f(STREAMFILE *streamfile, void *data, size_t data_size, void *read_callback, void *size_callback) { + STREAMFILE *new_sf = open_io_streamfile(streamfile, data, data_size, read_callback, size_callback); + if (!new_sf) + close_streamfile(streamfile); + return new_sf; +} /* **************************************************** */ @@ -566,20 +589,20 @@ typedef struct { char fakename[PATH_LIMIT]; } FAKENAME_STREAMFILE; -static size_t fakename_read(FAKENAME_STREAMFILE *streamfile, uint8_t * dest, off_t offset, size_t length) { - return streamfile->inner_sf->read(streamfile->inner_sf, dest, offset, length); /* default */ +static size_t fakename_read(FAKENAME_STREAMFILE *streamfile, uint8_t *dst, off_t offset, size_t length) { + return streamfile->inner_sf->read(streamfile->inner_sf, dst, offset, length); /* default */ } -static size_t fakename_get_size(FAKENAME_STREAMFILE * streamfile) { +static size_t fakename_get_size(FAKENAME_STREAMFILE *streamfile) { return streamfile->inner_sf->get_size(streamfile->inner_sf); /* default */ } -static size_t fakename_get_offset(FAKENAME_STREAMFILE * streamfile) { +static size_t fakename_get_offset(FAKENAME_STREAMFILE *streamfile) { return streamfile->inner_sf->get_offset(streamfile->inner_sf); /* default */ } static void fakename_get_name(FAKENAME_STREAMFILE *streamfile, char *buffer, size_t length) { strncpy(buffer,streamfile->fakename,length); buffer[length-1]='\0'; } -static STREAMFILE *fakename_open(FAKENAME_STREAMFILE *streamfile, const char * const filename, size_t buffersize) { +static STREAMFILE* fakename_open(FAKENAME_STREAMFILE *streamfile, const char * const filename, size_t buffersize) { /* detect re-opening the file */ if (strcmp(filename, streamfile->fakename) == 0) { STREAMFILE *new_inner_sf; @@ -598,8 +621,8 @@ static void fakename_close(FAKENAME_STREAMFILE *streamfile) { free(streamfile); } -STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, const char * fakename, const char* fakeext) { - FAKENAME_STREAMFILE *this_sf; +STREAMFILE* open_fakename_streamfile(STREAMFILE *streamfile, const char *fakename, const char *fakeext) { + FAKENAME_STREAMFILE *this_sf = NULL; if (!streamfile || (!fakename && !fakeext)) return NULL; @@ -623,6 +646,7 @@ STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, const char * fakena } else { streamfile->get_name(streamfile, this_sf->fakename, PATH_LIMIT); } + if (fakeext) { char * ext = strrchr(this_sf->fakename,'.'); if (ext != NULL) @@ -632,10 +656,15 @@ STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, const char * fakena return &this_sf->sf; } +STREAMFILE* open_fakename_streamfile_f(STREAMFILE *streamfile, const char *fakename, const char *fakeext) { + STREAMFILE *new_sf = open_fakename_streamfile(streamfile, fakename, fakeext); + if (!new_sf) + close_streamfile(streamfile); + return new_sf; +} /* **************************************************** */ - typedef struct { STREAMFILE sf; @@ -646,7 +675,7 @@ typedef struct { off_t offset; } MULTIFILE_STREAMFILE; -static size_t multifile_read(MULTIFILE_STREAMFILE *streamfile, uint8_t * dest, off_t offset, size_t length) { +static size_t multifile_read(MULTIFILE_STREAMFILE *streamfile, uint8_t *dst, off_t offset, size_t length) { int i, segment = 0; off_t segment_offset = 0; size_t done = 0; @@ -674,7 +703,7 @@ static size_t multifile_read(MULTIFILE_STREAMFILE *streamfile, uint8_t * dest, o if (segment >= streamfile->inner_sfs_size) /* over last segment, not fully done */ break; /* reads over segment size are ok, will return smaller value and continue next segment */ - done += streamfile->inner_sfs[segment]->read(streamfile->inner_sfs[segment], dest+done, segment_offset, length - done); + done += streamfile->inner_sfs[segment]->read(streamfile->inner_sfs[segment], dst + done, segment_offset, length - done); segment++; segment_offset = 0; } @@ -691,7 +720,7 @@ static size_t multifile_get_offset(MULTIFILE_STREAMFILE * streamfile) { static void multifile_get_name(MULTIFILE_STREAMFILE *streamfile, char *buffer, size_t length) { streamfile->inner_sfs[0]->get_name(streamfile->inner_sfs[0], buffer, length); } -static STREAMFILE *multifile_open(MULTIFILE_STREAMFILE *streamfile, const char * const filename, size_t buffersize) { +static STREAMFILE* multifile_open(MULTIFILE_STREAMFILE *streamfile, const char * const filename, size_t buffersize) { char original_filename[PATH_LIMIT]; STREAMFILE *new_sf = NULL; STREAMFILE **new_inner_sfs = NULL; @@ -740,11 +769,12 @@ static void multifile_close(MULTIFILE_STREAMFILE *streamfile) { free(streamfile); } -STREAMFILE *open_multifile_streamfile(STREAMFILE **streamfiles, size_t streamfiles_size) { - MULTIFILE_STREAMFILE *this_sf; +STREAMFILE* open_multifile_streamfile(STREAMFILE **streamfiles, size_t streamfiles_size) { + MULTIFILE_STREAMFILE *this_sf = NULL; int i; if (!streamfiles || !streamfiles_size) return NULL; + for (i = 0; i < streamfiles_size; i++) { if (!streamfiles[i]) return NULL; } @@ -783,18 +813,28 @@ fail: free(this_sf); return NULL; } +STREAMFILE* open_multifile_streamfile_f(STREAMFILE **streamfiles, size_t streamfiles_size) { + STREAMFILE *new_sf = open_multifile_streamfile(streamfiles, streamfiles_size); + if (!new_sf) { + int i; + for (i = 0; i < streamfiles_size; i++) { + close_streamfile(streamfiles[i]); + } + } + return new_sf; +} /* **************************************************** */ -STREAMFILE * open_streamfile(STREAMFILE *streamFile, const char * pathname) { - return streamFile->open(streamFile,pathname,STREAMFILE_DEFAULT_BUFFER_SIZE); +STREAMFILE* open_streamfile(STREAMFILE *streamfile, const char *pathname) { + return streamfile->open(streamfile, pathname, STREAMFILE_DEFAULT_BUFFER_SIZE); } -STREAMFILE * open_streamfile_by_ext(STREAMFILE *streamFile, const char * ext) { +STREAMFILE* open_streamfile_by_ext(STREAMFILE *streamfile, const char *ext) { char filename[PATH_LIMIT]; int filename_len, fileext_len; - streamFile->get_name(streamFile,filename,sizeof(filename)); + streamfile->get_name(streamfile, filename, sizeof(filename)); filename_len = strlen(filename); fileext_len = strlen(filename_extension(filename)); @@ -807,15 +847,17 @@ STREAMFILE * open_streamfile_by_ext(STREAMFILE *streamFile, const char * ext) { strcpy(filename + filename_len - fileext_len, ext); } - return streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + return streamfile->open(streamfile, filename, STREAMFILE_DEFAULT_BUFFER_SIZE); } -STREAMFILE * open_streamfile_by_filename(STREAMFILE *streamFile, const char * filename) { +STREAMFILE* open_streamfile_by_filename(STREAMFILE *streamfile, const char * filename) { char fullname[PATH_LIMIT]; char partname[PATH_LIMIT]; char *path, *name; - streamFile->get_name(streamFile, fullname, sizeof(fullname)); + if (!streamfile || !filename) return NULL; + + streamfile->get_name(streamfile, fullname, sizeof(fullname)); //todo normalize separators in a better way, safeops, improve copying path = strrchr(fullname,DIR_SEPARATOR); @@ -854,87 +896,82 @@ STREAMFILE * open_streamfile_by_filename(STREAMFILE *streamFile, const char * fi strcpy(fullname, filename); } - return streamFile->open(streamFile, fullname, STREAMFILE_DEFAULT_BUFFER_SIZE); + return streamfile->open(streamfile, fullname, STREAMFILE_DEFAULT_BUFFER_SIZE); } -STREAMFILE * reopen_streamfile(STREAMFILE *streamFile, size_t buffer_size) { +STREAMFILE* reopen_streamfile(STREAMFILE *streamfile, size_t buffer_size) { char pathname[PATH_LIMIT]; + if (!streamfile) return NULL; + if (buffer_size == 0) buffer_size = STREAMFILE_DEFAULT_BUFFER_SIZE; - streamFile->get_name(streamFile,pathname,sizeof(pathname)); - return streamFile->open(streamFile,pathname,buffer_size); + streamfile->get_name(streamfile,pathname,sizeof(pathname)); + return streamfile->open(streamfile,pathname,buffer_size); } +/* **************************************************** */ -/* Read a line into dst. The source files are lines separated by CRLF (Windows) / LF (Unux) / CR (Mac). - * The line will be null-terminated and CR/LF removed if found. - * - * Returns the number of bytes read (including CR/LF), note that this is not the string length. - * line_done_ptr is set to 1 if the complete line was read into dst; NULL can be passed to ignore. - */ -size_t get_streamfile_text_line(int dst_length, char * dst, off_t offset, STREAMFILE * streamfile, int *line_done_ptr) { +size_t read_line(char *buf, int buf_size, off_t offset, STREAMFILE *sf, int *p_line_ok) { int i; - off_t file_length = get_streamfile_size(streamfile); + off_t file_size = get_streamfile_size(sf); int extra_bytes = 0; /* how many bytes over those put in the buffer were read */ - if (line_done_ptr) *line_done_ptr = 0; + if (p_line_ok) *p_line_ok = 0; - for (i = 0; i < dst_length-1 && offset+i < file_length; i++) { - char in_char = read_8bit(offset+i,streamfile); + for (i = 0; i < buf_size-1 && offset+i < file_size; i++) { + char in_char = read_8bit(offset+i, sf); /* check for end of line */ - if (in_char == 0x0d && read_8bit(offset+i+1,streamfile) == 0x0a) { /* CRLF */ + if (in_char == 0x0d && read_8bit(offset+i+1, sf) == 0x0a) { /* CRLF */ extra_bytes = 2; - if (line_done_ptr) *line_done_ptr = 1; + if (p_line_ok) *p_line_ok = 1; break; } else if (in_char == 0x0d || in_char == 0x0a) { /* CR or LF */ extra_bytes = 1; - if (line_done_ptr) *line_done_ptr = 1; + if (p_line_ok) *p_line_ok = 1; break; } - dst[i] = in_char; + buf[i] = in_char; } - dst[i] = '\0'; + buf[i] = '\0'; /* did we fill the buffer? */ - if (i == dst_length) { - char in_char = read_8bit(offset+i,streamfile); + if (i == buf_size) { + char in_char = read_8bit(offset+i, sf); /* did the bytes we missed just happen to be the end of the line? */ - if (in_char == 0x0d && read_8bit(offset+i+1,streamfile) == 0x0a) { /* CRLF */ + if (in_char == 0x0d && read_8bit(offset+i+1, sf) == 0x0a) { /* CRLF */ extra_bytes = 2; - if (line_done_ptr) *line_done_ptr = 1; + if (p_line_ok) *p_line_ok = 1; } else if (in_char == 0x0d || in_char == 0x0a) { /* CR or LF */ extra_bytes = 1; - if (line_done_ptr) *line_done_ptr = 1; + if (p_line_ok) *p_line_ok = 1; } } /* did we hit the file end? */ - if (offset+i == file_length) { + if (offset+i == file_size) { /* then we did in fact finish reading the last line */ - if (line_done_ptr) *line_done_ptr = 1; + if (p_line_ok) *p_line_ok = 1; } return i + extra_bytes; } - -/* reads a c-string (ANSI only), up to maxsize or NULL, returning size. buf is optional (works as get_string_size). */ -size_t read_string(char * buf, size_t maxsize, off_t offset, STREAMFILE *streamFile) { +size_t read_string(char *buf, size_t buf_size, off_t offset, STREAMFILE *sf) { size_t pos; - for (pos = 0; pos < maxsize; pos++) { - char c = read_8bit(offset + pos, streamFile); + for (pos = 0; pos < buf_size; pos++) { + char c = read_8bit(offset + pos, sf); if (buf) buf[pos] = c; if (c == '\0') return pos; - if (pos+1 == maxsize) { /* null at maxsize and don't validate (expected to be garbage) */ + if (pos+1 == buf_size) { /* null at maxsize and don't validate (expected to be garbage) */ if (buf) buf[pos] = '\0'; - return maxsize; + return buf_size; } if (c < 0x20 || (uint8_t)c > 0xA5) goto fail; @@ -946,22 +983,18 @@ fail: } -/* Opens a file containing decryption keys and copies to buffer. - * Tries combinations of keynames based on the original filename. - * returns size of key if found and copied */ -size_t read_key_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile) { +size_t read_key_file(uint8_t *buf, size_t buf_size, STREAMFILE *sf) { char keyname[PATH_LIMIT]; char filename[PATH_LIMIT]; const char *path, *ext; STREAMFILE * streamFileKey = NULL; size_t keysize; - streamFile->get_name(streamFile,filename,sizeof(filename)); + sf->get_name(sf,filename,sizeof(filename)); if (strlen(filename)+4 > sizeof(keyname)) goto fail; - /* try to open a keyfile using variations: - * "(name.ext)key" (per song), "(.ext)key" (per folder) */ + /* try to open a keyfile using variations */ { ext = strrchr(filename,'.'); if (ext!=NULL) ext = ext+1; @@ -972,7 +1005,7 @@ size_t read_key_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile) { /* "(name.ext)key" */ strcpy(keyname, filename); strcat(keyname, "key"); - streamFileKey = streamFile->open(streamFile,keyname,STREAMFILE_DEFAULT_BUFFER_SIZE); + streamFileKey = sf->open(sf,keyname,STREAMFILE_DEFAULT_BUFFER_SIZE); if (streamFileKey) goto found; /* "(name.ext)KEY" */ @@ -993,7 +1026,7 @@ size_t read_key_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile) { } if (ext) strcat(keyname, ext); strcat(keyname, "key"); - streamFileKey = streamFile->open(streamFile,keyname,STREAMFILE_DEFAULT_BUFFER_SIZE); + streamFileKey = sf->open(sf,keyname,STREAMFILE_DEFAULT_BUFFER_SIZE); if (streamFileKey) goto found; /* "(.ext)KEY" */ @@ -1008,7 +1041,7 @@ size_t read_key_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile) { found: keysize = get_streamfile_size(streamFileKey); - if (keysize > bufsize) goto fail; + if (keysize > buf_size) goto fail; if (read_streamfile(buf, 0, keysize, streamFileKey) != keysize) goto fail; @@ -1021,7 +1054,6 @@ fail: return 0; } -/* hack to allow relative paths in various OSs */ void fix_dir_separators(char * filename) { char c; int i = 0; @@ -1032,19 +1064,14 @@ void fix_dir_separators(char * filename) { } } - -/** - * Checks if the stream filename is one of the extensions (comma-separated, ex. "adx" or "adx,aix"). - * Empty is ok to accept files without extension ("", "adx,,aix"). Returns 0 on failure - */ -int check_extensions(STREAMFILE *streamFile, const char * cmp_exts) { +int check_extensions(STREAMFILE *sf, const char * cmp_exts) { char filename[PATH_LIMIT]; const char * ext = NULL; const char * cmp_ext = NULL; const char * ststr_res = NULL; size_t ext_len, cmp_len; - streamFile->get_name(streamFile,filename,sizeof(filename)); + sf->get_name(sf,filename,sizeof(filename)); ext = filename_extension(filename); ext_len = strlen(ext); diff --git a/Frameworks/vgmstream/vgmstream/src/streamfile.h b/Frameworks/vgmstream/vgmstream/src/streamfile.h index 9dbee9dd0..e66564252 100644 --- a/Frameworks/vgmstream/vgmstream/src/streamfile.h +++ b/Frameworks/vgmstream/vgmstream/src/streamfile.h @@ -59,12 +59,12 @@ * to do file operations, as plugins may need to provide their own callbacks. * Reads from arbitrary offsets, meaning internally may need fseek equivalents during reads. */ typedef struct _STREAMFILE { - size_t (*read)(struct _STREAMFILE *,uint8_t * dest, off_t offset, size_t length); + size_t (*read)(struct _STREAMFILE *, uint8_t * dst, off_t offset, size_t length); size_t (*get_size)(struct _STREAMFILE *); off_t (*get_offset)(struct _STREAMFILE *); //todo: DO NOT USE, NOT RESET PROPERLY (remove?) /* for dual-file support */ - void (*get_name)(struct _STREAMFILE *,char *name,size_t length); - struct _STREAMFILE * (*open)(struct _STREAMFILE *,const char * const filename,size_t buffersize); + void (*get_name)(struct _STREAMFILE * ,char *name, size_t length); + struct _STREAMFILE * (*open)(struct _STREAMFILE *, const char * const filename, size_t buffersize); void (*close)(struct _STREAMFILE *); @@ -74,59 +74,68 @@ typedef struct _STREAMFILE { } STREAMFILE; +/* All open_ fuctions should be safe to call with wrong/null parameters. + * _f versions are the same but free the passed streamfile on failure and return NULL, + * to ease chaining by avoiding realloc-style temp ptr verbosity */ + /* Opens a standard STREAMFILE, opening from path. * Uses stdio (FILE) for operations, thus plugins may not want to use it. */ -STREAMFILE *open_stdio_streamfile(const char * filename); +STREAMFILE* open_stdio_streamfile(const char *filename); /* Opens a standard STREAMFILE from a pre-opened FILE. */ -STREAMFILE *open_stdio_streamfile_by_file(FILE * file, const char * filename); +STREAMFILE* open_stdio_streamfile_by_file(FILE *file, const char *filename); /* Opens a STREAMFILE that does buffered IO. * Can be used when the underlying IO may be slow (like when using custom IO). * Buffer size is optional. */ -STREAMFILE *open_buffer_streamfile(STREAMFILE *streamfile, size_t buffer_size); +STREAMFILE* open_buffer_streamfile(STREAMFILE *streamfile, size_t buffer_size); +STREAMFILE* open_buffer_streamfile_f(STREAMFILE *streamfile, size_t buffer_size); /* Opens a STREAMFILE that doesn't close the underlying streamfile. * Calls to open won't wrap the new SF (assumes it needs to be closed). * Can be used in metas to test custom IO without closing the external SF. */ -STREAMFILE *open_wrap_streamfile(STREAMFILE *streamfile); +STREAMFILE* open_wrap_streamfile(STREAMFILE *streamfile); +STREAMFILE* open_wrap_streamfile_f(STREAMFILE *streamfile); /* Opens a STREAMFILE that clamps reads to a section of a larger streamfile. * Can be used with subfiles inside a bigger file (to fool metas, or to simplify custom IO). */ -STREAMFILE *open_clamp_streamfile(STREAMFILE *streamfile, off_t start, size_t size); +STREAMFILE* open_clamp_streamfile(STREAMFILE *streamfile, off_t start, size_t size); +STREAMFILE* open_clamp_streamfile_f(STREAMFILE *streamfile, off_t start, size_t size); /* Opens a STREAMFILE that uses custom IO for streamfile reads. * Can be used to modify data on the fly (ex. decryption), or even transform it from a format to another. */ -STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_size, void* read_callback, void* size_callback); +STREAMFILE* open_io_streamfile(STREAMFILE *streamfile, void *data, size_t data_size, void *read_callback, void *size_callback); +STREAMFILE* open_io_streamfile_f(STREAMFILE *streamfile, void *data, size_t data_size, void *read_callback, void *size_callback); /* Opens a STREAMFILE that reports a fake name, but still re-opens itself properly. * Can be used to trick a meta's extension check (to call from another, with a modified SF). * When fakename isn't supplied it's read from the streamfile, and the extension swapped with fakeext. * If the fakename is an existing file, open won't work on it as it'll reopen the fake-named streamfile. */ -STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, const char * fakename, const char * fakeext); +STREAMFILE* open_fakename_streamfile(STREAMFILE *streamfile, const char * fakename, const char * fakeext); +STREAMFILE* open_fakename_streamfile_f(STREAMFILE *streamfile, const char * fakename, const char * fakeext); -//todo probably could simply use custom IO /* Opens streamfile formed from multiple streamfiles, their data joined during reads. * Can be used when data is segmented in multiple separate files. * The first streamfile is used to get names, stream index and so on. */ -STREAMFILE *open_multifile_streamfile(STREAMFILE **streamfiles, size_t streamfiles_size); +STREAMFILE* open_multifile_streamfile(STREAMFILE **streamfiles, size_t streamfiles_size); +STREAMFILE* open_multifile_streamfile_f(STREAMFILE **streamfiles, size_t streamfiles_size); /* Opens a STREAMFILE from a (path)+filename. * Just a wrapper, to avoid having to access the STREAMFILE's callbacks directly. */ -STREAMFILE * open_streamfile(STREAMFILE *streamFile, const char * pathname); +STREAMFILE* open_streamfile(STREAMFILE *streamfile, const char * pathname); /* Opens a STREAMFILE from a base pathname + new extension * Can be used to get companion headers. */ -STREAMFILE * open_streamfile_by_ext(STREAMFILE *streamFile, const char * ext); +STREAMFILE* open_streamfile_by_ext(STREAMFILE *streamfile, const char * ext); /* Opens a STREAMFILE from a base path + new filename. * Can be used to get companion files. Relative paths like * './filename', '../filename', 'dir/filename' also work. */ -STREAMFILE * open_streamfile_by_filename(STREAMFILE *streamFile, const char * filename); +STREAMFILE* open_streamfile_by_filename(STREAMFILE *streamfile, const char * filename); /* Reopen a STREAMFILE with a different buffer size, for fine-tuned bigfile parsing. * Uses default buffer size when buffer_size is 0 */ -STREAMFILE * reopen_streamfile(STREAMFILE *streamFile, size_t buffer_size); +STREAMFILE * reopen_streamfile(STREAMFILE *streamfile, size_t buffer_size); /* close a file, destroy the STREAMFILE object */ @@ -136,8 +145,8 @@ static inline void close_streamfile(STREAMFILE * streamfile) { } /* read from a file, returns number of bytes read */ -static inline size_t read_streamfile(uint8_t * dest, off_t offset, size_t length, STREAMFILE * streamfile) { - return streamfile->read(streamfile,dest,offset,length); +static inline size_t read_streamfile(uint8_t *dst, off_t offset, size_t length, STREAMFILE *streamfile) { + return streamfile->read(streamfile, dst, offset,length); } /* return file size */ @@ -256,16 +265,27 @@ static inline size_t align_size_to_block(size_t value, size_t block_align) { /* various STREAMFILE helpers functions */ -size_t get_streamfile_text_line(int dst_length, char * dst, off_t offset, STREAMFILE * streamfile, int *line_done_ptr); +/* Read into dst a line delimited by CRLF (Windows) / LF (Unux) / CR (Mac) / EOF, null-terminated + * and without line feeds. Returns bytes read (including CR/LF), *not* the same as string length. + * p_line_ok is set to 1 if the complete line was read; pass NULL to ignore. */ +size_t read_line(char *buf, int buf_size, off_t offset, STREAMFILE *sf, int *p_line_ok); -size_t read_string(char * buf, size_t bufsize, off_t offset, STREAMFILE *streamFile); +/* reads a c-string (ANSI only), up to bufsize or NULL, returning size. buf is optional (works as get_string_size). */ +size_t read_string(char *buf, size_t buf_size, off_t offset, STREAMFILE *sf); -size_t read_key_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile); +/* Opens a file containing decryption keys and copies to buffer. + * Tries "(name.ext)key" (per song), "(.ext)key" (per folder) keynames. + * returns size of key if found and copied */ +size_t read_key_file(uint8_t *buf, size_t buf_size, STREAMFILE *sf); -void fix_dir_separators(char * filename); +/* hack to allow relative paths in various OSs */ +void fix_dir_separators(char *filename); +/* Checks if the stream filename is one of the extensions (comma-separated, ex. "adx" or "adx,aix"). + * Empty is ok to accept files without extension ("", "adx,,aix"). Returns 0 on failure */ int check_extensions(STREAMFILE *streamFile, const char * cmp_exts); +/* chunk-style file helpers */ int find_chunk_be(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size); int find_chunk_le(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size); int find_chunk(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian_size, int zero_size_end); @@ -275,7 +295,7 @@ int find_chunk_riff_be(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_of /* same with chunk ids in variable endianess (so instead of "fmt " has " tmf" */ int find_chunk_riff_ve(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, size_t max_size, off_t *out_chunk_offset, size_t *out_chunk_size, int big_endian); - +/* filename helpers */ void get_streamfile_name(STREAMFILE *streamFile, char * buffer, size_t size); void get_streamfile_filename(STREAMFILE *streamFile, char * buffer, size_t size); void get_streamfile_basename(STREAMFILE *streamFile, char * buffer, size_t size); diff --git a/Frameworks/vgmstream/vgmstream/src/streamtypes.h b/Frameworks/vgmstream/vgmstream/src/streamtypes.h index 35c776254..9907b2eeb 100644 --- a/Frameworks/vgmstream/vgmstream/src/streamtypes.h +++ b/Frameworks/vgmstream/vgmstream/src/streamtypes.h @@ -7,12 +7,20 @@ #define _STREAMTYPES_H #ifdef _MSC_VER +/* Common versions: + * - 1500: VS2008 + * - 1600: VS2010 + * - 1700: VS2012 + * - 1800: VS2013 + * - 1900: VS2015 + * - 1920: VS2019 */ #if (_MSC_VER >= 1600) + #include #else #include -#endif /* (_MSC_VER >= 1600) */ +#endif #ifndef inline /* (_MSC_VER < 1900)? */ #define inline _inline @@ -23,10 +31,11 @@ #if (_MSC_VER < 1900) #define snprintf _snprintf -#endif /* (_MSC_VER < 1900) */ +#endif #else #include + #endif /* _MSC_VER */ typedef int16_t sample; //TODO: deprecated, remove diff --git a/Frameworks/vgmstream/vgmstream/src/util.h b/Frameworks/vgmstream/vgmstream/src/util.h index 8b4239472..bfc07ea36 100644 --- a/Frameworks/vgmstream/vgmstream/src/util.h +++ b/Frameworks/vgmstream/vgmstream/src/util.h @@ -33,6 +33,22 @@ static inline int64_t get_64bitLE(uint8_t * p) { return (uint64_t)(((uint64_t)p[0]) | ((uint64_t)p[1]<<8) | ((uint64_t)p[2]<<16) | ((uint64_t)p[3]<<24) | ((uint64_t)p[4]<<32) | ((uint64_t)p[5]<<40) | ((uint64_t)p[6]<<48) | ((uint64_t)p[7]<<56)); } +/* alias of the above */ +static inline int8_t get_s8 (uint8_t *p) { return ( int8_t)p[0]; } +static inline uint8_t get_u8 (uint8_t *p) { return (uint8_t)p[0]; } +static inline int16_t get_s16le(uint8_t *p) { return ( int16_t)get_16bitLE(p); } +static inline uint16_t get_u16le(uint8_t *p) { return (uint16_t)get_16bitLE(p); } +static inline int16_t get_s16be(uint8_t *p) { return ( int16_t)get_16bitBE(p); } +static inline uint16_t get_u16be(uint8_t *p) { return (uint16_t)get_16bitBE(p); } +static inline int32_t get_s32le(uint8_t *p) { return ( int32_t)get_32bitLE(p); } +static inline uint32_t get_u32le(uint8_t *p) { return (uint32_t)get_32bitLE(p); } +static inline int32_t get_s32be(uint8_t *p) { return ( int32_t)get_32bitBE(p); } +static inline uint32_t get_u32be(uint8_t *p) { return (uint32_t)get_32bitBE(p); } +static inline int64_t get_s64be(uint8_t *p) { return ( int64_t)get_64bitLE(p); } +static inline uint64_t get_u64be(uint8_t *p) { return (uint64_t)get_64bitLE(p); } +static inline int64_t get_s64le(uint8_t *p) { return ( int64_t)get_64bitBE(p); } +static inline uint64_t get_u64le(uint8_t *p) { return (uint64_t)get_64bitBE(p); } + void put_8bit(uint8_t * buf, int8_t i); void put_16bitLE(uint8_t * buf, int16_t i); diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.c b/Frameworks/vgmstream/vgmstream/src/vgmstream.c index 233472ea0..4bec02e99 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.c @@ -1215,10 +1215,10 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { return 128; case coding_MSADPCM: - return (vgmstream->interleave_block_size - 0x07*vgmstream->channels)*2 / vgmstream->channels + 2; + return (vgmstream->frame_size - 0x07*vgmstream->channels)*2 / vgmstream->channels + 2; case coding_MSADPCM_int: case coding_MSADPCM_ck: - return (vgmstream->interleave_block_size - 0x07)*2 + 2; + return (vgmstream->frame_size - 0x07)*2 + 2; case coding_WS: /* only works if output sample size is 8 bit, which always is for WS ADPCM */ return vgmstream->ws_output_size; case coding_AICA: @@ -1407,7 +1407,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_MSADPCM: case coding_MSADPCM_int: case coding_MSADPCM_ck: - return vgmstream->interleave_block_size; + return vgmstream->frame_size; case coding_WS: return vgmstream->current_block_size; case coding_AICA: @@ -2393,7 +2393,8 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { } /* codecs with configurable frame size */ - if (vgmstream->interleave_block_size > 0) { + if (vgmstream->frame_size > 0 || vgmstream->interleave_block_size > 0) { + int32_t frame_size = vgmstream->frame_size > 0 ? vgmstream->frame_size : vgmstream->interleave_block_size; switch (vgmstream->coding_type) { case coding_MSADPCM: case coding_MSADPCM_int: @@ -2403,7 +2404,7 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { case coding_WWISE_IMA: case coding_REF_IMA: case coding_PSX_cfg: - snprintf(temp,TEMPSIZE, "frame size: %#x bytes\n", (int32_t)vgmstream->interleave_block_size); + snprintf(temp,TEMPSIZE, "frame size: %#x bytes\n", frame_size); concatn(length,desc,temp); break; default: @@ -2628,8 +2629,7 @@ static STREAMFILE * get_vgmstream_average_bitrate_channel_streamfile(VGMSTREAM * #ifdef VGM_USE_VORBIS if (vgmstream->coding_type == coding_OGG_VORBIS) { - ogg_vorbis_codec_data *data = vgmstream->codec_data; - return data ? data->ov_streamfile.streamfile : NULL; + return ogg_vorbis_get_streamfile(vgmstream->codec_data); } #endif if (vgmstream->coding_type == coding_CRI_HCA) { @@ -2793,7 +2793,7 @@ int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t s vgmstream->coding_type == coding_PSX_pivotal) && (vgmstream->interleave_block_size == 0 || vgmstream->interleave_block_size > 0x50)) { VGM_LOG("VGMSTREAM: PSX-cfg decoder with wrong frame size %x\n", vgmstream->interleave_block_size); - return 0; + goto fail; } if ((vgmstream->coding_type == coding_CRI_ADX || @@ -2803,7 +2803,14 @@ int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t s vgmstream->coding_type == coding_CRI_ADX_fixed) && (vgmstream->interleave_block_size == 0 || vgmstream->interleave_block_size > 0x12)) { VGM_LOG("VGMSTREAM: ADX decoder with wrong frame size %x\n", vgmstream->interleave_block_size); - return 0; + goto fail; + } + + if ((vgmstream->coding_type == coding_MSADPCM || + vgmstream->coding_type == coding_MSADPCM_ck || + vgmstream->coding_type == coding_MSADPCM_int) && + vgmstream->frame_size == 0) { + vgmstream->frame_size = vgmstream->interleave_block_size; } /* if interleave is big enough keep a buffer per channel */ diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.h b/Frameworks/vgmstream/vgmstream/src/vgmstream.h index b06ae0cc7..cb27e6189 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.h +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.h @@ -840,6 +840,7 @@ typedef struct { size_t interleave_first_block_size; /* different interleave for first block */ size_t interleave_first_skip; /* data skipped before interleave first (needed to skip other channels) */ size_t interleave_last_block_size; /* smaller interleave for last block */ + size_t frame_size; /* for codecs with configurable size */ /* subsong config */ int num_streams; /* for multi-stream formats (0=not set/one stream, 1=one stream) */ @@ -909,7 +910,8 @@ typedef struct { } VGMSTREAM; #ifdef VGM_USE_VORBIS -/* Ogg with Vorbis */ + +/* standard Ogg Vorbis */ typedef struct { STREAMFILE *streamfile; ogg_int64_t start; /* file offset where the Ogg starts */ @@ -922,15 +924,9 @@ typedef struct { off_t scd_xor_length; uint32_t xor_value; -} ogg_vorbis_streamfile; +} ogg_vorbis_io; -typedef struct { - OggVorbis_File ogg_vorbis_file; - int bitstream; - - ogg_vorbis_streamfile ov_streamfile; - int disable_reordering; /* Xiph reorder channels on output, except for some devs */ -} ogg_vorbis_codec_data; +typedef struct ogg_vorbis_codec_data ogg_vorbis_codec_data; /* custom Vorbis modes */