Browse Source

Updated VGMStream to r1050-2574-g246222dd

master
Christopher Snowhill 5 months ago
parent
commit
242c0b9476
51 changed files with 1484 additions and 1056 deletions
  1. +4
    -0
      Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj
  2. +9
    -1
      Frameworks/vgmstream/vgmstream/src/coding/coding.h
  3. +4
    -17
      Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c
  4. +37
    -14
      Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c
  5. +77
    -37
      Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c
  6. +28
    -2
      Frameworks/vgmstream/vgmstream/src/coding/msadpcm_decoder.c
  7. +228
    -15
      Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c
  8. +24
    -11
      Frameworks/vgmstream/vgmstream/src/layout/blocked_xa.c
  9. +26
    -44
      Frameworks/vgmstream/vgmstream/src/meta/2dx9.c
  10. +6
    -15
      Frameworks/vgmstream/vgmstream/src/meta/acb.c
  11. +8
    -8
      Frameworks/vgmstream/vgmstream/src/meta/aix.c
  12. +7
    -25
      Frameworks/vgmstream/vgmstream/src/meta/aix_streamfile.h
  13. +2
    -2
      Frameworks/vgmstream/vgmstream/src/meta/akb.c
  14. +33
    -11
      Frameworks/vgmstream/vgmstream/src/meta/bwav.c
  15. +1
    -1
      Frameworks/vgmstream/vgmstream/src/meta/ck.c
  16. +4
    -4
      Frameworks/vgmstream/vgmstream/src/meta/dec.c
  17. +4
    -2
      Frameworks/vgmstream/vgmstream/src/meta/genh.c
  18. +1
    -1
      Frameworks/vgmstream/vgmstream/src/meta/meta.h
  19. +16
    -18
      Frameworks/vgmstream/vgmstream/src/meta/mus_acm.c
  20. +11
    -4
      Frameworks/vgmstream/vgmstream/src/meta/mzrt.c
  21. +31
    -61
      Frameworks/vgmstream/vgmstream/src/meta/nub.c
  22. +106
    -235
      Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c
  23. +104
    -126
      Frameworks/vgmstream/vgmstream/src/meta/riff.c
  24. +130
    -0
      Frameworks/vgmstream/vgmstream/src/meta/riff_ogg_streamfile.h
  25. +9
    -11
      Frameworks/vgmstream/vgmstream/src/meta/sd9.c
  26. +8
    -0
      Frameworks/vgmstream/vgmstream/src/meta/sgxd.c
  27. +10
    -10
      Frameworks/vgmstream/vgmstream/src/meta/sli.c
  28. +3
    -2
      Frameworks/vgmstream/vgmstream/src/meta/smp.c
  29. +85
    -84
      Frameworks/vgmstream/vgmstream/src/meta/spt_spd.c
  30. +23
    -20
      Frameworks/vgmstream/vgmstream/src/meta/sqex_scd.c
  31. +2
    -2
      Frameworks/vgmstream/vgmstream/src/meta/sqex_sead.c
  32. +12
    -10
      Frameworks/vgmstream/vgmstream/src/meta/txth.c
  33. +4
    -4
      Frameworks/vgmstream/vgmstream/src/meta/txtp.c
  34. +6
    -11
      Frameworks/vgmstream/vgmstream/src/meta/ubi_bao.c
  35. +3
    -3
      Frameworks/vgmstream/vgmstream/src/meta/ubi_hx.c
  36. +7
    -7
      Frameworks/vgmstream/vgmstream/src/meta/ubi_jade.c
  37. +5
    -2
      Frameworks/vgmstream/vgmstream/src/meta/ubi_raki.c
  38. +5
    -7
      Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c
  39. +16
    -12
      Frameworks/vgmstream/vgmstream/src/meta/vxn.c
  40. +9
    -5
      Frameworks/vgmstream/vgmstream/src/meta/waf.c
  41. +99
    -17
      Frameworks/vgmstream/vgmstream/src/meta/xa.c
  42. +7
    -2
      Frameworks/vgmstream/vgmstream/src/meta/xnb.c
  43. +6
    -5
      Frameworks/vgmstream/vgmstream/src/meta/xwb.c
  44. +4
    -3
      Frameworks/vgmstream/vgmstream/src/meta/xwc.c
  45. +4
    -4
      Frameworks/vgmstream/vgmstream/src/plugins.c
  46. +165
    -138
      Frameworks/vgmstream/vgmstream/src/streamfile.c
  47. +43
    -23
      Frameworks/vgmstream/vgmstream/src/streamfile.h
  48. +11
    -2
      Frameworks/vgmstream/vgmstream/src/streamtypes.h
  49. +16
    -0
      Frameworks/vgmstream/vgmstream/src/util.h
  50. +16
    -9
      Frameworks/vgmstream/vgmstream/src/vgmstream.c
  51. +5
    -9
      Frameworks/vgmstream/vgmstream/src/vgmstream.h

