mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 00:20:47 +01:00
Merge pull request #56 from bnnm/format-hevag-misc
Formats: HEVAG and others
This commit is contained in:
commit
1899a20934
3
BUILD.md
3
BUILD.md
@ -98,4 +98,5 @@ For new simple formats, assuming existing layout/coding:
|
||||
*xml-vgmstream/DllMain.c*: add new extension to the format list
|
||||
- *src/Makefile*
|
||||
*src/meta/Makefile.unix.am*
|
||||
*src/libvgmstream.vcproj/vcxproj*: to compile new (format-name).c parser
|
||||
*src/libvgmstream.vcproj/vcxproj/filters*: to compile new (format-name).c parser
|
||||
- if the format needs an external library don't forget to make it optional with: *#ifdef VGM_USE_X ... #endif*
|
||||
|
8
Makefile
8
Makefile
@ -1,6 +1,8 @@
|
||||
.PHONY: buildrelease mingw_test mingw_winamp sourceball mingwbin
|
||||
.PHONY: buildfullrelease buildrelease mingw_test mingw_winamp sourceball mingwbin
|
||||
|
||||
buildrelease: clean sourceball mingwbin
|
||||
buildfullrelease: clean sourceball mingwbin
|
||||
|
||||
buildrelease: clean mingwbin
|
||||
|
||||
sourceball:
|
||||
rm -rf vgmstream-`./version.sh`
|
||||
@ -12,7 +14,7 @@ sourceball:
|
||||
rm -rf vgmstream-`./version.sh`
|
||||
|
||||
mingwbin: mingw_test mingw_winamp
|
||||
zip -j "vgmstream-`./version.sh`-test.zip" readme.txt COPYING test/test.exe winamp/in_vgmstream.dll
|
||||
zip -FS -j "vgmstream-`./version.sh`-test.zip" COPYING readme.txt test/test.exe winamp/in_vgmstream.dll ext_libs/*.dll
|
||||
|
||||
mingw_test:
|
||||
$(MAKE) -C test -f Makefile.mingw test.exe
|
||||
|
@ -17,5 +17,14 @@ libg719_decode.a: libg719_decode.def
|
||||
libat3plusdecoder.a: at3plusdecoder.def
|
||||
$(DLLTOOL) -d at3plusdecoder.def -l libat3plusdecoder.a
|
||||
|
||||
libavcodec.a: avcodec-vgmstream-57.dll avcodec-vgmstream-57.def
|
||||
$(DLLTOOL) -D avcodec-vgmstream-57.dll -d avcodec-vgmstream-57.def -l libavcodec.a
|
||||
|
||||
libavformat.a: avformat-vgmstream-57.dll avformat-vgmstream-57.def
|
||||
$(DLLTOOL) -D avformat-vgmstream-57.dll -d avformat-vgmstream-57.def -l libavformat.a
|
||||
|
||||
libavutil.a: avutil-vgmstream-55.dll avutil-vgmstream-55.def
|
||||
$(DLLTOOL) -D avutil-vgmstream-55.dll -d avutil-vgmstream-55.def -l libavutil.a
|
||||
|
||||
clean:
|
||||
rm -f libvorbis.a libmpg123-0.a libg7221_decode.a libg719_decode.a libat3plusdecoder.a
|
||||
rm -f libvorbis.a libmpg123-0.a libg7221_decode.a libg719_decode.a libat3plusdecoder.a libavcodec.a libavformat.a libavutil.a
|
||||
|
@ -626,7 +626,6 @@ bool input_vgmstream::g_is_our_path(const char * p_path,const char * p_extension
|
||||
if(!stricmp_utf8(p_extension,"zwdsp")) return 1;
|
||||
|
||||
if(!stricmp_utf8(p_extension,"vgmstream")) return 1;
|
||||
if(!stricmp_utf8(p_extension,"vgms")) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -965,4 +964,3 @@ DECLARE_MULTIPLE_FILE_TYPE("ZSD Audio File (*.ZSD)", zsd);
|
||||
DECLARE_MULTIPLE_FILE_TYPE("ZWDSP Audio File (*.ZWDSP)", zwdsp);
|
||||
|
||||
DECLARE_MULTIPLE_FILE_TYPE("vgmstream Audio File (*.VGMSTREAM)", vgmstream);
|
||||
DECLARE_MULTIPLE_FILE_TYPE("vgmstream Audio File (*.VGMS)", vgms);
|
||||
|
@ -117,7 +117,7 @@ PS2/PSX ADPCM:
|
||||
- .xa2
|
||||
- .xa30
|
||||
|
||||
GC/Wii DSP ADPCM:
|
||||
GC/Wii/3DS DSP ADPCM:
|
||||
- .aaap
|
||||
- .agsc
|
||||
- .amts
|
||||
@ -140,6 +140,7 @@ GC/Wii DSP ADPCM:
|
||||
- .idsp
|
||||
- .ish+.isd
|
||||
- .lps
|
||||
- .mca
|
||||
- .mpdsp
|
||||
- .mss
|
||||
- .mus (not quite right)
|
||||
@ -260,6 +261,7 @@ etc:
|
||||
- .kcey (EACS IMA ADPCM)
|
||||
- .lsf (LSF ADPCM)
|
||||
- .mwv (Level-5 0x555 ADPCM)
|
||||
- .mtaf (Konami ADPCM)
|
||||
- .ogg, .logg (Ogg Vorbis)
|
||||
- .p3d (Radical ADPCM)
|
||||
- .rsf (CCITT G.721 ADPCM)
|
||||
@ -275,17 +277,18 @@ etc:
|
||||
- .stx (GC AFC ADPCM)
|
||||
- .um3 (Ogg Vorbis)
|
||||
- .xa (CD-ROM XA audio)
|
||||
- .xma (MS WMA Pro)
|
||||
|
||||
loop assists:
|
||||
- .mus (playlist for .acm)
|
||||
- .pos (loop info for .wav)
|
||||
- .pos (loop info for .wav: 32 bit LE loop start sample + loop end sample)
|
||||
- .sli (loop info for .ogg)
|
||||
- .sfl (loop info for .ogg)
|
||||
|
||||
other:
|
||||
- .adxkey (decryption key for .adx, in start/mult/add format)
|
||||
- .hcakey (decryption key for .hca, in HCA Decoder format)
|
||||
- .vgmstream/.vgms + .pos (to force FFmpeg formats + loop assist)
|
||||
- .vgmstream + .pos (FFmpeg formats + loop assist)
|
||||
|
||||
Enjoy!
|
||||
-hcs
|
||||
|
@ -60,6 +60,10 @@ void decode_ffxi_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelsp
|
||||
|
||||
void decode_baf_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_hevag_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_short_vag_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
void decode_xa(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void init_get_high_nibble(VGMSTREAM * vgmstream);
|
||||
|
||||
|
@ -2,17 +2,176 @@
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
double VAG_f[5][2] = { { 0.0 , 0.0 },
|
||||
{ 60.0 / 64.0 , 0.0 },
|
||||
{ 115.0 / 64.0 , -52.0 / 64.0 },
|
||||
{ 98.0 / 64.0 , -55.0 / 64.0 } ,
|
||||
{ 122.0 / 64.0 , -60.0 / 64.0 } } ;
|
||||
int32_t VAG_coefs[5][2] = { { 0 , 0 },
|
||||
{ 60 , 0 },
|
||||
{ 115 , -52 },
|
||||
{ 98 , -55 } ,
|
||||
{ 122 , -60 } } ;
|
||||
/* for some algos, maybe closer to the real thing */
|
||||
#define VAG_USE_INTEGER_TABLE 0
|
||||
|
||||
|
||||
/* PS ADPCM table (precalculated divs) */
|
||||
static const double VAG_f[5][2] = {
|
||||
{ 0.0 , 0.0 },
|
||||
{ 60.0 / 64.0 , 0.0 },
|
||||
{ 115.0 / 64.0 , -52.0 / 64.0 },
|
||||
{ 98.0 / 64.0 , -55.0 / 64.0 },
|
||||
{ 122.0 / 64.0 , -60.0 / 64.0 }
|
||||
};
|
||||
/* PS ADPCM table */
|
||||
static const int8_t VAG_coefs[5][2] = {
|
||||
{ 0 , 0 },
|
||||
{ 60 , 0 },
|
||||
{ 115 , -52 },
|
||||
{ 98 , -55 },
|
||||
{ 122 , -60 }
|
||||
};
|
||||
|
||||
|
||||
/* PSVita ADPCM table */
|
||||
static const int16_t HEVAG_coefs[128][4] = {
|
||||
{ 0, 0, 0, 0 },
|
||||
{ 7680, 0, 0, 0 },
|
||||
{ 14720, -6656, 0, 0 },
|
||||
{ 12544, -7040, 0, 0 },
|
||||
{ 15616, -7680, 0, 0 },
|
||||
{ 14731, -7059, 0, 0 },
|
||||
{ 14507, -7366, 0, 0 },
|
||||
{ 13920, -7522, 0, 0 },
|
||||
{ 13133, -7680, 0, 0 },
|
||||
{ 12028, -7680, 0, 0 },
|
||||
{ 10764, -7680, 0, 0 },
|
||||
{ 9359, -7680, 0, 0 },
|
||||
{ 7832, -7680, 0, 0 },
|
||||
{ 6201, -7680, 0, 0 },
|
||||
{ 4488, -7680, 0, 0 },
|
||||
{ 2717, -7680, 0, 0 },
|
||||
{ 910, -7680, 0, 0 },
|
||||
{ -910, -7680, 0, 0 },
|
||||
{ -2717, -7680, 0, 0 },
|
||||
{ -4488, -7680, 0, 0 },
|
||||
{ -6201, -7680, 0, 0 },
|
||||
{ -7832, -7680, 0, 0 },
|
||||
{ -9359, -7680, 0, 0 },
|
||||
{ -10764, -7680, 0, 0 },
|
||||
{ -12028, -7680, 0, 0 },
|
||||
{ -13133, -7680, 0, 0 },
|
||||
{ -13920, -7522, 0, 0 },
|
||||
{ -14507, -7366, 0, 0 },
|
||||
{ -14731, -7059, 0, 0 },
|
||||
{ 5376, -9216, 3328, -3072 },
|
||||
{ -6400, -7168, -3328, -2304 },
|
||||
{ -10496, -7424, -3584, -1024 },
|
||||
{ -167, -2722, -494, -541 },
|
||||
{ -7430, -2221, -2298, 424 },
|
||||
{ -8001, -3166, -2814, 289 },
|
||||
{ 6018, -4750, 2649, -1298 },
|
||||
{ 3798, -6946, 3875, -1216 },
|
||||
{ -8237, -2596, -2071, 227 },
|
||||
{ 9199, 1982, -1382, -2316 },
|
||||
{ 13021, -3044, -3792, 1267 },
|
||||
{ 13112, -4487, -2250, 1665 },
|
||||
{ -1668, -3744, -6456, 840 },
|
||||
{ 7819, -4328, 2111, -506 },
|
||||
{ 9571, -1336, -757, 487 },
|
||||
{ 10032, -2562, 300, 199 },
|
||||
{ -4745, -4122, -5486, -1493 },
|
||||
{ -5896, 2378, -4787, -6947 },
|
||||
{ -1193, -9117, -1237, -3114 },
|
||||
{ 2783, -7108, -1575, -1447 },
|
||||
{ -7334, -2062, -2212, 446 },
|
||||
{ 6127, -2577, -315, -18 },
|
||||
{ 9457, -1858, 102, 258 },
|
||||
{ 7876, -4483, 2126, -538 },
|
||||
{ -7172, -1795, -2069, 482 },
|
||||
{ -7358, -2102, -2233, 440 },
|
||||
{ -9170, -3509, -2674, -391 },
|
||||
{ -2638, -2647, -1929, -1637 },
|
||||
{ 1873, 9183, 1860, -5746 },
|
||||
{ 9214, 1859, -1124, -2427 },
|
||||
{ 13204, -3012, -4139, 1370 },
|
||||
{ 12437, -4792, -256, 622 },
|
||||
{ -2653, -1144, -3182, -6878 },
|
||||
{ 9331, -1048, -828, 507 },
|
||||
{ 1642, -620, -946, -4229 },
|
||||
{ 4246, -7585, -533, -2259 },
|
||||
{ -8988, -3891, -2807, 44 },
|
||||
{ -2562, -2735, -1730, -1899 },
|
||||
{ 3182, -483, -714, -1421 },
|
||||
{ 7937, -3844, 2821, -1019 },
|
||||
{ 10069, -2609, 314, 195 },
|
||||
{ 8400, -3297, 1551, -155 },
|
||||
{ -8529, -2775, -2432, -336 },
|
||||
{ 9477, -1882, 108, 256 },
|
||||
{ 75, -2241, -298, -6937 },
|
||||
{ -9143, -4160, -2963, 5 },
|
||||
{ -7270, -1958, -2156, 460 },
|
||||
{ -2740, 3745, 5936, -1089 },
|
||||
{ 8993, 1948, -683, -2704 },
|
||||
{ 13101, -2835, -3854, 1055 },
|
||||
{ 9543, -1961, 130, 250 },
|
||||
{ 5272, -4270, 3124, -3157 },
|
||||
{ -7696, -3383, -2907, -456 },
|
||||
{ 7309, 2523, 434, -2461 },
|
||||
{ 10275, -2867, 391, 172 },
|
||||
{ 10940, -3721, 665, 97 },
|
||||
{ 24, -310, -1262, 320 },
|
||||
{ -8122, -2411, -2311, -271 },
|
||||
{ -8511, -3067, -2337, 163 },
|
||||
{ 326, -3846, 419, -933 },
|
||||
{ 8895, 2194, -541, -2880 },
|
||||
{ 12073, -1876, -2017, -601 },
|
||||
{ 8729, -3423, 1674, -169 },
|
||||
{ 12950, -3847, -3007, 1946 },
|
||||
{ 10038, -2570, 302, 198 },
|
||||
{ 9385, -2757, 1008, 41 },
|
||||
{ -4720, -5006, -2852, -1161 },
|
||||
{ 7869, -4326, 2135, -501 },
|
||||
{ 2450, -8597, 1299, -2780 },
|
||||
{ 10192, -2763, 360, 181 },
|
||||
{ 11313, -4213, 833, 53 },
|
||||
{ 10154, -2716, 345, 185 },
|
||||
{ 9638, -1417, -737, 482 },
|
||||
{ 3854, -4554, 2843, -3397 },
|
||||
{ 6699, -5659, 2249, -1074 },
|
||||
{ 11082, -3908, 728, 80 },
|
||||
{ -1026, -9810, -805, -3462 },
|
||||
{ 10396, -3746, 1367, -96 },
|
||||
{ 10287, 988, -1915, -1437 },
|
||||
{ 7953, 3878, -764, -3263 },
|
||||
{ 12689, -3375, -3354, 2079 },
|
||||
{ 6641, 3166, 231, -2089 },
|
||||
{ -2348, -7354, -1944, -4122 },
|
||||
{ 9290, -4039, 1885, -246 },
|
||||
{ 4633, -6403, 1748, -1619 },
|
||||
{ 11247, -4125, 802, 61 },
|
||||
{ 9807, -2284, 219, 222 },
|
||||
{ 9736, -1536, -706, 473 },
|
||||
{ 8440, -3436, 1562, -176 },
|
||||
{ 9307, -1021, -835, 509 },
|
||||
{ 1698, -9025, 688, -3037 },
|
||||
{ 10214, -2791, 368, 179 },
|
||||
{ 8390, 3248, -758, -2989 },
|
||||
{ 7201, 3316, 46, -2614 },
|
||||
{ -88, -7809, -538, -4571 },
|
||||
{ 6193, -5189, 2760, -1245 },
|
||||
{ 12325, -1290, -3284, 253 },
|
||||
{ 13064, -4075, -2824, 1877 },
|
||||
{ 5333, 2999, 775, -1132 }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sony's VAG ADPCM, decodes 16 bytes into 28 samples.
|
||||
* The first 2 bytes are a header (shift, predictor, optional flag)
|
||||
*
|
||||
* Flags:
|
||||
* 0x0: Nothing
|
||||
* 0x1: End marker + decode
|
||||
* 0x2: Loop region
|
||||
* 0x3: Loop end
|
||||
* 0x4: Start marker
|
||||
* 0x5: ?
|
||||
* 0x6: Loop start
|
||||
* 0x7: End marker + don't decode
|
||||
* 0x8+ Not valid
|
||||
*/
|
||||
void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
|
||||
int predict_nr, shift_factor, sample;
|
||||
@ -28,7 +187,7 @@ void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
||||
|
||||
predict_nr = read_8bit(stream->offset+framesin*16,stream->streamfile) >> 4;
|
||||
shift_factor = read_8bit(stream->offset+framesin*16,stream->streamfile) & 0xf;
|
||||
flag = read_8bit(stream->offset+framesin*16+1,stream->streamfile);
|
||||
flag = read_8bit(stream->offset+framesin*16+1,stream->streamfile); /* only lower nibble needed */
|
||||
|
||||
first_sample = first_sample % 28;
|
||||
|
||||
@ -40,7 +199,7 @@ void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
||||
|
||||
short sample_byte = (short)read_8bit(stream->offset+(framesin*16)+2+i/2,stream->streamfile);
|
||||
|
||||
scale = ((i&1 ?
|
||||
scale = ((i&1 ? /* odd/even byte */
|
||||
sample_byte >> 4 :
|
||||
sample_byte & 0x0f)<<12);
|
||||
|
||||
@ -162,7 +321,7 @@ void decode_ffxi_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelsp
|
||||
sample_byte >> 4 :
|
||||
sample_byte & 0x0f)<<12);
|
||||
|
||||
#if 1
|
||||
#if !VAG_USE_INTEGER_TABLE
|
||||
predictor =
|
||||
(int)((hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1]));
|
||||
#else
|
||||
@ -212,3 +371,127 @@ void decode_baf_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspa
|
||||
stream->adpcm_history1_32=hist1;
|
||||
stream->adpcm_history2_32=hist2;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sony's HEVAG (High Efficiency VAG) ADPCM, used in PSVita games (hardware decoded).
|
||||
* Variation of the regular VAG, uses 4 history samples and a bigger table.
|
||||
*
|
||||
* Original research and algorithm by id-daemon / daemon1.
|
||||
*/
|
||||
void decode_hevag_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
|
||||
uint8_t predict_nr, shift, flag, byte;
|
||||
int32_t scale = 0;
|
||||
|
||||
int32_t sample;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int32_t hist2 = stream->adpcm_history2_32;
|
||||
int32_t hist3 = stream->adpcm_history3_32;
|
||||
int32_t hist4 = stream->adpcm_history4_32;
|
||||
|
||||
int i, sample_count;
|
||||
|
||||
|
||||
int framesin = first_sample / 28;
|
||||
|
||||
/* 4 byte header: predictor = 3rd and 1st, shift = 2nd, flag = 4th */
|
||||
byte = (uint8_t)read_8bit(stream->offset+framesin*16+0,stream->streamfile);
|
||||
predict_nr = byte >> 4;
|
||||
shift = byte & 0x0f;
|
||||
byte = (uint8_t)read_8bit(stream->offset+framesin*16+1,stream->streamfile);
|
||||
predict_nr = (byte & 0xF0) | predict_nr;
|
||||
flag = byte & 0x0f; /* no change in flags */
|
||||
|
||||
first_sample = first_sample % 28;
|
||||
|
||||
for (i = first_sample, sample_count = 0; i < first_sample + samples_to_do; i++, sample_count += channelspacing) {
|
||||
sample = 0;
|
||||
|
||||
if (flag < 7 && predict_nr < 128) {
|
||||
|
||||
if (i & 1) {/* odd/even nibble */
|
||||
scale = byte >> 4;
|
||||
} else {
|
||||
byte = read_8bit(stream->offset+(framesin*16)+2+i/2,stream->streamfile);
|
||||
scale = byte & 0x0f;
|
||||
}
|
||||
if (scale > 7) { /* sign extend */
|
||||
scale = scale - 16;
|
||||
}
|
||||
|
||||
sample = (hist1 * HEVAG_coefs[predict_nr][0] +
|
||||
hist2 * HEVAG_coefs[predict_nr][1] +
|
||||
hist3 * HEVAG_coefs[predict_nr][2] +
|
||||
hist4 * HEVAG_coefs[predict_nr][3] ) / 32;
|
||||
sample = (sample + (scale << (20 - shift)) + 128) >> 8;
|
||||
}
|
||||
|
||||
outbuf[sample_count] = clamp16(sample);
|
||||
hist4 = hist3;
|
||||
hist3 = hist2;
|
||||
hist2 = hist1;
|
||||
hist1 = sample;
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
stream->adpcm_history2_32 = hist2;
|
||||
stream->adpcm_history3_32 = hist3;
|
||||
stream->adpcm_history4_32 = hist4;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Short VAG ADPCM, found in PS3 Afrika (SGDX type 5).
|
||||
* Uses 8 byte blocks and no flag.
|
||||
*/
|
||||
void decode_short_vag_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
|
||||
uint8_t predict_nr, shift, byte;
|
||||
int16_t scale = 0;
|
||||
|
||||
int32_t sample;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int32_t hist2 = stream->adpcm_history2_32;
|
||||
|
||||
int i, sample_count;
|
||||
|
||||
|
||||
int framesin = first_sample / 6;
|
||||
|
||||
/* 2 byte header: predictor = 1st, shift = 2nd */
|
||||
byte = (uint8_t)read_8bit(stream->offset+framesin*8+0,stream->streamfile);
|
||||
predict_nr = byte >> 4;
|
||||
shift = byte & 0x0f;
|
||||
|
||||
first_sample = first_sample % 6;
|
||||
|
||||
for (i = first_sample, sample_count = 0; i < first_sample + samples_to_do; i++, sample_count += channelspacing) {
|
||||
sample = 0;
|
||||
|
||||
if (predict_nr < 5) {
|
||||
|
||||
if (i & 1) {/* odd/even nibble */
|
||||
scale = byte >> 4;
|
||||
} else {
|
||||
byte = (uint8_t)read_8bit(stream->offset+(framesin*8)+1+i/2,stream->streamfile);
|
||||
scale = (byte & 0x0f);
|
||||
}
|
||||
/*if (scale > 7) {
|
||||
scale = scale - 16;
|
||||
}*/
|
||||
scale = scale << 12; /* shift + sign extend only if scale is int16_t */
|
||||
|
||||
sample = (hist1 * VAG_coefs[predict_nr][0] +
|
||||
hist2 * VAG_coefs[predict_nr][1] ) / 64;
|
||||
sample = sample + (scale >> shift);
|
||||
}
|
||||
|
||||
outbuf[sample_count] = clamp16(sample);
|
||||
hist2 = hist1;
|
||||
hist1 = sample;
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
stream->adpcm_history2_32 = hist2;
|
||||
}
|
||||
|
@ -1,38 +1,29 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* VAG
|
||||
|
||||
PS2 SVAG format is an interleaved format found in many SONY Games
|
||||
The header start with a "VAG" id and is follow by :
|
||||
static int vag_find_loop_offsets(STREAMFILE *streamFile, off_t start_offset, off_t * loop_start, off_t * loop_end);
|
||||
|
||||
i : interleaved format
|
||||
|
||||
2008-05-17 - Fastelbja : First version ...
|
||||
/**
|
||||
* VAGp - SDK format, created by Sony's tools (like AIFF2VAG)
|
||||
*/
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_vag(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
// used for loop points ...
|
||||
uint8_t eofVAG[16]={0x00,0x07,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77};
|
||||
uint8_t eofVAG2[16]={0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
uint8_t readbuf[16];
|
||||
|
||||
off_t readOffset = 0x20;
|
||||
off_t loopStart = 0;
|
||||
off_t loopEnd = 0;
|
||||
|
||||
off_t loopStart = 0;
|
||||
off_t loopEnd = 0;
|
||||
uint8_t vagID;
|
||||
uint32_t version = 0;
|
||||
|
||||
uint8_t vagID;
|
||||
off_t start_offset;
|
||||
size_t fileLength;
|
||||
|
||||
size_t interleave;
|
||||
|
||||
size_t filesize = 0, datasize = 0;
|
||||
size_t interleave;
|
||||
off_t start_offset;
|
||||
|
||||
int loop_flag=0;
|
||||
int channel_count=1;
|
||||
int loop_samples_found = 0;
|
||||
int channel_count=0;
|
||||
int i;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
@ -40,166 +31,169 @@ VGMSTREAM * init_vgmstream_ps2_vag(STREAMFILE *streamFile) {
|
||||
if (strcasecmp("vag",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check VAG Header */
|
||||
if (((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) != 0x56414700) &&
|
||||
((read_32bitLE(0x00,streamFile) & 0xFFFFFF00) != 0x56414700))
|
||||
if (((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) != 0x56414700) && /* "VAG\0" */
|
||||
((read_32bitLE(0x00,streamFile) & 0xFFFFFF00) != 0x56414700))
|
||||
goto fail;
|
||||
|
||||
/* Check for correct channel count */
|
||||
vagID=read_8bit(0x03,streamFile);
|
||||
filesize = get_streamfile_size(streamFile);
|
||||
|
||||
switch(vagID) {
|
||||
case '1':
|
||||
/* version used to create the file
|
||||
* ex: 00000000 = v1.8 PC, 00000002 = v1.3 Mac, 00000003 = v1.6+ Mac, 00000020 = v2.0+ PC */
|
||||
version = read_32bitBE(0x04,streamFile);
|
||||
/* 0x08-0c: reserved */
|
||||
datasize = read_32bitBE(0x0c,streamFile);
|
||||
/* 0x14-20 reserved */
|
||||
/* 0x20-30: name (optional) */
|
||||
/* 0x30: data start (first 0x10 usually 0s to init SPU) */
|
||||
|
||||
/* Check for correct channel count and loop flag */
|
||||
vagID=read_8bit(0x03,streamFile);
|
||||
switch(vagID) {
|
||||
case '1': /* "VAG1" (1 channel) [Metal Gear Solid 3] */
|
||||
channel_count=1;
|
||||
break;
|
||||
case '2':
|
||||
case '2': /* "VAG2" (2 channels) [Metal Gear Solid 3] */
|
||||
channel_count=2;
|
||||
break;
|
||||
case 'i':
|
||||
channel_count=2;
|
||||
break;
|
||||
case 'V':
|
||||
if(read_32bitBE(0x20,streamFile)==0x53746572) // vag Stereo
|
||||
channel_count=2;
|
||||
case 'p':
|
||||
if((read_32bitBE(0x04,streamFile)<=0x00000004) && (read_32bitBE(0x0c,streamFile)<(get_streamfile_size(streamFile)/2))) {
|
||||
loop_flag=(read_32bitBE(0x14,streamFile)!=0);
|
||||
channel_count=2;
|
||||
} else {
|
||||
/* Search for loop in VAG */
|
||||
fileLength = get_streamfile_size(streamFile);
|
||||
|
||||
do {
|
||||
readOffset+=0x10;
|
||||
|
||||
// Loop Start ...
|
||||
if(read_8bit(readOffset+0x01,streamFile)==0x06) {
|
||||
if(loopStart==0) loopStart = readOffset;
|
||||
}
|
||||
case 'i': /* "VAGi" (interleaved) */
|
||||
channel_count=2;
|
||||
break;
|
||||
case 'V': /* pGAV (little endian / stereo) [Jak 3, Jak X] */
|
||||
if (read_32bitBE(0x20,streamFile)==0x53746572) /* "Ster" */
|
||||
channel_count=2;
|
||||
else
|
||||
channel_count=1;
|
||||
break;
|
||||
case 'p': /* "VAGp" (extended) [most common, ex Ratchet & Clank] */
|
||||
|
||||
// Loop End ...
|
||||
if(read_8bit(readOffset+0x01,streamFile)==0x03) {
|
||||
if(loopEnd==0) loopEnd = readOffset;
|
||||
}
|
||||
|
||||
// Loop from end to beginning ...
|
||||
if((read_8bit(readOffset+0x01,streamFile)==0x01)) {
|
||||
// Check if we have the eof tag after the loop point ...
|
||||
// if so we don't loop, if not present, we loop from end to start ...
|
||||
read_streamfile(readbuf,readOffset+0x10,0x10,streamFile);
|
||||
if((readbuf[0]!=0) && (readbuf[0]!=0x0c)) {
|
||||
if(memcmp(readbuf,eofVAG,0x10) && (memcmp(readbuf,eofVAG2,0x10))) {
|
||||
loopStart = 0x40;
|
||||
loopEnd = readOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while (streamFile->get_offset(streamFile)<(off_t)fileLength);
|
||||
loop_flag = (loopEnd!=0);
|
||||
}
|
||||
break;
|
||||
if ((version <= 0x00000004) && (datasize < filesize / 2)) {
|
||||
loop_flag=(read_32bitBE(0x14,streamFile)!=0);
|
||||
channel_count=2;
|
||||
}
|
||||
else if (version == 0x00020001) { /* HEVAG */
|
||||
loop_flag = vag_find_loop_offsets(streamFile, 0x30, &loopStart, &loopEnd);
|
||||
channel_count = read_8bit(0x1e,streamFile);
|
||||
if (channel_count == 0)
|
||||
channel_count = 1; /* ex. Lumines */
|
||||
}
|
||||
else {
|
||||
loop_flag = vag_find_loop_offsets(streamFile, 0x30, &loopStart, &loopEnd);
|
||||
channel_count = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->sample_rate = read_32bitBE(0x10,streamFile);
|
||||
|
||||
switch(vagID) {
|
||||
switch(vagID) {
|
||||
case '1': // VAG1
|
||||
vgmstream->layout_type=layout_none;
|
||||
vgmstream->sample_rate = read_32bitBE(0x10,streamFile);
|
||||
vgmstream->num_samples = read_32bitBE(0x0C,streamFile)/16*28;
|
||||
interleave = read_32bitLE(0x08,streamFile);
|
||||
vgmstream->layout_type=layout_none;
|
||||
vgmstream->num_samples = datasize / 16 * 28;
|
||||
interleave = read_32bitLE(0x08,streamFile);
|
||||
if (interleave != 0) goto fail;
|
||||
vgmstream->meta_type=meta_PS2_VAG1;
|
||||
start_offset=0x40;
|
||||
vgmstream->meta_type=meta_PS2_VAG1;
|
||||
start_offset=0x40; /* 0x30 is extra data in VAG1 */
|
||||
break;
|
||||
case '2': // VAG2
|
||||
vgmstream->layout_type=layout_interleave;
|
||||
vgmstream->sample_rate = read_32bitBE(0x10,streamFile);
|
||||
vgmstream->num_samples = read_32bitBE(0x0C,streamFile)/16*28;
|
||||
interleave = 0x800;
|
||||
vgmstream->meta_type=meta_PS2_VAG2;
|
||||
start_offset=0x40;
|
||||
vgmstream->layout_type=layout_interleave;
|
||||
vgmstream->num_samples = datasize / 16 * 28; /* datasize is for 1 channel only in VAG2 */
|
||||
interleave = 0x800;
|
||||
vgmstream->meta_type=meta_PS2_VAG2;
|
||||
start_offset=0x40; /* 0x30 is extra data in VAG2 */
|
||||
break;
|
||||
case 'i': // VAGi
|
||||
vgmstream->layout_type=layout_interleave;
|
||||
vgmstream->sample_rate = read_32bitBE(0x10,streamFile);
|
||||
vgmstream->num_samples = read_32bitBE(0x0C,streamFile)/16*28;
|
||||
interleave = read_32bitLE(0x08,streamFile);
|
||||
vgmstream->meta_type=meta_PS2_VAGi;
|
||||
start_offset=0x800;
|
||||
break;
|
||||
case 'p': // VAGp
|
||||
vgmstream->sample_rate = read_32bitBE(0x10,streamFile);
|
||||
interleave=0x10; // used for loop calc
|
||||
case 'i': // VAGi
|
||||
vgmstream->layout_type=layout_interleave;
|
||||
vgmstream->num_samples = datasize / 16 * 28;
|
||||
interleave = read_32bitLE(0x08,streamFile);
|
||||
vgmstream->meta_type=meta_PS2_VAGi;
|
||||
start_offset=0x800;
|
||||
break;
|
||||
case 'p': // VAGp
|
||||
interleave=0x10;
|
||||
|
||||
if((read_32bitBE(0x04,streamFile)==0x00000004) && (read_32bitBE(0x0c,streamFile)<(get_streamfile_size(streamFile)/2))) {
|
||||
vgmstream->channels=2;
|
||||
vgmstream->num_samples = read_32bitBE(0x0C,streamFile);
|
||||
if ((version == 0x00000004) && (datasize < filesize / 2)) {
|
||||
vgmstream->channels=2;
|
||||
vgmstream->num_samples = datasize; /* todo test if datasize/16*28? */
|
||||
|
||||
if(loop_flag) {
|
||||
vgmstream->loop_start_sample=read_32bitBE(0x14,streamFile);
|
||||
vgmstream->loop_end_sample =read_32bitBE(0x18,streamFile);
|
||||
}
|
||||
if(loop_flag) {
|
||||
vgmstream->loop_start_sample=read_32bitBE(0x14,streamFile);
|
||||
vgmstream->loop_end_sample =read_32bitBE(0x18,streamFile);
|
||||
loop_samples_found = 1;
|
||||
}
|
||||
|
||||
start_offset=0x80;
|
||||
vgmstream->layout_type=layout_interleave;
|
||||
vgmstream->meta_type=meta_PS2_VAGs;
|
||||
start_offset=0x80;
|
||||
vgmstream->layout_type=layout_interleave;
|
||||
vgmstream->meta_type=meta_PS2_VAGs;
|
||||
|
||||
// Double VAG Header @ 0x0000 & 0x1000
|
||||
if(read_32bitBE(0,streamFile)==read_32bitBE(0x1000,streamFile)) {
|
||||
vgmstream->num_samples = read_32bitBE(0x0C,streamFile)/16*28;
|
||||
interleave=0x1000;
|
||||
start_offset=0;
|
||||
}
|
||||
// Double VAG Header @ 0x0000 & 0x1000
|
||||
if(read_32bitBE(0,streamFile)==read_32bitBE(0x1000,streamFile)) {
|
||||
vgmstream->num_samples = datasize / 16 * 28;
|
||||
interleave=0x1000;
|
||||
start_offset=0;
|
||||
}
|
||||
}
|
||||
else if (version == 0x40000000) { /* Guerilla VAG (little endian) */
|
||||
datasize = read_32bitLE(0x0c,streamFile);
|
||||
vgmstream->sample_rate = read_32bitLE(0x10,streamFile);
|
||||
vgmstream->layout_type=layout_none;
|
||||
vgmstream->meta_type=meta_PS2_VAGp;
|
||||
|
||||
} else {
|
||||
vgmstream->layout_type=layout_none;
|
||||
vgmstream->num_samples = read_32bitBE(0x0C,streamFile)/16*28;
|
||||
vgmstream->meta_type=meta_PS2_VAGp;
|
||||
start_offset=0x30;
|
||||
}
|
||||
break;
|
||||
vgmstream->num_samples = datasize / channel_count / 16 * 28;
|
||||
start_offset = 0x30;
|
||||
}
|
||||
else if (version == 0x00020001) { /* HEVAG */
|
||||
vgmstream->coding_type = coding_HEVAG_ADPCM;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->meta_type = meta_PS2_VAGs;
|
||||
|
||||
vgmstream->num_samples = datasize / channel_count / 16 * 28;
|
||||
start_offset = 0x30;
|
||||
}
|
||||
else { /* VAGp, usually separate L/R files */
|
||||
vgmstream->layout_type=layout_none;
|
||||
vgmstream->meta_type=meta_PS2_VAGp;
|
||||
|
||||
vgmstream->num_samples = datasize / channel_count / 16 * 28;
|
||||
start_offset=0x30;
|
||||
}
|
||||
break;
|
||||
case 'V': // pGAV
|
||||
vgmstream->layout_type=layout_interleave;
|
||||
interleave=0x2000;
|
||||
interleave=0x2000; /* Jak 3 interleave, includes header */
|
||||
|
||||
// Jak X hack ...
|
||||
if(read_32bitLE(0x1000,streamFile)==0x56414770)
|
||||
interleave=0x1000;
|
||||
if(read_32bitLE(0x1000,streamFile)==0x56414770) /* "pGAV" */
|
||||
interleave=0x1000; /* Jak X interleave, includes header */
|
||||
|
||||
vgmstream->sample_rate = read_32bitLE(0x10,streamFile);
|
||||
vgmstream->num_samples = read_32bitLE(0x0C,streamFile)/16*14;
|
||||
vgmstream->meta_type=meta_PS2_pGAV;
|
||||
start_offset=0;
|
||||
break;
|
||||
vgmstream->sample_rate = read_32bitLE(0x10,streamFile);
|
||||
vgmstream->num_samples = read_32bitLE(0x0C,streamFile)/16*14;
|
||||
vgmstream->meta_type=meta_PS2_pGAV;
|
||||
start_offset=0;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
vgmstream->interleave_block_size=interleave;
|
||||
|
||||
/* Don't add the header size to loop calc points */
|
||||
if(vgmstream->meta_type!=meta_PS2_VAGs) {
|
||||
loopStart-=start_offset;
|
||||
loopEnd-=start_offset;
|
||||
vgmstream->interleave_block_size=interleave;
|
||||
|
||||
if(loop_flag!=0) {
|
||||
vgmstream->loop_start_sample = (int32_t)((loopStart/(interleave*channel_count))*interleave)/16*28;
|
||||
vgmstream->loop_start_sample += (int32_t)(loopStart%(interleave*channel_count))/16*28;
|
||||
vgmstream->loop_end_sample = (int32_t)((loopEnd/(interleave*channel_count))*interleave)/16*28;
|
||||
vgmstream->loop_end_sample += (int32_t)(loopEnd%(interleave*channel_count))/16*28;
|
||||
}
|
||||
}
|
||||
/* Don't add the header size to loop calc points */
|
||||
if(loop_flag && !loop_samples_found) {
|
||||
loopStart-=start_offset;
|
||||
loopEnd-=start_offset;
|
||||
|
||||
vgmstream->loop_start_sample = (int32_t)((loopStart/(interleave*channel_count))*interleave)/16*28;
|
||||
vgmstream->loop_start_sample += (int32_t)(loopStart%(interleave*channel_count))/16*28;
|
||||
vgmstream->loop_end_sample = (int32_t)((loopEnd/(interleave*channel_count))*interleave)/16*28;
|
||||
vgmstream->loop_end_sample += (int32_t)(loopEnd%(interleave*channel_count))/16*28;
|
||||
}
|
||||
|
||||
/* Compression Scheme */
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
@ -225,3 +219,76 @@ fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds loop points in VAG data using flag markers and updates loop_start and loop_end with the global offsets.
|
||||
*
|
||||
* returns 0 if not found
|
||||
*/
|
||||
static int vag_find_loop_offsets(STREAMFILE *streamFile, off_t start_offset, off_t * loop_start, off_t * loop_end) {
|
||||
off_t loopStart = 0;
|
||||
off_t loopEnd = 0;
|
||||
|
||||
/* used for loop points (todo: variations: 0x0c0700..00, 0x070077..77 ) */
|
||||
/* 'used to prevent unnecessary SPU interrupts' (optional if no IRQ or no looping) */
|
||||
uint8_t eofVAG[16]={0x00,0x07,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77};
|
||||
uint8_t eofVAG2[16]={0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
uint8_t readbuf[16];
|
||||
uint8_t flag;
|
||||
|
||||
/* Search for loop in VAG */
|
||||
size_t fileLength = get_streamfile_size(streamFile);
|
||||
|
||||
|
||||
off_t readOffset = start_offset - 0x10;
|
||||
do {
|
||||
readOffset+=0x10;
|
||||
|
||||
flag = read_8bit(readOffset+0x01,streamFile) & 0x0F; /* lower nibble (for HEVAG) */
|
||||
|
||||
// Loop Start ...
|
||||
if (flag == 0x06 && !loopStart) {
|
||||
loopStart = readOffset;
|
||||
}
|
||||
|
||||
// Loop End ...
|
||||
if (flag == 0x03 && !loopEnd) {
|
||||
loopEnd = readOffset;
|
||||
|
||||
if (loopStart && loopEnd)
|
||||
break;
|
||||
}
|
||||
|
||||
/* hack for some games that don't have loop points but play the same track on repeat
|
||||
* (sometimes this will loop non-looping tracks incorrectly)
|
||||
* if there is a "partial" 0x07 end flag pretend it wants to loop */
|
||||
if (flag == 0x01) {
|
||||
// Check if we have a full eof tag after the loop point ...
|
||||
// if so we don't loop, if not present, we loop from end to start ...
|
||||
int read = read_streamfile(readbuf,readOffset+0x10,0x10,streamFile);
|
||||
/* is there valid data after flag 0x1? */
|
||||
if (read > 0
|
||||
&& readbuf[0] != 0x00
|
||||
&& readbuf[0] != 0x0c
|
||||
&& readbuf[0] != 0x3c /* Ecco the Dolphin, Ratchet & Clank 2 */
|
||||
) {
|
||||
if (memcmp(readbuf,eofVAG,0x10) && (memcmp(readbuf,eofVAG2,0x10))) { /* full end flags */
|
||||
loopStart = start_offset + 0x10; /* todo proper start */
|
||||
loopEnd = readOffset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while (streamFile->get_offset(streamFile)<(off_t)fileLength);
|
||||
|
||||
|
||||
if (loopStart && loopEnd) {
|
||||
*loop_start = loopStart;
|
||||
*loop_end = loopEnd;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -194,21 +194,12 @@ VGMSTREAM * init_vgmstream_ps3_sgdx(STREAMFILE *streamFile) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case 0x05: /* todo PCM? */
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
if (vgmstream->channels > 1) {
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x1;
|
||||
} else {
|
||||
vgmstream->layout_type = layout_none;
|
||||
}
|
||||
case 0x05: /* Short VAG ADPCM */
|
||||
vgmstream->coding_type = coding_SHORT_VAG_ADPCM;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x4;
|
||||
|
||||
break;
|
||||
*/
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x06: /* AC3 */
|
||||
|
128
src/meta/xma.c
128
src/meta/xma.c
@ -23,6 +23,7 @@ typedef struct {
|
||||
int32_t fmt_codec;
|
||||
uint8_t xma2_version;
|
||||
int needs_header;
|
||||
int force_little_endian; /* FFmpeg can't parse big endian "fmt" chunks */
|
||||
|
||||
/* info */
|
||||
int loop_flag;
|
||||
@ -39,6 +40,7 @@ typedef struct {
|
||||
static int parse_header(xma_header_data * xma, STREAMFILE *streamFile);
|
||||
static void parse_xma1_sample_data(xma_header_data * xma, STREAMFILE *streamFile);
|
||||
static int create_riff_header(uint8_t * buf, size_t buf_size, xma_header_data * xma, STREAMFILE *streamFile);
|
||||
static int fmt_chunk_swap_endian(uint8_t * chunk, uint16_t codec);
|
||||
#if ADJUST_SAMPLE_RATE
|
||||
static int get_xma_sample_rate(int32_t general_rate);
|
||||
#endif
|
||||
@ -61,7 +63,9 @@ VGMSTREAM * init_vgmstream_xma(STREAMFILE *streamFile) {
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("xma",filename_extension(filename))
|
||||
&& strcasecmp("xma2",filename_extension(filename)) ) /* Skullgirls */
|
||||
&& strcasecmp("xma2",filename_extension(filename)) /* Skullgirls */
|
||||
&& strcasecmp("past",filename_extension(filename)) /* SoulCalibur II HD */
|
||||
)
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
@ -74,7 +78,7 @@ VGMSTREAM * init_vgmstream_xma(STREAMFILE *streamFile) {
|
||||
fake_riff_size = create_riff_header(fake_riff, FAKE_RIFF_BUFFER_SIZE, &xma, streamFile);
|
||||
if (fake_riff_size <= 0) goto fail;
|
||||
|
||||
data = init_ffmpeg_header_offset(streamFile, fake_riff, (uint64_t)fake_riff_size, xma.data_offset+4+4, xma.data_size);
|
||||
data = init_ffmpeg_header_offset(streamFile, fake_riff, (uint64_t)fake_riff_size, xma.data_offset, xma.data_size);
|
||||
if (!data) goto fail;
|
||||
}
|
||||
else { /* no change */
|
||||
@ -130,20 +134,28 @@ static int parse_header(xma_header_data * xma, STREAMFILE *streamFile) {
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||
uint32_t id;
|
||||
enum { RIFF } header_type;
|
||||
int big_endian = 0;
|
||||
enum {
|
||||
id_RIFF = UINT32_C(0x52494646), /* "RIFF" */
|
||||
id_RIFX = UINT32_C(0x52494658), /* "RIFX" */
|
||||
id_NXMA = UINT32_C(0x786D6100), /* "xma\0" */
|
||||
id_PASX = UINT32_C(0x50415358), /* "PASX" */
|
||||
};
|
||||
|
||||
|
||||
/* check header */
|
||||
id = read_32bitBE(0x00,streamFile);
|
||||
if (id == 0x52494646 || id == 0x52494658) { /* "RIFF" / "RIFX" */
|
||||
big_endian = id == 0x52494658;
|
||||
header_type = RIFF;
|
||||
switch (id) {
|
||||
case id_RIFF:
|
||||
break;
|
||||
case id_RIFX:
|
||||
case id_NXMA:
|
||||
case id_PASX:
|
||||
big_endian = 1;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
memset(xma,0,sizeof(xma_header_data));
|
||||
xma->big_endian = big_endian;
|
||||
@ -159,7 +171,7 @@ static int parse_header(xma_header_data * xma, STREAMFILE *streamFile) {
|
||||
xma->file_size = streamFile->get_size(streamFile);
|
||||
|
||||
/* find offsets */
|
||||
if (header_type == RIFF) { /* regular RIFF header */
|
||||
if (id == id_RIFF || id == id_RIFX) { /* regular RIFF header */
|
||||
off_t current_chunk = 0xc;
|
||||
off_t fmt_offset = 0, xma2_offset = 0;
|
||||
size_t riff_size = 0, fmt_size = 0, xma2_size = 0;
|
||||
@ -184,7 +196,7 @@ static int parse_header(xma_header_data * xma, STREAMFILE *streamFile) {
|
||||
case 0x64617461: /* "data" */
|
||||
if (xma->data_offset) goto fail;
|
||||
|
||||
xma->data_offset = current_chunk;
|
||||
xma->data_offset = current_chunk + 4 + 4;
|
||||
xma->data_size = chunk_size;
|
||||
break;
|
||||
case 0x584D4132: /* "XMA2" */
|
||||
@ -210,10 +222,42 @@ static int parse_header(xma_header_data * xma, STREAMFILE *streamFile) {
|
||||
xma->chunk_offset = fmt_offset;
|
||||
xma->chunk_size = fmt_size;
|
||||
xma->fmt_codec = read_16bit(xma->chunk_offset,streamFile);
|
||||
xma->force_little_endian = xma->big_endian;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else if (id == id_NXMA) { /* Namco (Tekken 6, Galaga Legions DX) */
|
||||
/* custom header with a "XMA2" or "fmt " data chunk inside, most other values are unknown */
|
||||
uint32_t chunk_type = read_32bit(0xC,streamFile);
|
||||
xma->data_offset = 0x100;
|
||||
xma->data_size = read_32bit(0x14,streamFile);
|
||||
xma->chunk_offset = 0xBC;
|
||||
xma->chunk_size = read_32bit(0x24,streamFile);
|
||||
if (chunk_type == 0x4) { /* "XMA2" */
|
||||
xma->xma2_version = read_8bit(xma->chunk_offset,streamFile);
|
||||
} else if (chunk_type == 0x8) { /* "fmt " */
|
||||
xma->fmt_codec = read_16bit(xma->chunk_offset,streamFile);
|
||||
xma->force_little_endian = 1;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
xma->needs_header = 1;
|
||||
|
||||
if (xma->data_size + xma->data_offset > xma->file_size) goto fail;
|
||||
}
|
||||
else if (id == id_PASX) { /* SoulCalibur II HD */
|
||||
/* custom header with a "fmt " data chunk inside */
|
||||
xma->chunk_size = read_32bit(0x08,streamFile);
|
||||
xma->data_size = read_32bit(0x0c,streamFile);
|
||||
xma->chunk_offset = read_32bit(0x10,streamFile);
|
||||
/* 0x14: chunk offset end */
|
||||
xma->data_offset = read_32bit(0x18,streamFile);
|
||||
xma->fmt_codec = read_16bit(xma->chunk_offset,streamFile);
|
||||
xma->needs_header = 1;
|
||||
xma->force_little_endian = 1;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -237,8 +281,8 @@ static int parse_header(xma_header_data * xma, STREAMFILE *streamFile) {
|
||||
xma->loop_flag = (uint8_t)read_8bit(xma->chunk_offset+0x30,streamFile) > 0 /* never set in practice */
|
||||
|| xma->loop_end_sample;
|
||||
/* not needed but may affect looping? (sometimes these don't match loop/total samples) */
|
||||
/* int32_t play_begin_sample = read_32bit(xma->fmt_offset+0x28,streamFile); */
|
||||
/* int32_t play_end_sample = play_begin_sample + read_32bit(xma->fmt_offset+0x24,streamFile); */
|
||||
/* int32_t play_begin_sample = read_32bit(xma->chunk_offset+0x20,streamFile); */
|
||||
/* int32_t play_end_sample = play_begin_sample + read_32bit(xma->chunk_offset+0x24,streamFile); */
|
||||
}
|
||||
else if (xma->fmt_codec == 0x165) { /* pure XMA1 */
|
||||
xma->loop_flag = (uint8_t)read_8bit(xma->chunk_offset+0xA,streamFile) > 0;
|
||||
@ -248,7 +292,7 @@ static int parse_header(xma_header_data * xma, STREAMFILE *streamFile) {
|
||||
/* find samples count + loop samples since they are not in the header */
|
||||
parse_xma1_sample_data(xma, streamFile);
|
||||
}
|
||||
else { /* RIFF with no XMA data or unknown version */
|
||||
else { /* unknown chunk */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -272,9 +316,9 @@ static void parse_xma1_sample_data(xma_header_data * xma, STREAMFILE *streamFile
|
||||
uint32_t size;
|
||||
|
||||
uint32_t packet_size = XMA_BYTES_PER_PACKET;
|
||||
uint32_t offset = xma->data_offset + 4 + 4;
|
||||
uint32_t offset = xma->data_offset;
|
||||
uint32_t offset_b = 0;
|
||||
uint32_t stream_offset_b = (xma->data_offset + 4 + 4) * 8;
|
||||
uint32_t stream_offset_b = xma->data_offset * 8;
|
||||
|
||||
size = offset + xma->data_size;
|
||||
packet_size_b = packet_size*8;
|
||||
@ -333,7 +377,9 @@ static int create_riff_header(uint8_t * buf, size_t buf_size, xma_header_data *
|
||||
uint8_t internal[FAKE_RIFF_BUFFER_SIZE];
|
||||
size_t head_size, file_size, internal_size;
|
||||
|
||||
if (xma->big_endian) {
|
||||
int use_be = xma->big_endian && !xma->force_little_endian;
|
||||
|
||||
if (use_be) {
|
||||
put_32bit = put_32bitBE;
|
||||
} else {
|
||||
put_32bit = put_32bitLE;
|
||||
@ -347,7 +393,7 @@ static int create_riff_header(uint8_t * buf, size_t buf_size, xma_header_data *
|
||||
if (xma->xma2_version == 3) { /* old XMA2 v3: change to v4 (extra 8 bytes in the middle) */
|
||||
internal_size = 4+4+xma->chunk_size + 8;
|
||||
|
||||
memcpy(internal + 0x0, "XMA2", 4); /* "XMA2" chunk (interal data is BE) */
|
||||
memcpy(internal + 0x0, "XMA2", 4); /* "XMA2" chunk (internal data is BE) */
|
||||
put_32bit(internal + 0x4, xma->chunk_size + 8); /* v3 > v4 size*/
|
||||
put_8bit(internal + 0x8, 4); /* v4 */
|
||||
memcpy(internal + 0x9, chunk+1, 15); /* first v3 part (fixed) */
|
||||
@ -358,6 +404,11 @@ static int create_riff_header(uint8_t * buf, size_t buf_size, xma_header_data *
|
||||
else { /* direct copy (old XMA2 v4 ignoring "fmt", pure XMA1/2) */
|
||||
internal_size = 4+4+xma->chunk_size;
|
||||
|
||||
if (xma->force_little_endian ) {
|
||||
if ( !fmt_chunk_swap_endian(chunk, xma->fmt_codec) )
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(internal + 0x0, xma->xma2_version ? "XMA2" : "fmt ", 4);
|
||||
put_32bit(internal + 0x4, xma->chunk_size);
|
||||
memcpy(internal + 0x8, chunk, xma->chunk_size);
|
||||
@ -368,7 +419,7 @@ static int create_riff_header(uint8_t * buf, size_t buf_size, xma_header_data *
|
||||
file_size = head_size-4-4 + xma->data_size;
|
||||
if (head_size > buf_size) goto fail;
|
||||
|
||||
memcpy(buf + 0x0, xma->big_endian ? "RIFX" : "RIFF", 4);
|
||||
memcpy(buf + 0x0, use_be ? "RIFX" : "RIFF", 4);
|
||||
put_32bit(buf + 0x4, file_size);
|
||||
memcpy(buf + 0x8, "WAVE", 4);
|
||||
memcpy(buf + 0xc, internal, internal_size);
|
||||
@ -382,6 +433,41 @@ fail:
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Swaps endianness
|
||||
*
|
||||
* returns 0 on error
|
||||
*/
|
||||
static int fmt_chunk_swap_endian(uint8_t * chunk, uint16_t codec) {
|
||||
if (codec != 0x166)
|
||||
goto fail;
|
||||
|
||||
put_16bitLE(chunk + 0x00, get_16bitBE(chunk + 0x00));/*wFormatTag*/
|
||||
put_16bitLE(chunk + 0x02, get_16bitBE(chunk + 0x02));/*nChannels*/
|
||||
put_32bitLE(chunk + 0x04, get_32bitBE(chunk + 0x04));/*nSamplesPerSec*/
|
||||
put_32bitLE(chunk + 0x08, get_32bitBE(chunk + 0x08));/*nAvgBytesPerSec*/
|
||||
put_16bitLE(chunk + 0x0c, get_16bitBE(chunk + 0x0c));/*nBlockAlign*/
|
||||
put_16bitLE(chunk + 0x0e, get_16bitBE(chunk + 0x0e));/*wBitsPerSample*/
|
||||
put_16bitLE(chunk + 0x10, get_16bitBE(chunk + 0x10));/*cbSize*/
|
||||
put_16bitLE(chunk + 0x12, get_16bitBE(chunk + 0x12));/*NumStreams*/
|
||||
put_32bitLE(chunk + 0x14, get_32bitBE(chunk + 0x14));/*ChannelMask*/
|
||||
put_32bitLE(chunk + 0x18, get_32bitBE(chunk + 0x18));/*SamplesEncoded*/
|
||||
put_32bitLE(chunk + 0x1c, get_32bitBE(chunk + 0x1c));/*BytesPerBlock*/
|
||||
put_32bitLE(chunk + 0x20, get_32bitBE(chunk + 0x20));/*PlayBegin*/
|
||||
put_32bitLE(chunk + 0x24, get_32bitBE(chunk + 0x24));/*PlayLength*/
|
||||
put_32bitLE(chunk + 0x28, get_32bitBE(chunk + 0x28));/*LoopBegin*/
|
||||
put_32bitLE(chunk + 0x2c, get_32bitBE(chunk + 0x2c));/*LoopLength*/
|
||||
/* put_8bit(chunk + 0x30, get_8bit(chunk + 0x30));*//*LoopCount*/
|
||||
/* put_8bit(chunk + 0x31, get_8bit(chunk + 0x31));*//*EncoderVersion*/
|
||||
put_16bitLE(chunk + 0x32, get_16bitBE(chunk + 0x32));/*BlockCount*/
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if ADJUST_SAMPLE_RATE
|
||||
/**
|
||||
* Get real XMA sample rate (from Microsoft docs, apparently info only and not correct for playback).
|
||||
|
@ -376,8 +376,9 @@ VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) {
|
||||
|
||||
/* Sanify loops! */
|
||||
if (vgmstream->loop_flag) {
|
||||
if ((vgmstream->loop_end_sample <= vgmstream->loop_start_sample) ||
|
||||
(vgmstream->loop_end_sample > vgmstream->num_samples))
|
||||
if ((vgmstream->loop_end_sample <= vgmstream->loop_start_sample)
|
||||
|| (vgmstream->loop_end_sample > vgmstream->num_samples)
|
||||
|| (vgmstream->loop_start_sample < 0) )
|
||||
vgmstream->loop_flag = 0;
|
||||
}
|
||||
|
||||
@ -1032,8 +1033,11 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
||||
case coding_PSX:
|
||||
case coding_PSX_badflags:
|
||||
case coding_invert_PSX:
|
||||
case coding_HEVAG_ADPCM:
|
||||
case coding_XA:
|
||||
return 28;
|
||||
case coding_SHORT_VAG_ADPCM:
|
||||
return 6;
|
||||
case coding_XBOX:
|
||||
case coding_INT_XBOX:
|
||||
case coding_BAF_ADPCM:
|
||||
@ -1159,9 +1163,12 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
||||
return 9;
|
||||
case coding_PSX:
|
||||
case coding_PSX_badflags:
|
||||
case coding_HEVAG_ADPCM:
|
||||
case coding_invert_PSX:
|
||||
case coding_NDS_PROCYON:
|
||||
return 16;
|
||||
case coding_SHORT_VAG_ADPCM:
|
||||
return 4;
|
||||
case coding_XA:
|
||||
return 14*vgmstream->channels;
|
||||
case coding_XBOX:
|
||||
@ -1435,6 +1442,20 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_HEVAG_ADPCM:
|
||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||
decode_hevag_adpcm(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||
vgmstream->channels,vgmstream->samples_into_block,
|
||||
samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_SHORT_VAG_ADPCM:
|
||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||
decode_short_vag_adpcm(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||
vgmstream->channels,vgmstream->samples_into_block,
|
||||
samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_XA:
|
||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||
decode_xa(vgmstream,buffer+samples_written*vgmstream->channels+chan,
|
||||
@ -1746,6 +1767,8 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) {
|
||||
vgmstream->loop_ch[i].adpcm_history2_32 = vgmstream->ch[i].adpcm_history2_32;
|
||||
}
|
||||
}
|
||||
/* todo preserve hevag, baf_adpcm, etc history? */
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
int i;
|
||||
@ -1960,6 +1983,12 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||
case coding_BAF_ADPCM:
|
||||
snprintf(temp,TEMPSIZE,"Bizarre Creations Playstation-ish 4-bit ADPCM");
|
||||
break;
|
||||
case coding_HEVAG_ADPCM:
|
||||
snprintf(temp,TEMPSIZE,"PSVita HEVAG ADPCM");
|
||||
break;
|
||||
case coding_SHORT_VAG_ADPCM:
|
||||
snprintf(temp,TEMPSIZE,"Short VAG (SGXD type 5) ADPCM");
|
||||
break;
|
||||
case coding_XA:
|
||||
snprintf(temp,TEMPSIZE,"CD-ROM XA 4-bit ADPCM");
|
||||
break;
|
||||
|
@ -93,6 +93,8 @@ typedef enum {
|
||||
coding_PSX_badflags, /* with garbage in the flags byte */
|
||||
coding_FFXI, /* FF XI PSX-ish ADPCM */
|
||||
coding_BAF_ADPCM, /* Bizarre Creations PSX-ish ADPCM */
|
||||
coding_HEVAG_ADPCM, /* PSVita games */
|
||||
coding_SHORT_VAG_ADPCM, /* SGXD type 5 (PS3 Afrika) */
|
||||
coding_XA, /* PSX CD-XA */
|
||||
coding_XBOX, /* XBOX IMA */
|
||||
coding_INT_XBOX, /* XBOX 'real interleaved' IMA */
|
||||
@ -633,6 +635,10 @@ typedef struct {
|
||||
int16_t adpcm_history3_16;
|
||||
int32_t adpcm_history3_32;
|
||||
};
|
||||
union {
|
||||
int16_t adpcm_history4_16;
|
||||
int32_t adpcm_history4_32;
|
||||
};
|
||||
|
||||
double adpcm_history1_double;
|
||||
double adpcm_history2_double;
|
||||
|
@ -1,11 +1,11 @@
|
||||
# optional parts
|
||||
VGM_ENABLE_FFMPEG=0
|
||||
VGM_ENABLE_FFMPEG=1
|
||||
ifeq ($(VGM_ENABLE_FFMPEG),1)
|
||||
FFMPEG_CC=-DVGM_USE_FFMPEG -DVGM_USE_FFMPEG_ACCURATE_LOOPING -I../../vgmstream-ffmpeg/include
|
||||
FFMPEG_LD=-L../../vgmstream-ffmpeg/lib -lavcodec -lavformat -lavutil
|
||||
FFMPEG_CC=-DVGM_USE_FFMPEG -DVGM_USE_FFMPEG_ACCURATE_LOOPING
|
||||
FFMPEG_LD=-lavcodec -lavformat -lavutil
|
||||
endif
|
||||
|
||||
VGM_ENABLE_MAIATRAC3PLUS=1
|
||||
VGM_ENABLE_MAIATRAC3PLUS=0
|
||||
ifeq ($(VGM_ENABLE_MAIATRAC3PLUS),1)
|
||||
MAT3P_CC=-DVGM_USE_MAIATRAC3PLUS
|
||||
MAT3P_LD=-lat3plusdecoder
|
||||
@ -31,9 +31,9 @@ export CC=i686-w64-mingw32-gcc
|
||||
export AR=i686-w64-mingw32-ar
|
||||
export STRIP=i686-w64-mingw32-strip
|
||||
|
||||
.PHONY: libvgmstream.a libvorbis.a libmpg123-0.a libg7221_decode.a libg719_decode.a libat3plusdecoder.a
|
||||
.PHONY: libvgmstream.a libvorbis.a libmpg123-0.a libg7221_decode.a libg719_decode.a libat3plusdecoder.a libavcodec.a libavformat.a libavutil.a
|
||||
|
||||
test.exe: libvgmstream.a libvorbis.a libmpg123-0.a libg7221_decode.a libg719_decode.a libat3plusdecoder.a
|
||||
test.exe: libvgmstream.a libvorbis.a libmpg123-0.a libg7221_decode.a libg719_decode.a libat3plusdecoder.a libavcodec.a libavformat.a libavutil.a
|
||||
$(CC) $(CFLAGS) "-DVERSION=\"`../version.sh`\"" test.c $(LDFLAGS) -o test.exe
|
||||
$(STRIP) test.exe
|
||||
|
||||
@ -54,6 +54,15 @@ libg719_decode.a:
|
||||
|
||||
libat3plusdecoder.a:
|
||||
$(MAKE) -C ../ext_libs -f Makefile.mingw $@
|
||||
|
||||
|
||||
libavcodec.a:
|
||||
$(MAKE) -C ../ext_libs -f Makefile.mingw $@
|
||||
|
||||
libavformat.a:
|
||||
$(MAKE) -C ../ext_libs -f Makefile.mingw $@
|
||||
|
||||
libavutil.a:
|
||||
$(MAKE) -C ../ext_libs -f Makefile.mingw $@
|
||||
|
||||
clean:
|
||||
rm -f test.exe
|
||||
|
@ -1,38 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include "streamfile.h"
|
||||
|
||||
char buf[0x1002];
|
||||
|
||||
int main(void) {
|
||||
STREAMFILE * infile;
|
||||
FILE * outfile;
|
||||
size_t filesize,i;
|
||||
|
||||
infile = open_streamfile("bob.bin");
|
||||
if (!infile) {
|
||||
printf("failed to open\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
outfile = fopen("fred.bin","wb");
|
||||
|
||||
filesize = get_streamfile_size(infile);
|
||||
|
||||
for (i=0;i<filesize;i+=0x1002) {
|
||||
size_t bytes_read = read_streamfile(buf,i,0x1002,infile);
|
||||
|
||||
fwrite(buf,1,bytes_read,outfile);
|
||||
|
||||
if (bytes_read != 0x1002) {
|
||||
if (bytes_read+i==filesize) break;
|
||||
printf("error, short read\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(outfile);
|
||||
|
||||
close_streamfile(infile);
|
||||
|
||||
return 0;
|
||||
}
|
178
test/vrts.bat
Normal file
178
test/vrts.bat
Normal file
@ -0,0 +1,178 @@
|
||||
@echo off
|
||||
chcp 65001
|
||||
REM #-------------------------------------------------------------------------
|
||||
REM # VGMSTREAM REGRESSION TESTING SCRIPT
|
||||
REM #
|
||||
REM # Searches for files in a directory (or optionally subdirs) and compares
|
||||
REM # the output of two test.exe versions, both wav and stdout, for regression
|
||||
REM # testing. This creates and deletes temp files, trying to process all
|
||||
REM # extensions found unless specified (except a few).
|
||||
REM #
|
||||
REM # Options: see below.
|
||||
REM #-------------------------------------------------------------------------
|
||||
REM #TODO: escape & ! % in file/folder names
|
||||
|
||||
setlocal enableDelayedExpansion
|
||||
|
||||
|
||||
REM #options
|
||||
REM # -vo <exe> -vn <exe>: path to old/new exe
|
||||
set OP_CMD_OLD=test_old.exe
|
||||
set OP_CMD_NEW=test.exe
|
||||
REM # -f <filename>: search wildcard (ex. -f "*.adx")
|
||||
set OP_SEARCH="*.*"
|
||||
REM # -r: recursive subfolders
|
||||
set OP_RECURSIVE=
|
||||
REM # -nd: don't delete compared files
|
||||
set OP_NODELETE=
|
||||
REM # -nc: don't report correct files
|
||||
set OP_NOCORRECT=
|
||||
|
||||
|
||||
REM # parse options
|
||||
:set_options
|
||||
if "%~1"=="" goto end_options
|
||||
if "%~1"=="-vo" set OP_CMD_OLD=%2
|
||||
if "%~1"=="-vn" set OP_CMD_NEW=%2
|
||||
if "%~1"=="-f" set OP_SEARCH=%2
|
||||
if "%~1"=="-r" set OP_RECURSIVE=/s
|
||||
if "%~1"=="-nd" set OP_NODELETE=true
|
||||
if "%~1"=="-nc" set OP_NOCORRECT=true
|
||||
shift
|
||||
goto set_options
|
||||
:end_options
|
||||
|
||||
REM # output color defs
|
||||
set C_W=0e
|
||||
set C_E=0c
|
||||
set C_O=0f
|
||||
|
||||
|
||||
REM # check exe
|
||||
set CMD_CHECK=where "%OP_CMD_OLD%" "%OP_CMD_NEW%"
|
||||
%CMD_CHECK% > nul
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo Old/new exe not found
|
||||
goto error
|
||||
)
|
||||
if %OP_SEARCH%=="" (
|
||||
echo Search wildcard not specified
|
||||
goto error
|
||||
)
|
||||
|
||||
REM # process start
|
||||
echo VRTS: start @%time%
|
||||
|
||||
REM # search for files
|
||||
set CMD_DIR=dir /a:-d /b %OP_RECURSIVE% %OP_SEARCH%
|
||||
set CMD_FIND=findstr /i /v "\.exe$ \.dll$ \.zip$ \.7z$ \.rar$ \.bat$ \.sh$ \.txt$ \.lnk$ \.wav$"
|
||||
|
||||
REM # process files
|
||||
for /f "delims=" %%x in ('%CMD_DIR% ^| %CMD_FIND%') do (
|
||||
set CMD_FILE=%%x
|
||||
call :process_file "!CMD_FILE!"
|
||||
)
|
||||
|
||||
REM # process end (ok)
|
||||
goto done
|
||||
|
||||
|
||||
REM # test a single file
|
||||
:process_file outer
|
||||
REM # ignore files starting with dot (no filename)
|
||||
set CMD_SHORTNAME=%~n1
|
||||
if "%CMD_SHORTNAME%" == "" goto continue
|
||||
|
||||
REM # get file
|
||||
set CMD_FILE=%1
|
||||
set CMD_FILE=%CMD_FILE:"=%
|
||||
REM echo VTRS: file %CMD_FILE%
|
||||
|
||||
REM # old/new temp output
|
||||
set WAV_OLD=%CMD_FILE%.old.wav
|
||||
set TXT_OLD=%CMD_FILE%.old.txt
|
||||
set CMD_VGM_OLD="%OP_CMD_OLD%" -o "%WAV_OLD%" "%CMD_FILE%"
|
||||
%CMD_VGM_OLD% 1> "%TXT_OLD%" 2>&1 & REM || goto error
|
||||
|
||||
set WAV_NEW=%CMD_FILE%.new.wav
|
||||
set TXT_NEW=%CMD_FILE%.new.txt
|
||||
set CMD_VGM_NEW="%OP_CMD_NEW%" -o "%WAV_NEW%" "%CMD_FILE%"
|
||||
%CMD_VGM_NEW% 1> "%TXT_NEW%" 2>&1 & REM || goto error
|
||||
|
||||
REM # ignore if no files are created (unsupported formats)
|
||||
if not exist "%WAV_NEW%" (
|
||||
if not exist "%WAV_OLD%" (
|
||||
REM echo VRTS: nothing created for file %CMD_FILE%
|
||||
if exist "%TXT_NEW%" del /a:a "%TXT_NEW%"
|
||||
if exist "%TXT_OLD%" del /a:a "%TXT_OLD%"
|
||||
goto continue
|
||||
)
|
||||
)
|
||||
|
||||
REM # compare files (doesn't use /b for speedup, somehow)
|
||||
set CMP_WAV=fc /a /lb1 "%WAV_OLD%" "%WAV_NEW%"
|
||||
set CMP_TXT=fc /a /lb1 "%TXT_OLD%" "%TXT_NEW%"
|
||||
|
||||
%CMP_WAV% 1> nul 2>&1
|
||||
set CMP_WAV_ERROR=0
|
||||
if %ERRORLEVEL% NEQ 0 set CMP_WAV_ERROR=1
|
||||
|
||||
%CMP_TXT% 1> nul 2>&1
|
||||
set CMP_TXT_ERROR=0
|
||||
if %ERRORLEVEL% NEQ 0 set CMP_TXT_ERROR=1
|
||||
|
||||
REM # print output
|
||||
if %CMP_WAV_ERROR% EQU 1 (
|
||||
if %CMP_TXT_ERROR% EQU 1 (
|
||||
call :echo_color %C_E% "%CMD_FILE%" "wav and txt diffs"
|
||||
) else (
|
||||
call :echo_color %C_E% "%CMD_FILE%" "wav diffs"
|
||||
)
|
||||
) else (
|
||||
if %CMP_TXT_ERROR% EQU 1 (
|
||||
call :echo_color %C_W% "%CMD_FILE%" "txt diffs"
|
||||
) else (
|
||||
if "%OP_NOCORRECT%" == "" (
|
||||
call :echo_color %C_O% "%CMD_FILE%" "no diffs"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
REM # delete temp files
|
||||
if "%OP_NODELETE%" == "" (
|
||||
if exist "%WAV_OLD%" del /a:a "%WAV_OLD%"
|
||||
if exist "%TXT_OLD%" del /a:a "%TXT_OLD%"
|
||||
if exist "%WAV_NEW%" del /a:a "%WAV_NEW%"
|
||||
if exist "%TXT_NEW%" del /a:a "%TXT_NEW%"
|
||||
)
|
||||
|
||||
:continue
|
||||
exit /B
|
||||
REM :process_file end, continue from last call
|
||||
|
||||
|
||||
REM # hack to get colored output in Windows CMD using findstr + temp file
|
||||
:echo_color
|
||||
set TEMP_FILE=%2-result
|
||||
set TEMP_FILE=%TEMP_FILE:"=%
|
||||
set TEMP_TEXT=%3
|
||||
set TEMP_TEXT=%TEMP_TEXT:"=%
|
||||
echo %TEMP_TEXT% > "%TEMP_FILE%"
|
||||
REM # show colored filename + any text in temp file
|
||||
findstr /v /a:%1 /r "^$" "%TEMP_FILE%" nul
|
||||
del "%TEMP_FILE%"
|
||||
exit /B
|
||||
REM :echo_color end, continue from last call
|
||||
|
||||
|
||||
:done
|
||||
echo VRTS: done @%time%
|
||||
goto exit
|
||||
|
||||
|
||||
:error
|
||||
echo VRTS: error @%time%
|
||||
goto exit
|
||||
|
||||
|
||||
:exit
|
@ -1,11 +1,11 @@
|
||||
# optional parts
|
||||
VGM_ENABLE_FFMPEG=0
|
||||
VGM_ENABLE_FFMPEG=1
|
||||
ifeq ($(VGM_ENABLE_FFMPEG),1)
|
||||
FFMPEG_CC=-DVGM_USE_FFMPEG -DVGM_USE_FFMPEG_ACCURATE_LOOPING -I../../vgmstream-ffmpeg/include
|
||||
FFMPEG_LD=-L../../vgmstream-ffmpeg/lib -lavcodec -lavformat -lavutil
|
||||
FFMPEG_CC=-DVGM_USE_FFMPEG -DVGM_USE_FFMPEG_ACCURATE_LOOPING
|
||||
FFMPEG_LD=-lavcodec -lavformat -lavutil
|
||||
endif
|
||||
|
||||
VGM_ENABLE_MAIATRAC3PLUS=1
|
||||
VGM_ENABLE_MAIATRAC3PLUS=0
|
||||
ifeq ($(VGM_ENABLE_MAIATRAC3PLUS),1)
|
||||
MAT3P_CC=-DVGM_USE_MAIATRAC3PLUS
|
||||
MAT3P_LD=-lat3plusdecoder
|
||||
@ -33,9 +33,9 @@ export WINDRES=i586-mingw32msvc-windres
|
||||
#export STRIP=i686-w64-mingw32-strip
|
||||
#export WINDRES=i686-w64-mingw32-windres
|
||||
|
||||
.PHONY: libvgmstream.a libvorbis.a libmpg123-0.a libg7221_decode.a libg719_decode.a at3plusdecoder.a
|
||||
.PHONY: libvgmstream.a libvorbis.a libmpg123-0.a libg7221_decode.a libg719_decode.a libat3plusdecoder.a libavcodec.a libavformat.a libavutil.a
|
||||
|
||||
in_vgmstream.dll: libvgmstream.a libvorbis.a libmpg123-0.a libg7221_decode.a libg719_decode.a libat3plusdecoder.a in_vgmstream.c resource.o
|
||||
in_vgmstream.dll: libvgmstream.a libvorbis.a libmpg123-0.a libg7221_decode.a libg719_decode.a libat3plusdecoder.a libavcodec.a libavformat.a libavutil.a resource.o
|
||||
$(CC) -shared -static-libgcc $(CFLAGS) "-DVERSION=\"`../version.sh`\"" in_vgmstream.c resource.o $(LDFLAGS) -o in_vgmstream.dll
|
||||
$(STRIP) in_vgmstream.dll
|
||||
|
||||
@ -60,5 +60,14 @@ libg719_decode.a:
|
||||
libat3plusdecoder.a:
|
||||
$(MAKE) -C ../ext_libs -f Makefile.mingw $@
|
||||
|
||||
libavcodec.a:
|
||||
$(MAKE) -C ../ext_libs -f Makefile.mingw $@
|
||||
|
||||
libavformat.a:
|
||||
$(MAKE) -C ../ext_libs -f Makefile.mingw $@
|
||||
|
||||
libavutil.a:
|
||||
$(MAKE) -C ../ext_libs -f Makefile.mingw $@
|
||||
|
||||
clean:
|
||||
rm -f in_vgmstream.dll resource.o
|
||||
|
@ -371,7 +371,6 @@ char * extension_list[] = {
|
||||
"zwdsp\0ZWDSP Audio File (*.ZWDSP)\0",
|
||||
|
||||
"vgmstream\0vgmstream Audio File (*.VGMSTREAM)\0",
|
||||
"vgms\00vgmstream Audio File (*.VGMS)\0",
|
||||
};
|
||||
|
||||
void about(HWND hwndParent) {
|
||||
|
@ -332,7 +332,7 @@ void __stdcall GetAdditionalFields(char* blerp) {
|
||||
XMPIN vgmstream_intf = {
|
||||
XMPIN_FLAG_CANSTREAM,
|
||||
"vgmstream for XMPlay",
|
||||
"vgmstream files\0""2dx9/aaap/aax/acm/adp/adpcm/ads/adx/afc/agsc/ahx/aifc/aiff/aix/amts/as4/asd/asf/asr/ass/ast/aud/aus/baf/baka/bar/bcstm/bcwav/bfstm/bfwav/bfwavnsmbu/bg00/bgw/bh2pcm/bmdx/bns/bnsf/bo2/brstm/caf/capdsp/ccc/cfn/cnk/dcs/dcsw/ddsp/de2/dmsg/dsp/dvi/dxh/eam/emff/enth/fag/filp/fsb/fwav/gca/gcm/gcsw/gcw/genh/gms/gsp/hca/hgc1/his/hps/hwas/idsp/idvi/ikm/ild/int/isd/ish/ivaud/ivb/joe/kces/kcey/khv/kraw/leg/logg/lps/lsf/lwav/matx/mcg/mi4/mib/mic/mihb/mpdsp/msa/mss/msvp/mus/musc/musx/mwv/myspd/ndp/npsf/nus3bank/nwa/omu/otm/p3d/pcm/pdt/pnb/pos/psh/psw/raw/rkv/rnd/rrds/rsd/rsf/rstm/rwar/rwav/rws/rwsd/rwx/rxw/s14/sab/sad/sap/sc/scd/sd9/sdt/seg/sfl/sfs/sl3/sli/smp/smpl/snd/sng/sns/spd/sps/spsd/spt/spw/ss2/ss7/ssm/sss/ster/sth/stm/stma/str/strm/sts/stx/svag/svs/swav/swd/tec/thp/tk5/tydsp/um3/vag/vas/vgs/vig/vjdsp/voi/vpk/vs/vsf/waa/wac/wad/wam/was/wavm/wb/wii/wp2/wsd/wsi/wvs/xa/xa2/xa30/xma/xma2/xmu/xss/xvas/xwav/xwb/ydsp/ymf/zsd/zwdsp/vgmstream/vgms",
|
||||
"vgmstream files\0""2dx9/aaap/aax/acm/adp/adpcm/ads/adx/afc/agsc/ahx/aifc/aiff/aix/amts/as4/asd/asf/asr/ass/ast/aud/aus/baf/baka/bar/bcstm/bcwav/bfstm/bfwav/bfwavnsmbu/bg00/bgw/bh2pcm/bmdx/bns/bnsf/bo2/brstm/caf/capdsp/ccc/cfn/cnk/dcs/dcsw/ddsp/de2/dmsg/dsp/dvi/dxh/eam/emff/enth/fag/filp/fsb/fwav/gca/gcm/gcsw/gcw/genh/gms/gsp/hca/hgc1/his/hps/hwas/idsp/idvi/ikm/ild/int/isd/ish/ivaud/ivb/joe/kces/kcey/khv/kraw/leg/logg/lps/lsf/lwav/matx/mcg/mi4/mib/mic/mihb/mpdsp/mca/msa/mss/msvp/mus/musc/musx/mwv/myspd/ndp/npsf/nus3bank/nwa/omu/otm/p3d/pcm/pdt/pnb/pos/psh/psw/raw/rkv/rnd/rrds/rsd/rsf/rstm/rwar/rwav/rws/rwsd/rwx/rxw/s14/sab/sad/sap/sc/scd/sd9/sdt/seg/sfl/sfs/sl3/sli/smp/smpl/snd/sng/sns/spd/sps/spsd/spt/spw/ss2/ss7/ssm/sss/ster/sth/stm/stma/str/strm/sts/stx/svag/svs/swav/swd/tec/thp/tk5/tydsp/um3/vag/vas/vgs/vig/vjdsp/voi/vpk/vs/vsf/waa/wac/wad/wam/was/wavm/wb/wii/wp2/wsd/wsi/wvs/xa/xa2/xa30/xma/xma2/xmu/xss/xvas/xwav/xwb/ydsp/ymf/zsd/zwdsp/vgmstream",
|
||||
XMPAbout,
|
||||
NULL,
|
||||
XMP_CheckFile,
|
||||
|
Loading…
Reference in New Issue
Block a user