Browse Source

Updated VGMStream to r1050-2696-g0a04a738

master
Christopher Snowhill 3 months ago
parent
commit
90ac083705
52 changed files with 20065 additions and 19645 deletions
  1. +8
    -4
      Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj
  2. +56
    -56
      Frameworks/vgmstream/vgmstream/src/coding/asf_decoder.c
  3. +282
    -281
      Frameworks/vgmstream/vgmstream/src/coding/atrac9_decoder.c
  4. +53
    -53
      Frameworks/vgmstream/vgmstream/src/coding/dsa_decoder.c
  5. +78
    -78
      Frameworks/vgmstream/vgmstream/src/coding/fadpcm_decoder.c
  6. +700
    -700
      Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c
  7. +190
    -190
      Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils.c
  8. +422
    -422
      Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils.c
  9. +114
    -114
      Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils_ahx.c
  10. +854
    -854
      Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils_ealayer3.c
  11. +176
    -176
      Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils_eamp3.c
  12. +153
    -153
      Frameworks/vgmstream/vgmstream/src/coding/mta2_decoder.c
  13. +1
    -1
      Frameworks/vgmstream/vgmstream/src/coding/psx_decoder.c
  14. +112
    -112
      Frameworks/vgmstream/vgmstream/src/coding/ptadpcm_decoder.c
  15. +65
    -65
      Frameworks/vgmstream/vgmstream/src/coding/xmd_decoder.c
  16. +1347
    -1345
      Frameworks/vgmstream/vgmstream/src/formats.c
  17. +1
    -1
      Frameworks/vgmstream/vgmstream/src/layout/blocked_ea_sns.c
  18. +36
    -26
      Frameworks/vgmstream/vgmstream/src/layout/blocked_thp.c
  19. +352
    -346
      Frameworks/vgmstream/vgmstream/src/meta/adx_keys.h
  20. +1617
    -1534
      Frameworks/vgmstream/vgmstream/src/meta/ea_eaac.c
  21. +270
    -270
      Frameworks/vgmstream/vgmstream/src/meta/ea_eaac_streamfile.h
  22. +3
    -3
      Frameworks/vgmstream/vgmstream/src/meta/ea_schl.c
  23. +1
    -7
      Frameworks/vgmstream/vgmstream/src/meta/gin.c
  24. +323
    -311
      Frameworks/vgmstream/vgmstream/src/meta/hca_keys.h
  25. +50
    -0
      Frameworks/vgmstream/vgmstream/src/meta/ivag.c
  26. +3
    -2
      Frameworks/vgmstream/vgmstream/src/meta/meta.h
  27. +128
    -128
      Frameworks/vgmstream/vgmstream/src/meta/mta2.c
  28. +135
    -135
      Frameworks/vgmstream/vgmstream/src/meta/mta2_streamfile.h
  29. +38
    -16
      Frameworks/vgmstream/vgmstream/src/meta/musx.c
  30. +1292
    -1287
      Frameworks/vgmstream/vgmstream/src/meta/ngc_dsp_std.c
  31. +599
    -527
      Frameworks/vgmstream/vgmstream/src/meta/nub.c
  32. +119
    -119
      Frameworks/vgmstream/vgmstream/src/meta/nus3audio.c
  33. +269
    -183
      Frameworks/vgmstream/vgmstream/src/meta/nus3bank.c
  34. +126
    -0
      Frameworks/vgmstream/vgmstream/src/meta/nus3bank_streamfile.h
  35. +84
    -84
      Frameworks/vgmstream/vgmstream/src/meta/ps2_2pfs.c
  36. +0
    -84
      Frameworks/vgmstream/vgmstream/src/meta/ps3_ivag.c
  37. +190
    -190
      Frameworks/vgmstream/vgmstream/src/meta/sgxd.c
  38. +665
    -657
      Frameworks/vgmstream/vgmstream/src/meta/sqex_sead.c
  39. +100
    -103
      Frameworks/vgmstream/vgmstream/src/meta/thp.c
  40. +1756
    -1756
      Frameworks/vgmstream/vgmstream/src/meta/txth.c
  41. +1510
    -1501
      Frameworks/vgmstream/vgmstream/src/meta/txtp.c
  42. +3058
    -3058
      Frameworks/vgmstream/vgmstream/src/meta/ubi_sb.c
  43. +6
    -4
      Frameworks/vgmstream/vgmstream/src/meta/vag.c
  44. +99
    -99
      Frameworks/vgmstream/vgmstream/src/meta/wave.c
  45. +1001
    -1001
      Frameworks/vgmstream/vgmstream/src/meta/xwb_xsb.h
  46. +1111
    -1111
      Frameworks/vgmstream/vgmstream/src/mixing.c
  47. +42
    -42
      Frameworks/vgmstream/vgmstream/src/mixing.h
  48. +348
    -344
      Frameworks/vgmstream/vgmstream/src/plugins.c
  49. +106
    -106
      Frameworks/vgmstream/vgmstream/src/plugins.h
  50. +8
    -0
      Frameworks/vgmstream/vgmstream/src/util.h
  51. +5
    -4
      Frameworks/vgmstream/vgmstream/src/vgmstream.c
  52. +3
    -2
      Frameworks/vgmstream/vgmstream/src/vgmstream.h

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

@@ -89,6 +89,8 @@
8323894B1D22419B00482226 /* clHCA.h in Headers */ = {isa = PBXBuildFile; fileRef = 832389491D22419B00482226 /* clHCA.h */; settings = {ATTRIBUTES = (Public, ); }; };
832389501D2246C300482226 /* hca.c in Sources */ = {isa = PBXBuildFile; fileRef = 8323894F1D2246C300482226 /* hca.c */; };
832389521D224C0800482226 /* hca_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 832389511D224C0800482226 /* hca_decoder.c */; };
83269DD22399F5DE00F49FE3 /* nus3bank_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83269DD02399F5DD00F49FE3 /* nus3bank_streamfile.h */; };
83269DD32399F5DE00F49FE3 /* ivag.c in Sources */ = {isa = PBXBuildFile; fileRef = 83269DD12399F5DE00F49FE3 /* ivag.c */; };
83299FD01E7660C7003A3242 /* bik.c in Sources */ = {isa = PBXBuildFile; fileRef = 83299FCE1E7660C7003A3242 /* bik.c */; };
83299FD11E7660C7003A3242 /* dsp_adx.c in Sources */ = {isa = PBXBuildFile; fileRef = 83299FCF1E7660C7003A3242 /* dsp_adx.c */; };
832BF7FF21E050B7006F50F1 /* circus_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BF7FC21E050B6006F50F1 /* circus_decoder.c */; };
@@ -378,7 +380,6 @@
836F700E18BDC2190095E648 /* ps2_xa2.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED218BDC2190095E648 /* ps2_xa2.c */; };
836F700F18BDC2190095E648 /* ps2_xa30.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED318BDC2190095E648 /* ps2_xa30.c */; };
836F701118BDC2190095E648 /* ps3_cps.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED518BDC2190095E648 /* ps3_cps.c */; };
836F701218BDC2190095E648 /* ps3_ivag.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED618BDC2190095E648 /* ps3_ivag.c */; };
836F701518BDC2190095E648 /* ps3_past.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6ED918BDC2190095E648 /* ps3_past.c */; };
836F701E18BDC2190095E648 /* redspark.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EE218BDC2190095E648 /* redspark.c */; };
836F701F18BDC2190095E648 /* riff.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6EE318BDC2190095E648 /* riff.c */; };
@@ -776,6 +777,8 @@
832389491D22419B00482226 /* clHCA.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = clHCA.h; sourceTree = "<group>"; };
8323894F1D2246C300482226 /* hca.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hca.c; sourceTree = "<group>"; };
832389511D224C0800482226 /* hca_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hca_decoder.c; sourceTree = "<group>"; };
83269DD02399F5DD00F49FE3 /* nus3bank_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nus3bank_streamfile.h; sourceTree = "<group>"; };
83269DD12399F5DE00F49FE3 /* ivag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ivag.c; sourceTree = "<group>"; };
83299FCE1E7660C7003A3242 /* bik.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bik.c; sourceTree = "<group>"; };
83299FCF1E7660C7003A3242 /* dsp_adx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dsp_adx.c; sourceTree = "<group>"; };
832BF7FC21E050B6006F50F1 /* circus_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = circus_decoder.c; sourceTree = "<group>"; };
@@ -1065,7 +1068,6 @@
836F6ED218BDC2190095E648 /* ps2_xa2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_xa2.c; sourceTree = "<group>"; };
836F6ED318BDC2190095E648 /* ps2_xa30.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2_xa30.c; sourceTree = "<group>"; };
836F6ED518BDC2190095E648 /* ps3_cps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_cps.c; sourceTree = "<group>"; };
836F6ED618BDC2190095E648 /* ps3_ivag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_ivag.c; sourceTree = "<group>"; };
836F6ED918BDC2190095E648 /* ps3_past.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps3_past.c; sourceTree = "<group>"; };
836F6EE218BDC2190095E648 /* redspark.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = redspark.c; sourceTree = "<group>"; };
836F6EE318BDC2190095E648 /* riff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = riff.c; sourceTree = "<group>"; };
@@ -1647,6 +1649,7 @@
836F6E5518BDC2180095E648 /* ios_psnd.c */,
83AFABBB23795202002F3947 /* isb.c */,
836F6E5618BDC2180095E648 /* ish_isd.c */,
83269DD12399F5DE00F49FE3 /* ivag.c */,
836F6E5718BDC2180095E648 /* ivaud.c */,
836F6E5818BDC2180095E648 /* ivb.c */,
837CEAE923487F2B00E62A4A /* jstm_streamfile.h */,
@@ -1715,6 +1718,7 @@
83C727FC22BC893900678B4A /* nps.c */,
837CEAE223487F2A00E62A4A /* nub.c */,
832BF81B21E0514B006F50F1 /* nus3audio.c */,
83269DD02399F5DD00F49FE3 /* nus3bank_streamfile.h */,
834FE0D1215C79E9000A5D3D /* nus3bank.c */,
836F6E8118BDC2180095E648 /* nwa.c */,
832BF81421E0514A006F50F1 /* nwav.c */,
@@ -1800,7 +1804,6 @@
836F6ED218BDC2190095E648 /* ps2_xa2.c */,
836F6ED318BDC2190095E648 /* ps2_xa30.c */,
836F6ED518BDC2190095E648 /* ps3_cps.c */,
836F6ED618BDC2190095E648 /* ps3_ivag.c */,
836F6ED918BDC2190095E648 /* ps3_past.c */,
837CEAE823487F2B00E62A4A /* psf.c */,
83997F5722D9569E00633184 /* rad.c */,
@@ -2033,6 +2036,7 @@
837CEAF323487F2C00E62A4A /* mzrt_streamfile.h in Headers */,
8349A91B1FE6258200E26435 /* adx_keys.h in Headers */,
836F6F4D18BDC2190095E648 /* layout.h in Headers */,
83269DD22399F5DE00F49FE3 /* nus3bank_streamfile.h in Headers */,
83AA5D251F6E2F9C0020821C /* hca_keys.h in Headers */,
836F6F2318BDC2190095E648 /* coding.h in Headers */,
);
@@ -2217,6 +2221,7 @@
8301659C1F256BD000CA0941 /* nds_strm_ffta2.c in Sources */,
837CEA7923487E2500E62A4A /* ubi_adpcm_decoder.c in Sources */,
834FE0EB215C79ED000A5D3D /* str_wav.c in Sources */,
83269DD32399F5DE00F49FE3 /* ivag.c in Sources */,
8349A8DF1FE6251F00E26435 /* vorbis_custom_utils_vid1.c in Sources */,
83A21F8D201D8982000F04B9 /* sqex_sead.c in Sources */,
83EED5D3203A8BC7008BEB45 /* ea_swvr.c in Sources */,
@@ -2537,7 +2542,6 @@
83A21F8A201D8982000F04B9 /* fsb_encrypted.c in Sources */,
8306B0B120984552000302D4 /* blocked_halpst.c in Sources */,
836F6FD018BDC2190095E648 /* ps2_b1s.c in Sources */,
836F701218BDC2190095E648 /* ps3_ivag.c in Sources */,
83AA5D181F6E2F600020821C /* mpeg_custom_utils_awc.c in Sources */,
834FE0FE215C79ED000A5D3D /* ps_headerless.c in Sources */,
8306B0BB20984552000302D4 /* blocked_gsb.c in Sources */,