+ 4
- 0
Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj View File

@@ -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 = "<group>"; };
83F412871E932F9A002E37D0 /* Vorbis.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Vorbis.xcodeproj; path = ../Vorbis/macosx/Vorbis.xcodeproj; sourceTree = "<group>"; };
83F5F8821908D0A400C8E65F /* fsb5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fsb5.c; sourceTree = "<group>"; };
83FBD502235D31F700D35BCD /* riff_ogg_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = riff_ogg_streamfile.h; sourceTree = "<group>"; };
83FF0EBB1E93282100C58054 /* wwise.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wwise.c; sourceTree = "<group>"; };
/* 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 */,


+ 9
- 1
Frameworks/vgmstream/vgmstream/src/coding/coding.h View File

@@ -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);


+ 4
- 17
Frameworks/vgmstream/vgmstream/src/coding/coding_utils.c View File

@@ -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;
}

+ 37
- 14
Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder.c View File

@@ -1,3 +1,4 @@
#include <math.h>
#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));
}
}
}


+ 77
- 37
Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c View File

@@ -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

+ 28
- 2
Frameworks/vgmstream/vgmstream/src/coding/msadpcm_decoder.c View File

@@ -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;
}

+ 228
- 15
Frameworks/vgmstream/vgmstream/src/coding/ogg_vorbis_decoder.c View File

@@ -5,21 +5,183 @@
#ifdef VGM_USE_VORBIS
#include <vorbis/vorbisfile.h>

#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;
};


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) {
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

+ 24
- 11
Frameworks/vgmstream/vgmstream/src/layout/blocked_xa.c View File

@@ -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;


+ 26
- 44
Frameworks/vgmstream/vgmstream/src/meta/2dx9.c View File

@@ -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->meta_type = meta_2DX9;
vgmstream->sample_rate = read_32bitLE(0x30,streamFile);
vgmstream->coding_type = coding_MSADPCM;
vgmstream->num_samples = read_32bitLE(0x66,streamFile);
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = read_16bitLE(0x38,streamFile);
vgmstream->meta_type = meta_2DX9;
/* 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;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
vgmstream->frame_size = read_16bitLE(0x38,streamFile);
if (!msadpcm_check_coefs(streamFile, 0x40))
goto fail;
}
}
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;
}

+ 6
- 15
Frameworks/vgmstream/vgmstream/src/meta/acb.c View File

@@ -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;
}


+ 8
- 8
Frameworks/vgmstream/vgmstream/src/meta/aix.c View File

@@ -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;
}



+ 7
- 25
Frameworks/vgmstream/vgmstream/src/meta/aix_streamfile.h View File

@@ -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_ */

+ 2
- 2
Frameworks/vgmstream/vgmstream/src/meta/akb.c View File

@@ -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)


+ 33
- 11
Frameworks/vgmstream/vgmstream/src/meta/bwav.c View File

@@ -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;


+ 1
- 1
Frameworks/vgmstream/vgmstream/src/meta/ck.c View File

@@ -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;


+ 4
- 4
Frameworks/vgmstream/vgmstream/src/meta/dec.c View File

@@ -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;



+ 4
- 2
Frameworks/vgmstream/vgmstream/src/meta/genh.c View File

@@ -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;


+ 1
- 1
Frameworks/vgmstream/vgmstream/src/meta/meta.h View File

@@ -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);


+ 16
- 18
Frameworks/vgmstream/vgmstream/src/meta/mus_acm.c View File

@@ -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;


+ 11
- 4
Frameworks/vgmstream/vgmstream/src/meta/mzrt.c View File

@@ -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


+ 31
- 61
Frameworks/vgmstream/vgmstream/src/meta/nub.c View File

@@ -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;
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;
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};
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;
}

+ 106
- 235
Frameworks/vgmstream/vgmstream/src/meta/ogg_vorbis.c View File

@@ -1,123 +1,60 @@
#include "../vgmstream.h"

#ifdef VGM_USE_VORBIS
#include <stdio.h>
#include <string.h>
#include <vorbis/vorbisfile.h>
#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;
int disable_reordering = ovmi->disable_reordering;

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};
//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;

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);
}


/* proceed to init codec_data and reopen a STREAMFILE for this stream */
{
char filename[PATH_LIMIT];

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);

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);
const char * comment = NULL;

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) */