diff --git a/README.md b/README.md index 1de80a91..c82368f0 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ left together. Similarly some formats split header and/or data in separate files (.sgh+sgd, .wav.str+.wav, (file)_L.dsp+(file)_R.dsp, etc). vgmstream will also detect -and use those as needed and must be tegether, even if only one of the two +and use those as needed and must be together, even if only one of the two will be used to play. .pos is a small file with 32 bit little endian values: loop start sample @@ -308,7 +308,7 @@ the format defined. ## Supported codec types -Quick list of codecs vgmstream supports, including many obscure ones that +Quick list of codecs vgmstream supports, including many obscure ones that are used in few games. - PCM 16-bit @@ -322,7 +322,7 @@ are used in few games. - Nintendo AFC ADPCM - ITU-T G.721 - CD-ROM XA ADPCM -- Sony PSX ADPCM a.k.a VAG (standard, badflags, configurable) +- Sony PSX ADPCM a.k.a VAG (standard, badflags, configurable, Pivotal) - Sony HEVAG - Electronic Arts EA-XA (stereo, mono, Maxis) - Electronic Arts EA-XAS (v0, v1) diff --git a/cli/vgmstream123.c b/cli/vgmstream123.c index d9e1a4cd..a4a84b2e 100644 --- a/cli/vgmstream123.c +++ b/cli/vgmstream123.c @@ -630,7 +630,7 @@ int main(int argc, char **argv) { goto done; } - again: +again: { struct params default_par = DEFAULT_PARAMS; @@ -639,6 +639,12 @@ int main(int argc, char **argv) { while ((opt = getopt(argc, argv, "-D:F:L:M:S:b:d:f:o:@:hrv")) != -1) { switch (opt) { + case 1: + if (play_file(optarg, &par)) { + status = 1; + goto done; + } + break; case '@': if (play_playlist(optarg, &par)) { status = 1; @@ -689,9 +695,12 @@ int main(int argc, char **argv) { verbose = 1; break; default: + VGM_LOG("vgmstream123: unknown opt %x", opt); goto done; } } + + /* try to read infile here in case getopt didn't pass "1" to the above switch I guess */ argc -= optind; argv += optind; @@ -707,7 +716,7 @@ int main(int argc, char **argv) { goto again; } - done: +done: if (device) ao_close(device); diff --git a/src/coding/coding.h b/src/coding/coding.h index 2707b2d8..f9499568 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -83,6 +83,7 @@ size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample); /* psx_decoder */ void decode_psx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int is_badflags); void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size); +void decode_psx_pivotal(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size); int ps_find_loop_offsets(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end); int ps_find_loop_offsets_full(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end); size_t ps_find_padding(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int discard_empty); @@ -108,10 +109,10 @@ void decode_ea_xas_v0(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspa void decode_ea_xas_v1(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); /* sdx2_decoder */ -void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); -void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); -void decode_cbd2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); -void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_sdx2(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_cbd2(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); /* ws_decoder */ void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); diff --git a/src/coding/psx_decoder.c b/src/coding/psx_decoder.c index 47c66ac7..f5e7ebd4 100644 --- a/src/coding/psx_decoder.c +++ b/src/coding/psx_decoder.c @@ -3,11 +3,11 @@ /* PS-ADPCM table, defined as rational numbers (as in the spec) */ static const double ps_adpcm_coefs_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 }, + { 0.0 , 0.0 }, //{ 0.0 , 0.0 }, + { 0.9375 , 0.0 }, //{ 60.0 / 64.0 , 0.0 }, + { 1.796875 , -0.8125 }, //{ 115.0 / 64.0 , -52.0 / 64.0 }, + { 1.53125 , -0.859375 }, //{ 98.0 / 64.0 , -55.0 / 64.0 }, + { 1.90625 , -0.9375 }, //{ 122.0 / 64.0 , -60.0 / 64.0 }, }; /* PS-ADPCM table, defined as spec_coef*64 (for int implementations) */ @@ -101,7 +101,7 @@ void decode_psx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing /* PS-ADPCM with configurable frame size and no flag (int math version). - * Found in some PC/PS3 games (FF XI in sizes 3/5/9/41, Afrika in size 4, Blur/James Bond in size 33, etc). + * Found in some PC/PS3 games (FF XI in sizes 0x3/0x5/0x9/0x41, Afrika in size 0x4, Blur/James Bond in size 0x33, etc). * * Uses int math to decode, which seems more likely (based on FF XI PC's code in Moogle Toolbox). */ void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size) { @@ -114,7 +114,7 @@ void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int c /* external interleave (variable size), mono */ bytes_per_frame = frame_size; - samples_per_frame = (bytes_per_frame - 0x01) * 2; /* always 28 */ + samples_per_frame = (bytes_per_frame - 0x01) * 2; frames_in = first_sample / samples_per_frame; first_sample = first_sample % samples_per_frame; @@ -152,6 +152,56 @@ void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int c stream->adpcm_history2_32 = hist2; } +/* PS-ADPCM from Pivotal games, exactly like psx_cfg but with float math (reverse engineered from the exe) */ +void decode_psx_pivotal(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size) { + off_t frame_offset; + int i, frames_in, sample_count = 0; + size_t bytes_per_frame, samples_per_frame; + uint8_t coef_index, shift_factor; + int32_t hist1 = stream->adpcm_history1_32; + int32_t hist2 = stream->adpcm_history2_32; + float scale; + + /* external interleave (variable size), mono */ + bytes_per_frame = frame_size; + samples_per_frame = (bytes_per_frame - 0x01) * 2; + frames_in = first_sample / samples_per_frame; + first_sample = first_sample % samples_per_frame; + + /* parse frame header */ + frame_offset = stream->offset + bytes_per_frame*frames_in; + coef_index = ((uint8_t)read_8bit(frame_offset+0x00,stream->streamfile) >> 4) & 0xf; + shift_factor = ((uint8_t)read_8bit(frame_offset+0x00,stream->streamfile) >> 0) & 0xf; + + VGM_ASSERT_ONCE(coef_index > 5 || shift_factor > 12, "PS-ADPCM: incorrect coefs/shift at %x\n", (uint32_t)frame_offset); + if (coef_index > 5) /* just in case */ + coef_index = 5; + if (shift_factor > 12) /* same */ + shift_factor = 12; + scale = (float)(1.0 / (double)(1 << shift_factor)); + + /* decode nibbles */ + for (i = first_sample; i < first_sample + samples_to_do; i++) { + int32_t sample = 0; + uint8_t nibbles = (uint8_t)read_8bit(frame_offset+0x01+i/2,stream->streamfile); + + sample = !(i&1) ? /* low nibble first */ + (nibbles >> 0) & 0x0f : + (nibbles >> 4) & 0x0f; + sample = (int16_t)((sample << 12) & 0xf000); /* 16b sign extend + default scale */ + sample = sample*scale + ps_adpcm_coefs_f[coef_index][0]*hist1 + ps_adpcm_coefs_f[coef_index][1]*hist2; /* actually substracts negative coefs but whatevs */ + + outbuf[sample_count] = clamp16(sample); + sample_count += channelspacing; + + hist2 = hist1; + hist1 = sample; /* not clamped but no difference */ + } + + stream->adpcm_history1_32 = hist1; + stream->adpcm_history2_32 = hist2; +} + /* Find loop samples in PS-ADPCM data and return if the file loops. * @@ -339,7 +389,8 @@ size_t ps_bytes_to_samples(size_t bytes, int channels) { } size_t ps_cfg_bytes_to_samples(size_t bytes, size_t frame_size, int channels) { - return bytes / channels / frame_size * 28; + int samples_per_frame = (frame_size - 0x01) * 2; + return bytes / channels / frame_size * samples_per_frame; } /* test PS-ADPCM frames for correctness */ diff --git a/src/coding/sdx2_decoder.c b/src/coding/sdx2_decoder.c index b911f511..ff6022c3 100644 --- a/src/coding/sdx2_decoder.c +++ b/src/coding/sdx2_decoder.c @@ -5,114 +5,112 @@ /* SDX2 - 2:1 Squareroot-delta-exact compression */ /* CBD2 - 2:1 Cuberoot-delta-exact compression (from the unreleased 3DO M2) */ -/* for (i=-128;i<128;i++) squares[i+128]=i<0?(-i*i)*2:(i*i)*2; */ +/* for (i=-128;i<128;i++) { squares[i+128] = i<0?(-i*i)*2:(i*i)*2; } */ static int16_t squares[256] = { --32768,-32258,-31752,-31250,-30752,-30258,-29768,-29282,-28800,-28322,-27848, --27378,-26912,-26450,-25992,-25538,-25088,-24642,-24200,-23762,-23328,-22898, --22472,-22050,-21632,-21218,-20808,-20402,-20000,-19602,-19208,-18818,-18432, --18050,-17672,-17298,-16928,-16562,-16200,-15842,-15488,-15138,-14792,-14450, --14112,-13778,-13448,-13122,-12800,-12482,-12168,-11858,-11552,-11250,-10952, --10658,-10368,-10082, -9800, -9522, -9248, -8978, -8712, -8450, -8192, -7938, - -7688, -7442, -7200, -6962, -6728, -6498, -6272, -6050, -5832, -5618, -5408, - -5202, -5000, -4802, -4608, -4418, -4232, -4050, -3872, -3698, -3528, -3362, - -3200, -3042, -2888, -2738, -2592, -2450, -2312, -2178, -2048, -1922, -1800, - -1682, -1568, -1458, -1352, -1250, -1152, -1058, -968, -882, -800, -722, - -648, -578, -512, -450, -392, -338, -288, -242, -200, -162, -128, - -98, -72, -50, -32, -18, -8, -2, 0, 2, 8, 18, - 32, 50, 72, 98, 128, 162, 200, 242, 288, 338, 392, - 450, 512, 578, 648, 722, 800, 882, 968, 1058, 1152, 1250, - 1352, 1458, 1568, 1682, 1800, 1922, 2048, 2178, 2312, 2450, 2592, - 2738, 2888, 3042, 3200, 3362, 3528, 3698, 3872, 4050, 4232, 4418, - 4608, 4802, 5000, 5202, 5408, 5618, 5832, 6050, 6272, 6498, 6728, - 6962, 7200, 7442, 7688, 7938, 8192, 8450, 8712, 8978, 9248, 9522, - 9800, 10082, 10368, 10658, 10952, 11250, 11552, 11858, 12168, 12482, 12800, - 13122, 13448, 13778, 14112, 14450, 14792, 15138, 15488, 15842, 16200, 16562, - 16928, 17298, 17672, 18050, 18432, 18818, 19208, 19602, 20000, 20402, 20808, - 21218, 21632, 22050, 22472, 22898, 23328, 23762, 24200, 24642, 25088, 25538, - 25992, 26450, 26912, 27378, 27848, 28322, 28800, 29282, 29768, 30258, 30752, - 31250, 31752, 32258 + -32768,-32258,-31752,-31250,-30752,-30258,-29768,-29282,-28800,-28322,-27848, + -27378,-26912,-26450,-25992,-25538,-25088,-24642,-24200,-23762,-23328,-22898, + -22472,-22050,-21632,-21218,-20808,-20402,-20000,-19602,-19208,-18818,-18432, + -18050,-17672,-17298,-16928,-16562,-16200,-15842,-15488,-15138,-14792,-14450, + -14112,-13778,-13448,-13122,-12800,-12482,-12168,-11858,-11552,-11250,-10952, + -10658,-10368,-10082, -9800, -9522, -9248, -8978, -8712, -8450, -8192, -7938, + -7688, -7442, -7200, -6962, -6728, -6498, -6272, -6050, -5832, -5618, -5408, + -5202, -5000, -4802, -4608, -4418, -4232, -4050, -3872, -3698, -3528, -3362, + -3200, -3042, -2888, -2738, -2592, -2450, -2312, -2178, -2048, -1922, -1800, + -1682, -1568, -1458, -1352, -1250, -1152, -1058, -968, -882, -800, -722, + -648, -578, -512, -450, -392, -338, -288, -242, -200, -162, -128, + -98, -72, -50, -32, -18, -8, -2, 0, 2, 8, 18, + 32, 50, 72, 98, 128, 162, 200, 242, 288, 338, 392, + 450, 512, 578, 648, 722, 800, 882, 968, 1058, 1152, 1250, + 1352, 1458, 1568, 1682, 1800, 1922, 2048, 2178, 2312, 2450, 2592, + 2738, 2888, 3042, 3200, 3362, 3528, 3698, 3872, 4050, 4232, 4418, + 4608, 4802, 5000, 5202, 5408, 5618, 5832, 6050, 6272, 6498, 6728, + 6962, 7200, 7442, 7688, 7938, 8192, 8450, 8712, 8978, 9248, 9522, + 9800, 10082, 10368, 10658, 10952, 11250, 11552, 11858, 12168, 12482, 12800, + 13122, 13448, 13778, 14112, 14450, 14792, 15138, 15488, 15842, 16200, 16562, + 16928, 17298, 17672, 18050, 18432, 18818, 19208, 19602, 20000, 20402, 20808, + 21218, 21632, 22050, 22472, 22898, 23328, 23762, 24200, 24642, 25088, 25538, + 25992, 26450, 26912, 27378, 27848, 28322, 28800, 29282, 29768, 30258, 30752, + 31250, 31752, 32258 }; -//for (i=-128;i<128;i++) -//{ -// double j = (i/2)/2.0; -// cubes[i+128]=floor(j*j*j); -//} -static int16_t cubes[256]={ --32768,-31256,-31256,-29791,-29791,-28373,-28373,-27000,-27000,-25672,-25672, --24389,-24389,-23149,-23149,-21952,-21952,-20797,-20797,-19683,-19683,-18610, --18610,-17576,-17576,-16581,-16581,-15625,-15625,-14706,-14706,-13824,-13824, --12978,-12978,-12167,-12167,-11391,-11391,-10648,-10648, -9938, -9938, -9261, - -9261, -8615, -8615, -8000, -8000, -7415, -7415, -6859, -6859, -6332, -6332, - -5832, -5832, -5359, -5359, -4913, -4913, -4492, -4492, -4096, -4096, -3724, - -3724, -3375, -3375, -3049, -3049, -2744, -2744, -2460, -2460, -2197, -2197, - -1953, -1953, -1728, -1728, -1521, -1521, -1331, -1331, -1158, -1158, -1000, - -1000, -857, -857, -729, -729, -614, -614, -512, -512, -422, -422, - -343, -343, -275, -275, -216, -216, -166, -166, -125, -125, -91, - -91, -64, -64, -43, -43, -27, -27, -16, -16, -8, -8, - -3, -3, -1, -1, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 3, 3, 8, 8, 16, 16, 27, 27, 43, - 43, 64, 64, 91, 91, 125, 125, 166, 166, 216, 216, - 275, 275, 343, 343, 422, 422, 512, 512, 614, 614, 729, - 729, 857, 857, 1000, 1000, 1158, 1158, 1331, 1331, 1521, 1521, - 1728, 1728, 1953, 1953, 2197, 2197, 2460, 2460, 2744, 2744, 3049, - 3049, 3375, 3375, 3724, 3724, 4096, 4096, 4492, 4492, 4913, 4913, - 5359, 5359, 5832, 5832, 6332, 6332, 6859, 6859, 7415, 7415, 8000, - 8000, 8615, 8615, 9261, 9261, 9938, 9938, 10648, 10648, 11391, 11391, - 12167, 12167, 12978, 12978, 13824, 13824, 14706, 14706, 15625, 15625, 16581, - 16581, 17576, 17576, 18610, 18610, 19683, 19683, 20797, 20797, 21952, 21952, - 23149, 23149, 24389, 24389, 25672, 25672, 27000, 27000, 28373, 28373, 29791, - 29791, 31256, 31256}; -static void decode_delta_exact(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int16_t * table) { +/* for (i=-128;i<128;i++) { double j = (i/2)/2.0; cubes[i+128] = floor(j*j*j); } */ +static int16_t cubes[256] = { + -32768,-31256,-31256,-29791,-29791,-28373,-28373,-27000,-27000,-25672,-25672, + -24389,-24389,-23149,-23149,-21952,-21952,-20797,-20797,-19683,-19683,-18610, + -18610,-17576,-17576,-16581,-16581,-15625,-15625,-14706,-14706,-13824,-13824, + -12978,-12978,-12167,-12167,-11391,-11391,-10648,-10648, -9938, -9938, -9261, + -9261, -8615, -8615, -8000, -8000, -7415, -7415, -6859, -6859, -6332, -6332, + -5832, -5832, -5359, -5359, -4913, -4913, -4492, -4492, -4096, -4096, -3724, + -3724, -3375, -3375, -3049, -3049, -2744, -2744, -2460, -2460, -2197, -2197, + -1953, -1953, -1728, -1728, -1521, -1521, -1331, -1331, -1158, -1158, -1000, + -1000, -857, -857, -729, -729, -614, -614, -512, -512, -422, -422, + -343, -343, -275, -275, -216, -216, -166, -166, -125, -125, -91, + -91, -64, -64, -43, -43, -27, -27, -16, -16, -8, -8, + -3, -3, -1, -1, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 3, 3, 8, 8, 16, 16, 27, 27, 43, + 43, 64, 64, 91, 91, 125, 125, 166, 166, 216, 216, + 275, 275, 343, 343, 422, 422, 512, 512, 614, 614, 729, + 729, 857, 857, 1000, 1000, 1158, 1158, 1331, 1331, 1521, 1521, + 1728, 1728, 1953, 1953, 2197, 2197, 2460, 2460, 2744, 2744, 3049, + 3049, 3375, 3375, 3724, 3724, 4096, 4096, 4492, 4492, 4913, 4913, + 5359, 5359, 5832, 5832, 6332, 6332, 6859, 6859, 7415, 7415, 8000, + 8000, 8615, 8615, 9261, 9261, 9938, 9938, 10648, 10648, 11391, 11391, + 12167, 12167, 12978, 12978, 13824, 13824, 14706, 14706, 15625, 15625, 16581, + 16581, 17576, 17576, 18610, 18610, 19683, 19683, 20797, 20797, 21952, 21952, + 23149, 23149, 24389, 24389, 25672, 25672, 27000, 27000, 28373, 28373, 29791, + 29791, 31256, 31256 +}; - int32_t hist = stream->adpcm_history1_32; +static void decode_delta_exact(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int16_t * table) { + int32_t hist = stream->adpcm_history1_32; - int i; - int32_t sample_count; - - for (i=first_sample,sample_count=0; ioffset+i,stream->streamfile); int16_t sample; if (!(sample_byte & 1)) hist = 0; sample = hist + table[sample_byte+128]; - hist = outbuf[sample_count] = clamp16(sample); - } - stream->adpcm_history1_32=hist; + hist = outbuf[sample_count] = clamp16(sample); + } + + stream->adpcm_history1_32 = hist; } -static void decode_delta_exact_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int16_t * table) { +static void decode_delta_exact_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int16_t * table) { + int32_t hist = stream->adpcm_history1_32; - int32_t hist = stream->adpcm_history1_32; + int i; + int32_t sample_count = 0; - int i; - int32_t sample_count; - - for (i=first_sample,sample_count=0; ioffset+i*channelspacing,stream->streamfile); int16_t sample; if (!(sample_byte & 1)) hist = 0; sample = hist + table[sample_byte+128]; - hist = outbuf[sample_count] = clamp16(sample); - } - stream->adpcm_history1_32=hist; + hist = outbuf[sample_count] = clamp16(sample); + } + + stream->adpcm_history1_32 = hist; } -void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_sdx2(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { decode_delta_exact(stream, outbuf, channelspacing, first_sample, samples_to_do, squares); } -void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { decode_delta_exact_int(stream, outbuf, channelspacing, first_sample, samples_to_do, squares); } -void decode_cbd2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_cbd2(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { decode_delta_exact(stream, outbuf, channelspacing, first_sample, samples_to_do, cubes); } -void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { decode_delta_exact_int(stream, outbuf, channelspacing, first_sample, samples_to_do, cubes); } diff --git a/src/formats.c b/src/formats.c index 861d844e..81278130 100644 --- a/src/formats.c +++ b/src/formats.c @@ -333,6 +333,7 @@ static const char* extension_list[] = { "pona", "pos", "ps2stm", //fake extension for .stm (renamed? to be removed?) + "psf", "psh", //fake extension for .vsv (to be removed) "psnd", "psw", //fake extension for .wam (renamed, to be removed) @@ -616,6 +617,7 @@ static const coding_info coding_info_list[] = { {coding_PSX, "Playstation 4-bit ADPCM"}, {coding_PSX_badflags, "Playstation 4-bit ADPCM (bad flags)"}, {coding_PSX_cfg, "Playstation 4-bit ADPCM (configurable)"}, + {coding_PSX_pivotal, "Playstation 4-bit ADPCM (Pivotal)"}, {coding_HEVAG, "Sony HEVAG 4-bit ADPCM"}, {coding_EA_XA, "Electronic Arts EA-XA 4-bit ADPCM v1"}, @@ -832,7 +834,7 @@ static const meta_info meta_info_list[] = { {meta_DSP_WSI, "Alone in the Dark .WSI header"}, {meta_AIFC, "Apple AIFF-C (Audio Interchange File Format) header"}, {meta_AIFF, "Apple AIFF (Audio Interchange File Format) header"}, - {meta_STR_SNDS, ".str SNDS SHDR chunk"}, + {meta_STR_SNDS, "3DO .str header"}, {meta_WS_AUD, "Westwood Studios .aud header"}, {meta_WS_AUD_old, "Westwood Studios .aud (old) header"}, {meta_PS2_IVB, "IVB/BVII header"}, @@ -881,7 +883,7 @@ static const meta_info meta_info_list[] = { {meta_SCD_PCM, "Lunar: Eternal Blue .PCM header"}, {meta_PS2_PCM, "Konami KCEJ East .PCM header"}, {meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV PS2 header"}, - {meta_PS2_VAS, "Pro Baseball Spirits 5 VAS Header"}, + {meta_PS2_VAS, "Konami .VAS header"}, {meta_PS2_TEC, "assumed TECMO badflagged stream by .tec extension"}, {meta_PS2_ENTH, ".enth Header"}, {meta_SDT, "High Voltage .sdt header"}, @@ -904,24 +906,7 @@ static const meta_info meta_info_list[] = { {meta_PS2_MIHB, "Sony MultiStream MIC header"}, {meta_DSP_WII_MUS, "mus header"}, {meta_WII_SNG, "SNG DSP Header"}, - {meta_RSD2VAG, "Radical RSD2/VAG header"}, - {meta_RSD2PCMB, "Radical RSD2/PCMB header"}, - {meta_RSD2XADP, "Radical RSD2/XADP header"}, - {meta_RSD3VAG, "Radical RSD3/VAG header"}, - {meta_RSD3GADP, "Radical RSD3/GADP header"}, - {meta_RSD3PCM, "Radical RSD3/PCM header"}, - {meta_RSD3PCMB, "Radical RSD3/PCMB header"}, - {meta_RSD4PCMB, "Radical RSD4/PCMB header"}, - {meta_RSD4PCM, "Radical RSD4/PCM header"}, - {meta_RSD4RADP, "Radical RSD4/RADP header"}, - {meta_RSD4VAG, "Radical RSD4/VAG header"}, - {meta_RSD6XADP, "Radical RSD6/XADP header"}, - {meta_RSD6VAG, "Radical RSD6/VAG header"}, - {meta_RSD6WADP, "Radical RSD6/WADP header"}, - {meta_RSD6RADP, "Radical RSD6/RADP header"}, - {meta_RSD6XMA, "Radical RSD6/XMA header"}, - {meta_RSD6AT3P, "Radical RSD6/AT3+ header"}, - {meta_RSD6WMA, "Radical RSD6/WMA header"}, + {meta_RSD, "Radical RSD header"}, {meta_DC_ASD, "ASD Header"}, {meta_NAOMI_SPSD, "Naomi SPSD header"}, {meta_FFXI_BGW, "Square Enix .BGW header"}, @@ -980,7 +965,6 @@ static const meta_info meta_info_list[] = { {meta_PS2_VGV, "Rune: Viking Warlord VGV Header"}, {meta_NGC_GCUB, "GCub Header"}, {meta_NGC_SCK_DSP, "The Scorpion King SCK Header"}, - {meta_NGC_SWD, "PSF + Standard DSP Headers"}, {meta_CAFF, "Apple Core Audio Format File header"}, {meta_PC_MXST, "Lego Island MxSt Header"}, {meta_SAB, "Team17 SAB header"}, @@ -1063,7 +1047,6 @@ static const meta_info meta_info_list[] = { {meta_PS2_HSF, "Lowrider 'HSF' header"}, {meta_PS3_IVAG, "PS3 'IVAG' Header"}, {meta_PS2_2PFS, "Konami 2PFS header"}, - {meta_RSD6OOGV, "RSD6/OOGV Header"}, {meta_UBI_CKD, "Ubisoft CKD RIFF header"}, {meta_PS2_VBK, "PS2 VBK Header"}, {meta_OTM, "Otomedius OTM Header"}, @@ -1205,6 +1188,8 @@ static const meta_info meta_info_list[] = { {meta_SMACKER, "RAD Game Tools SMACKER header"}, {meta_MZRT, "id Software MZRT header"}, {meta_XAVS, "Reflections XAVS header"}, + {meta_PSF, "Pivotal PSF header"}, + {meta_DSP_ITL_i, "Infernal .ITL DSP header"}, }; diff --git a/src/layout/interleave.c b/src/layout/interleave.c index d61cc3e2..94715a3f 100644 --- a/src/layout/interleave.c +++ b/src/layout/interleave.c @@ -8,19 +8,48 @@ * Incompatible with decoders that move offsets. */ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { int samples_written = 0; - int frame_size, samples_per_frame, samples_this_block; + int samples_per_frame, samples_this_block; /* used */ + int samples_per_frame_d = 0, samples_this_block_d = 0; /* default */ + int samples_per_frame_f = 0, samples_this_block_f = 0; /* first */ + int samples_per_frame_l = 0, samples_this_block_l = 0; /* last */ + int has_interleave_first = vgmstream->interleave_first_block_size && vgmstream->channels > 1; int has_interleave_last = vgmstream->interleave_last_block_size && vgmstream->channels > 1; - frame_size = get_vgmstream_frame_size(vgmstream); - samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); - samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame; - if (has_interleave_last && - vgmstream->current_sample - vgmstream->samples_into_block + samples_this_block > vgmstream->num_samples) { - /* adjust values again if inside last interleave */ - frame_size = get_vgmstream_shortframe_size(vgmstream); - samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream); - samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame; + /* setup */ + { + int frame_size_d = get_vgmstream_frame_size(vgmstream); + samples_per_frame_d = get_vgmstream_samples_per_frame(vgmstream); + if (frame_size_d == 0 || samples_per_frame_d == 0) goto fail; + samples_this_block_d = vgmstream->interleave_block_size / frame_size_d * samples_per_frame_d; + } + if (has_interleave_first) { + int frame_size_f = get_vgmstream_frame_size(vgmstream); + samples_per_frame_f = get_vgmstream_samples_per_frame(vgmstream); //todo samples per shortframe + if (frame_size_f == 0 || samples_per_frame_f == 0) goto fail; + samples_this_block_f = vgmstream->interleave_first_block_size / frame_size_f * samples_per_frame_f; + } + if (has_interleave_last) { + int frame_size_l = get_vgmstream_shortframe_size(vgmstream); + samples_per_frame_l = get_vgmstream_samples_per_shortframe(vgmstream); + if (frame_size_l == 0 || samples_per_frame_l == 0) goto fail; + samples_this_block_l = vgmstream->interleave_last_block_size / frame_size_l * samples_per_frame_l; + } + + /* set current values */ + if (has_interleave_first && + vgmstream->current_sample < samples_this_block_f) { + samples_per_frame = samples_per_frame_f; + samples_this_block = samples_this_block_f; + } + else if (has_interleave_last && + vgmstream->current_sample - vgmstream->samples_into_block + samples_this_block_d > vgmstream->num_samples) { + samples_per_frame = samples_per_frame_l; + samples_this_block = samples_this_block_l; + } + else { + samples_per_frame = samples_per_frame_d; + samples_this_block = samples_this_block_d; } /* mono interleaved stream with no layout set, just behave like flat layout */ @@ -28,18 +57,28 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR samples_this_block = vgmstream->num_samples; + /* write samples */ while (samples_written < sample_count) { int samples_to_do; if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { /* handle looping, restore standard interleave sizes */ - if (has_interleave_last) { /* assumes that won't loop back into a interleave_last */ - frame_size = get_vgmstream_frame_size(vgmstream); - samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); - samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame; + + if (has_interleave_first && + vgmstream->current_sample < samples_this_block_f) { + /* use first interleave*/ + samples_per_frame = samples_per_frame_f; + samples_this_block = samples_this_block_f; if (samples_this_block == 0 && vgmstream->channels == 1) samples_this_block = vgmstream->num_samples; } + else if (has_interleave_last) { /* assumes that won't loop back into a interleave_last */ + samples_per_frame = samples_per_frame_d; + samples_this_block = samples_this_block_d; + if (samples_this_block == 0 && vgmstream->channels == 1) + samples_this_block = vgmstream->num_samples; + } + continue; } @@ -48,9 +87,7 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR samples_to_do = sample_count - samples_written; if (samples_to_do == 0) { /* happens when interleave is not set */ - VGM_LOG("layout_interleave: wrong samples_to_do found\n"); - memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample_t)); - break; + goto fail; } decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer); @@ -64,18 +101,34 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR if (vgmstream->samples_into_block == samples_this_block) { int ch; - if (has_interleave_last && - vgmstream->current_sample + samples_this_block > vgmstream->num_samples) { - /* adjust values again if inside last interleave */ - frame_size = get_vgmstream_shortframe_size(vgmstream); - samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream); - samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame; + if (has_interleave_first && + vgmstream->current_sample == samples_this_block_f) { + /* restore standard frame size after going past first interleave */ + samples_per_frame = samples_per_frame_d; + samples_this_block = samples_this_block_d; if (samples_this_block == 0 && vgmstream->channels == 1) samples_this_block = vgmstream->num_samples; for (ch = 0; ch < vgmstream->channels; ch++) { - off_t skip = vgmstream->interleave_block_size*(vgmstream->channels-ch) + - vgmstream->interleave_last_block_size*ch;; + off_t skip = + vgmstream->interleave_first_skip*(vgmstream->channels-1-ch) + + vgmstream->interleave_first_block_size*(vgmstream->channels-ch) + + vgmstream->interleave_block_size*ch; + vgmstream->ch[ch].offset += skip; + } + } + else if (has_interleave_last && + vgmstream->current_sample + samples_this_block > vgmstream->num_samples) { + /* adjust values again if inside last interleave */ + samples_per_frame = samples_per_frame_l; + samples_this_block = samples_this_block_l; + if (samples_this_block == 0 && vgmstream->channels == 1) + samples_this_block = vgmstream->num_samples; + + for (ch = 0; ch < vgmstream->channels; ch++) { + off_t skip = + vgmstream->interleave_block_size*(vgmstream->channels-ch) + + vgmstream->interleave_last_block_size*ch; vgmstream->ch[ch].offset += skip; } } @@ -88,6 +141,9 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR vgmstream->samples_into_block = 0; } - } + return; +fail: + VGM_LOG("layout_interleave: wrong values found\n"); + memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample_t)); } diff --git a/src/layout/segmented.c b/src/layout/segmented.c index 2c2e18c8..3477bf4c 100644 --- a/src/layout/segmented.c +++ b/src/layout/segmented.c @@ -2,7 +2,7 @@ #include "../vgmstream.h" #include "../mixing.h" -#define VGMSTREAM_MAX_SEGMENTS 255 +#define VGMSTREAM_MAX_SEGMENTS 512 #define VGMSTREAM_SEGMENT_SAMPLE_BUFFER 8192 diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index aa7aa84e..e04fbe58 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -1366,10 +1366,14 @@ RelativePath=".\meta\mta2.c" > - - + + + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 892a9e48..de48b9dc 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -195,6 +195,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 454f77e6..0eecc019 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -1369,6 +1369,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files diff --git a/src/meta/adpcm_capcom.c b/src/meta/adpcm_capcom.c index e55ee8d2..c6e83a51 100644 --- a/src/meta/adpcm_capcom.c +++ b/src/meta/adpcm_capcom.c @@ -11,7 +11,8 @@ VGMSTREAM * init_vgmstream_adpcm_capcom(STREAMFILE *streamFile) { /* checks */ - if (!check_extensions(streamFile,"adpcm")) + /* .mca: Monster Hunter Generations Ultimate / XX */ + if (!check_extensions(streamFile,"adpcm,mca")) goto fail; if (read_32bitBE(0x00,streamFile) != 0x02000000) goto fail; diff --git a/src/meta/meta.h b/src/meta/meta.h index 24b69c4f..73af3cbf 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -31,7 +31,6 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_idsp_nus3(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_sadb(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_sadf(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_ngc_swd(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_idsp_nl(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_wii_wsd(STREAMFILE *streamFile); @@ -51,6 +50,7 @@ VGMSTREAM * init_vgmstream_dsp_itl_ch(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_dsp_adpy(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_dsp_adpx(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_dsp_ds2(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_dsp_itl(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_csmp(STREAMFILE *streamFile); @@ -240,6 +240,7 @@ VGMSTREAM * init_vgmstream_ps2_pcm(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ps2_rkv(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ps2_vas(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ps2_tec(STREAMFILE * streamFile); @@ -302,25 +303,7 @@ VGMSTREAM * init_vgmstream_ngc_pdt(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_wii_mus(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd2vag(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd2pcmb(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd2xadp(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd3pcm(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd3pcmb(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd3gadp(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd3vag(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd4pcmb(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd4pcm(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd4radp(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd4vag(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd6vag(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd6wadp(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd6xadp(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd6radp(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd6oogv(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_rsd6xma(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_rsd6at3p(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_rsd6wma(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_rsd(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_dc_asd(STREAMFILE * streamFile); @@ -871,4 +854,7 @@ VGMSTREAM * init_vgmstream_mzrt(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_xavs(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_psf_single(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_psf_segmented(STREAMFILE * streamFile); + #endif /*_META_H*/ diff --git a/src/meta/ngc_dsp_std.c b/src/meta/ngc_dsp_std.c index f00024c4..b6f65464 100644 --- a/src/meta/ngc_dsp_std.c +++ b/src/meta/ngc_dsp_std.c @@ -79,6 +79,8 @@ typedef struct { size_t header_spacing; /* distance between DSP header of other channels */ off_t start_offset; /* data start */ size_t interleave; /* distance between data of other channels */ + size_t interleave_first; /* same, in the first block */ + size_t interleave_first_skip; /* extra info */ size_t interleave_last; /* same, in the last block */ meta_t meta_type; @@ -208,6 +210,8 @@ static VGMSTREAM * init_vgmstream_dsp_common(STREAMFILE *streamFile, dsp_meta *d if (dspm->interleave == 0 || vgmstream->coding_type == coding_NGC_DSP_subint) vgmstream->layout_type = layout_none; vgmstream->interleave_block_size = dspm->interleave; + vgmstream->interleave_first_block_size = dspm->interleave_first; + vgmstream->interleave_first_skip = dspm->interleave_first_skip; vgmstream->interleave_last_block_size = dspm->interleave_last; { @@ -690,33 +694,6 @@ fail: return NULL; } -/* SWD - PSF chunks + interleaved dsps [Conflict: Desert Storm 1 & 2] */ -VGMSTREAM * init_vgmstream_ngc_swd(STREAMFILE *streamFile) { - dsp_meta dspm = {0}; - - /* checks */ - if (!check_extensions(streamFile, "swd")) - goto fail; - - //todo blocked layout when first chunk is 0x50534631 (count + table of 0x0c with offset/sizes) - - if (read_32bitBE(0x00,streamFile) != 0x505346d1) /* PSF\0xd1 */ - goto fail; - - dspm.channel_count = 2; - dspm.max_channels = 2; - - dspm.header_offset = 0x08; - dspm.header_spacing = 0x60; - dspm.start_offset = dspm.header_offset + 0x60 * dspm.channel_count; - dspm.interleave = 0x08; - - dspm.meta_type = meta_NGC_SWD; - return init_vgmstream_dsp_common(streamFile, &dspm); -fail: - return NULL; -} - /* IDSP - Traveller's Tales header + interleaved dsps [Lego Batman (Wii), Lego Dimensions (Wii U)] */ VGMSTREAM * init_vgmstream_idsp_tt(STREAMFILE *streamFile) { dsp_meta dspm = {0}; @@ -1278,3 +1255,34 @@ VGMSTREAM * init_vgmstream_dsp_ds2(STREAMFILE *streamFile) { fail: return NULL; } + +/* .itl - Incinerator Studios interleaved dsp [Cars Race-o-rama (Wii), MX vs ATV Untamed (Wii)] */ +VGMSTREAM * init_vgmstream_dsp_itl(STREAMFILE *streamFile) { + dsp_meta dspm = {0}; + size_t stream_size; + + /* checks */ + /* .itl: standard + * .dsp: default to catch a similar file, not sure which devs */ + if (!check_extensions(streamFile, "itl,dsp")) + goto fail; + + stream_size = get_streamfile_size(streamFile); + dspm.channel_count = 2; + dspm.max_channels = 2; + + dspm.start_offset = 0x60; + dspm.interleave = 0x10000; + dspm.interleave_first_skip = dspm.start_offset; + dspm.interleave_first = dspm.interleave - dspm.interleave_first_skip; + dspm.interleave_last = (stream_size / dspm.channel_count) % dspm.interleave; + dspm.header_offset = 0x00; + dspm.header_spacing = dspm.interleave; + + //todo some files end in half a frame and may click at the very end + //todo when .dsp should refer to Ultimate Board Collection (Wii), not sure about dev + dspm.meta_type = meta_DSP_ITL_i; + return init_vgmstream_dsp_common(streamFile, &dspm); +fail: + return NULL; +} diff --git a/src/meta/ogg_vorbis.c b/src/meta/ogg_vorbis.c index 6847a6d1..da7e38cc 100644 --- a/src/meta/ogg_vorbis.c +++ b/src/meta/ogg_vorbis.c @@ -108,12 +108,16 @@ static void kovs_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, v } static void psychic_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) { + ogg_vorbis_streamfile * const ov_streamfile = datasource; size_t bytes_read = size*nmemb; + uint8_t key[6] = { 0x23,0x31,0x20,0x2e,0x2e,0x28 }; int i; - /* bytes add 0x23 ('#') */ //todo incorrect, add changes every 0x64 bytes + //todo incorrect, picked value changes (fixed order for all files), or key is bigger + /* bytes add key that changes every 0x64 bytes */ for (i = 0; i < bytes_read; i++) { - ((uint8_t*)ptr)[i] += 0x23; + int pos = (ov_streamfile->offset + i) / 0x64; + ((uint8_t*)ptr)[i] += key[pos % sizeof(key)]; } } @@ -455,6 +459,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb ogg_vorbis_codec_data * data = NULL; OggVorbis_File *ovf = NULL; vorbis_info *vi; + char name[STREAM_NAME_SIZE] = {0}; int loop_flag = ovmi->loop_flag; int32_t loop_start = ovmi->loop_start; @@ -626,6 +631,10 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb data->disable_reordering = 1; } + if (strstr(user_comment, "TITLE=") == user_comment) { + strncpy(name, user_comment + 6, sizeof(name) - 1); + } + ;VGM_LOG("OGG: user_comment=%s\n", user_comment); } } @@ -638,9 +647,14 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb vgmstream->codec_data = data; /* store our fun extra datas */ vgmstream->channels = vi->channels; vgmstream->sample_rate = vi->rate; - vgmstream->num_streams = ovmi->total_subsongs; vgmstream->stream_size = stream_size; + if (ovmi->total_subsongs) /* not setting it has some effect when showing stream names */ + vgmstream->num_streams = ovmi->total_subsongs; + + if (name[0] != '\0') + strcpy(vgmstream->stream_name, name); + vgmstream->num_samples = ov_pcm_total(ovf,-1); /* let libvorbisfile find total samples */ if (loop_flag) { vgmstream->loop_start_sample = loop_start; diff --git a/src/meta/ps2_vas.c b/src/meta/ps2_vas.c index b4e279e3..806f7822 100644 --- a/src/meta/ps2_vas.c +++ b/src/meta/ps2_vas.c @@ -1,66 +1,122 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* VAS (from Pro Baseball Spirits 5) */ + +/* .VAS - from Konami Jikkyou Powerful Pro Yakyuu games */ VGMSTREAM * init_vgmstream_ps2_vas(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; off_t start_offset; - int loop_flag; - int channel_count; + int loop_flag, channel_count; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("vas",filename_extension(filename))) goto fail; - /* check header */ -#if 0 - if (read_32bitBE(0x00,streamFile) != 0x00000000) /* 0x0 */ + /* checks */ + if (!check_extensions(streamFile, "vas")) + goto fail; + if (read_32bitLE(0x00,streamFile) + 0x800 != get_streamfile_size(streamFile)) goto fail; -#endif - loop_flag = (read_32bitLE(0x10,streamFile)!=0); + loop_flag = (read_32bitLE(0x10,streamFile) != 0); channel_count = 2; - - /* build the VGMSTREAM */ + start_offset = 0x800; + + /* header is too simple so test a bit */ + if (!ps_check_format(streamFile, start_offset, 0x1000)) + goto fail; + + + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = 0x800; - vgmstream->channels = channel_count; + vgmstream->meta_type = meta_PS2_VAS; vgmstream->sample_rate = read_32bitLE(0x04,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = read_32bitLE(0x00,streamFile)*28/16/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile)*28/16/channel_count; - vgmstream->loop_end_sample = read_32bitLE(0x00,streamFile)*28/16/channel_count; - } + vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x200; - vgmstream->meta_type = meta_PS2_VAS; - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } + vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x00,streamFile), channel_count); + vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitLE(0x14,streamFile), channel_count); + vgmstream->loop_end_sample = vgmstream->num_samples; + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); + return NULL; +} + + +/* .VAS in containers */ +VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE *streamFile) { + VGMSTREAM *vgmstream = NULL; + STREAMFILE *temp_streamFile = NULL; + off_t subfile_offset = 0; + size_t subfile_size = 0; + int total_subsongs, target_subsong = streamFile->stream_index; + int has_table; + + + /* checks */ + if (!check_extensions(streamFile, "vas")) + goto fail; + + if (read_32bitBE(0x00, streamFile) != 0xAB8A5A00) /* fixed value */ + goto fail; + if (read_32bitLE(0x04, streamFile)*0x800 + 0x800 != get_streamfile_size(streamFile)) /* just in case */ + goto fail; + + /* offset table, 0x98 has table size */ + has_table = read_32bitLE(0x94, streamFile); + + + total_subsongs = read_32bitLE(0x08, streamFile); /* also at 0x10 */ + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; + + + if (has_table) { + off_t header_offset = 0x800 + 0x10*(target_subsong-1); + + /* some values are repeats found in the file sub-header */ + subfile_offset = read_32bitLE(header_offset + 0x00,streamFile) * 0x800; + subfile_size = read_32bitLE(header_offset + 0x08,streamFile) + 0x800; + } + else { + /* a bunch of files */ + off_t offset = 0x800; + int i; + + for (i = 0; i < total_subsongs; i++) { + size_t size = read_32bitLE(offset, streamFile) + 0x800; + + if (i + 1 == target_subsong) { + subfile_offset = offset; + subfile_size = size; + break; + } + + offset += size; + } + if (i == total_subsongs) + goto fail; + } + + temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL); + if (!temp_streamFile) goto fail; + + vgmstream = init_vgmstream_ps2_vas(temp_streamFile); + if (!vgmstream) goto fail; + + vgmstream->num_streams = total_subsongs; + + close_streamfile(temp_streamFile); + return vgmstream; + +fail: + close_streamfile(temp_streamFile); + close_vgmstream(vgmstream); return NULL; } diff --git a/src/meta/psf.c b/src/meta/psf.c new file mode 100644 index 00000000..a7f79ef4 --- /dev/null +++ b/src/meta/psf.c @@ -0,0 +1,242 @@ +#include "meta.h" +#include "../layout/layout.h" +#include "../coding/coding.h" + + +/* PSF single - Pivotal games single segment (external in some PC/Xbox or inside bigfiles) [The Great Escape, Conflict series] */ +VGMSTREAM * init_vgmstream_psf_single(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag, channel_count, sample_rate, rate_value, interleave; + uint32_t psf_config; + uint8_t flags; + size_t data_size; + coding_t codec; + + + /* checks */ + /* .psf: actual extension + * .swd: bigfile extension */ + if (!check_extensions(streamFile, "psf,swd")) + goto fail; + if ((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) != 0x50534600) /* "PSF\00" */ + goto fail; + + flags = read_8bit(0x03,streamFile); + switch(flags) { + case 0xC0: /* [The Great Escape (PS2), Conflict: Desert Storm (PS2)] */ + case 0xA1: /* [Conflict: Desert Storm 2 (PS2)] */ + case 0x21: /* [Conflict: Desert Storm 2 (PS2), Conflict: Global Storm (PS2)] */ + //case 0x22: /* [Conflict: Vietman (PS2)] */ //todo weird size value, stereo, only one found + channel_count = 2; + if (flags == 0x21) + channel_count = 1; + interleave = 0x10; + codec = coding_PSX; + start_offset = 0x08; + break; + + case 0x80: /* [The Great Escape (PC/Xbox), Conflict: Desert Storm (Xbox/GC), Conflict: Desert Storm 2 (Xbox)] */ + case 0x81: /* [Conflict: Desert Storm 2 (Xbox), Conflict: Vietnam (Xbox)] */ + case 0x01: /* [Conflict: Global Storm (Xbox)] */ + channel_count = 2; + if (flags == 0x01) + channel_count = 1; + interleave = 0x10; + codec = coding_PSX_pivotal; + start_offset = 0x08; + break; + + case 0xD1: /* [Conflict: Desert Storm 2 (GC)] */ + channel_count = 2; + interleave = 0x08; + codec = coding_NGC_DSP; + start_offset = 0x08 + 0x60 * channel_count; + break; + + default: + goto fail; + } + + loop_flag = 0; + + psf_config = read_32bitLE(0x04, streamFile); + + /* pitch/cents? */ + rate_value = (psf_config >> 20) & 0xFFF; + switch(rate_value) { + //case 0xEB5: + //case 0xEB4: + case 0xEB3: sample_rate = 44100; break; + case 0x555: sample_rate = 16000; break; + case 0x355: sample_rate = 11050; break; + case 0x1d5: sample_rate = 6000; break; /* ? */ + case 0x1cc: sample_rate = 5000; break; + default: + VGM_LOG("PSF: unknown rate value %x\n", rate_value); + goto fail; + } + + data_size = (psf_config & 0xFFFFF) * (interleave * channel_count); /* in blocks */ + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_PSF; + vgmstream->sample_rate = sample_rate; + + switch(codec) { + case coding_PSX: + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + + vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count); + break; + + case coding_PSX_pivotal: + vgmstream->coding_type = coding_PSX_pivotal; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + + vgmstream->num_samples = ps_cfg_bytes_to_samples(data_size, 0x10, channel_count); + break; + + case coding_NGC_DSP: + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + /* has standard DSP headers at 0x08 */ + dsp_read_coefs_be(vgmstream,streamFile,0x08+0x1c,0x60); + dsp_read_hist_be (vgmstream,streamFile,0x08+0x40,0x60); + + vgmstream->num_samples = read_32bitBE(0x08, streamFile);//dsp_bytes_to_samples(data_size, channel_count); + break; + + default: + goto fail; + } + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + +/* PSF segmented - Pivotal games multiple segments (external in some PC/Xbox or inside bigfiles) [The Great Escape, Conflict series] */ +VGMSTREAM * init_vgmstream_psf_segmented(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + STREAMFILE* temp_streamFile = NULL; + segmented_layout_data *data = NULL; + int i, segment_count, loop_flag = 0, loop_start = 0, loop_end = 0; + off_t offset; + + + /* checks */ + /* .psf: actual extension + * .swd: bigfile extension */ + if (!check_extensions(streamFile, "psf,swd")) + goto fail; + + if (read_32bitBE(0x00,streamFile) != 0x50534660 && /* "PSF\60" [The Great Escape (PC/Xbox/PS2), Conflict: Desert Storm (Xbox/GC)] */ + read_32bitBE(0x00,streamFile) != 0x50534631) /* "PSF\31" [Conflict: Desert Storm 2 (Xbox/GC/PS2)] */ + goto fail; + + segment_count = read_32bitLE(0x04, streamFile); + loop_flag = 0; + + offset = 0x08; + offset += 0x0c; /* first segment points to itself? */ + segment_count--; + + /* build segments */ + data = init_layout_segmented(segment_count); + if (!data) goto fail; + + for (i = 0; i < segment_count; i++) { + off_t psf_offset; + size_t psf_size; + uint32_t psf_id; + + /* mini table */ + psf_offset = read_32bitLE(offset + 0x00, streamFile); + /* 0x04-0c: 0x02*4 transition segments (possibly to 4 song variations) */ + + /* use last section transition as loop */ + if (i + 1 == segment_count) { + loop_flag = 1; + loop_start = read_16bitLE(offset + 0x0a, streamFile) - 1; /* also ignore first segment */ + loop_end = i; + } + + /* multiple segment can point to the same PSF offset (for repeated song sections) */ + //todo reuse repeated VGMSTREAMs to improve memory a bit + + psf_id = read_32bitBE(psf_offset + 0x00, streamFile); + psf_size = read_32bitLE(psf_offset + 0x04, streamFile); + if (psf_id == 0x505346D1) //todo improve + psf_size = (psf_size & 0xFFFFF) * 0x10; + else + psf_size = (psf_size & 0xFFFFF) * 0x20; + //;VGM_LOG("PSF: offset=%lx, size=%x\n", psf_offset, psf_size); + + temp_streamFile = setup_subfile_streamfile(streamFile, psf_offset, psf_size, "psf"); + if (!temp_streamFile) goto fail; + + data->segments[i] = init_vgmstream_psf_single(temp_streamFile); + if (!data->segments[i]) goto fail; + + offset += 0x0c; + } + + /* setup VGMSTREAMs */ + if (!setup_layout_segmented(data)) + goto fail; + vgmstream = allocate_segmented_vgmstream(data,loop_flag, loop_start, loop_end); + if (!vgmstream) goto fail; + + vgmstream->stream_size = get_streamfile_size(streamFile); + + return vgmstream; +fail: + if (!vgmstream) free_layout_segmented(data); + close_streamfile(temp_streamFile); + close_vgmstream(vgmstream); + return NULL; +} + +#if 0 +VGMSTREAM * init_vgmstream_sch(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag, channel_count; + + + /* checks */ + if (!check_extensions(streamFile, "sch")) + goto fail; + + /* chunked format (id+size, GC pads to 0x20 and uses BE/inverted ids): + * - SCH\0: start + * - IMUS: points to a external .psf + segment table (same as in .psf, TGE only?) + * - BANK: volume/etc info? points to something? + * - PFSM: single .psf-like file (larger header) + * - PFST: points to single PSF offset (.psf in TGE, or STREAMS.SWD); may be chained to next PFST? + * + * no other info so total subsongs would be count of usable chunks + * in later games, segmented .psf seems to be removed and PFST is used instead + */ + + return vgmstream; +fail: + if (!vgmstream) free_layout_layered(data); + close_streamfile(temp_streamFile); + close_vgmstream(vgmstream); + return NULL; +} +#endif diff --git a/src/meta/rsd.c b/src/meta/rsd.c index e40b3b74..188de02f 100644 --- a/src/meta/rsd.c +++ b/src/meta/rsd.c @@ -1,1197 +1,229 @@ #include "meta.h" -#include "../util.h" #include "../coding/coding.h" -/* RSD */ -/* RSD2VAG */ -VGMSTREAM * init_vgmstream_rsd2vag(STREAMFILE *streamFile) { + +/* RSD - from Radical Entertainment games */ +VGMSTREAM * init_vgmstream_rsd(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("rsd",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x52534432) /* RSD2 */ - goto fail; - if (read_32bitBE(0x4,streamFile) != 0x56414720) /* VAG\0x20 */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x8,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x800; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = loop_flag; - vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile); - vgmstream->meta_type = meta_RSD2VAG; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - -/* RSD2PCMB - Big Endian */ -VGMSTREAM * init_vgmstream_rsd2pcmb(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("rsd",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x52534432) /* RSD2 */ - goto fail; - if (read_32bitBE(0x4,streamFile) != 0x50434D42) /* PCMB */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x8,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = read_32bitLE(0x18,streamFile); - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->coding_type = coding_PCM16BE; - vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = loop_flag; - vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; - } - - - if (channel_count == 1) { - vgmstream->layout_type = layout_none; - } else if (channel_count == 2) { - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x2; - } - - - vgmstream->meta_type = meta_RSD2PCMB; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - -/* RSD2XADP */ -VGMSTREAM * init_vgmstream_rsd2xadp(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset; - int loop_flag, channel_count; + off_t start_offset, name_offset; size_t data_size; - - /* check extension */ - if (!check_extensions(streamFile,"rsd")) - goto fail; - - if (read_32bitBE(0x00,streamFile) != 0x52534432) /* RSD2 */ - goto fail; - if (read_32bitBE(0x04,streamFile) != 0x58414450) /* XADP */ - goto fail; - - start_offset = read_32bitLE(0x18,streamFile); /* not sure about this */ - data_size = get_streamfile_size(streamFile); - loop_flag = 0; - channel_count = read_32bitLE(0x08,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, vgmstream->channels); - - vgmstream->coding_type = coding_XBOX_IMA; - vgmstream->layout_type = layout_none; - vgmstream->meta_type = meta_RSD2XADP; - - if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) - goto fail; - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} - - -/* RSD3VAG */ -VGMSTREAM * init_vgmstream_rsd3vag(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("rsd",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x52534433) /* RSD3 */ - goto fail; - if (read_32bitBE(0x4,streamFile) != 0x56414720) /* VAG\0x20 */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x8,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x800; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = loop_flag; - vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile); - vgmstream->meta_type = meta_RSD3VAG; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - -/* RSD3GADP */ -VGMSTREAM * init_vgmstream_rsd3gadp(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("rsd",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x52534433) /* RSD3 */ - goto fail; - if (read_32bitBE(0x4,streamFile) != 0x47414450) /* WADP */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x8,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = read_32bitLE(0x18,streamFile); - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = loop_flag; - vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; - } - - vgmstream->layout_type = layout_none; - vgmstream->meta_type = meta_RSD3GADP; - - if (vgmstream->coding_type == coding_NGC_DSP) { - int i; - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x1D+i*2,streamFile); - } - } - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - - } - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - -/* RSD3PCM - Little Endian */ -VGMSTREAM * init_vgmstream_rsd3pcm(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("rsd",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x52534433) /* RSD3 */ - goto fail; - if (read_32bitBE(0x4,streamFile) != 0x50434D20) /* PCM\0x20 */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x8,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = read_32bitLE(0x18,streamFile); - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->coding_type = coding_PCM16LE; - vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = loop_flag; - vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; - } - - - if (channel_count == 1) { - vgmstream->layout_type = layout_none; - } else if (channel_count == 2) { - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x2; - } - - vgmstream->meta_type = meta_RSD3PCM; - - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - - -/* RSD3PCMB - Big Endian */ -VGMSTREAM * init_vgmstream_rsd3pcmb(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("rsd",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x52534433) /* RSD3 */ - goto fail; - if (read_32bitBE(0x4,streamFile) != 0x50434D42) /* PCMB */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x8,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = read_32bitLE(0x18,streamFile); - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->coding_type = coding_PCM16BE; - vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = loop_flag; - vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset)/2/channel_count; - } - - - if (channel_count == 1) { - vgmstream->layout_type = layout_none; - } else if (channel_count == 2) { - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x2; - } - - - vgmstream->meta_type = meta_RSD3PCMB; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - - -/* RSD4VAG */ -VGMSTREAM * init_vgmstream_rsd4vag(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("rsd",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x52534434) /* RSD4 */ - goto fail; - if (read_32bitBE(0x4,streamFile) != 0x56414720) /* VAG\0x20 */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x8,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x800; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = loop_flag; - vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0xC,streamFile); - vgmstream->meta_type = meta_RSD4VAG; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - -/* RSD4PCM - Little Endian */ -VGMSTREAM * init_vgmstream_rsd4pcm(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("rsd",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x52534434) /* RSD4 */ - goto fail; - if (read_32bitBE(0x4,streamFile) != 0x50434D20) /* PCM\0x20 */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x8,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x800; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->coding_type = coding_PCM16LE; - vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)/2/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = loop_flag; - vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-0x800)/2/channel_count; - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x2; - vgmstream->meta_type = meta_RSD4PCM; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - - -/* RSD4PCMB - Big Endian */ -VGMSTREAM * init_vgmstream_rsd4pcmb(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("rsd",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x52534434) /* RSD4 */ - goto fail; - if (read_32bitBE(0x4,streamFile) != 0x50434D42) /* PCMB */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x8,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x80; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->coding_type = coding_PCM16BE; - vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)/2/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = loop_flag; - vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-0x800)/2/channel_count; - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x2; - vgmstream->meta_type = meta_RSD4PCMB; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - -/* RSD4RADP */ -VGMSTREAM * init_vgmstream_rsd4radp(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("rsd",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x52534434) /* RSD4 */ - goto fail; - if (read_32bitBE(0x4,streamFile) != 0x52414450) /* RADP */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x8,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x800; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->coding_type = coding_RAD_IMA; - vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/0x14/channel_count*32; - if (loop_flag) { - vgmstream->loop_start_sample = loop_flag; - vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset)*28/16/channel_count; - } - vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = 0x14*channel_count; - vgmstream->meta_type = meta_RSD4RADP; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].offset=vgmstream->ch[i].channel_start_offset=start_offset; - } - } - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - -/* RSD6RADP */ -VGMSTREAM * init_vgmstream_rsd6radp(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("rsd",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x52534436) /* RSD6 */ - goto fail; - if (read_32bitBE(0x4,streamFile) != 0x52414450) /* RADP */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x8,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x800; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->coding_type = coding_RAD_IMA; - vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/0x14/channel_count*32; - if (loop_flag) { - vgmstream->loop_start_sample = loop_flag; - vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset)*28/16/channel_count; - } - vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = 0x14*channel_count; - vgmstream->meta_type = meta_RSD6RADP; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].offset=vgmstream->ch[i].channel_start_offset=start_offset; - } - } - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - -/* RSD6VAG */ -VGMSTREAM * init_vgmstream_rsd6vag(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("rsd",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x52534436) /* RSD6 */ - goto fail; - if (read_32bitBE(0x4,streamFile) != 0x56414720) /* VAG\0x20 */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x8,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x800; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = loop_flag; - vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0xC,streamFile); - vgmstream->meta_type = meta_RSD6VAG; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - -/* RSD6WADP */ -VGMSTREAM * init_vgmstream_rsd6wadp(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset; - int loop_flag, channel_count; - - /* check extension, case insensitive */ - if (!check_extensions(streamFile,"rsd")) - goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x52534436) /* RSD6 */ - goto fail; - if (read_32bitBE(0x4,streamFile) != 0x57414450) /* WADP */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x8,streamFile); - start_offset = 0x800; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count; - - vgmstream->coding_type = coding_NGC_DSP_subint; - vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = 0x02; //read_32bitLE(0xC,streamFile); - vgmstream->meta_type = meta_RSD6WADP; - - dsp_read_coefs_be(vgmstream,streamFile,0x1a4,0x28); - - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) - goto fail; - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - -/* RSD6OGG */ -VGMSTREAM * init_vgmstream_rsd6oogv(STREAMFILE *streamFile) { -#ifdef VGM_USE_VORBIS - off_t start_offset; - - /* check extension */ - if (!check_extensions(streamFile, "rsd")) - goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x52534436) /* RSD6 */ - goto fail; - if (read_32bitBE(0x4,streamFile) != 0x4F4F4756) /* OOGV */ - goto fail; - - { - ogg_vorbis_meta_info_t ovmi = {0}; - VGMSTREAM * result = NULL; - - ovmi.meta_type = meta_RSD6OOGV; - - start_offset = 0x800; - result = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi); - - if (result != NULL) { - return result; - } - } - -fail: - /* clean up anything we may have opened */ -#endif - return NULL; -} - -/* RSD6XADP - from Crash Tag Team Racing (Xbox), Scarface (Xbox) */ -VGMSTREAM * init_vgmstream_rsd6xadp(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset; - int loop_flag, channel_count; - size_t data_size; - - /* check extension */ - if (!check_extensions(streamFile,"rsd")) - goto fail; - - if (read_32bitBE(0x0,streamFile) != 0x52534436) /* RSD6 */ - goto fail; - if (read_32bitBE(0x4,streamFile) != 0x58414450) /* XADP */ - goto fail; - - start_offset = 0x800; - data_size = get_streamfile_size(streamFile) - start_offset; - loop_flag = 0; - channel_count = read_32bitLE(0x8,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, vgmstream->channels); - - vgmstream->meta_type = meta_RSD6XADP; - vgmstream->coding_type = (channel_count > 2) ? coding_XBOX_IMA_mch : coding_XBOX_IMA; - vgmstream->layout_type = layout_none; - - - if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) - goto fail; - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} - - -/* RSD6XMA */ -VGMSTREAM * init_vgmstream_rsd6xma(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset; - int loop_flag, channel_count; - uint32_t version; - - /* check extension, case insensitive */ - if (!check_extensions(streamFile,"rsd")) - goto fail; - - /* check header */ - if (read_32bitBE(0x0, streamFile) != 0x52534436) /* RSD6 */ - goto fail; - if (read_32bitBE(0x04,streamFile) != 0x584D4120) /* XMA */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x8, streamFile); - version = read_32bitBE(0x80C, streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = read_32bitBE(0x800, streamFile) + read_32bitBE(0x804, streamFile) + 0xc; /* assumed, seek table always at 0x800 */ - vgmstream->channels = channel_count; - vgmstream->meta_type = meta_RSD6XMA; - vgmstream->sample_rate = read_32bitBE(0x818, streamFile); - - switch (version) { - case 0x03010000: { - vgmstream->num_samples = read_32bitBE(0x824, streamFile); - - -#ifdef VGM_USE_FFMPEG - { - ffmpeg_codec_data *ffmpeg_data = NULL; - uint8_t buf[100]; - size_t bytes, datasize, block_size, block_count; - - block_count = read_32bitBE(0x828, streamFile); - block_size = 0x10000; - datasize = read_32bitBE(0x808, streamFile); - - bytes = ffmpeg_make_riff_xma2(buf, 100, vgmstream->num_samples, datasize, vgmstream->channels, vgmstream->sample_rate, block_count, block_size); - ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf, bytes, start_offset, datasize); - if (!ffmpeg_data) goto fail; - vgmstream->codec_data = ffmpeg_data; - vgmstream->coding_type = coding_FFmpeg; - vgmstream->layout_type = layout_none; - - /* for some reason (dev trickery?) .rsd don't set skip in the bitstream, though they should */ - //xma_fix_raw_samples(vgmstream, streamFile, start_offset,datasize, 0, 0,0); - ffmpeg_set_skip_samples(ffmpeg_data, 512+64); - } -#else - goto fail; -#endif - break; - } - case 0x04010000: { - vgmstream->num_samples = read_32bitBE(0x814, streamFile); - - -#ifdef VGM_USE_FFMPEG - { - ffmpeg_codec_data *ffmpeg_data = NULL; - uint8_t buf[100]; - size_t bytes, datasize, block_size, block_count; - - block_count = read_32bitBE(0x830, streamFile); - block_size = 0x10000; - datasize = read_32bitBE(0x808, streamFile); - - bytes = ffmpeg_make_riff_xma2(buf, 100, vgmstream->num_samples, datasize, vgmstream->channels, vgmstream->sample_rate, block_count, block_size); - ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf, bytes, start_offset, datasize); - if (!ffmpeg_data) goto fail; - vgmstream->codec_data = ffmpeg_data; - vgmstream->coding_type = coding_FFmpeg; - vgmstream->layout_type = layout_none; - - /* for some reason (dev trickery?) .rsd don't set skip in the bitstream, though they should */ - //xma_fix_raw_samples(vgmstream, streamFile, start_offset,datasize, 0, 0,0); - ffmpeg_set_skip_samples(ffmpeg_data, 512+64); - } -#else - goto fail; -#endif - break; - } - default: - goto fail; - } - /* open the file for reading */ - if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) - goto fail; - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - -/* RSD6AT3+ [Crash of the Titans (PSP)] */ -VGMSTREAM * init_vgmstream_rsd6at3p(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset; - size_t data_size; - int loop_flag, channel_count; - - - /* check extension, case insensitive */ - if (!check_extensions(streamFile,"rsd")) - goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x52534436) /* "RSD6" */ - goto fail; - if (read_32bitBE(0x04,streamFile) != 0x4154332B) /* "AT3+" */ - goto fail; - - loop_flag = 0; - channel_count = read_32bitLE(0x08, streamFile); - start_offset = 0x800; - data_size = get_streamfile_size(streamFile) - start_offset; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - vgmstream->meta_type = meta_RSD6AT3P; - vgmstream->sample_rate = read_32bitLE(0x10, streamFile); - -#ifdef VGM_USE_FFMPEG - { - ffmpeg_codec_data *ffmpeg_data = NULL; - - /* full RIFF header at start_offset */ - ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,data_size); - if (!ffmpeg_data) goto fail; - vgmstream->codec_data = ffmpeg_data; - vgmstream->coding_type = coding_FFmpeg; - vgmstream->layout_type = layout_none; - - if (channel_count != ffmpeg_data->channels) goto fail; - - vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact samples */ - - if (ffmpeg_data->skipSamples <= 0) /* in case FFmpeg didn't get them */ - ffmpeg_set_skip_samples(ffmpeg_data, riff_get_fact_skip_samples(streamFile, start_offset)); - } -#else - goto fail; -#endif - - if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) - goto fail; - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} - - -/* RSD6WMA [Scarface (Xbox)] */ -VGMSTREAM * init_vgmstream_rsd6wma(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset; - size_t data_size; - int loop_flag, channel_count; + int loop_flag, channel_count, sample_rate, interleave; + uint32_t codec; + uint8_t version; /* checks */ if (!check_extensions(streamFile,"rsd")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x52534436) /* "RSD6" */ - goto fail; - if (read_32bitBE(0x04,streamFile) != 0x574D4120) /* "WMA " */ + if ((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) != 0x52534400) /* "RSD\00" */ goto fail; loop_flag = 0; + + codec = read_32bitBE(0x04,streamFile); channel_count = read_32bitLE(0x08, streamFile); - start_offset = 0x800; + /* 0x0c: always 16? */ + sample_rate = read_32bitLE(0x10, streamFile); + + version = read_8bit(0x03, streamFile); + switch(version) { + case '2': /* known codecs: VAG/XADP/PCMB [The Simpsons: Road Rage] */ + case '3': /* known codecs: VAG/PCM/PCMB/GADP? [Dark Summit] */ + interleave = read_32bitLE(0x14,streamFile); /* VAG only, 0x04 otherwise */ + start_offset = read_32bitLE(0x18,streamFile); + name_offset = 0; + break; + + case '4': /* known codecs: VAG/PCM/RADP/PCMB [The Simpsons: Hit & Run, Tetris Worlds, Hulk] */ + /* 0x14: padding */ + /* 0x18: padding */ + interleave = 0; + start_offset = 0x800; + name_offset = 0; + + /* PCMB/PCM/GADP normally start early but sometimes have padding [The Simpsons: Hit & Run (GC/Xbox)] */ + if ((codec == 0x50434D20 || codec == 0x550434D42 || codec == 0x47414450) + && read_32bitLE(0x80,streamFile) != 0x2D2D2D2D) + start_offset = 0x80; + break; + + case '6': /* known codecs: VAG/XADP/WADP/RADP/OOGV/AT3+/XMA [Hulk 2, Crash Tag Team Racing, Crash: Mind over Mutant, Scarface] */ + /* 0x14: padding */ + name_offset = 0x18; /* dev file path */ + interleave = 0; + start_offset = 0x800; + break; + + default: + goto fail; + } + data_size = get_streamfile_size(streamFile) - start_offset; + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - vgmstream->meta_type = meta_RSD6WMA; - //vgmstream->num_samples = read_32bitLE(start_offset + 0x00, streamFile) / channel_count / 2; /* may be PCM data size, but not exact */ - vgmstream->sample_rate = read_32bitLE(start_offset + 0x04, streamFile); + vgmstream->meta_type = meta_RSD; + vgmstream->sample_rate = sample_rate; + + switch(codec) { + case 0x50434D20: /* "PCM " [Dark Summit (Xbox), Hulk (PC)] */ + vgmstream->coding_type = coding_PCM16LE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2; + + vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, 16); + break; + + case 0x50434D42: /* "PCMB" [The Simpsons: Road Rage (GC), Dark Summit (GC)] */ + vgmstream->coding_type = coding_PCM16BE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2; + + vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, 16); + break; + + case 0x56414720: /* "VAG " [The Simpsons: Road Rage (PS2), Crash Tag Team Racing (PSP)] */ + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = (interleave == 0) ? 0x10 : interleave; + + vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count); + break; + + case 0x58414450: /* "XADP" [The Simpsons: Road Rage (Xbox)], Crash Tag Team Racing (Xbox)] */ + vgmstream->coding_type = (channel_count > 2) ? coding_XBOX_IMA_mch : coding_XBOX_IMA; + vgmstream->layout_type = layout_none; + + vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, vgmstream->channels); + break; + + case 0x47414450: /* "GADP" [Hulk (GC)] */ + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x08; /* assumed, known files are mono */ + dsp_read_coefs_le(vgmstream,streamFile,0x14,0x2e); /* LE! */ + dsp_read_hist_le (vgmstream,streamFile,0x38,0x2e); + + vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count); + break; + + case 0x57414450: /* "WADP" [Crash: Mind Over Mutant (Wii)] */ + vgmstream->coding_type = coding_NGC_DSP_subint; + vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = 0x02; + dsp_read_coefs_be(vgmstream,streamFile,0x1a4,0x28); + dsp_read_hist_be (vgmstream,streamFile,0x1c8,0x28); + + vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count); + break; + + case 0x52414450: /* "RADP" [The Simpsons: Hit & Run (GC), Scarface (Wii)] */ + vgmstream->coding_type = coding_RAD_IMA; + vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = 0x14*channel_count; + + vgmstream->num_samples = data_size / 0x14 / channel_count * 32; /* bytes-to-samples */ + break; + +#ifdef VGM_USE_VORBIS + case 0x4F4F4756: { /* "OOGV" [Scarface (PC)] */ + ogg_vorbis_meta_info_t ovmi = {0}; + + ovmi.meta_type = meta_RSD; + close_vgmstream(vgmstream); + vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi); + if (!vgmstream) goto fail; + break; + } +#endif #ifdef VGM_USE_FFMPEG - { - ffmpeg_codec_data *ffmpeg_data = NULL; + case 0x574D4120: { /* "WMA " [Scarface (Xbox)] */ + ffmpeg_codec_data *ffmpeg_data = NULL; - /* mini header + WMA header at start_offset */ - ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset+0x08,data_size); - if (!ffmpeg_data) goto fail; - vgmstream->codec_data = ffmpeg_data; - vgmstream->coding_type = coding_FFmpeg; - vgmstream->layout_type = layout_none; + /* mini header + WMA header at start_offset */ + ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset+0x08,data_size); + if (!ffmpeg_data) goto fail; + vgmstream->codec_data = ffmpeg_data; + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; - vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples; /* an estimation, sometimes cuts files a bit early */ - } -#else - goto fail; + vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples; /* an estimation, sometimes cuts files a bit early */ + //vgmstream->num_samples = read_32bitLE(start_offset + 0x00, streamFile) / channel_count / 2; /* may be PCM data size, but not exact */ + vgmstream->sample_rate = read_32bitLE(start_offset + 0x04, streamFile); + break; + } + + case 0x4154332B: { /* "AT3+" [Crash of the Titans (PSP)] */ + ffmpeg_codec_data *ffmpeg_data = NULL; + + /* full RIFF header at start_offset */ + ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,data_size); + if (!ffmpeg_data) goto fail; + vgmstream->codec_data = ffmpeg_data; + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; + + if (ffmpeg_data->skipSamples <= 0) /* in case FFmpeg didn't get them */ + ffmpeg_set_skip_samples(ffmpeg_data, riff_get_fact_skip_samples(streamFile, start_offset)); + + vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact samples */ + break; + } + + case 0x584D4120: { /* "XMA " [Crash of the Titans (X360)-v1, Crash: Mind over Mutant (X360)-v2] */ + ffmpeg_codec_data *ffmpeg_data = NULL; + uint8_t buf[0x100]; + size_t bytes, xma_size, block_size, block_count; + int xma_version; + + + /* skip mini header */ + start_offset = read_32bitBE(0x800, streamFile) + read_32bitBE(0x804, streamFile) + 0xc; /* assumed, seek table always at 0x800 */ + xma_size = read_32bitBE(0x808, streamFile); + xma_version = read_32bitBE(0x80C, streamFile); + + switch (xma_version) { + case 0x03010000: + vgmstream->sample_rate = read_32bitBE(0x818, streamFile); + vgmstream->num_samples = read_32bitBE(0x824, streamFile); + block_count = read_32bitBE(0x828, streamFile); + block_size = 0x10000; + break; + case 0x04010000: + vgmstream->num_samples = read_32bitBE(0x814, streamFile); + vgmstream->sample_rate = read_32bitBE(0x818, streamFile); + block_count = read_32bitBE(0x830, streamFile); + block_size = 0x10000; + break; + default: + goto fail; + } + + bytes = ffmpeg_make_riff_xma2(buf,sizeof(buf), vgmstream->num_samples, xma_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size); + ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf, bytes, start_offset, xma_size); + if (!ffmpeg_data) goto fail; + vgmstream->codec_data = ffmpeg_data; + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; + + /* for some reason (dev trickery?) .rsd don't set skip in the bitstream, though they should */ + //xma_fix_raw_samples(vgmstream, streamFile, start_offset,xma_size, 0, 0,0); + ffmpeg_set_skip_samples(ffmpeg_data, 512+64); + break; + } #endif + default: + goto fail; + } + + if (name_offset) + read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamFile); + if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) goto fail; return vgmstream; diff --git a/src/meta/seg.c b/src/meta/seg.c index 9a09210a..87e6f85b 100644 --- a/src/meta/seg.c +++ b/src/meta/seg.c @@ -67,11 +67,14 @@ VGMSTREAM * init_vgmstream_seg(STREAMFILE *streamFile) { vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x2000; + vgmstream->interleave_first_skip = 0x60; + vgmstream->interleave_first_block_size = vgmstream->interleave_block_size - vgmstream->interleave_first_skip; /* standard dsp header at start_offset */ dsp_read_coefs_be(vgmstream, streamFile, start_offset+0x1c, vgmstream->interleave_block_size); dsp_read_hist_be(vgmstream, streamFile, start_offset+0x40, vgmstream->interleave_block_size); - //todo first_interleave: 0x2000 - 60 + + start_offset += vgmstream->interleave_first_skip; break; case 0x70635F00: /* "pc_\0" */ diff --git a/src/meta/str_snds.c b/src/meta/str_snds.c index 6a43997a..b232898c 100644 --- a/src/meta/str_snds.c +++ b/src/meta/str_snds.c @@ -1,118 +1,98 @@ #include "meta.h" #include "../coding/coding.h" #include "../layout/layout.h" -#include "../util.h" -/* 3DO format, .str extension and possibly a CTRL header, blocks and - * AIFF-C style format specifier. Blocks are not IFF-compliant. Interesting - * blocks are all SNDS - */ +/* .str - 3DO format with CTRL/SNDS/SHDR blocks [Icebreaker (3DO), Battle Pinball (3DO)] */ VGMSTREAM * init_vgmstream_str_snds(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; + off_t start_offset, shdr_offset = -1; + int loop_flag, channel_count, found_shdr = 0; + size_t file_size, ctrl_size = -1; - int channel_count; - int loop_flag = 0; - off_t SHDR_offset = -1; - int FoundSHDR = 0; - int CTRL_size = -1; - size_t file_size; + /* checks */ + if (!check_extensions(streamFile, "str")) + goto fail; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("str",filename_extension(filename))) goto fail; - - /* check for opening CTRL or SNDS chunk */ - if (read_32bitBE(0x0,streamFile) != 0x4354524c && /* CTRL */ - read_32bitBE(0x0,streamFile) != 0x534e4453 && // SNDS - read_32bitBE(0x0,streamFile) != 0x53484452) // SHDR + if (read_32bitBE(0x00,streamFile) != 0x4354524c && /* "CTRL" */ + read_32bitBE(0x00,streamFile) != 0x534e4453 && /* "SNDS" */ + read_32bitBE(0x00,streamFile) != 0x53484452) /* "SHDR" */ goto fail; file_size = get_streamfile_size(streamFile); + start_offset = 0x00; /* scan chunks until we find a SNDS containing a SHDR */ { - off_t current_chunk; + off_t current_chunk = 0; - current_chunk = 0; - - while (!FoundSHDR && current_chunk < file_size) { + while (!found_shdr && current_chunk < file_size) { if (current_chunk < 0) goto fail; - if (current_chunk+read_32bitBE(current_chunk+4,streamFile) >= - file_size) goto fail; + if (current_chunk+read_32bitBE(current_chunk+0x04,streamFile) >= file_size) + goto fail; - switch (read_32bitBE(current_chunk,streamFile)) - { - case 0x4354524C: /* CTRL */ - /* to distinguish between styles */ - CTRL_size = read_32bitBE(current_chunk+4,streamFile); - break; - case 0x534e4453: /* SNDS */ - switch (read_32bitBE(current_chunk+16,streamFile)) - { - case 0x53484452: /* SHDR */ - FoundSHDR = 1; - SHDR_offset = current_chunk+16; - break; - - default: - break; + switch (read_32bitBE(current_chunk,streamFile)) { + case 0x4354524C: /* "CTRL" */ + ctrl_size = read_32bitBE(current_chunk+4,streamFile); + break; + + case 0x534e4453: /* "SNDS" */ + switch (read_32bitBE(current_chunk+16,streamFile)) { + case 0x53484452: /* SHDR */ + found_shdr = 1; + shdr_offset = current_chunk+16; + break; + default: + break; } break; - case 0x53484452: /* SHDR */ - switch (read_32bitBE(current_chunk+0x7C, streamFile)) - { - case 0x4354524C: /* CTRL */ - // to distinguish between styles - CTRL_size = read_32bitBE(current_chunk + 0x80, streamFile); - break; - - default: - break; + + case 0x53484452: /* "SHDR" */ + switch (read_32bitBE(current_chunk+0x7C, streamFile)) { + case 0x4354524C: /* "CTRL" */ + /* to distinguish between styles */ + ctrl_size = read_32bitBE(current_chunk + 0x80, streamFile); + break; + + default: + break; } - break; - default: + break; + + default: /* ignore others for now */ break; } - current_chunk += read_32bitBE(current_chunk+4,streamFile); + current_chunk += read_32bitBE(current_chunk+0x04,streamFile); } } - if (!FoundSHDR) goto fail; + if (!found_shdr) goto fail; - /* details */ - channel_count = read_32bitBE(SHDR_offset+0x20,streamFile); + channel_count = read_32bitBE(shdr_offset+0x20,streamFile); loop_flag = 0; - /* build the VGMSTREAM */ + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - if ((CTRL_size == 0x1C) || - (CTRL_size == 0x0B) || - (CTRL_size == -1)) - { - vgmstream->num_samples = - read_32bitBE(SHDR_offset+0x2c,streamFile)-1; /* sample count? */ + vgmstream->meta_type = meta_STR_SNDS; + vgmstream->sample_rate = read_32bitBE(shdr_offset+0x1c,streamFile); + + if (ctrl_size == 0x1C || ctrl_size == 0x0B || ctrl_size == -1) { + vgmstream->num_samples = read_32bitBE(shdr_offset+0x2c,streamFile) - 1; /* sample count? */ } - else { - vgmstream->num_samples = - read_32bitBE(SHDR_offset+0x2c,streamFile) /* frame count? */ - * 0x10; + else { + vgmstream->num_samples = read_32bitBE(shdr_offset+0x2c,streamFile) * 0x10; /* frame count? */ } + vgmstream->num_samples /= vgmstream->channels; - vgmstream->num_samples/=vgmstream->channels; - - vgmstream->sample_rate = read_32bitBE(SHDR_offset+0x1c,streamFile); - switch (read_32bitBE(SHDR_offset+0x24,streamFile)) { - case 0x53445832: /* SDX2 */ + switch (read_32bitBE(shdr_offset+0x24,streamFile)) { + case 0x53445832: /* "SDX2" */ if (channel_count > 1) { vgmstream->coding_type = coding_SDX2_int; vgmstream->interleave_block_size = 1; @@ -123,33 +103,12 @@ VGMSTREAM * init_vgmstream_str_snds(STREAMFILE *streamFile) { goto fail; } vgmstream->layout_type = layout_blocked_str_snds; - vgmstream->meta_type = meta_STR_SNDS; - - /* channels and loop flag are set by allocate_vgmstream */ - if (loop_flag) { - /* just guessin', no way to set loop flag anyway */ - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = vgmstream->num_samples; - } - - /* open the file for reading by each channel */ - { - int i; - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename, - STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) goto fail; - for (i=0;ich[i].streamfile = vgmstream->ch[0].streamfile; - } - } - - /* start me up */ - block_update_str_snds(0,vgmstream); + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } diff --git a/src/meta/vag.c b/src/meta/vag.c index bc351c80..a34c632e 100644 --- a/src/meta/vag.c +++ b/src/meta/vag.c @@ -6,7 +6,7 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; - size_t file_size, channel_size, interleave; + size_t file_size, channel_size, interleave, interleave_first = 0, interleave_first_skip = 0; meta_t meta_type; int channel_count = 0, loop_flag, sample_rate; uint32_t vag_id, version; @@ -80,7 +80,7 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { case 0x70474156: /* pGAV (little endian / stereo) [Jak 3 (PS2), Jak X (PS2)] */ meta_type = meta_PS2_pGAV; - start_offset = 0x00; //todo 0x30, requires interleave_first + start_offset = 0x30; if (read_32bitBE(0x20,streamFile) == 0x53746572) { /* "Ster" */ channel_count = 2; @@ -91,7 +91,8 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { interleave = 0x1000; /* Jak X interleave, includes header */ else interleave = 0x2000; /* Jak 3 interleave in rare files, no header */ - //todo interleave_first = interleave - start_offset; /* interleave includes header */ + interleave_first = interleave - start_offset; /* interleave includes header */ + interleave_first_skip = start_offset; } else { channel_count = 1; @@ -127,21 +128,21 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { } else if (read_32bitBE(0x6000,streamFile) == 0x56414770) { /* "VAGp" */ /* The Simpsons Wrestling (PS1) */ - start_offset = 0x00; //todo 0x30, requires interleave_first + start_offset = 0x30; channel_count = 2; interleave = 0x6000; - //todo interleave_first = interleave - start_offset; /* includes header */ - channel_size += 0x30; + interleave_first = interleave - start_offset; /* includes header */ + interleave_first_skip = start_offset; loop_flag = 0; } else if (read_32bitBE(0x1000,streamFile) == 0x56414770) { /* "VAGp" */ /* Shikigami no Shiro (PS2) */ - start_offset = 0x00; //todo 0x30, requires interleave_first + start_offset = 0x30; channel_count = 2; interleave = 0x1000; - //todo interleave_first = interleave - start_offset; /* includes header */ - channel_size += 0x30; + interleave_first = interleave - start_offset; /* includes header */ + interleave_first_skip = start_offset; loop_flag = ps_find_loop_offsets(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start_sample, &loop_end_sample); } @@ -244,6 +245,9 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { vgmstream->coding_type = coding_HEVAG; vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave; vgmstream->interleave_block_size = interleave; + vgmstream->interleave_first_block_size = interleave_first; + vgmstream->interleave_first_skip = interleave_first_skip; + read_string(vgmstream->stream_name,0x10+1, 0x20,streamFile); /* always, can be null */ diff --git a/src/meta/wwise.c b/src/meta/wwise.c index 7e3a20a6..b0cdd6c2 100644 --- a/src/meta/wwise.c +++ b/src/meta/wwise.c @@ -221,6 +221,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { goto fail; } + start_offset = ww.data_offset; /* build the VGMSTREAM */ @@ -303,7 +304,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { cfg.setup_type = WWV_EXTERNAL_CODEBOOKS; /* setup_type will be corrected later */ break; - case 0x2a: /* uncommon (mid 2011) [inFamous 2 (PS3)] */ + case 0x2a: /* uncommon (mid 2011) [inFamous 2 (PS3), Captain America: Super Soldier (X360)] */ data_offsets = 0x10; block_offsets = 0x28; cfg.header_type = WWV_TYPE_2; @@ -325,6 +326,14 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { } ww.data_size -= audio_offset; + + /* detect normal packets */ + if (vorb_size == 0x2a) { + /* almost all blocksizes are 0x08+0x0B except a few with 0x0a+0x0a [Captain America: Super Soldier (X360) voices/sfx] */ + if (cfg.blocksize_0_exp == cfg.blocksize_1_exp) + cfg.packet_type = WWV_STANDARD; + } + /* detect setup type: * - full inline: ~2009, ex. The King of Fighters XII (X360), The Saboteur (PC) * - trimmed inline: ~2010, ex. Army of Two: 40 days (X360) some multiplayer files @@ -378,11 +387,9 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { cfg.blocksize_0_exp = read_8bit(extra_offset + block_offsets + 0x01, streamFile); /* big */ ww.data_size -= audio_offset; - /* Normal packets are used rarely (ex. Oddworld New 'n' Tasty! (PSV)). They are hard to detect (decoding - * will mostly work with garbage results) but we'll try. Setup size and "fmt" bitrate fields may matter too. */ + /* detect normal packets */ if (ww.extra_size == 0x30) { - /* all blocksizes I've seen are 0x08+0x0B except Oddworld (PSV), that uses 0x09+0x09 - * (maybe lower spec machines = needs simpler packets) */ + /* almost all blocksizes are 0x08+0x0B except some with 0x09+0x09 [Oddworld New 'n' Tasty! (PSV)] */ if (cfg.blocksize_0_exp == cfg.blocksize_1_exp) cfg.packet_type = WWV_STANDARD; } @@ -438,6 +445,15 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { goto fail; } + /* for some reason all(?) DSP .wem do full loops (even mono/jingles/etc) but + * several tracks do loop like this, so disable it for short-ish tracks */ + if (ww.loop_flag && vgmstream->loop_start_sample == 0 && + vgmstream->loop_end_sample < 20*ww.sample_rate) { /* in seconds */ + vgmstream->loop_flag = 0; + } + + + /* get coefs and default history */ dsp_read_coefs(vgmstream,streamFile,wiih_offset, 0x2e, ww.big_endian); for (i=0; i < ww.channels; i++) { diff --git a/src/meta/xwb.c b/src/meta/xwb.c index f60cf6fd..d926235f 100644 --- a/src/meta/xwb.c +++ b/src/meta/xwb.c @@ -635,10 +635,11 @@ static int get_xsb_name(char * buf, size_t maxsize, int target_subsong, xwb_head } //;VGM_LOG("XSB: name found=%i at %lx\n", xsb.parse_found, xsb.name_offset); - if (!xsb.parse_found || xsb.name_offset == 0) + if (!xsb.name_len || xsb.name[0] == '\0') goto fail; - read_string(buf,maxsize, xsb.name_offset,streamFile); /* null-terminated */ + strncpy(buf,xsb.name,maxsize); + buf[maxsize-1] = '\0'; return 1; fail: return 0; diff --git a/src/meta/xwb_xsb.h b/src/meta/xwb_xsb.h index f42b24dc..b254a7fe 100644 --- a/src/meta/xwb_xsb.h +++ b/src/meta/xwb_xsb.h @@ -1,5 +1,6 @@ #ifndef _XWB_XSB_H_ #define _XWB_XSB_H_ +#include "meta.h" #define XSB_XACT1_0_MAX 5 /* Unreal Championship (Xbox) */ #define XSB_XACT1_1_MAX 8 /* Die Hard: Vendetta (Xbox) */ @@ -30,9 +31,9 @@ typedef struct { off_t cue_names_offset; /* output */ - int parse_found; int parse_done; - off_t name_offset; + char name[STREAM_NAME_SIZE]; + int name_len; } xsb_header; @@ -41,24 +42,30 @@ static void xsb_check_stream(xsb_header * xsb, int stream_index, int wavebank_in if (xsb->parse_done) return; - /* multiple names may correspond to a stream, so commenting parse_done - * will allow to search for other names instead of first only */ + /* multiple names may correspond to a stream (ex. Blue Dragon), so we concat all */ if (xsb->selected_stream == stream_index && (xsb->selected_wavebank == wavebank_index || wavebank_index == -1 || wavebank_index == 255)) { - xsb->name_offset = name_offset; - xsb->parse_found = 1; - xsb->parse_done = 1; + char name[STREAM_NAME_SIZE]; + size_t name_size; + + name_size = read_string(name,sizeof(name), name_offset,sf); /* null-terminated */ + + if (xsb->name_len) { + const char *cat = "; "; + int cat_len = 2; + + if (xsb->name_len + cat_len + name_size + 1 < STREAM_NAME_SIZE) { + strcat(xsb->name + xsb->name_len, cat); + strcat(xsb->name + xsb->name_len, name); + } + } + else { + strcpy(xsb->name, name); + } + xsb->name_len += name_size; + //xsb->parse_done = 1; /* uncomment this to stop reading after first name */ //;VGM_LOG("XSB: parse found stream=%i, wavebank=%i, name_offset=%lx\n", stream_index, wavebank_index, name_offset); } - -#if 0 // for debugging purposes - { - char stream_name[255]; - read_string(stream_name,255, name_offset,sf); /* null-terminated */ - ;VGM_LOG("XSB: stream=%i, wavebank=%i, name=%lx=%s vs s=%i, w=%i\n", stream_index, wavebank_index, name_offset, stream_name, xsb->selected_stream, xsb->selected_wavebank); - xsb->parse_done = 0; /* keep parsing */ - } -#endif } /* old XACT1 is a bit different and much of it is unknown but this seems to work. diff --git a/src/vgmstream.c b/src/vgmstream.c index 5d88113f..94ac6cba 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -118,12 +118,12 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ps2_pcm, init_vgmstream_ps2_rkv, init_vgmstream_ps2_vas, + init_vgmstream_ps2_vas_container, init_vgmstream_ps2_tec, init_vgmstream_ps2_enth, init_vgmstream_sdt, init_vgmstream_aix, init_vgmstream_ngc_tydsp, - init_vgmstream_ngc_swd, init_vgmstream_capdsp, init_vgmstream_xbox_wvs, init_vgmstream_ngc_wvs, @@ -157,21 +157,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_wii_mus, init_vgmstream_dc_asd, init_vgmstream_naomi_spsd, - init_vgmstream_rsd2vag, - init_vgmstream_rsd2pcmb, - init_vgmstream_rsd2xadp, - init_vgmstream_rsd3vag, - init_vgmstream_rsd3gadp, - init_vgmstream_rsd3pcm, - init_vgmstream_rsd3pcmb, - init_vgmstream_rsd4pcmb, - init_vgmstream_rsd4pcm, - init_vgmstream_rsd4radp, - init_vgmstream_rsd4vag, - init_vgmstream_rsd6vag, - init_vgmstream_rsd6wadp, - init_vgmstream_rsd6xadp, - init_vgmstream_rsd6radp, + init_vgmstream_rsd, init_vgmstream_bgw, init_vgmstream_spw, init_vgmstream_ps2_ass, @@ -305,7 +291,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ps3_ivag, init_vgmstream_ps2_2pfs, init_vgmstream_xnb, - init_vgmstream_rsd6oogv, init_vgmstream_ubi_ckd, init_vgmstream_ps2_vbk, init_vgmstream_otm, @@ -335,7 +320,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ogl, init_vgmstream_mc3, init_vgmstream_gtd, - init_vgmstream_rsd6xma, init_vgmstream_ta_aac_x360, init_vgmstream_ta_aac_ps3, init_vgmstream_ta_aac_mobile, @@ -395,8 +379,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_waf, init_vgmstream_wave, init_vgmstream_wave_segmented, - init_vgmstream_rsd6at3p, - init_vgmstream_rsd6wma, init_vgmstream_smv, init_vgmstream_nxap, init_vgmstream_ea_wve_au00, @@ -486,6 +468,9 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_smk, init_vgmstream_mzrt, init_vgmstream_xavs, + init_vgmstream_psf_single, + init_vgmstream_psf_segmented, + init_vgmstream_dsp_itl, /* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */ @@ -1190,7 +1175,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_HEVAG: return 28; case coding_PSX_cfg: - return (vgmstream->interleave_block_size - 1) * 2; /* decodes 1 byte into 2 bytes */ + case coding_PSX_pivotal: + return (vgmstream->interleave_block_size - 0x01) * 2; /* size 0x01 header */ case coding_EA_XA: case coding_EA_XA_int: @@ -1378,6 +1364,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_HEVAG: return 0x10; case coding_PSX_cfg: + case coding_PSX_pivotal: return vgmstream->interleave_block_size; case coding_EA_XA: @@ -1693,6 +1680,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to vgmstream->channels,vgmstream->samples_into_block,samples_to_do, vgmstream->interleave_block_size); } break; + case coding_PSX_pivotal: + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_psx_pivotal(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, + vgmstream->interleave_block_size); + } + break; case coding_HEVAG: for (ch = 0; ch < vgmstream->channels; ch++) { decode_hevag(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, @@ -2429,6 +2423,11 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { snprintf(temp,TEMPSIZE, "interleave: %#x bytes\n", (int32_t)vgmstream->interleave_block_size); concatn(length,desc,temp); + if (vgmstream->interleave_first_block_size) { + snprintf(temp,TEMPSIZE, "interleave first block: %#x bytes\n", (int32_t)vgmstream->interleave_first_block_size); + concatn(length,desc,temp); + } + if (vgmstream->interleave_last_block_size) { snprintf(temp,TEMPSIZE, "interleave last block: %#x bytes\n", (int32_t)vgmstream->interleave_last_block_size); concatn(length,desc,temp); @@ -2824,6 +2823,12 @@ int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t s vgmstream->coding_type == coding_CRI_HCA) return 1; +#ifdef VGM_USE_VORBIS + /* stream/offsets not needed, managed by decoder */ + if (vgmstream->coding_type == coding_OGG_VORBIS) + return 1; +#endif + #ifdef VGM_USE_FFMPEG /* stream/offsets not needed, managed by decoder */ if (vgmstream->coding_type == coding_FFmpeg) diff --git a/src/vgmstream.h b/src/vgmstream.h index e2ced4bc..48b889d4 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -104,7 +104,8 @@ typedef enum { coding_XA, /* CD-ROM XA */ coding_PSX, /* Sony PS ADPCM (VAG) */ coding_PSX_badflags, /* Sony PS ADPCM with custom flag byte */ - coding_PSX_cfg, /* Sony PS ADPCM with configurable frame size (FF XI, SGXD type 5, Bizarre Creations) */ + coding_PSX_cfg, /* Sony PS ADPCM with configurable frame size (int math) */ + coding_PSX_pivotal, /* Sony PS ADPCM with configurable frame size (float math) */ coding_HEVAG, /* Sony PSVita ADPCM */ coding_EA_XA, /* Electronic Arts EA-XA ADPCM v1 (stereo) aka "EA ADPCM" */ @@ -389,7 +390,6 @@ typedef enum { meta_PS2_ENTH, /* Enthusia */ meta_SDT, /* Baldur's Gate - Dark Alliance */ meta_NGC_TYDSP, /* Ty - The Tasmanian Tiger */ - meta_NGC_SWD, /* Conflict - Desert Storm 1 & 2 */ meta_CAPDSP, /* Capcom DSP Header [no header_id] */ meta_DC_STR, /* SEGA Stream Asset Builder */ meta_DC_STR_V2, /* variant of SEGA Stream Asset Builder */ @@ -420,27 +420,7 @@ typedef enum { meta_NGC_PDT, /* Mario Party 6 */ meta_DC_ASD, /* Miss Moonligh */ meta_NAOMI_SPSD, /* Guilty Gear X */ - - meta_RSD2VAG, /* RSD2VAG */ - meta_RSD2PCMB, /* RSD2PCMB */ - meta_RSD2XADP, /* RSD2XADP */ - meta_RSD3VAG, /* RSD3VAG */ - meta_RSD3GADP, /* RSD3GADP */ - meta_RSD3PCM, /* RSD3PCM */ - meta_RSD3PCMB, /* RSD3PCMB */ - meta_RSD4PCMB, /* RSD4PCMB */ - meta_RSD4PCM, /* RSD4PCM */ - meta_RSD4RADP, /* RSD4RADP */ - meta_RSD4VAG, /* RSD4VAG */ - meta_RSD6VAG, /* RSD6VAG */ - meta_RSD6WADP, /* RSD6WADP */ - meta_RSD6XADP, /* RSD6XADP */ - meta_RSD6RADP, /* RSD6RADP */ - meta_RSD6OOGV, /* RSD6OOGV */ - meta_RSD6XMA, /* RSD6XMA */ - meta_RSD6AT3P, /* RSD6AT3+ */ - meta_RSD6WMA, /* RSD6WMA */ - + meta_RSD, meta_PS2_ASS, /* ASS */ meta_SEG, /* Eragon */ meta_NDS_STRM_FFTA2, /* Final Fantasy Tactics A2 */ @@ -732,6 +712,8 @@ typedef enum { meta_SMACKER, meta_MZRT, meta_XAVS, + meta_PSF, + meta_DSP_ITL_i, } meta_t; @@ -843,6 +825,8 @@ typedef struct { /* layouts/block config */ size_t interleave_block_size; /* interleave, or block/frame size (depending on the codec) */ + size_t interleave_first_block_size; /* different interleave for first block */ + size_t interleave_first_skip; /* data skipped before interleave first (needed to skip other channels) */ size_t interleave_last_block_size; /* smaller interleave for last block */ /* subsong config */