+ 56
- 56
Frameworks/vgmstream/vgmstream/src/coding/asf_decoder.c View File

@@ -1,56 +1,56 @@
#include "coding.h"
/* Decodes Argonaut's ASF ADPCM codec, used in some of their PC games.
* Reverse engineered from asfcodec.adl DLL. */
void decode_asf(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
uint8_t frame[0x11] = {0};
off_t frame_offset;
int i, frames_in, sample_count = 0;
size_t bytes_per_frame, samples_per_frame;
int shift, mode;
int32_t hist1 = stream->adpcm_history1_32;
int32_t hist2 = stream->adpcm_history2_32;
/* external interleave (fixed size), mono */
bytes_per_frame = 0x11;
samples_per_frame = (bytes_per_frame - 0x01) * 2;
frames_in = first_sample / samples_per_frame;
//first_sample = first_sample % samples_per_frame; /* for flat layout */
/* parse frame header */
frame_offset = stream->offset + bytes_per_frame*frames_in;
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
shift = (frame[0x00] >> 4) & 0xf;
mode = (frame[0x00] >> 0) & 0xf;
/* decode nibbles */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
uint8_t nibbles = frame[0x01 + i/2];
int32_t sample;
sample = i&1 ? /* high nibble first */
get_low_nibble_signed(nibbles):
get_high_nibble_signed(nibbles);
sample = (sample << 4) << (shift + 2); /* move sample to upper nibble, then shift + 2 (IOW: shift + 6) */
/* mode is checked as a flag, so there are 2 modes only, but lower nibble
* may have other values at last frame (ex 0x02/09), could be control flags (loop related?) */
if (mode & 0x4) { /* ~filters: 2, -1 */
sample = (sample + (hist1 << 7) - (hist2 << 6)) >> 6;
}
else { /* ~filters: 1, 0 */
sample = (sample + (hist1 << 6)) >> 6;
}
outbuf[sample_count] = (int16_t)sample; /* must not clamp */
sample_count += channelspacing;
hist2 = hist1;
hist1 = sample;
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_history2_32 = hist2;
}
#include "coding.h"
/* Decodes Argonaut's ASF ADPCM codec, used in some of their PC games.
* Reverse engineered from asfcodec.adl DLL. */
void decode_asf(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
uint8_t frame[0x11] = {0};
off_t frame_offset;
int i, frames_in, sample_count = 0;
size_t bytes_per_frame, samples_per_frame;
int shift, mode;
int32_t hist1 = stream->adpcm_history1_32;
int32_t hist2 = stream->adpcm_history2_32;
/* external interleave (fixed size), mono */
bytes_per_frame = 0x11;
samples_per_frame = (bytes_per_frame - 0x01) * 2;
frames_in = first_sample / samples_per_frame;
//first_sample = first_sample % samples_per_frame; /* for flat layout */
/* parse frame header */
frame_offset = stream->offset + bytes_per_frame*frames_in;
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
shift = (frame[0x00] >> 4) & 0xf;
mode = (frame[0x00] >> 0) & 0xf;
/* decode nibbles */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
uint8_t nibbles = frame[0x01 + i/2];
int32_t sample;
sample = i&1 ? /* high nibble first */
get_low_nibble_signed(nibbles):
get_high_nibble_signed(nibbles);
sample = (sample << 4) << (shift + 2); /* move sample to upper nibble, then shift + 2 (IOW: shift + 6) */
/* mode is checked as a flag, so there are 2 modes only, but lower nibble
* may have other values at last frame (ex 0x02/09), could be control flags (loop related?) */
if (mode & 0x4) { /* ~filters: 2, -1 */
sample = (sample + (hist1 << 7) - (hist2 << 6)) >> 6;
}
else { /* ~filters: 1, 0 */
sample = (sample + (hist1 << 6)) >> 6;
}
outbuf[sample_count] = (int16_t)sample; /* must not clamp */
sample_count += channelspacing;
hist2 = hist1;
hist1 = sample;
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_history2_32 = hist2;
}

+ 282
- 281
Frameworks/vgmstream/vgmstream/src/coding/atrac9_decoder.c View File

@@ -1,281 +1,282 @@
#include "coding.h"
#ifdef VGM_USE_ATRAC9
#ifdef __MACOSX__
#include <libatrac9/libatrac9.h>
#else
#include "libatrac9.h"
#endif
/* opaque struct */
struct atrac9_codec_data {
uint8_t *data_buffer;
size_t data_buffer_size;
sample_t *sample_buffer;
size_t samples_filled; /* number of samples in the buffer */
size_t samples_used; /* number of samples extracted from the buffer */
int samples_to_discard;
atrac9_config config;
void *handle; /* decoder handle */
Atrac9CodecInfo info; /* decoder info */
};
atrac9_codec_data *init_atrac9(atrac9_config *cfg) {
int status;
uint8_t config_data[4];
atrac9_codec_data *data = NULL;
data = calloc(1, sizeof(atrac9_codec_data));
if (!data) goto fail;
data->handle = Atrac9GetHandle();
if (!data->handle) goto fail;
put_32bitBE(config_data, cfg->config_data);
status = Atrac9InitDecoder(data->handle, config_data);
if (status < 0) goto fail;
status = Atrac9GetCodecInfo(data->handle, &data->info);
if (status < 0) goto fail;
//;VGM_LOG("ATRAC9: config=%x, sf-size=%x, sub-frames=%i x %i samples\n", cfg->config_data, data->info.superframeSize, data->info.framesInSuperframe, data->info.frameSamples);
if (cfg->channels && cfg->channels != data->info.channels) {
VGM_LOG("ATRAC9: channels in header %i vs config %i don't match\n", cfg->channels, data->info.channels);
goto fail; /* unknown multichannel layout */
}
/* must hold at least one superframe and its samples */
data->data_buffer_size = data->info.superframeSize;
/* extra leeway as Atrac9Decode seems to overread ~2 bytes (doesn't affect decoding though) */
data->data_buffer = calloc(sizeof(uint8_t), data->data_buffer_size + 0x10);
/* while ATRAC9 uses float internally, Sony's API only return PCM16 */
data->sample_buffer = calloc(sizeof(sample_t), data->info.channels * data->info.frameSamples * data->info.framesInSuperframe);
data->samples_to_discard = cfg->encoder_delay;
memcpy(&data->config, cfg, sizeof(atrac9_config));
return data;
fail:
free_atrac9(data);
return NULL;
}
void decode_atrac9(VGMSTREAM *vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0];
atrac9_codec_data * data = vgmstream->codec_data;
int samples_done = 0;
while (samples_done < samples_to_do) {
if (data->samples_filled) { /* consume samples */
int samples_to_get = data->samples_filled;
if (data->samples_to_discard) {
/* discard samples for looping */
if (samples_to_get > data->samples_to_discard)
samples_to_get = data->samples_to_discard;
data->samples_to_discard -= samples_to_get;
}
else {
/* get max samples and copy */
if (samples_to_get > samples_to_do - samples_done)
samples_to_get = samples_to_do - samples_done;
memcpy(outbuf + samples_done*channels,
data->sample_buffer + data->samples_used*channels,
samples_to_get*channels * sizeof(sample));
samples_done += samples_to_get;
}
/* mark consumed samples */
data->samples_used += samples_to_get;
data->samples_filled -= samples_to_get;
}
else { /* decode data */
int iframe, status;
int bytes_used = 0;
uint8_t *buffer = data->data_buffer;
size_t bytes;
data->samples_used = 0;
/* ATRAC9 is made of decodable superframes with several sub-frames. AT9 config data gives
* superframe size, number of frames and samples (~100-200 bytes and ~256/1024 samples). */
/* read one raw block (superframe) and advance offsets */
bytes = read_streamfile(data->data_buffer,stream->offset, data->info.superframeSize,stream->streamfile);
if (bytes != data->data_buffer_size) goto decode_fail;
stream->offset += bytes;
/* decode all frames in the superframe block */
for (iframe = 0; iframe < data->info.framesInSuperframe; iframe++) {
status = Atrac9Decode(data->handle, buffer, data->sample_buffer + data->samples_filled*channels, &bytes_used);
if (status < 0) goto decode_fail;
buffer += bytes_used;
data->samples_filled += data->info.frameSamples;
}
}
}
return;
decode_fail:
/* on error just put some 0 samples */
VGM_LOG("ATRAC9: decode fail at %x, missing %i samples\n", (uint32_t)stream->offset, (samples_to_do - samples_done));
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample) * channels);
}
void reset_atrac9(VGMSTREAM *vgmstream) {
atrac9_codec_data *data = vgmstream->codec_data;
if (!data) return;
if (!data->handle)
goto fail;
#if 0
/* reopen/flush, not needed as superframes decode separatedly and there is no carried state */
{
int status;
uint8_t config_data[4];
Atrac9ReleaseHandle(data->handle);
data->handle = Atrac9GetHandle();
if (!data->handle) goto fail;
put_32bitBE(config_data, data->config.config_data);
status = Atrac9InitDecoder(data->handle, config_data);
if (status < 0) goto fail;
}
#endif
data->samples_used = 0;
data->samples_filled = 0;
data->samples_to_discard = data->config.encoder_delay;
return;
fail:
return; /* decode calls should fail... */
}
void seek_atrac9(VGMSTREAM *vgmstream, int32_t num_sample) {
atrac9_codec_data *data = vgmstream->codec_data;
if (!data) return;
reset_atrac9(vgmstream);
/* find closest offset to desired sample, and samples to discard after that offset to reach loop */
{
int32_t seek_sample = data->config.encoder_delay + num_sample;
off_t seek_offset;
int32_t seek_discard;
int32_t superframe_samples = data->info.frameSamples * data->info.framesInSuperframe;
size_t superframe_number, superframe_back;
superframe_number = (seek_sample / superframe_samples); /* closest */
/* decoded frames affect each other slightly, so move offset back to make PCM stable
* and equivalent to a full discard loop */
superframe_back = 1; /* 1 seems enough (even when only 1 subframe in superframe) */
if (superframe_back > superframe_number)
superframe_back = superframe_number;
seek_discard = (seek_sample % superframe_samples) + (superframe_back * superframe_samples);
seek_offset = (superframe_number - superframe_back) * data->info.superframeSize;
data->samples_to_discard = seek_discard; /* already includes encoder delay */
if (vgmstream->loop_ch)
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset + seek_offset;
}
#if 0
//old full discard loop
{
data->samples_to_discard = num_sample;
data->samples_to_discard += data->config.encoder_delay;
/* loop offsets are set during decode; force them to stream start so discard works */
if (vgmstream->loop_ch)
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset;
}
#endif
}
void free_atrac9(atrac9_codec_data *data) {
if (!data) return;
if (data->handle) Atrac9ReleaseHandle(data->handle);
free(data->data_buffer);
free(data->sample_buffer);
free(data);
}
static int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_channels, size_t *out_frame_size, size_t *out_samples_per_frame) {
static const int sample_rate_table[16] = {
11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
44100, 48000, 64000, 88200, 96000,128000,176400,192000
};
static const int samples_power_table[16] = {
6, 6, 7, 7, 7, 8, 8, 8,
6, 6, 7, 7, 7, 8, 8, 8
};
static const int channel_table[8] = {
1, 2, 2, 6, 8, 4, 0, 0
};
int superframe_size, frames_per_superframe, samples_per_frame, samples_per_superframe;
uint32_t sync = (atrac9_config >> 24) & 0xff; /* 8b */
uint8_t sample_rate_index = (atrac9_config >> 20) & 0x0f; /* 4b */
uint8_t channels_index = (atrac9_config >> 17) & 0x07; /* 3b */
/* uint8_t validation bit = (atrac9_config >> 16) & 0x01; */ /* 1b */
size_t frame_size = (atrac9_config >> 5) & 0x7FF; /* 11b */
size_t superframe_index = (atrac9_config >> 3) & 0x3; /* 2b */
/* uint8_t unused = (atrac9_config >> 0) & 0x7);*/ /* 3b */
superframe_size = ((frame_size+1) << superframe_index);
frames_per_superframe = (1 << superframe_index);
samples_per_frame = 1 << samples_power_table[sample_rate_index];
samples_per_superframe = samples_per_frame * frames_per_superframe;
if (sync != 0xFE)
goto fail;
if (out_sample_rate)
*out_sample_rate = sample_rate_table[sample_rate_index];
if (out_channels)
*out_channels = channel_table[channels_index];
if (out_frame_size)
*out_frame_size = superframe_size;
if (out_samples_per_frame)
*out_samples_per_frame = samples_per_superframe;
return 1;
fail:
return 0;
}
size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data *data) {
return bytes / data->info.superframeSize * (data->info.frameSamples * data->info.framesInSuperframe);
}
size_t atrac9_bytes_to_samples_cfg(size_t bytes, uint32_t atrac9_config) {
size_t frame_size, samples_per_frame;
if (!atrac9_parse_config(atrac9_config, NULL, NULL, &frame_size, &samples_per_frame))
return 0;
return bytes / frame_size * samples_per_frame;
}
#endif
#include "coding.h"

#ifdef VGM_USE_ATRAC9
#ifdef __MACOSX__
#include <libatrac9/libatrac9.h>
#else
#include "libatrac9.h"
#endif


/* opaque struct */
struct atrac9_codec_data {
uint8_t *data_buffer;
size_t data_buffer_size;

sample_t *sample_buffer;
size_t samples_filled; /* number of samples in the buffer */
size_t samples_used; /* number of samples extracted from the buffer */

int samples_to_discard;

atrac9_config config;

void *handle; /* decoder handle */
Atrac9CodecInfo info; /* decoder info */
};


atrac9_codec_data *init_atrac9(atrac9_config *cfg) {
int status;
uint8_t config_data[4];
atrac9_codec_data *data = NULL;

data = calloc(1, sizeof(atrac9_codec_data));
if (!data) goto fail;

data->handle = Atrac9GetHandle();
if (!data->handle) goto fail;

put_32bitBE(config_data, cfg->config_data);
status = Atrac9InitDecoder(data->handle, config_data);
if (status < 0) goto fail;

status = Atrac9GetCodecInfo(data->handle, &data->info);
if (status < 0) goto fail;
//;VGM_LOG("ATRAC9: config=%x, sf-size=%x, sub-frames=%i x %i samples\n", cfg->config_data, data->info.superframeSize, data->info.framesInSuperframe, data->info.frameSamples);

if (cfg->channels && cfg->channels != data->info.channels) {
VGM_LOG("ATRAC9: channels in header %i vs config %i don't match\n", cfg->channels, data->info.channels);
goto fail; /* unknown multichannel layout */
}


/* must hold at least one superframe and its samples */
data->data_buffer_size = data->info.superframeSize;
/* extra leeway as Atrac9Decode seems to overread ~2 bytes (doesn't affect decoding though) */
data->data_buffer = calloc(sizeof(uint8_t), data->data_buffer_size + 0x10);
/* while ATRAC9 uses float internally, Sony's API only return PCM16 */
data->sample_buffer = calloc(sizeof(sample_t), data->info.channels * data->info.frameSamples * data->info.framesInSuperframe);

data->samples_to_discard = cfg->encoder_delay;

memcpy(&data->config, cfg, sizeof(atrac9_config));

return data;

fail:
free_atrac9(data);
return NULL;
}

void decode_atrac9(VGMSTREAM *vgmstream, sample_t * outbuf, int32_t samples_to_do, int channels) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0];
atrac9_codec_data * data = vgmstream->codec_data;
int samples_done = 0;


while (samples_done < samples_to_do) {

if (data->samples_filled) { /* consume samples */
int samples_to_get = data->samples_filled;

if (data->samples_to_discard) {
/* discard samples for looping */
if (samples_to_get > data->samples_to_discard)
samples_to_get = data->samples_to_discard;
data->samples_to_discard -= samples_to_get;
}
else {
/* get max samples and copy */
if (samples_to_get > samples_to_do - samples_done)
samples_to_get = samples_to_do - samples_done;

memcpy(outbuf + samples_done*channels,
data->sample_buffer + data->samples_used*channels,
samples_to_get*channels * sizeof(sample));

samples_done += samples_to_get;
}

/* mark consumed samples */
data->samples_used += samples_to_get;
data->samples_filled -= samples_to_get;
}
else { /* decode data */
int iframe, status;
int bytes_used = 0;
uint8_t *buffer = data->data_buffer;
size_t bytes;

data->samples_used = 0;

/* ATRAC9 is made of decodable superframes with several sub-frames. AT9 config data gives
* superframe size, number of frames and samples (~100-200 bytes and ~256/1024 samples). */

/* read one raw block (superframe) and advance offsets */
bytes = read_streamfile(data->data_buffer,stream->offset, data->info.superframeSize,stream->streamfile);
if (bytes != data->data_buffer_size) goto decode_fail;

stream->offset += bytes;

/* decode all frames in the superframe block */
for (iframe = 0; iframe < data->info.framesInSuperframe; iframe++) {
status = Atrac9Decode(data->handle, buffer, data->sample_buffer + data->samples_filled*channels, &bytes_used);
if (status < 0) goto decode_fail;

buffer += bytes_used;
data->samples_filled += data->info.frameSamples;
}
}
}

return;

decode_fail:
/* on error just put some 0 samples */
VGM_LOG("ATRAC9: decode fail at %x, missing %i samples\n", (uint32_t)stream->offset, (samples_to_do - samples_done));
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample) * channels);
}

void reset_atrac9(VGMSTREAM *vgmstream) {
atrac9_codec_data *data = vgmstream->codec_data;
if (!data) return;

if (!data->handle)
goto fail;

#if 0
/* reopen/flush, not needed as superframes decode separatedly and there is no carried state */
{
int status;
uint8_t config_data[4];

Atrac9ReleaseHandle(data->handle);
data->handle = Atrac9GetHandle();
if (!data->handle) goto fail;

put_32bitBE(config_data, data->config.config_data);
status = Atrac9InitDecoder(data->handle, config_data);
if (status < 0) goto fail;
}
#endif

data->samples_used = 0;
data->samples_filled = 0;
data->samples_to_discard = data->config.encoder_delay;

return;

fail:
return; /* decode calls should fail... */
}

void seek_atrac9(VGMSTREAM *vgmstream, int32_t num_sample) {
atrac9_codec_data *data = vgmstream->codec_data;
if (!data) return;

reset_atrac9(vgmstream);

/* find closest offset to desired sample, and samples to discard after that offset to reach loop */
{
int32_t seek_sample = data->config.encoder_delay + num_sample;
off_t seek_offset;
int32_t seek_discard;
int32_t superframe_samples = data->info.frameSamples * data->info.framesInSuperframe;
size_t superframe_number, superframe_back;

superframe_number = (seek_sample / superframe_samples); /* closest */

/* decoded frames affect each other slightly, so move offset back to make PCM stable
* and equivalent to a full discard loop */
superframe_back = 1; /* 1 seems enough (even when only 1 subframe in superframe) */
if (superframe_back > superframe_number)
superframe_back = superframe_number;

seek_discard = (seek_sample % superframe_samples) + (superframe_back * superframe_samples);
seek_offset = (superframe_number - superframe_back) * data->info.superframeSize;

data->samples_to_discard = seek_discard; /* already includes encoder delay */

if (vgmstream->loop_ch)
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset + seek_offset;
}

#if 0
//old full discard loop
{
data->samples_to_discard = num_sample;
data->samples_to_discard += data->config.encoder_delay;

/* loop offsets are set during decode; force them to stream start so discard works */
if (vgmstream->loop_ch)
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset;
}
#endif

}

void free_atrac9(atrac9_codec_data *data) {
if (!data) return;

if (data->handle) Atrac9ReleaseHandle(data->handle);
free(data->data_buffer);
free(data->sample_buffer);
free(data);
}


static int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_channels, size_t *out_frame_size, size_t *out_samples_per_frame) {
static const int sample_rate_table[16] = {
11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
44100, 48000, 64000, 88200, 96000,128000,176400,192000
};
static const int samples_power_table[16] = {
6, 6, 7, 7, 7, 8, 8, 8,
6, 6, 7, 7, 7, 8, 8, 8
};
static const int channel_table[8] = {
1, 2, 2, 6, 8, 4, 0, 0
};

int superframe_size, frames_per_superframe, samples_per_frame, samples_per_superframe;
uint32_t sync = (atrac9_config >> 24) & 0xff; /* 8b */
uint8_t sample_rate_index = (atrac9_config >> 20) & 0x0f; /* 4b */
uint8_t channels_index = (atrac9_config >> 17) & 0x07; /* 3b */
/* uint8_t validation bit = (atrac9_config >> 16) & 0x01; */ /* 1b */
size_t frame_size = (atrac9_config >> 5) & 0x7FF; /* 11b */
size_t superframe_index = (atrac9_config >> 3) & 0x3; /* 2b */
/* uint8_t unused = (atrac9_config >> 0) & 0x7);*/ /* 3b */

superframe_size = ((frame_size+1) << superframe_index);
frames_per_superframe = (1 << superframe_index);
samples_per_frame = 1 << samples_power_table[sample_rate_index];
samples_per_superframe = samples_per_frame * frames_per_superframe;

if (sync != 0xFE)
goto fail;
if (out_sample_rate)
*out_sample_rate = sample_rate_table[sample_rate_index];
if (out_channels)
*out_channels = channel_table[channels_index];
if (out_frame_size)
*out_frame_size = superframe_size;
if (out_samples_per_frame)
*out_samples_per_frame = samples_per_superframe;

return 1;
fail:
return 0;
}

size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data *data) {
return bytes / data->info.superframeSize * (data->info.frameSamples * data->info.framesInSuperframe);
}

size_t atrac9_bytes_to_samples_cfg(size_t bytes, uint32_t atrac9_config) {
size_t frame_size, samples_per_frame;
if (!atrac9_parse_config(atrac9_config, NULL, NULL, &frame_size, &samples_per_frame))
return 0;
return bytes / frame_size * samples_per_frame;
}
#endif

+ 53
- 53
Frameworks/vgmstream/vgmstream/src/coding/dsa_decoder.c View File

@@ -1,53 +1,53 @@
#include "coding.h"
static const int dsa_coefs[16] = {
0x0, 0x1999, 0x3333, 0x4CCC,
0x6666, 0x8000, 0x9999, 0xB333,
0xCCCC, 0xE666, 0x10000, 0x11999,
0x13333, 0x18000, 0x1CCCC, 0x21999
};
/* Decodes Ocean DSA ADPCM codec from Last Rites (PC).
* Reverse engineered from daemon1's reverse engineering. */
void decode_dsa(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
uint8_t frame[0x08] = {0};
off_t frame_offset;
int i, frames_in, sample_count = 0;
size_t bytes_per_frame, samples_per_frame;
int index, shift, coef;
int32_t hist1 = stream->adpcm_history1_32;
/* external interleave (fixed size), mono */
bytes_per_frame = 0x08;
samples_per_frame = (bytes_per_frame - 0x01) * 2;
frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame; /* for flat layout */
/* parse frame header */
frame_offset = stream->offset + bytes_per_frame * frames_in;
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
index = ((frame[0] >> 0) & 0xf);
shift = 12 - ((frame[0] >> 4) & 0xf);
coef = dsa_coefs[index];
/* decode nibbles */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
uint8_t nibbles = frame[0x01 + i/2];
int32_t sample;
sample = i&1 ? /* high nibble first */
(nibbles >> 0) & 0xf :
(nibbles >> 4) & 0xf;
sample = ((int16_t)(sample << 12) >> shift); /* 16b sign extend + scale */
sample = sample + ((hist1 * coef) >> 16);
outbuf[sample_count] = (sample_t)(sample << 2);
sample_count += channelspacing;
hist1 = sample;
}
stream->adpcm_history1_32 = hist1;
}
#include "coding.h"
static const int dsa_coefs[16] = {
0x0, 0x1999, 0x3333, 0x4CCC,
0x6666, 0x8000, 0x9999, 0xB333,
0xCCCC, 0xE666, 0x10000, 0x11999,
0x13333, 0x18000, 0x1CCCC, 0x21999
};
/* Decodes Ocean DSA ADPCM codec from Last Rites (PC).
* Reverse engineered from daemon1's reverse engineering. */
void decode_dsa(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
uint8_t frame[0x08] = {0};
off_t frame_offset;
int i, frames_in, sample_count = 0;
size_t bytes_per_frame, samples_per_frame;
int index, shift, coef;
int32_t hist1 = stream->adpcm_history1_32;
/* external interleave (fixed size), mono */
bytes_per_frame = 0x08;
samples_per_frame = (bytes_per_frame - 0x01) * 2;
frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame; /* for flat layout */
/* parse frame header */
frame_offset = stream->offset + bytes_per_frame * frames_in;
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
index = ((frame[0] >> 0) & 0xf);
shift = 12 - ((frame[0] >> 4) & 0xf);
coef = dsa_coefs[index];
/* decode nibbles */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
uint8_t nibbles = frame[0x01 + i/2];
int32_t sample;
sample = i&1 ? /* high nibble first */
(nibbles >> 0) & 0xf :
(nibbles >> 4) & 0xf;
sample = ((int16_t)(sample << 12) >> shift); /* 16b sign extend + scale */
sample = sample + ((hist1 * coef) >> 16);
outbuf[sample_count] = (sample_t)(sample << 2);
sample_count += channelspacing;
hist1 = sample;
}
stream->adpcm_history1_32 = hist1;
}

+ 78
- 78
Frameworks/vgmstream/vgmstream/src/coding/fadpcm_decoder.c View File

@@ -1,78 +1,78 @@
#include "coding.h"
/* tweaked XA/PSX coefs << 6 */
static const int8_t fadpcm_coefs[8][2] = {
{ 0, 0 },
{ 60, 0 },
{ 122, 60 },
{ 115, 52 },
{ 98, 55 },
/* rest is 0s */
};
/* FMOD's FADPCM, basically XA/PSX ADPCM with a fancy header layout.
* Code/layout could be simplified but tries to emulate FMOD's code.
* Algorithm and tables debugged from their PC DLLs (byte-accurate). */
void decode_fadpcm(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
uint8_t frame[0x8c] = {0};
off_t frame_offset;
int i, j, k, frames_in, sample_count = 0, samples_done = 0;
size_t bytes_per_frame, samples_per_frame;
uint32_t coefs, shifts;
int32_t hist1; //= stream->adpcm_history1_32;
int32_t hist2; //= stream->adpcm_history2_32;
/* external interleave (fixed size), mono */
bytes_per_frame = 0x8c;
samples_per_frame = (bytes_per_frame - 0xc) * 2;
frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame;
/* parse 0xc header (header samples are not written to outbuf) */
frame_offset = stream->offset + bytes_per_frame * frames_in;
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
coefs = get_u32le(frame + 0x00);
shifts = get_u32le(frame + 0x04);
hist1 = get_s16le(frame + 0x08);
hist2 = get_s16le(frame + 0x0a);
/* decode nibbles, grouped in 8 sets of 0x10 * 0x04 * 2 */
for (i = 0; i < 8; i++) {
int index, shift, coef1, coef2;
/* each set has its own coefs/shifts (indexes > 7 are repeat, ex. 0x9 is 0x2) */
index = ((coefs >> i*4) & 0x0f) % 0x07;
shift = (shifts >> i*4) & 0x0f;
coef1 = fadpcm_coefs[index][0];
coef2 = fadpcm_coefs[index][1];
shift = 22 - shift; /* pre-adjust for 32b sign extend */
for (j = 0; j < 4; j++) {
uint32_t nibbles = get_u32le(frame + 0x0c + 0x10*i + 0x04*j);
for (k = 0; k < 8; k++) {
int32_t sample;
sample = (nibbles >> k*4) & 0x0f;
sample = (sample << 28) >> shift; /* 32b sign extend + scale */
sample = (sample - hist2*coef2 + hist1*coef1) >> 6;
sample = clamp16(sample);
if (sample_count >= first_sample && samples_done < samples_to_do) {
outbuf[samples_done * channelspacing] = sample;
samples_done++;
}
sample_count++;
hist2 = hist1;
hist1 = sample;
}
}
}
//stream->adpcm_history1_32 = hist1;
//stream->adpcm_history2_32 = hist2;
}
#include "coding.h"
/* tweaked XA/PSX coefs << 6 */
static const int8_t fadpcm_coefs[8][2] = {
{ 0, 0 },
{ 60, 0 },
{ 122, 60 },
{ 115, 52 },
{ 98, 55 },
/* rest is 0s */
};
/* FMOD's FADPCM, basically XA/PSX ADPCM with a fancy header layout.
* Code/layout could be simplified but tries to emulate FMOD's code.
* Algorithm and tables debugged from their PC DLLs (byte-accurate). */
void decode_fadpcm(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
uint8_t frame[0x8c] = {0};
off_t frame_offset;
int i, j, k, frames_in, sample_count = 0, samples_done = 0;
size_t bytes_per_frame, samples_per_frame;
uint32_t coefs, shifts;
int32_t hist1; //= stream->adpcm_history1_32;
int32_t hist2; //= stream->adpcm_history2_32;
/* external interleave (fixed size), mono */
bytes_per_frame = 0x8c;
samples_per_frame = (bytes_per_frame - 0xc) * 2;
frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame;
/* parse 0xc header (header samples are not written to outbuf) */
frame_offset = stream->offset + bytes_per_frame * frames_in;
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
coefs = get_u32le(frame + 0x00);
shifts = get_u32le(frame + 0x04);
hist1 = get_s16le(frame + 0x08);
hist2 = get_s16le(frame + 0x0a);
/* decode nibbles, grouped in 8 sets of 0x10 * 0x04 * 2 */
for (i = 0; i < 8; i++) {
int index, shift, coef1, coef2;
/* each set has its own coefs/shifts (indexes > 7 are repeat, ex. 0x9 is 0x2) */
index = ((coefs >> i*4) & 0x0f) % 0x07;
shift = (shifts >> i*4) & 0x0f;
coef1 = fadpcm_coefs[index][0];
coef2 = fadpcm_coefs[index][1];
shift = 22 - shift; /* pre-adjust for 32b sign extend */
for (j = 0; j < 4; j++) {
uint32_t nibbles = get_u32le(frame + 0x0c + 0x10*i + 0x04*j);
for (k = 0; k < 8; k++) {
int32_t sample;
sample = (nibbles >> k*4) & 0x0f;
sample = (sample << 28) >> shift; /* 32b sign extend + scale */
sample = (sample - hist2*coef2 + hist1*coef1) >> 6;
sample = clamp16(sample);
if (sample_count >= first_sample && samples_done < samples_to_do) {
outbuf[samples_done * channelspacing] = sample;
samples_done++;
}
sample_count++;
hist2 = hist1;
hist1 = sample;
}
}
}
//stream->adpcm_history1_32 = hist1;
//stream->adpcm_history2_32 = hist2;
}

+ 700
- 700
Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_custom_opus.c
File diff suppressed because it is too large
View File


+ 190
- 190
Frameworks/vgmstream/vgmstream/src/coding/ffmpeg_decoder_utils.c View File

@@ -1,190 +1,190 @@
#include "coding.h"
#ifdef VGM_USE_FFMPEG
static int ffmpeg_make_riff_atrac3(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int joint_stereo, int encoder_delay) {
uint16_t codec_ATRAC3 = 0x0270;
size_t riff_size = 4+4+ 4 + 0x28 + 0x10 + 4+4;
if (buf_size < riff_size)
return -1;
memcpy(buf+0x00, "RIFF", 4);
put_32bitLE(buf+0x04, (int32_t)(riff_size-4-4 + data_size)); /* riff size */
memcpy(buf+0x08, "WAVE", 4);
memcpy(buf+0x0c, "fmt ", 4);
put_32bitLE(buf+0x10, 0x20);/*fmt size*/
put_16bitLE(buf+0x14, codec_ATRAC3);
put_16bitLE(buf+0x16, channels);
put_32bitLE(buf+0x18, sample_rate);
put_32bitLE(buf+0x1c, sample_rate*channels / sizeof(sample)); /* average bytes per second (wrong) */
put_32bitLE(buf+0x20, (int16_t)(block_align)); /* block align */
put_16bitLE(buf+0x24, 0x0e); /* extra data size */
put_16bitLE(buf+0x26, 1); /* unknown, always 1 */
put_16bitLE(buf+0x28, 0x0800 * channels); /* unknown (some size? 0x1000=2ch, 0x0800=1ch) */
put_16bitLE(buf+0x2a, 0); /* unknown, always 0 */
put_16bitLE(buf+0x2c, joint_stereo ? 0x0001 : 0x0000);
put_16bitLE(buf+0x2e, joint_stereo ? 0x0001 : 0x0000); /* repeated? */
put_16bitLE(buf+0x30, 1); /* unknown, always 1 (frame_factor?) */
put_16bitLE(buf+0x32, 0); /* unknown, always 0 */
memcpy(buf+0x34, "fact", 4);
put_32bitLE(buf+0x38, 0x8); /* fact size */
put_32bitLE(buf+0x3c, sample_count);
put_32bitLE(buf+0x40, encoder_delay);
memcpy(buf+0x44, "data", 4);
put_32bitLE(buf+0x48, data_size); /* data size */
return riff_size;
}
ffmpeg_codec_data * init_ffmpeg_atrac3_raw(STREAMFILE *sf, off_t offset, size_t data_size, int sample_count, int channels, int sample_rate, int block_align, int encoder_delay) {
ffmpeg_codec_data *ffmpeg_data = NULL;
uint8_t buf[0x100];
int bytes;
int joint_stereo = (block_align == 0x60*channels) && channels > 1; /* only lowest block size does joint stereo */
int is_at3 = 1; /* could detect using block size */
/* create fake header + init ffmpeg + apply fixes to FFmpeg decoding */
bytes = ffmpeg_make_riff_atrac3(buf,sizeof(buf), sample_count, data_size, channels, sample_rate, block_align, joint_stereo, encoder_delay);
ffmpeg_data = init_ffmpeg_header_offset(sf, buf,bytes, offset,data_size);
if (!ffmpeg_data) goto fail;
/* unlike with RIFF ATRAC3 we don't set implicit delay, as raw ATRAC3 headers often give loop/samples
* in offsets, so calcs are expected to be handled externally (presumably the game would call raw decoding API
* and any skips would be handled manually) */
/* FFmpeg reads this but just in case they fiddle with it in the future */
ffmpeg_data->totalSamples = sample_count;
/* encoder delay: encoder introduces some garbage (not always silent) samples to skip at the beginning (at least 1 frame)
* FFmpeg doesn't set this, and even if it ever does it's probably better to force it for the implicit skip. */
ffmpeg_set_skip_samples(ffmpeg_data, encoder_delay);
/* invert ATRAC3: waveform is inverted vs official tools (not noticeable but for accuracy) */
if (is_at3) {
ffmpeg_data->invert_floats_set = 1;
}
return ffmpeg_data;
fail:
free_ffmpeg(ffmpeg_data);
return NULL;
}
/* init ATRAC3/plus while adding some fixes */
ffmpeg_codec_data * init_ffmpeg_atrac3_riff(STREAMFILE *sf, off_t offset, int* out_samples) {
ffmpeg_codec_data *ffmpeg_data = NULL;
int is_at3 = 0, is_at3p = 0, codec;
size_t riff_size;
int fact_samples, skip_samples, implicit_skip;
off_t fact_offset = 0;
size_t fact_size = 0;
/* some simplified checks just in case */
if (read_32bitBE(offset + 0x00,sf) != 0x52494646) /* "RIFF" */
goto fail;
riff_size = read_32bitLE(offset + 0x04,sf) + 0x08;
codec = (uint16_t)read_16bitLE(offset + 0x14, sf);
switch(codec) {
case 0x0270: is_at3 = 1; break;
case 0xFFFE: is_at3p = 1; break;
default: goto fail;
}
/* init ffmpeg + apply fixes to FFmpeg decoding (with these fixes should be
* sample-accurate vs official tools, except usual +-1 float-to-pcm conversion) */
ffmpeg_data = init_ffmpeg_offset(sf, offset, riff_size);
if (!ffmpeg_data) goto fail;
/* well behaved .at3 define "fact" but official tools accept files without it */
if (find_chunk_le(sf,0x66616374,offset + 0x0c,0, &fact_offset, &fact_size)) { /* "fact" */
if (fact_size == 0x08) { /* early AT3 (mainly PSP games) */
fact_samples = read_32bitLE(fact_offset + 0x00, sf);
skip_samples = read_32bitLE(fact_offset + 0x04, sf); /* base skip samples */
}
else if (fact_size == 0x0c) { /* late AT3 (mainly PS3 games and few PSP games) */
fact_samples = read_32bitLE(fact_offset + 0x00, sf);
/* 0x04: base skip samples, ignored by decoder */
skip_samples = read_32bitLE(fact_offset + 0x08, sf); /* skip samples with implicit skip of 184 added */
}
else {
VGM_LOG("ATRAC3: unknown fact size\n");
goto fail;
}
}
else {
fact_samples = 0; /* tools output 0 samples in this case unless loop end is defined */
if (is_at3)
skip_samples = 1024; /* 1 frame */
else if (is_at3p)
skip_samples = 2048; /* 1 frame */
else
skip_samples = 0;
}
/* implicit skip: official tools skip this even with encoder delay forced to 0. Maybe FFmpeg decodes late,
* but when forcing tools to decode all frame samples it always ends a bit before last frame, so maybe it's
* really an internal skip, since encoder adds extra frames so fact num_samples + encoder delay + implicit skip
* never goes past file. Same for all bitrate/channels, not added to loops. This is probably "decoder delay"
* also seen in codecs like MP3 */
if (is_at3) {
implicit_skip = 69;
}
else if (is_at3p && fact_size == 0x08) {
implicit_skip = 184*2;
}
else if (is_at3p && fact_size == 0x0c) {
implicit_skip = 184; /* first 184 is already added to delay vs field at 0x08 */
}
else if (is_at3p) {
implicit_skip = 184; /* default for unknown sizes */
}
else {
implicit_skip = 0;
}
/* FFmpeg reads this but just in case they fiddle with it in the future */
ffmpeg_data->totalSamples = fact_samples;
/* encoder delay: encoder introduces some garbage (not always silent) samples to skip at the beginning (at least 1 frame)
* FFmpeg doesn't set this, and even if it ever does it's probably better to force it for the implicit skip. */
ffmpeg_set_skip_samples(ffmpeg_data, skip_samples + implicit_skip);
/* invert ATRAC3: waveform is inverted vs official tools (not noticeable but for accuracy) */
if (is_at3) {
ffmpeg_data->invert_floats_set = 1;
}
/* multichannel fix: LFE channel should be reordered on decode (ATRAC3Plus only, only 1/2/6/8ch exist):
* - 6ch: FL FR FC BL BR LFE > FL FR FC LFE BL BR
* - 8ch: FL FR FC BL BR SL SR LFE > FL FR FC LFE BL BR SL SR */
if (is_at3p && ffmpeg_data->channels == 6) {
/* LFE BR BL > LFE BL BR > same */
int channel_remap[] = { 0, 1, 2, 5, 5, 5, };
ffmpeg_set_channel_remapping(ffmpeg_data, channel_remap);
}
else if (is_at3p && ffmpeg_data->channels == 8) {
/* LFE BR SL SR BL > LFE BL SL SR BR > LFE BL BR SR SL > LFE BL BR SL SR > same */
int channel_remap[] = { 0, 1, 2, 7, 7, 7, 7, 7};
ffmpeg_set_channel_remapping(ffmpeg_data, channel_remap);
}
if (out_samples)
*out_samples = fact_samples;
return ffmpeg_data;
fail:
free_ffmpeg(ffmpeg_data);
return NULL;
}
#endif
#include "coding.h"
#ifdef VGM_USE_FFMPEG
static int ffmpeg_make_riff_atrac3(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int joint_stereo, int encoder_delay) {
uint16_t codec_ATRAC3 = 0x0270;
size_t riff_size = 4+4+ 4 + 0x28 + 0x10 + 4+4;
if (buf_size < riff_size)
return -1;
memcpy(buf+0x00, "RIFF", 4);
put_32bitLE(buf+0x04, (int32_t)(riff_size-4-4 + data_size)); /* riff size */
memcpy(buf+0x08, "WAVE", 4);
memcpy(buf+0x0c, "fmt ", 4);
put_32bitLE(buf+0x10, 0x20);/*fmt size*/
put_16bitLE(buf+0x14, codec_ATRAC3);
put_16bitLE(buf+0x16, channels);
put_32bitLE(buf+0x18, sample_rate);
put_32bitLE(buf+0x1c, sample_rate*channels / sizeof(sample)); /* average bytes per second (wrong) */
put_32bitLE(buf+0x20, (int16_t)(block_align)); /* block align */
put_16bitLE(buf+0x24, 0x0e); /* extra data size */
put_16bitLE(buf+0x26, 1); /* unknown, always 1 */
put_16bitLE(buf+0x28, 0x0800 * channels); /* unknown (some size? 0x1000=2ch, 0x0800=1ch) */
put_16bitLE(buf+0x2a, 0); /* unknown, always 0 */
put_16bitLE(buf+0x2c, joint_stereo ? 0x0001 : 0x0000);
put_16bitLE(buf+0x2e, joint_stereo ? 0x0001 : 0x0000); /* repeated? */
put_16bitLE(buf+0x30, 1); /* unknown, always 1 (frame_factor?) */
put_16bitLE(buf+0x32, 0); /* unknown, always 0 */
memcpy(buf+0x34, "fact", 4);
put_32bitLE(buf+0x38, 0x8); /* fact size */
put_32bitLE(buf+0x3c, sample_count);
put_32bitLE(buf+0x40, encoder_delay);
memcpy(buf+0x44, "data", 4);
put_32bitLE(buf+0x48, data_size); /* data size */
return riff_size;
}
ffmpeg_codec_data * init_ffmpeg_atrac3_raw(STREAMFILE *sf, off_t offset, size_t data_size, int sample_count, int channels, int sample_rate, int block_align, int encoder_delay) {
ffmpeg_codec_data *ffmpeg_data = NULL;
uint8_t buf[0x100];
int bytes;
int joint_stereo = (block_align == 0x60*channels) && channels > 1; /* only lowest block size does joint stereo */
int is_at3 = 1; /* could detect using block size */
/* create fake header + init ffmpeg + apply fixes to FFmpeg decoding */
bytes = ffmpeg_make_riff_atrac3(buf,sizeof(buf), sample_count, data_size, channels, sample_rate, block_align, joint_stereo, encoder_delay);
ffmpeg_data = init_ffmpeg_header_offset(sf, buf,bytes, offset,data_size);
if (!ffmpeg_data) goto fail;
/* unlike with RIFF ATRAC3 we don't set implicit delay, as raw ATRAC3 headers often give loop/samples
* in offsets, so calcs are expected to be handled externally (presumably the game would call raw decoding API
* and any skips would be handled manually) */
/* FFmpeg reads this but just in case they fiddle with it in the future */
ffmpeg_data->totalSamples = sample_count;
/* encoder delay: encoder introduces some garbage (not always silent) samples to skip at the beginning (at least 1 frame)
* FFmpeg doesn't set this, and even if it ever does it's probably better to force it for the implicit skip. */
ffmpeg_set_skip_samples(ffmpeg_data, encoder_delay);
/* invert ATRAC3: waveform is inverted vs official tools (not noticeable but for accuracy) */
if (is_at3) {
ffmpeg_data->invert_floats_set = 1;
}
return ffmpeg_data;
fail:
free_ffmpeg(ffmpeg_data);
return NULL;
}
/* init ATRAC3/plus while adding some fixes */
ffmpeg_codec_data * init_ffmpeg_atrac3_riff(STREAMFILE *sf, off_t offset, int* out_samples) {
ffmpeg_codec_data *ffmpeg_data = NULL;
int is_at3 = 0, is_at3p = 0, codec;
size_t riff_size;
int fact_samples, skip_samples, implicit_skip;
off_t fact_offset = 0;
size_t fact_size = 0;
/* some simplified checks just in case */
if (read_32bitBE(offset + 0x00,sf) != 0x52494646) /* "RIFF" */
goto fail;
riff_size = read_32bitLE(offset + 0x04,sf) + 0x08;
codec = (uint16_t)read_16bitLE(offset + 0x14, sf);
switch(codec) {
case 0x0270: is_at3 = 1; break;
case 0xFFFE: is_at3p = 1; break;
default: goto fail;
}
/* init ffmpeg + apply fixes to FFmpeg decoding (with these fixes should be
* sample-accurate vs official tools, except usual +-1 float-to-pcm conversion) */
ffmpeg_data = init_ffmpeg_offset(sf, offset, riff_size);
if (!ffmpeg_data) goto fail;
/* well behaved .at3 define "fact" but official tools accept files without it */
if (find_chunk_le(sf,0x66616374,offset + 0x0c,0, &fact_offset, &fact_size)) { /* "fact" */
if (fact_size == 0x08) { /* early AT3 (mainly PSP games) */
fact_samples = read_32bitLE(fact_offset + 0x00, sf);
skip_samples = read_32bitLE(fact_offset + 0x04, sf); /* base skip samples */
}
else if (fact_size == 0x0c) { /* late AT3 (mainly PS3 games and few PSP games) */
fact_samples = read_32bitLE(fact_offset + 0x00, sf);
/* 0x04: base skip samples, ignored by decoder */
skip_samples = read_32bitLE(fact_offset + 0x08, sf); /* skip samples with implicit skip of 184 added */
}
else {
VGM_LOG("ATRAC3: unknown fact size\n");
goto fail;
}
}
else {
fact_samples = 0; /* tools output 0 samples in this case unless loop end is defined */
if (is_at3)
skip_samples = 1024; /* 1 frame */
else if (is_at3p)
skip_samples = 2048; /* 1 frame */
else
skip_samples = 0;
}
/* implicit skip: official tools skip this even with encoder delay forced to 0. Maybe FFmpeg decodes late,
* but when forcing tools to decode all frame samples it always ends a bit before last frame, so maybe it's
* really an internal skip, since encoder adds extra frames so fact num_samples + encoder delay + implicit skip
* never goes past file. Same for all bitrate/channels, not added to loops. This is probably "decoder delay"
* also seen in codecs like MP3 */
if (is_at3) {
implicit_skip = 69;
}
else if (is_at3p && fact_size == 0x08) {
implicit_skip = 184*2;
}
else if (is_at3p && fact_size == 0x0c) {
implicit_skip = 184; /* first 184 is already added to delay vs field at 0x08 */
}
else if (is_at3p) {
implicit_skip = 184; /* default for unknown sizes */
}
else {
implicit_skip = 0;
}
/* FFmpeg reads this but just in case they fiddle with it in the future */
ffmpeg_data->totalSamples = fact_samples;
/* encoder delay: encoder introduces some garbage (not always silent) samples to skip at the beginning (at least 1 frame)
* FFmpeg doesn't set this, and even if it ever does it's probably better to force it for the implicit skip. */
ffmpeg_set_skip_samples(ffmpeg_data, skip_samples + implicit_skip);
/* invert ATRAC3: waveform is inverted vs official tools (not noticeable but for accuracy) */
if (is_at3) {
ffmpeg_data->invert_floats_set = 1;
}
/* multichannel fix: LFE channel should be reordered on decode (ATRAC3Plus only, only 1/2/6/8ch exist):
* - 6ch: FL FR FC BL BR LFE > FL FR FC LFE BL BR
* - 8ch: FL FR FC BL BR SL SR LFE > FL FR FC LFE BL BR SL SR */
if (is_at3p && ffmpeg_data->channels == 6) {
/* LFE BR BL > LFE BL BR > same */
int channel_remap[] = { 0, 1, 2, 5, 5, 5, };
ffmpeg_set_channel_remapping(ffmpeg_data, channel_remap);
}
else if (is_at3p && ffmpeg_data->channels == 8) {
/* LFE BR SL SR BL > LFE BL SL SR BR > LFE BL BR SR SL > LFE BL BR SL SR > same */
int channel_remap[] = { 0, 1, 2, 7, 7, 7, 7, 7};
ffmpeg_set_channel_remapping(ffmpeg_data, channel_remap);
}
if (out_samples)
*out_samples = fact_samples;
return ffmpeg_data;
fail:
free_ffmpeg(ffmpeg_data);
return NULL;
}
#endif

+ 422
- 422
Frameworks/vgmstream/vgmstream/src/coding/mpeg_custom_utils.c View File

@@ -1,422 +1,422 @@
#include "mpeg_decoder.h"
#ifdef VGM_USE_MPEG
/* init config and validate per type */
int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type) {
mpeg_frame_info info;
/* get frame info at offset */
if ( !mpeg_get_frame_info(streamFile, start_offset, &info))
goto fail;
switch(info.layer) {
case 1: *coding_type = coding_MPEG_layer1; break;
case 2: *coding_type = coding_MPEG_layer2; break;
case 3: *coding_type = coding_MPEG_layer3; break;
default: goto fail;
}
data->channels_per_frame = info.channels;
data->samples_per_frame = info.frame_samples;
data->bitrate_per_frame = info.bit_rate;
data->sample_rate_per_frame = info.sample_rate;
/* extra checks per type */
switch(data->type) {
case MPEG_XVAG:
if (data->config.chunk_size <= 0 || data->config.interleave <= 0)
goto fail; /* needs external fixed size */
break;
case MPEG_FSB:
if (data->config.fsb_padding != 0
&& data->config.fsb_padding != 2
&& data->config.fsb_padding != 4
&& data->config.fsb_padding != 16)
goto fail; /* aligned to closest 0/2/4/16 bytes */
/* get find interleave to stream offsets are set up externally */
{
int current_data_size = info.frame_size;
int current_padding = 0;
/* FSB padding for Layer III or multichannel Layer II */
if ((info.layer == 3 && data->config.fsb_padding) || data->config.fsb_padding == 16) {
current_padding = (current_data_size % data->config.fsb_padding)
? data->config.fsb_padding - (current_data_size % data->config.fsb_padding)
: 0;
}
data->config.interleave = current_data_size + current_padding; /* should be constant for all stream */
}
break;
case MPEG_P3D:
case MPEG_SCD:
if (data->config.interleave <= 0)
goto fail; /* needs external fixed size */
break;
case MPEG_LYN:
if (data->config.interleave <= 0)
goto fail; /* needs external fixed size */
data->default_buffer_size = data->config.interleave;
//todo simplify/unify XVAG/P3D/SCD/LYN and just feed arbitrary chunks to the decoder
break;
case MPEG_STANDARD:
case MPEG_AHX:
case MPEG_EA:
if (info.channels != data->config.channels)
goto fail; /* no multichannel expected */
break;
default:
break; /* nothing special needed */
}
//todo: test more: this improves the output, but seems formats aren't usually prepared
// (and/or the num_samples includes all possible samples in file, so by discarding some it'll reach EOF)
/* set encoder delay (samples to skip at the beginning of a stream) if needed, which varies with encoder used */
switch(data->type) {
//case MPEG_AHX: data->skip_samples = 480; break; /* observed default */
//case MPEG_P3D: data->skip_samples = info.frame_samples; break; /* matches Radical ADPCM (PC) output */
/* FSBs (with FMOD DLLs) don't seem to need it. Particularly a few games (all from Wayforward?)
* contain audible garbage at the beginning, but it's actually there in-game too */
//case MPEG_FSB: data->skip_samples = 0; break;
case MPEG_XVAG: /* set in header and needed for gapless looping */
data->skip_samples = data->config.skip_samples; break;
case MPEG_STANDARD:
data->skip_samples = data->config.skip_samples; break;
case MPEG_EA:
/* typical MP2 decoder delay, verified vs sx.exe, also SCHl blocks header takes discard
* samples into account (so block_samples+240*2+1 = total frame samples) */
if (info.layer == 2) {
data->skip_samples = 240*2 + 1;
}
/* MP3 probably uses 576 + 528+1 but no known games use it */
break;
default:
break;
}
data->samples_to_discard = data->skip_samples;
return 1;
fail:
return 0;
}
/* writes data to the buffer and moves offsets */
int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream) {
mpeg_custom_stream *ms = data->streams[num_stream];
mpeg_frame_info info;
size_t current_data_size = 0;
size_t current_padding = 0;
size_t current_interleave_pre = 0; /* interleaved data size before current stream */
size_t current_interleave_post = 0; /* interleaved data size after current stream */
size_t current_interleave = 0; /* interleave in this block (usually this + pre + post = interleave*streams = block) */
/* Get data size to give to the decoder, per stream. Usually 1 frame at a time,
* but doesn't really need to be a full frame (decoder would request more data). */
switch(data->type) {
case MPEG_XVAG: /* frames of fixed size (though we could read frame info too) */
current_interleave = data->config.interleave; /* big interleave */
current_interleave_pre = current_interleave*num_stream;
current_interleave_post = current_interleave*(data->streams_size-1) - current_interleave_pre;
current_data_size = data->config.chunk_size;
break;
case MPEG_FSB: /* frames with padding + interleave */
current_interleave = data->config.interleave; /* constant for multi-stream FSbs (1 frame + padding) */
current_interleave_pre = current_interleave*num_stream;
current_interleave_post = current_interleave*(data->streams_size-1) - current_interleave_pre;
if (!mpeg_get_frame_info(stream->streamfile, stream->offset + current_interleave_pre, &info))
goto fail;
current_data_size = info.frame_size;
/* get FSB padding for Layer III or multichannel Layer II (Layer I isn't supported by FMOD).
* Padding sometimes contains garbage like the next frame header so we can't feed it to mpg123 or it gets confused. */
if ((info.layer == 3 && data->config.fsb_padding) || data->config.fsb_padding == 16) {
current_padding = (current_data_size % data->config.fsb_padding)
? data->config.fsb_padding - (current_data_size % data->config.fsb_padding)
: 0;
/* Rare Mafia II (PS3) bug (GP_0701_music multilang only): some frame paddings "4" are incorrect,
* calcs give 0xD0+0x00 but need 0xD0+0x04 (unlike all other fsbs, which never do that).
* FMOD tools decode fine, so they may be doing special detection too, since even
* re-encoding the same file and using the same FSB flags/modes won't trigger the bug. */
if (info.layer == 3 && data->config.fsb_padding == 4 && current_data_size == 0xD0) {
uint32_t next_header;
off_t next_offset;
next_offset = stream->offset + current_data_size + current_padding;
if (current_interleave && ((next_offset - stream->channel_start_offset + current_interleave_pre + current_interleave_post) % current_interleave == 0)) {
next_offset += current_interleave_pre + current_interleave_post;
}
next_header = read_32bitBE(next_offset, stream->streamfile);
if ((next_header & 0xFFE00000) != 0xFFE00000) { /* doesn't land in a proper frame, fix sizes and hope */
VGM_LOG_ONCE("MPEG FSB: stream with wrong padding found\n");
current_padding = 0x04;
}
}
}
VGM_ASSERT(data->streams_size > 1 && current_interleave != current_data_size+current_padding,
"MPEG FSB: %i streams with non-constant interleave found @ 0x%08x\n", data->streams_size, (uint32_t)stream->offset);
break;
case MPEG_P3D: /* fixed interleave, not frame-aligned (ie. blocks may end/start in part of a frame) */
case MPEG_SCD:
case MPEG_LYN:
current_interleave = data->config.interleave;
/* check if current interleave block is short */
{
off_t block_offset = stream->offset - stream->channel_start_offset;
size_t next_block = data->streams_size*data->config.interleave;
if (data->config.data_size && block_offset + next_block >= data->config.data_size)
current_interleave = (data->config.data_size % next_block) / data->streams_size; /* short_interleave*/
}
current_interleave_pre = current_interleave*num_stream;
current_interleave_post = current_interleave*(data->streams_size-1) - current_interleave_pre;
current_data_size = current_interleave;
break;
default: /* standard frames (CBR or VBR) */
if ( !mpeg_get_frame_info(stream->streamfile, stream->offset, &info) )
goto fail;
current_data_size = info.frame_size;
break;
}
if (!current_data_size || current_data_size > ms->buffer_size) {
VGM_LOG("MPEG: incorrect data_size 0x%x vs buffer 0x%x\n", current_data_size, ms->buffer_size);
goto fail;
}
/* This assumes all streams' offsets start in the first stream, and advances
* the 'full interleaved block' at once, ex:
* start at s0=0x00, s1=0x00, interleave=0x40 (block = 0x40*2=0x80)
* @0x00 read 0x40 of s0, skip 0x40 of s1 (block of 0x80 done) > new offset = 0x80
* @0x00 skip 0x40 of s0, read 0x40 of s1 (block of 0x80 done) > new offset = 0x800
*/
/* read chunk (skipping other interleaves if needed) */
ms->bytes_in_buffer = read_streamfile(ms->buffer,stream->offset + current_interleave_pre, current_data_size, stream->streamfile);
/* update offsets and skip other streams */
stream->offset += current_data_size + current_padding;
/* skip rest of block (interleave per stream) once this stream's interleaved data is done, if defined */
if (current_interleave && ((stream->offset - stream->channel_start_offset + current_interleave_pre + current_interleave_post) % current_interleave == 0)) {
stream->offset += current_interleave_pre + current_interleave_post;
}
return 1;
fail:
return 0;
}
/*****************/
/* FRAME HELPERS */
/*****************/
/**
* Gets info from a MPEG frame header at offset. Normally you would use mpg123_info but somehow
* it's wrong at times (maybe because we use an ancient version) so here we do our thing.
*/
static int mpeg_get_frame_info_h(uint32_t header, mpeg_frame_info *info) {
/* index tables */
static const int versions[4] = { /* MPEG 2.5 */ 3, /* reserved */ -1, /* MPEG 2 */ 2, /* MPEG 1 */ 1 };
static const int layers[4] = { -1,3,2,1 };
static const int bit_rates[5][16] = { /* [version index ][bit rate index] (0=free, -1=bad) */
{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1 }, /* MPEG1 Layer I */
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1 }, /* MPEG1 Layer II */
{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 }, /* MPEG1 Layer III */
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 }, /* MPEG2/2.5 Layer I */
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 }, /* MPEG2/2.5 Layer II/III */
};
static const int sample_rates[4][4] = { /* [version][sample rate index] */
{ 44100, 48000, 32000, -1}, /* MPEG1 */
{ 22050, 24000, 16000, -1}, /* MPEG2 */
{ 11025, 12000, 8000, -1}, /* MPEG2.5 */
};
static const int channels[4] = { 2,2,2, 1 }; /* [channel] */
static const int frame_samples[3][3] = { /* [version][layer] */
{ 384, 1152, 1152 }, /* MPEG1 */
{ 384, 1152, 576 }, /* MPEG2 */
{ 384, 1152, 576 } /* MPEG2.5 */
};
int idx, padding;
memset(info, 0, sizeof(*info));
if ((header >> 21) != 0x7FF) /* 31-21: sync */
goto fail;
info->version = versions[(header >> 19) & 0x3]; /* 20,19: version */
if (info->version <= 0) goto fail;
info->layer = layers[(header >> 17) & 0x3]; /* 18,17: layer */
if (info->layer <= 0 || info->layer > 3) goto fail;
//crc = (header >> 16) & 0x1; /* 16: protected by crc? */
idx = (info->version==1 ? info->layer-1 : (3 + (info->layer==1 ? 0 : 1)));
info->bit_rate = bit_rates[idx][(header >> 12) & 0xf]; /* 15-12: bit rate */
if (info->bit_rate <= 0) goto fail;
info->sample_rate = sample_rates[info->version-1][(header >> 10) & 0x3]; /* 11-10: sampling rate */
if (info->sample_rate <= 0) goto fail;
padding = (header >> 9) & 0x1; /* 9: padding? */
//private = (header >> 8) & 0x1; /* 8: private bit */
info->channels = channels[(header >> 6) & 0x3]; /* 7,6: channel mode */
//js_mode = (header >> 4) & 0x3; /* 5,4: mode extension for joint stereo */
//copyright = (header >> 3) & 0x1; /* 3: copyrighted */
//original = (header >> 2) & 0x1; /* 2: original */
//emphasis = (header >> 0) & 0x3; /* 1,0: emphasis */
info->frame_samples = frame_samples[info->version-1][info->layer-1];
/* calculate frame length (from hcs's fsb_mpeg) */
switch (info->frame_samples) {
case 384: info->frame_size = (12l * info->bit_rate * 1000l / info->sample_rate + padding) * 4; break; /* 384/32 = 12 */
case 576: info->frame_size = (72l * info->bit_rate * 1000l / info->sample_rate + padding); break; /* 576/8 = 72 */
case 1152: info->frame_size = (144l * info->bit_rate * 1000l / info->sample_rate + padding); break; /* 1152/8 = 144 */
default: goto fail;
}
return 1;
fail:
return 0;
}
int mpeg_get_frame_info(STREAMFILE *sf, off_t offset, mpeg_frame_info *info) {
uint32_t header = read_u32be(offset, sf);
return mpeg_get_frame_info_h(header, info);
}
size_t mpeg_get_samples(STREAMFILE *sf, off_t start_offset, size_t bytes) {
off_t offset = start_offset;
off_t max_offset = start_offset + bytes;
int frames = 0, samples = 0, encoder_delay = 0, encoder_padding = 0;
mpeg_frame_info info;
if (!sf)
return 0;
if (max_offset > get_streamfile_size(sf))
max_offset = get_streamfile_size(sf);
/* MPEG may use VBR so must read all frames */
while (offset < max_offset) {
uint32_t header = read_u32be(offset+0x00, sf);
/* skip ID3v2 */
if ((header & 0xFFFFFF00) == 0x49443300) { /* "ID3\0" */
size_t frame_size = 0;
uint8_t flags = read_u8(offset+0x05, sf);
/* this is how it's officially read :/ */
frame_size += read_u8(offset+0x06, sf) << 21;
frame_size += read_u8(offset+0x07, sf) << 14;
frame_size += read_u8(offset+0x08, sf) << 7;
frame_size += read_u8(offset+0x09, sf) << 0;
frame_size += 0x0a;
if (flags & 0x10) /* footer? */
frame_size += 0x0a;
offset += frame_size;
continue;
}
/* skip ID3v1 */
if ((header & 0xFFFFFF00) == 0x54414700) { /* "TAG\0" */
;VGM_LOG("MPEG: ID3v1 at %lx\n", offset);
offset += 0x80;
continue;
}
/* regular frame */
if (!mpeg_get_frame_info_h(header, &info)) {
VGM_LOG("MPEG: unknown frame at %lx\n", offset);
break;
}
/* detect Xing header (disguised as a normal frame) */
if (frames < 3 && /* should be first after tags */
info.frame_size >= 0x24 + 0x78 &&
read_u32be(offset + 0x04, sf) == 0 &&
(read_u32be(offset + 0x24, sf) == 0x58696E67 || /* "Xing" (mainly for VBR) */
read_u32be(offset + 0x24, sf) == 0x496E666F)) { /* "Info" (mainly for CBR) */
uint32_t flags = read_u32be(offset + 0x28, sf);
if (flags & 1) { /* other flags indicate seek table and stuff */
uint32_t frame_count = read_u32be(offset + 0x2c, sf);
samples = frame_count * info.frame_samples;
}
/* vendor specific */
if (info.frame_size > 0x24 + 0x78 + 0x24 &&
read_u32be(offset + 0x9c, sf) == 0x4C414D45) { /* "LAME" */
if (info.layer == 3) {
uint32_t delays = read_u32be(offset + 0xb0, sf);
encoder_delay = ((delays >> 12) & 0xFFF);
encoder_padding = ((delays >> 0) & 0xFFF);
encoder_delay += (528 + 1); /* implicit MDCT decoder delay (seen in LAME source) */
if (encoder_padding > 528 + 1)
encoder_padding -= (528 + 1);
}
else {
encoder_delay = 240 + 1;
}
/* replay gain and stuff */
}
/* there is also "iTunes" vendor with no apparent extra info, iTunes delays are in "iTunSMPB" ID3 tag */
;VGM_LOG("MPEG: found Xing header\n");
break; /* we got samples */
}
//TODO: detect "VBRI" header (Fraunhofer encoder)
// https://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header#VBRIHeader
/* could detect VBR/CBR but read frames to remove ID3 end tags */
frames++;
offset += info.frame_size;
samples += info.frame_samples;
}
;VGM_LOG("MPEG: samples=%i, ed=%i, ep=%i, end=%i\n", samples,encoder_delay,encoder_padding, samples - encoder_delay - encoder_padding);
//todo return encoder delay
samples = samples - encoder_delay - encoder_padding;
return samples;
}
#endif
#include "mpeg_decoder.h"
#ifdef VGM_USE_MPEG
/* init config and validate per type */
int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type) {
mpeg_frame_info info;
/* get frame info at offset */
if ( !mpeg_get_frame_info(streamFile, start_offset, &info))
goto fail;
switch(info.layer) {
case 1: *coding_type = coding_MPEG_layer1; break;
case 2: *coding_type = coding_MPEG_layer2; break;
case 3: *coding_type = coding_MPEG_layer3; break;
default: goto fail;
}
data->channels_per_frame = info.channels;
data->samples_per_frame = info.frame_samples;
data->bitrate_per_frame = info.bit_rate;
data->sample_rate_per_frame = info.sample_rate;
/* extra checks per type */
switch(data->type) {
case MPEG_XVAG:
if (data->config.chunk_size <= 0 || data->config.interleave <= 0)
goto fail; /* needs external fixed size */
break;
case MPEG_FSB:
if (data->config.fsb_padding != 0
&& data->config.fsb_padding != 2
&& data->config.fsb_padding != 4
&& data->config.fsb_padding != 16)
goto fail; /* aligned to closest 0/2/4/16 bytes */
/* get find interleave to stream offsets are set up externally */
{
int current_data_size = info.frame_size;
int current_padding = 0;
/* FSB padding for Layer III or multichannel Layer II */
if ((info.layer == 3 && data->config.fsb_padding) || data->config.fsb_padding == 16) {
current_padding = (current_data_size % data->config.fsb_padding)
? data->config.fsb_padding - (current_data_size % data->config.fsb_padding)
: 0;
}
data->config.interleave = current_data_size + current_padding; /* should be constant for all stream */
}
break;
case MPEG_P3D:
case MPEG_SCD:
if (data->config.interleave <= 0)
goto fail; /* needs external fixed size */
break;
case MPEG_LYN:
if (data->config.interleave <= 0)
goto fail; /* needs external fixed size */
data->default_buffer_size = data->config.interleave;
//todo simplify/unify XVAG/P3D/SCD/LYN and just feed arbitrary chunks to the decoder
break;
case MPEG_STANDARD:
case MPEG_AHX:
case MPEG_EA:
if (info.channels != data->config.channels)
goto fail; /* no multichannel expected */
break;
default:
break; /* nothing special needed */
}
//todo: test more: this improves the output, but seems formats aren't usually prepared
// (and/or the num_samples includes all possible samples in file, so by discarding some it'll reach EOF)
/* set encoder delay (samples to skip at the beginning of a stream) if needed, which varies with encoder used */
switch(data->type) {
//case MPEG_AHX: data->skip_samples = 480; break; /* observed default */
//case MPEG_P3D: data->skip_samples = info.frame_samples; break; /* matches Radical ADPCM (PC) output */
/* FSBs (with FMOD DLLs) don't seem to need it. Particularly a few games (all from Wayforward?)
* contain audible garbage at the beginning, but it's actually there in-game too */
//case MPEG_FSB: data->skip_samples = 0; break;
case MPEG_XVAG: /* set in header and needed for gapless looping */
data->skip_samples = data->config.skip_samples; break;
case MPEG_STANDARD:
data->skip_samples = data->config.skip_samples; break;
case MPEG_EA:
/* typical MP2 decoder delay, verified vs sx.exe, also SCHl blocks header takes discard
* samples into account (so block_samples+240*2+1 = total frame samples) */
if (info.layer == 2) {
data->skip_samples = 240*2 + 1;
}
/* MP3 probably uses 576 + 528+1 but no known games use it */
break;
default:
break;
}
data->samples_to_discard = data->skip_samples;
return 1;
fail:
return 0;
}
/* writes data to the buffer and moves offsets */
int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream) {
mpeg_custom_stream *ms = data->streams[num_stream];
mpeg_frame_info info;
size_t current_data_size = 0;
size_t current_padding = 0;
size_t current_interleave_pre = 0; /* interleaved data size before current stream */
size_t current_interleave_post = 0; /* interleaved data size after current stream */
size_t current_interleave = 0; /* interleave in this block (usually this + pre + post = interleave*streams = block) */
/* Get data size to give to the decoder, per stream. Usually 1 frame at a time,
* but doesn't really need to be a full frame (decoder would request more data). */
switch(data->type) {
case MPEG_XVAG: /* frames of fixed size (though we could read frame info too) */
current_interleave = data->config.interleave; /* big interleave */
current_interleave_pre = current_interleave*num_stream;
current_interleave_post = current_interleave*(data->streams_size-1) - current_interleave_pre;
current_data_size = data->config.chunk_size;
break;
case MPEG_FSB: /* frames with padding + interleave */
current_interleave = data->config.interleave; /* constant for multi-stream FSbs (1 frame + padding) */
current_interleave_pre = current_interleave*num_stream;
current_interleave_post = current_interleave*(data->streams_size-1) - current_interleave_pre;
if (!mpeg_get_frame_info(stream->streamfile, stream->offset + current_interleave_pre, &info))
goto fail;
current_data_size = info.frame_size;
/* get FSB padding for Layer III or multichannel Layer II (Layer I isn't supported by FMOD).
* Padding sometimes contains garbage like the next frame header so we can't feed it to mpg123 or it gets confused. */
if ((info.layer == 3 && data->config.fsb_padding) || data->config.fsb_padding == 16) {
current_padding = (current_data_size % data->config.fsb_padding)
? data->config.fsb_padding - (current_data_size % data->config.fsb_padding)
: 0;
/* Rare Mafia II (PS3) bug (GP_0701_music multilang only): some frame paddings "4" are incorrect,
* calcs give 0xD0+0x00 but need 0xD0+0x04 (unlike all other fsbs, which never do that).
* FMOD tools decode fine, so they may be doing special detection too, since even
* re-encoding the same file and using the same FSB flags/modes won't trigger the bug. */
if (info.layer == 3 && data->config.fsb_padding == 4 && current_data_size == 0xD0) {
uint32_t next_header;
off_t next_offset;
next_offset = stream->offset + current_data_size + current_padding;
if (current_interleave && ((next_offset - stream->channel_start_offset + current_interleave_pre + current_interleave_post) % current_interleave == 0)) {
next_offset += current_interleave_pre + current_interleave_post;
}
next_header = read_32bitBE(next_offset, stream->streamfile);
if ((next_header & 0xFFE00000) != 0xFFE00000) { /* doesn't land in a proper frame, fix sizes and hope */
VGM_LOG_ONCE("MPEG FSB: stream with wrong padding found\n");
current_padding = 0x04;
}
}
}
VGM_ASSERT(data->streams_size > 1 && current_interleave != current_data_size+current_padding,
"MPEG FSB: %i streams with non-constant interleave found @ 0x%08x\n", data->streams_size, (uint32_t)stream->offset);
break;
case MPEG_P3D: /* fixed interleave, not frame-aligned (ie. blocks may end/start in part of a frame) */
case MPEG_SCD:
case MPEG_LYN:
current_interleave = data->config.interleave;
/* check if current interleave block is short */
{
off_t block_offset = stream->offset - stream->channel_start_offset;
size_t next_block = data->streams_size*data->config.interleave;
if (data->config.data_size && block_offset + next_block >= data->config.data_size)
current_interleave = (data->config.data_size % next_block) / data->streams_size; /* short_interleave*/
}
current_interleave_pre = current_interleave*num_stream;
current_interleave_post = current_interleave*(data->streams_size-1) - current_interleave_pre;
current_data_size = current_interleave;
break;
default: /* standard frames (CBR or VBR) */
if ( !mpeg_get_frame_info(stream->streamfile, stream->offset, &info) )
goto fail;
current_data_size = info.frame_size;
break;
}
if (!current_data_size || current_data_size > ms->buffer_size) {
VGM_LOG("MPEG: incorrect data_size 0x%x vs buffer 0x%x\n", current_data_size, ms->buffer_size);
goto fail;
}
/* This assumes all streams' offsets start in the first stream, and advances
* the 'full interleaved block' at once, ex:
* start at s0=0x00, s1=0x00, interleave=0x40 (block = 0x40*2=0x80)
* @0x00 read 0x40 of s0, skip 0x40 of s1 (block of 0x80 done) > new offset = 0x80
* @0x00 skip 0x40 of s0, read 0x40 of s1 (block of 0x80 done) > new offset = 0x800
*/
/* read chunk (skipping other interleaves if needed) */
ms->bytes_in_buffer = read_streamfile(ms->buffer,stream->offset + current_interleave_pre, current_data_size, stream->streamfile);
/* update offsets and skip other streams */
stream->offset += current_data_size + current_padding;
/* skip rest of block (interleave per stream) once this stream's interleaved data is done, if defined */
if (current_interleave && ((stream->offset - stream->channel_start_offset + current_interleave_pre + current_interleave_post) % current_interleave == 0)) {
stream->offset += current_interleave_pre + current_interleave_post;
}
return 1;
fail:
return 0;
}
/*****************/
/* FRAME HELPERS */
/*****************/
/**
* Gets info from a MPEG frame header at offset. Normally you would use mpg123_info but somehow
* it's wrong at times (maybe because we use an ancient version) so here we do our thing.
*/
static int mpeg_get_frame_info_h(uint32_t header, mpeg_frame_info *info) {
/* index tables */
static const int versions[4] = { /* MPEG 2.5 */ 3, /* reserved */ -1, /* MPEG 2 */ 2, /* MPEG 1 */ 1 };
static const int layers[4] = { -1,3,2,1 };
static const int bit_rates[5][16] = { /* [version index ][bit rate index] (0=free, -1=bad) */
{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1 }, /* MPEG1 Layer I */
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1 }, /* MPEG1 Layer II */
{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 }, /* MPEG1 Layer III */
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 }, /* MPEG2/2.5 Layer I */
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 }, /* MPEG2/2.5 Layer II/III */
};
static const int sample_rates[4][4] = { /* [version][sample rate index] */
{ 44100, 48000, 32000, -1}, /* MPEG1 */
{ 22050, 24000, 16000, -1}, /* MPEG2 */
{ 11025, 12000, 8000, -1}, /* MPEG2.5 */
};
static const int channels[4] = { 2,2,2, 1 }; /* [channel] */
static const int frame_samples[3][3] = { /* [version][layer] */
{ 384, 1152, 1152 }, /* MPEG1 */
{ 384, 1152, 576 }, /* MPEG2 */
{ 384, 1152, 576 } /* MPEG2.5 */
};
int idx, padding;
memset(info, 0, sizeof(*info));
if ((header >> 21) != 0x7FF) /* 31-21: sync */
goto fail;
info->version = versions[(header >> 19) & 0x3]; /* 20,19: version */
if (info->version <= 0) goto fail;
info->layer = layers[(header >> 17) & 0x3]; /* 18,17: layer */
if (info->layer <= 0 || info->layer > 3) goto fail;
//crc = (header >> 16) & 0x1; /* 16: protected by crc? */
idx = (info->version==1 ? info->layer-1 : (3 + (info->layer==1 ? 0 : 1)));
info->bit_rate = bit_rates[idx][(header >> 12) & 0xf]; /* 15-12: bit rate */
if (info->bit_rate <= 0) goto fail;
info->sample_rate = sample_rates[info->version-1][(header >> 10) & 0x3]; /* 11-10: sampling rate */
if (info->sample_rate <= 0) goto fail;
padding = (header >> 9) & 0x1; /* 9: padding? */
//private = (header >> 8) & 0x1; /* 8: private bit */
info->channels = channels[(header >> 6) & 0x3]; /* 7,6: channel mode */
//js_mode = (header >> 4) & 0x3; /* 5,4: mode extension for joint stereo */
//copyright = (header >> 3) & 0x1; /* 3: copyrighted */
//original = (header >> 2) & 0x1; /* 2: original */
//emphasis = (header >> 0) & 0x3; /* 1,0: emphasis */
info->frame_samples = frame_samples[info->version-1][info->layer-1];
/* calculate frame length (from hcs's fsb_mpeg) */
switch (info->frame_samples) {
case 384: info->frame_size = (12l * info->bit_rate * 1000l / info->sample_rate + padding) * 4; break; /* 384/32 = 12 */
case 576: info->frame_size = (72l * info->bit_rate * 1000l / info->sample_rate + padding); break; /* 576/8 = 72 */
case 1152: info->frame_size = (144l * info->bit_rate * 1000l / info->sample_rate + padding); break; /* 1152/8 = 144 */
default: goto fail;
}
return 1;
fail:
return 0;
}
int mpeg_get_frame_info(STREAMFILE *sf, off_t offset, mpeg_frame_info *info) {
uint32_t header = read_u32be(offset, sf);
return mpeg_get_frame_info_h(header, info);
}
size_t mpeg_get_samples(STREAMFILE *sf, off_t start_offset, size_t bytes) {
off_t offset = start_offset;
off_t max_offset = start_offset + bytes;