From 2d5fece2afc6512ae17322a47f9ac1b11f4cf1c2 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 18 May 2017 19:06:22 +0200 Subject: [PATCH 01/17] Added simple MTAF block skip; meta cleanup [Metal Gear Solid 3 HD] --- src/coding/mtaf_decoder.c | 257 +++++++++++++++++++------------------- src/meta/ps2_mtaf.c | 196 ++++++++--------------------- 2 files changed, 184 insertions(+), 269 deletions(-) diff --git a/src/coding/mtaf_decoder.c b/src/coding/mtaf_decoder.c index 50e27672..642aa34d 100644 --- a/src/coding/mtaf_decoder.c +++ b/src/coding/mtaf_decoder.c @@ -1,142 +1,152 @@ -//#include -//#include #include "coding.h" #include "../util.h" -#define MTAF_BLOCK_SUPPORT 0 +#define MTAF_BLOCK_SUPPORT -// A hybrid of IMA and Yamaha ADPCM found in Metal Gear Solid 3 -// Thanks to X_Tra (http://metalgear.in/) for pointing me to the step size table. -int index_table[16] = { +/* A hybrid of IMA and Yamaha ADPCM found in Metal Gear Solid 3 + * Thanks to X_Tra (http://metalgear.in/) for pointing me to the step size table. + * + * Layout: N tracks of 0x10 header + 0x80*2 (always 2ch; multichannels uses 4ch = 2ch track0 + 2ch track1 xN) + * "macroblocks" support is not really needed as the extractors should remove them but they are + * autodetected and skipped if found (ideally should keep a special layout/count, but this is simpler). + */ + +static const int index_table[16] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 }; -static int16_t step_size[32][16] = { -{ 1, 5, 9, 13, 16, 20, 24, 28, - -1, -5, -9, -13, -16, -20, -24, -28, }, -{ 2, 6, 11, 15, 20, 24, 29, 33, - -2, -6, -11, -15, -20, -24, -29, -33, }, -{ 2, 7, 13, 18, 23, 28, 34, 39, - -2, -7, -13, -18, -23, -28, -34, -39, }, -{ 3, 9, 15, 21, 28, 34, 40, 46, - -3, -9, -15, -21, -28, -34, -40, -46, }, -{ 3, 11, 18, 26, 33, 41, 48, 56, - -3, -11, -18, -26, -33, -41, -48, -56, }, -{ 4, 13, 22, 31, 40, 49, 58, 67, - -4, -13, -22, -31, -40, -49, -58, -67, }, -{ 5, 16, 26, 37, 48, 59, 69, 80, - -5, -16, -26, -37, -48, -59, -69, -80, }, -{ 6, 19, 31, 44, 57, 70, 82, 95, - -6, -19, -31, -44, -57, -70, -82, -95, }, -{ 7, 22, 38, 53, 68, 83, 99, 114, - -7, -22, -38, -53, -68, -83, -99, -114, }, -{ 9, 27, 45, 63, 81, 99, 117, 135, - -9, -27, -45, -63, -81, -99, -117, -135, }, -{ 10, 32, 53, 75, 96, 118, 139, 161, - -10, -32, -53, -75, -96, -118, -139, -161, }, -{ 12, 38, 64, 90, 115, 141, 167, 193, - -12, -38, -64, -90, -115, -141, -167, -193, }, -{ 15, 45, 76, 106, 137, 167, 198, 228, - -15, -45, -76, -106, -137, -167, -198, -228, }, -{ 18, 54, 91, 127, 164, 200, 237, 273, - -18, -54, -91, -127, -164, -200, -237, -273, }, -{ 21, 65, 108, 152, 195, 239, 282, 326, - -21, -65, -108, -152, -195, -239, -282, -326, }, -{ 25, 77, 129, 181, 232, 284, 336, 388, - -25, -77, -129, -181, -232, -284, -336, -388, }, -{ 30, 92, 153, 215, 276, 338, 399, 461, - -30, -92, -153, -215, -276, -338, -399, -461, }, -{ 36, 109, 183, 256, 329, 402, 476, 549, - -36, -109, -183, -256, -329, -402, -476, -549, }, -{ 43, 130, 218, 305, 392, 479, 567, 654, - -43, -130, -218, -305, -392, -479, -567, -654, }, -{ 52, 156, 260, 364, 468, 572, 676, 780, - -52, -156, -260, -364, -468, -572, -676, -780, }, -{ 62, 186, 310, 434, 558, 682, 806, 930, - -62, -186, -310, -434, -558, -682, -806, -930, }, -{ 73, 221, 368, 516, 663, 811, 958, 1106, - -73, -221, -368, -516, -663, -811, -958, -1106, }, -{ 87, 263, 439, 615, 790, 966, 1142, 1318, - -87, -263, -439, -615, -790, -966, -1142, -1318, }, -{ 104, 314, 523, 733, 942, 1152, 1361, 1571, - -104, -314, -523, -733, -942, -1152, -1361, -1571, }, -{ 124, 374, 623, 873, 1122, 1372, 1621, 1871, - -124, -374, -623, -873, -1122, -1372, -1621, -1871, }, -{ 148, 445, 743, 1040, 1337, 1634, 1932, 2229, - -148, -445, -743, -1040, -1337, -1634, -1932, -2229, }, -{ 177, 531, 885, 1239, 1593, 1947, 2301, 2655, - -177, -531, -885, -1239, -1593, -1947, -2301, -2655, }, -{ 210, 632, 1053, 1475, 1896, 2318, 2739, 3161, - -210, -632, -1053, -1475, -1896, -2318, -2739, -3161, }, -{ 251, 753, 1255, 1757, 2260, 2762, 3264, 3766, - -251, -753, -1255, -1757, -2260, -2762, -3264, -3766, }, -{ 299, 897, 1495, 2093, 2692, 3290, 3888, 4486, - -299, -897, -1495, -2093, -2692, -3290, -3888, -4486, }, -{ 356, 1068, 1781, 2493, 3206, 3918, 4631, 5343, - -356, -1068, -1781, -2493, -3206, -3918, -4631, -5343, }, -{ 424, 1273, 2121, 2970, 3819, 4668, 5516, 6365, - -424, -1273, -2121, -2970, -3819, -4668, -5516, -6365, }, +static const int16_t step_size[32][16] = { + { 1, 5, 9, 13, 16, 20, 24, 28, + -1, -5, -9, -13, -16, -20, -24, -28, }, + { 2, 6, 11, 15, 20, 24, 29, 33, + -2, -6, -11, -15, -20, -24, -29, -33, }, + { 2, 7, 13, 18, 23, 28, 34, 39, + -2, -7, -13, -18, -23, -28, -34, -39, }, + { 3, 9, 15, 21, 28, 34, 40, 46, + -3, -9, -15, -21, -28, -34, -40, -46, }, + { 3, 11, 18, 26, 33, 41, 48, 56, + -3, -11, -18, -26, -33, -41, -48, -56, }, + { 4, 13, 22, 31, 40, 49, 58, 67, + -4, -13, -22, -31, -40, -49, -58, -67, }, + { 5, 16, 26, 37, 48, 59, 69, 80, + -5, -16, -26, -37, -48, -59, -69, -80, }, + { 6, 19, 31, 44, 57, 70, 82, 95, + -6, -19, -31, -44, -57, -70, -82, -95, }, + { 7, 22, 38, 53, 68, 83, 99, 114, + -7, -22, -38, -53, -68, -83, -99, -114, }, + { 9, 27, 45, 63, 81, 99, 117, 135, + -9, -27, -45, -63, -81, -99, -117, -135, }, + { 10, 32, 53, 75, 96, 118, 139, 161, + -10, -32, -53, -75, -96, -118, -139, -161, }, + { 12, 38, 64, 90, 115, 141, 167, 193, + -12, -38, -64, -90, -115, -141, -167, -193, }, + { 15, 45, 76, 106, 137, 167, 198, 228, + -15, -45, -76, -106, -137, -167, -198, -228, }, + { 18, 54, 91, 127, 164, 200, 237, 273, + -18, -54, -91, -127, -164, -200, -237, -273, }, + { 21, 65, 108, 152, 195, 239, 282, 326, + -21, -65, -108, -152, -195, -239, -282, -326, }, + { 25, 77, 129, 181, 232, 284, 336, 388, + -25, -77, -129, -181, -232, -284, -336, -388, }, + { 30, 92, 153, 215, 276, 338, 399, 461, + -30, -92, -153, -215, -276, -338, -399, -461, }, + { 36, 109, 183, 256, 329, 402, 476, 549, + -36, -109, -183, -256, -329, -402, -476, -549, }, + { 43, 130, 218, 305, 392, 479, 567, 654, + -43, -130, -218, -305, -392, -479, -567, -654, }, + { 52, 156, 260, 364, 468, 572, 676, 780, + -52, -156, -260, -364, -468, -572, -676, -780, }, + { 62, 186, 310, 434, 558, 682, 806, 930, + -62, -186, -310, -434, -558, -682, -806, -930, }, + { 73, 221, 368, 516, 663, 811, 958, 1106, + -73, -221, -368, -516, -663, -811, -958, -1106, }, + { 87, 263, 439, 615, 790, 966, 1142, 1318, + -87, -263, -439, -615, -790, -966, -1142, -1318, }, + { 104, 314, 523, 733, 942, 1152, 1361, 1571, + -104, -314, -523, -733, -942, -1152, -1361, -1571, }, + { 124, 374, 623, 873, 1122, 1372, 1621, 1871, + -124, -374, -623, -873, -1122, -1372, -1621, -1871, }, + { 148, 445, 743, 1040, 1337, 1634, 1932, 2229, + -148, -445, -743, -1040, -1337, -1634, -1932, -2229, }, + { 177, 531, 885, 1239, 1593, 1947, 2301, 2655, + -177, -531, -885, -1239, -1593, -1947, -2301, -2655, }, + { 210, 632, 1053, 1475, 1896, 2318, 2739, 3161, + -210, -632, -1053, -1475, -1896, -2318, -2739, -3161, }, + { 251, 753, 1255, 1757, 2260, 2762, 3264, 3766, + -251, -753, -1255, -1757, -2260, -2762, -3264, -3766, }, + { 299, 897, 1495, 2093, 2692, 3290, 3888, 4486, + -299, -897, -1495, -2093, -2692, -3290, -3888, -4486, }, + { 356, 1068, 1781, 2493, 3206, 3918, 4631, 5343, + -356, -1068, -1781, -2493, -3206, -3918, -4631, -5343, }, + { 424, 1273, 2121, 2970, 3819, 4668, 5516, 6365, + -424, -1273, -2121, -2970, -3819, -4668, -5516, -6365, }, }; +#ifdef MTAF_BLOCK_SUPPORT +/* autodetect and skip "macroblocks" */ +static void mtaf_block_update(VGMSTREAMCHANNEL * stream) { + int block_type, block_size, block_empty, block_tracks, repeat = 1; + + do { + block_type = read_32bitLE(stream->offset+0x00, stream->streamfile); + block_size = read_32bitLE(stream->offset+0x04, stream->streamfile); /* including this header */ + block_empty = read_32bitLE(stream->offset+0x08, stream->streamfile); /* always 0 */ + block_tracks = read_32bitLE(stream->offset+0x0c, stream->streamfile); /* total tracks of 0x110 (can be 0)*/ + + /* 0x110001: music (type 0x11=adpcm), 0xf0: loop control (goes at the end) */ + if ((block_type != 0x00110001 && block_type != 0x000000F0) || block_empty != 0) + return; /* not a block */ + + /* track=001100+01 could be mistaken as block_type, do extra checks */ + { + int track = read_8bit(stream->offset+0x10, stream->streamfile); + if (track != 0 && track != 1) + return; /* if this is a block, next header should be from track 0/1 */ + if (block_tracks > 0 && (block_size-0x10) != block_tracks*0x110) + return; /* wrong expected size */ + } + + if (block_size <= 0 || block_tracks < 0) { /* nonsense block (maybe at EOF) */ + VGM_LOG("MTAF: bad block @ %08lx\n", stream->offset); + stream->offset += 0x10; + repeat = 0; + } + else if (block_tracks == 0) { /* empty block (common), keep repeating */ + stream->offset += block_size; + } + else { /* normal block, position into next track header */ + stream->offset += 0x10; + repeat = 0; + } + + } while(repeat); +} +#endif void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int channels) { int32_t sample_count; - off_t cur_off = stream->offset; int i; - int c = channel%2; /* global channel to stream channel */ + int c = channel%2; /* global channel to track channel */ int32_t hist = stream->adpcm_history1_16; int32_t step_idx = stream->adpcm_step_index; - uint8_t byte = 0; -#if MTAF_BLOCK_SUPPORT - { - /* "macroblock" support (layout/mtaf_block.c) was removed since the extractor now produces clean files; - * this a hack to skip those blocks, left as a reminder (not well tested) */ - int unk, size, empty, frames, repeat = 1; - do { - unk = read_32bitLE(cur_off+0x00, stream->streamfile); /* always BE 0x01001100? */ - size = read_32bitLE(cur_off+0x04, stream->streamfile); /* block size */ - empty = read_32bitLE(cur_off+0x08, stream->streamfile); /* always 0? */ - frames = read_32bitLE(cur_off+0x0c, stream->streamfile); /* total frames of 0x110 */ - if (unk == 0x00110001 && empty == 0 && size > 0) { - if (frames == 0) { - stream->offset += size; /* full skip */ - } else if ((size-0x10) == frames*0x110) { - stream->offset += 0x10; /* header skip */ - repeat = 0; - } - cur_off = stream->offset; - } - else { - repeat = 0; - } - - } while(repeat); - } -#endif + #ifdef MTAF_BLOCK_SUPPORT + /* autodetect and skip macroblock header */ + mtaf_block_update(stream); + #endif + /* read header when we hit a new track every 0x100 samples */ first_sample = first_sample % 0x100; - /* read header when we hit a new frame every 0x100 samples */ if (first_sample == 0) { - int32_t init_idx, init_hist; - - /* 0x10 header: owner stream, frame count, step-L, step-R, hist-L, hist-R */ - /* uint32_t stream = read_8bit(cur_off+0+c*2, stream->streamfile); */ /* 0=first */ - /* uint24_t frames = (uint24_t)read_16bitLE(cur_off+1, stream->streamfile); */ /* 1=first */ - init_idx = read_16bitLE(cur_off+4+c*2, stream->streamfile); /* step-L/R */ - init_hist = read_16bitLE(cur_off+4+4+c*4, stream->streamfile); /* hist-L/R: hist 16bit + empty 16bit */ - - VGM_ASSERT( read_16bitLE(cur_off+4+4+2+c*4, stream->streamfile) != 0, - "init_hist not 16bit at 0x%lx, ch=%d\n", cur_off, c); - VGM_ASSERT( init_idx < 0 || init_idx > 31, - "init_idx out of range at 0x%lx, ch=%d\n", cur_off, c); - VGM_ASSERT( step_idx != init_idx, - "step_idx does not match init_idx at 0x%lx, step=%d, init=%d\n",cur_off,step_idx, init_idx); + /* 0x10 header: track (8b, 0=first), track count (24b, 1=first), step-L, step-R, hist-L, hist-R */ + int32_t init_idx = read_16bitLE(stream->offset+4+0+c*2, stream->streamfile); /* step-L/R */ + int32_t init_hist = read_16bitLE(stream->offset+4+4+c*4, stream->streamfile); /* hist-L/R: hist 16bit + empty 16bit */ + VGM_ASSERT(init_idx < 0 || init_idx > 31, "MTAF: bad header idx @ 0x%lx\n", stream->offset); /* avoid index out of range in corrupt files */ if (init_idx < 0) { init_idx = 0; @@ -149,18 +159,12 @@ void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, } + /* skip to nibble */ for (i=first_sample,sample_count=0; istreamfile); - nibble = byte & 0x0f; - } else { /* high nibble last */ - nibble = byte >> 4; - } + uint8_t byte = read_8bit(stream->offset + 0x10 + 0x80*c + i/2, stream->streamfile); + uint8_t nibble = (byte >> (!(i&1)?0:4)) & 0xf; /* lower first */ hist = clamp16(hist+step_size[step_idx][nibble]); - outbuf[sample_count] = hist; step_idx += index_table[nibble]; @@ -169,10 +173,9 @@ void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, } else if (step_idx > 31) { step_idx = 31; } - } /* end sample loop */ + } - // update state + /* update state */ stream->adpcm_step_index = step_idx; stream->adpcm_history1_16 = hist; - } diff --git a/src/meta/ps2_mtaf.c b/src/meta/ps2_mtaf.c index 8465e356..0c99479a 100644 --- a/src/meta/ps2_mtaf.c +++ b/src/meta/ps2_mtaf.c @@ -1,182 +1,94 @@ -//#include #include "meta.h" #include "../util.h" -/* MTAF (Metal Gear Solid 3: Snake Eater) */ + +/* MTAF - found in Metal Gear Solid 3: Snake Eater (Subsistence and HD too) */ VGMSTREAM * init_vgmstream_ps2_mtaf(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; off_t start_offset; + int loop_flag, channel_count; + int32_t loop_start, loop_end; - int stream_count; - int loop_flag = 1; - int channel_count; - int32_t loop_start; - int32_t loop_end; - int i; + /* check extension */ + if ( !check_extensions(streamFile,"mtaf")) + goto fail; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("mtaf",filename_extension(filename))) goto fail; + /* base header */ + if (read_32bitBE(0x00, streamFile) != 0x4d544146) /* "MTAF" */ + goto fail; + /* 0x04(4): pseudo file size (close but smaller) */ + /* 0x08(4): version? (0), 0x0c(20): null, 0x30(32): some kind of id or config? */ - /* check header */ - // master MTAF header (mostly useless) + /* HEAD chunk */ + if (read_32bitBE(0x40, streamFile) != 0x48454144) /* "HEAD" */ + goto fail; + if (read_32bitLE(0x44, streamFile) != 0xB0) /* HEAD size */ + goto fail; - if (read_32bitBE(0, streamFile) != 0x4d544146) // "MTAF" - { - //fprintf(stderr, "no MTAF header at 0x%08lx\n", cur_off); + + /* 0x48(4): null, 0x4c: usually channel count (sometimes 0x10 with 2ch), 0x50(4): 0x7F (vol?), 0x54(2): 0x40 (pan?) */ + channel_count = 2 * read_8bit(0x61, streamFile); /* 0x60(4): full block size (0x110 * channels), but this works */ + /* 0x70(4): ? (00/05/07), 0x80 .. 0xf8: null */ + + loop_start = read_32bitLE(0x58, streamFile); + loop_end = read_32bitLE(0x5c, streamFile); + loop_flag = (loop_start != loop_end); + + /* check loop points vs frame counts */ + if (loop_start/0x100 != read_32bitLE(0x64, streamFile) || + loop_end /0x100 != read_32bitLE(0x68, streamFile) ) { + VGM_LOG("MTAF: wrong loop points\n"); goto fail; } - //const uint32_t pseudo_size = readint32(&mtaf_header_buf[4]); + /* TRKP chunks (x16) */ + /* just seem to contain pan/vol stuff (0x7f/0x40), one TRKP with data per channel and the rest fixed values */ - // check the rest is clear - for (i = 0x8; i < 0x20; i++) - { - if (read_8bit(i, streamFile) != 0) - { - //fprintf(stderr, "unexpected nonzero in MTAF header at 0x%08lx\n", cur_off+i); - goto fail; - } - } - - // ignore the rest for now - - // HEAD chunk header - - if (read_32bitBE(0x40, streamFile) != 0x48454144) // "HEAD" - { - //fprintf(stderr, "no HEAD chunk at 0x%08lx\n", cur_off); - goto fail; - } - - { - uint32_t mtaf_head_chunk_size = read_32bitLE(0x44, streamFile); - if (mtaf_head_chunk_size != 0xB0) - { - //fprintf(stderr, "unexpected size for MTAF header at 0x%08lx\n", cur_off); - goto fail; - } - } - - stream_count = read_8bit(0x61, streamFile); - - // check some standard stuff - if ( 0 != read_32bitLE(0x48, streamFile) || - 0x7F != read_32bitLE(0x50, streamFile) || - 0x40 != read_32bitLE(0x54, streamFile) || - 0 != read_16bitLE(0x62, streamFile) || - 0 != read_32bitLE(0x6c, streamFile)) // || - //5 != readint32(&mtaf_header_buf[0x68])) || - //(dc.streams==3 ? 12:0) != readint32(&mtaf_header_buf[0x7c])) - { - //fprintf(stderr, "unexpected header values at 0x%08lx\n", cur_off); + /* DATA chunk */ + if (read_32bitBE(0x7f8, streamFile) != 0x44415441) /* "DATA" */ goto fail; - } + /* 0x7fc: data size (without blocks in case of blocked layout) */ - // 0 streams should be impossible - if (stream_count == 0) - { - //fprintf(stderr, "0 streams at 0x%08lx\n", cur_off); - goto fail; - } + /* without blocks it should start with 0x00000100 ("frame 1 from track 0") */ + //is_blocked = read_32bitLE(0x800,streamFile) != 0x00000100 && read_32bitLE(0x810,streamFile) == 0x00000100; - // check the other stream count indicator - if (stream_count*0x10 != read_8bit(0x60, streamFile)) - { - //fprintf(stderr, "secondary stream count mismatch at 0x%08lx\n", cur_off); - goto fail; - } - -#if 0 - // maybe this is how to compute channels per stream? - // check total channel count - if (2*stream_count != read_32bitLE(0x4c, streamFile)) - { - //fprintf(stderr, "total channel count does not match stream count at 0x%08lx\n", cur_off); - goto fail; - } -#endif - - // check loop points as frame counts - if (read_32bitLE(0x64, streamFile) != read_32bitLE(0x58, streamFile)/0x100 || - read_32bitLE(0x68, streamFile) != read_32bitLE(0x5c, streamFile)/0x100) - { - //fprintf(stderr, "loop frame count mismatch at 0x%lx\n", cur_off); - goto fail; - } - - // check that rest is clear - for (i = 0x78; i < 0xf8; i++) - { - if (read_8bit(i, streamFile) != 0) - { - //fprintf(stderr, "unexpected nonzero in HEAD chunk at 0x%lx\n", cur_off+i); - goto fail; - } - } - - // check TRKP chunks - for (i = 0; i < 16; i++) - { - if (read_32bitBE(0xf8+0x70*i, streamFile) != 0x54524b50 || // "TRKP" - read_32bitLE(0xf8+0x70*i+4, streamFile) != 0x68) - { - //fprintf(stderr, "missing or unusual TRKP chunk #%d at 0x%lx\n", i, cur_off); - goto fail; - } - } - - // check for grand finale, DATA - if (read_32bitBE(0x7f8, streamFile) != 0x44415441) // "DATA" - { - //fprintf(stderr, "missing DATA header at 0x%lx\n", cur_off); - goto fail; - } start_offset = 0x800; - // seems to always be the case - channel_count = 2 * stream_count; - - loop_start = read_32bitLE(0x58, streamFile); - loop_end = read_32bitLE(0x5c, streamFile); - if (loop_start == loop_end) loop_flag = 0; - + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count, loop_flag); if (!vgmstream) goto fail; - // a guess - vgmstream->channels = channel_count; - vgmstream->sample_rate = 48000; - vgmstream->coding_type = coding_MTAF; - vgmstream->num_samples = read_32bitLE(0x5c, streamFile); - + vgmstream->sample_rate = 48000; /* always */ + vgmstream->num_samples = loop_end; vgmstream->loop_start_sample = loop_start; vgmstream->loop_end_sample = loop_end; - vgmstream->interleave_block_size = 0x110/2; - + vgmstream->coding_type = coding_MTAF; vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x110/2; /* kinda hacky for MTAF track layout */ vgmstream->meta_type = meta_PS2_MTAF; - //const uint32_t pseudo_data_size = readint32(&mtaf_header_buf[4]); - // TODO: first block + /* open the file for reading, in a specific way */ + { + int i; + char filename[PATH_LIMIT]; - /* open the file for reading */ - for (i = 0; i < channel_count; i++) { - STREAMFILE * file = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); - if (!file) goto fail; - vgmstream->ch[i].streamfile = file; - vgmstream->ch[i].channel_start_offset = vgmstream->ch[i].offset = start_offset + vgmstream->interleave_block_size*2*(i/2); + streamFile->get_name(streamFile,filename,sizeof(filename)); + for (i = 0; i < channel_count; i++) { + STREAMFILE * file = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); + if (!file) goto fail; + vgmstream->ch[i].streamfile = file; + vgmstream->ch[i].channel_start_offset = vgmstream->ch[i].offset = start_offset + vgmstream->interleave_block_size*2*(i/2); + } } return vgmstream; fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } From 661ed2da20eee1ac964e66ad4671768f45fc2df1 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 18 May 2017 19:06:58 +0200 Subject: [PATCH 02/17] Fix GTD #ifdef issue --- src/meta/gtd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/meta/gtd.c b/src/meta/gtd.c index 8aaf228a..8550c79e 100644 --- a/src/meta/gtd.c +++ b/src/meta/gtd.c @@ -19,7 +19,7 @@ VGMSTREAM * init_vgmstream_gtd(STREAMFILE *streamFile) { if (read_32bitBE(0x00,streamFile) != 0x47485320) /* "GHS " */ goto fail; -VGM_LOG("1"); + /* header type, not formally specified */ if (read_32bitBE(0x04,streamFile) == 1 && read_16bitBE(0x0C,streamFile) == 0x0166) { /* XMA2 */ /* 0x08(4): seek table size */ @@ -55,8 +55,8 @@ VGM_LOG("1"); vgmstream->meta_type = meta_GTD; switch(codec) { - case XMA2: { #ifdef VGM_USE_FFMPEG + case XMA2: { uint8_t buf[0x100]; size_t bytes; From 08a01fec1f527bfeb84feb7371c5f51cb3cc3085 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 18 May 2017 19:11:21 +0200 Subject: [PATCH 03/17] Fixed .str XMA [Sonic & Sega All Stars Racing with Banjo X360] --- src/meta/ps2_strlr.c | 4 ++++ src/meta/xma.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/meta/ps2_strlr.c b/src/meta/ps2_strlr.c index cdfe4a14..ce56b8cc 100644 --- a/src/meta/ps2_strlr.c +++ b/src/meta/ps2_strlr.c @@ -23,6 +23,10 @@ VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE *streamFile) { goto fail; #endif + /* don't hijack Sonic & Sega All Stars Racing X360 (xma) */ + if (read_32bitBE(0x00,streamFile) == 0x52494646) /* "RIFF"*/ + goto fail; + loop_flag = 0; channel_count = 2; diff --git a/src/meta/xma.c b/src/meta/xma.c index c54acef0..d8247f17 100644 --- a/src/meta/xma.c +++ b/src/meta/xma.c @@ -11,8 +11,8 @@ VGMSTREAM * init_vgmstream_xma(STREAMFILE *streamFile) { /* check extension, case insensitive */ - /* .xma2: Skullgirls, .nps: Beautiful Katamari (renamed .xma) */ - if ( !check_extensions(streamFile, "xma,xma2,nps") ) + /* .xma2: Skullgirls, .nps: Beautiful Katamari (renamed .xma), .str: Sonic & Sega All Stars Racing */ + if ( !check_extensions(streamFile, "xma,xma2,nps,str") ) goto fail; { From 625c18a87eb8eebea2fd7fce627a8162dd5bc456 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 18 May 2017 19:16:44 +0200 Subject: [PATCH 04/17] Add MTA2 decoder/meta support [Metal Gear Solid 4 (PS3)] --- src/coding/coding.h | 3 + src/coding/mta2_decoder.c | 186 +++++++++++++++++++++++++++++++ src/formats.c | 7 +- src/libvgmstream.vcproj | 8 ++ src/libvgmstream.vcxproj | 2 + src/libvgmstream.vcxproj.filters | 6 + src/meta/meta.h | 2 + src/meta/ps3_mta2.c | 104 +++++++++++++++++ src/vgmstream.c | 12 ++ src/vgmstream.h | 2 + 10 files changed, 330 insertions(+), 2 deletions(-) create mode 100644 src/coding/mta2_decoder.c create mode 100644 src/meta/ps3_mta2.c diff --git a/src/coding/coding.h b/src/coding/coding.h index c487ef38..9cbc24db 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -114,6 +114,9 @@ void decode_lsf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, /* mtaf_decoder */ void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int channels); +/* mta2_decoder */ +void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); + /* mc3_decoder */ void decode_mc3(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); diff --git a/src/coding/mta2_decoder.c b/src/coding/mta2_decoder.c new file mode 100644 index 00000000..650bb856 --- /dev/null +++ b/src/coding/mta2_decoder.c @@ -0,0 +1,186 @@ +#include "coding.h" +#include "../util.h" + +/* MTA2 (EA XAS variant?) decoder based on: + * - MGS Developer Wiki: https://www.mgsdevwiki.com/wiki/index.php/MTA2_(Codec) [codec by daemon1] + * - Solid4 tools: https://github.com/GHzGangster/Drebin + * + * MTA2 layout: + * - data is divided into N tracks of 0x10 header + 0x90 frame per track channel, forming N streams + * ex: 8ch: track0 4ch + track1 4ch + track0 4ch + track1 4ch ...; or 2ch = 1ch track0 + 1ch track1 + * * up to 16 possible tracks, but max seen is 3 (ex. track0=sneaking, track1=action, track2=ambience) + * - each ch frame is divided into 4 headers + 4 vertical groups with nibbles (0x4*4 + 0x20*4) + * ex. group1 is 0x04(4) + 0x14(4) + 0x24(4) + 0x34(4) ... (vertically maybe for paralelism?) + * - in case of "macroblock" layout, there are also headers before N tracks (like other MGS games) + * + * Due to this vertical layout and multiple hist/indexes, it decodes everything in a block between calls + * but discards unwanted data, instead of trying to skip to the target nibble. Meaning no need to save hist, and + * expects samples_to_do to be block_samples at most (could be simplified, I guess). + * + * Because of how the macroblock/track and stream's offset per channel work, they are supported by + * autodetecting and skipping when needed (ideally should keep a special layout/count, but this is simpler). + */ + +static const int c1[8] = { /* mod table 1 */ + 0, 240, 460, 392, 488, 460, 460, 240 +}; +static const int c2[8] = { /* mod table 2 */ + 0, 0, -208, -220, -240, -240, -220, -104 +}; +static const int c3[32] = { /* shift table */ + 256, 335, 438, 573, 749, 979, 1281, 1675, + 2190, 2864, 3746, 4898, 6406, 8377, 10955, 14327, + 18736, 24503, 32043, 41905, 54802, 71668, 93724, 122568, + 160290, 209620, 274133, 358500, 468831, 613119, 801811, 1048576 +}; + +/* expands nibble */ +static short calculate_output(int nibble, short smp1, short smp2, int mod, int sh) { + int output; + if (nibble > 7) /* sign extend */ + nibble = nibble - 16; + + output = (smp1 * c1[mod] + smp2 * c2[mod] + (nibble * c3[sh]) + 128) >> 8; + output = clamp16(output); + return (short)output; +} + + +/* autodetect and skip "macroblocks" */ +static void mta2_block_update(VGMSTREAMCHANNEL * stream) { + int block_type, block_size, block_tracks, repeat = 1; + + /* may need to skip N empty blocks */ + do { + block_type = read_32bitBE(stream->offset + 0x00, stream->streamfile); + block_size = read_32bitBE(stream->offset + 0x04, stream->streamfile); /* including this header */ + /* 0x08: always null */ + block_tracks = read_32bitBE(stream->offset + 0x0c, stream->streamfile); /* total tracks of variable size (can be 0) */ + + /* 0x10001: music, 0x20001: sfx?, 0xf0: loop control (goes at the end) */ + if (block_type != 0x00010001 && block_type != 0x00020001 && block_type != 0x000000F0) + return; /* not a block */ + + /* frame=010001+00/etc can be mistaken as block_type, do extra checks */ + { + int i, track_channels = 0; + uint16_t channel_layout = (block_size >> 16); + uint16_t track_size = (block_size & 0xFFFF); + + /* has chanel layout == may be a track */ + if (channel_layout > 0 && channel_layout <= 0xFF) { + for (i = 0; i < 8; i++) { + if ((channel_layout >> i) & 0x01) + track_channels++; + } + if (track_channels*0x90 == track_size) + return; + } + } + + if (block_size <= 0 || block_tracks < 0) { /* nonsense block (maybe at EOF) */ + VGM_LOG("MTA2: bad block @ %08lx\n", stream->offset); + stream->offset += 0x10; + repeat = 0; + } + else if (block_tracks == 0) { /* empty block (common), keep repeating */ + stream->offset += block_size; + } + else { /* normal block, position into next track header */ + stream->offset += 0x10; + repeat = 0; + } + } while (repeat); +} + +/* decodes a block for a channel, skipping macroblocks/tracks if needed */ +void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { + int samples_done = 0, sample_count = 0, channel_block_samples, channel_first_sample, frame_size = 0; + int i, group, row, col; + int num_track = 0, channel_layout, track_channels = 0, track_channel; + + + /* block/track skip */ + do { + /* autodetect and skip macroblock header */ + mta2_block_update(stream); + + /* parse track header (0x10) and skip tracks that our current channel doesn't belong to */ + num_track = read_8bit(stream->offset+0x00,stream->streamfile); /* 0=first */ + /* 0x01(3): num_frame (0=first), 0x04(1): 0? */ + channel_layout = read_8bit(stream->offset+0x05,stream->streamfile); /* bitmask, see mta2.c */ + frame_size = read_16bitBE(stream->offset+0x06,stream->streamfile); /* not including this header */ + /* 0x08(8): null */ + + if (num_track < 0) + break; /* EOF: whatever */ + + track_channels = 0; + for (i = 0; i < 8; i++) { + if ((channel_layout >> i) & 0x01) + track_channels++; + } + + /* assumes tracks channels are divided evenly in all tracks (ex. not 2ch + 1ch + 1ch) */ + if (channel / track_channels == num_track) + break; /* channel belongs to this track */ + + /* keep looping for our track */ + stream->offset += 0x10 + frame_size; + } + while (1); + + track_channel = channel % track_channels; + channel_block_samples = (0x80*2); + channel_first_sample = first_sample % (0x80*2); + + + /* parse channel frame (header 0x04*4 + data 0x20*4) */ + for (group = 0; group < 4; group++) { + short smp2, smp1, mod, sh, output; + int group_header = read_32bitBE(stream->offset + 0x10 + track_channel*0x90 + group*0x4, stream->streamfile); + smp2 = (short) ((group_header >> 16) & 0xfff0); /* upper 16b discarding 4b */ + smp1 = (short) ((group_header >> 4) & 0xfff0); /* lower 16b discarding 4b */ + mod = (group_header >> 5) & 0x7; /* mid 3b */ + sh = group_header & 0x1f; /* lower 5b */ + + /* write header samples (skips the last 2 group nibbles), like Drebin's decoder + * last 2 nibbles and next 2 header hist should match though */ + if (sample_count >= channel_first_sample && samples_done < samples_to_do) { + outbuf[samples_done * channelspacing] = smp2; + samples_done++; + } + sample_count++; + if (sample_count >= channel_first_sample && samples_done < samples_to_do) { + outbuf[samples_done * channelspacing] = smp1; + samples_done++; + } + sample_count++; + + for (row = 0; row < 8; row++) { + for (col = 0; col < 4*2; col++) { + uint8_t nibbles = read_8bit(stream->offset + 0x10 + 0x10 + track_channel*0x90 + group*0x4 + row*0x10 + col/2, stream->streamfile); + int nibble_shift = (!(col&1) ? 4 : 0); /* upper first */ + output = calculate_output((nibbles >> nibble_shift) & 0xf, smp1, smp2, mod, sh); + + /* ignore last 2 nibbles (uses first 2 header samples) */ + if (row < 7 || col < 3*2) { + if (sample_count >= channel_first_sample && samples_done < samples_to_do) { + outbuf[samples_done * channelspacing] = output; + samples_done++; + } + sample_count++; + } + + smp2 = smp1; + smp1 = output; + } + } + } + + + /* block fully done */ + if (channel_first_sample + samples_done == channel_block_samples) { + stream->offset += 0x10 + frame_size; + } +} diff --git a/src/formats.c b/src/formats.c index d6e4c9eb..f7f05094 100644 --- a/src/formats.c +++ b/src/formats.c @@ -53,6 +53,7 @@ static const char* extension_list[] = { "bfwav", "bfwavnsmbu", "bg00", + "bgm", "bgw", "bh2pcm", "bik", @@ -82,6 +83,7 @@ static const char* extension_list[] = { "cps", "cxs", + "dbm", "dcs", "ddsp", "de2", @@ -168,6 +170,7 @@ static const char* extension_list[] = { "msf", "mss", "msvp", + "mta2", "mtaf", "mus", "musc", @@ -288,11 +291,9 @@ static const char* extension_list[] = { "vgs", "vgv", "vig", - "vds", "vdm", "vms", - "vms", "voi", "vpk", "vs", @@ -446,6 +447,7 @@ static const coding_info coding_info_list[] = { {coding_SASSC, "Activision / EXAKT SASSC 8-bit DPCM"}, {coding_LSF, "lsf 4-bit ADPCM"}, {coding_MTAF, "Konami MTAF 4-bit ADPCM"}, + {coding_MTA2, "Konami MTA2 4-bit ADPCM"}, {coding_MC3, "Paradigm MC3 3-bit ADPCM"}, #ifdef VGM_USE_VORBIS @@ -861,6 +863,7 @@ static const meta_info meta_info_list[] = { {meta_GTD, "GTD/GHS header"}, {meta_TA_AAC_X360, "tri-Ace AAC (X360) header"}, {meta_TA_AAC_PS3, "tri-Ace AAC (PS3) header"}, + {meta_PS3_MTA2, "Konami MTA2 header"}, #ifdef VGM_USE_VORBIS {meta_OGG_VORBIS, "Ogg Vorbis"}, diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 840dca62..8059d0f6 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -966,6 +966,10 @@ RelativePath=".\meta\ps3_msf.c" > + + @@ -1358,6 +1362,10 @@ RelativePath=".\coding\mtaf_decoder.c" > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index fea8ae16..2d76ac07 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -129,6 +129,7 @@ + @@ -343,6 +344,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 96658cea..160078f5 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -580,6 +580,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files @@ -1009,6 +1012,9 @@ coding\Source Files + + coding\Source Files + meta\Source Files diff --git a/src/meta/meta.h b/src/meta/meta.h index 7f0be80b..3cdb2839 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -677,4 +677,6 @@ VGMSTREAM * init_vgmstream_gtd(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ta_aac_x360(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ta_aac_ps3(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_ps3_mta2(STREAMFILE *streamFile); + #endif /*_META_H*/ diff --git a/src/meta/ps3_mta2.c b/src/meta/ps3_mta2.c new file mode 100644 index 00000000..83825f81 --- /dev/null +++ b/src/meta/ps3_mta2.c @@ -0,0 +1,104 @@ +#include "meta.h" +#include "../util.h" + + +/* MTA2 - found in Metal Gear Solid 4 */ +VGMSTREAM * init_vgmstream_ps3_mta2(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t header_offset, start_offset; + int loop_flag, channel_count, sample_rate; //block_offset; + int32_t loop_start, loop_end; + + + /* check extension */ + /* .mta2: normal file, .bgm: mta2 with block layout, .dbm: iPod metadata + block layout mta2 */ + if ( !check_extensions(streamFile,"mta2,bgm,dbm")) + goto fail; + + /* base header (everything is very similar to MGS3's MTAF but BE) */ + if (read_32bitBE(0x00,streamFile) == 0x4d544132) { /* "MTA2" (.mta) */ + //block_offset = 0; + header_offset = 0x00; + } else if (read_32bitBE(0x20,streamFile) == 0x4d544132) { /* "MTA2" @ 0x20 (.bgm) */ + //block_offset = 0x10; + header_offset = 0x20; + } else if (read_32bitBE(0x00, streamFile) == 0x444C424D + && read_32bitBE(0x820,streamFile) == 0x4d544132) { /* "DLBM" + "MTA2" @ 0x820 (.dbm) */ + //block_offset = 0x810; + header_offset = 0x820; + } else { + goto fail; + } + /* 0x04(4): file size -4-4 (not including block headers in case of block layout) */ + /* 0x08(4): version? (1), 0x0c(52): null */ + + + /* HEAD chunk */ + if (read_32bitBE(header_offset+0x40, streamFile) != 0x48454144) /* "HEAD" */ + goto fail; + if (read_32bitBE(header_offset+0x44, streamFile) != 0xB0) /* HEAD size */ + goto fail; + + + + /* 0x48(4): null, 0x4c: ? (0x10), 0x50(4): 0x7F (vol?), 0x54(2): 0x40 (pan?) */ + channel_count = read_16bitBE(header_offset+0x56, streamFile); /* counting all tracks */ + /* 0x60(4): full block size (0x110 * channels), indirectly channels_per_track = channels / (block_size / 0x110) */ + /* 0x80 .. 0xf8: null */ + + loop_start = read_32bitBE(header_offset+0x58, streamFile); + loop_end = read_32bitBE(header_offset+0x5c, streamFile); + loop_flag = (loop_start != loop_end); /* also flag possibly @ 0x73 */ +#if 0 + /* those values look like some kind of loop offsets */ + if (loop_start/0x100 != read_32bitBE(header_offset+0x68, streamFile) || + loop_end /0x100 != read_32bitBE(header_offset+0x6C, streamFile) ) { + VGM_LOG("MTA2: wrong loop points\n"); + goto fail; + } +#endif + + sample_rate = read_32bitBE(header_offset+0x7c, streamFile); + if (sample_rate) { /* sample rate in 32b float (WHY?) typically 48000.0 */ + float sample_float; + memcpy(&sample_float, &sample_rate, 4); + sample_rate = (int)sample_float; + } else { /* default when not specified (most of the time) */ + sample_rate = 48000; + } + + + /* TRKP chunks (x16) */ + /* just seem to contain pan/vol stuff (0x7f/0x40), TRKP per track (sometimes +1 main track?) */ + /* there is channel layout bitmask @ 0x0f (ex. 1ch = 0x04, 3ch = 0x07, 4ch = 0x33, 6ch = 0x3f), surely: + * FRONT_L = 0x01, FRONT_R = 0x02, FRONT_M = 0x04, BACK_L = 0x08, BACK_R = 0x10, BACK_M = 0x20 */ + + /* DATA chunk */ + if (read_32bitBE(header_offset+0x7f8, streamFile) != 0x44415441) // "DATA" + goto fail; + /* 0x7fc: data size (without blocks in case of blocked layout) */ + + start_offset = header_offset + 0x800; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = loop_end; + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; + + vgmstream->coding_type = coding_MTA2; + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_PS3_MTA2; + + /* open the file for reading */ + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/vgmstream.c b/src/vgmstream.c index e8adb533..01d772b4 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -360,6 +360,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_rsd6xma, init_vgmstream_ta_aac_x360, init_vgmstream_ta_aac_ps3, + init_vgmstream_ps3_mta2, #ifdef VGM_USE_FFMPEG init_vgmstream_mp4_aac_ffmpeg, @@ -1065,6 +1066,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { return 54; case coding_MTAF: return 0x80*2; + case coding_MTA2: + return 0x80*2; case coding_MC3: return 10; case coding_CRI_HCA: @@ -1191,6 +1194,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_MSADPCM: case coding_MTAF: return vgmstream->interleave_block_size; + case coding_MTA2: + return 0x90; case coding_MC3: return 4; default: @@ -1735,6 +1740,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to chan, vgmstream->channels); } break; + case coding_MTA2: + for (chan=0;chanchannels;chan++) { + decode_mta2(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels, vgmstream->samples_into_block, samples_to_do, + chan); + } + break; case coding_MC3: for (chan=0;chanchannels;chan++) { decode_mc3(vgmstream, &vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, diff --git a/src/vgmstream.h b/src/vgmstream.h index 726e08df..d6e72a45 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -134,6 +134,7 @@ typedef enum { coding_SASSC, /* Activision EXAKT SASSC DPCM */ coding_LSF, /* lsf ADPCM (Fastlane Street Racing iPhone)*/ coding_MTAF, /* Konami MTAF ADPCM (IMA-derived) */ + coding_MTA2, /* Konami MTA2 ADPCM */ coding_MC3, /* Paradigm MC3 3-bit ADPCM */ /* others */ @@ -615,6 +616,7 @@ typedef enum { meta_GTD, /* Knights Contract (X360/PS3), Valhalla Knights 3 (PSV) */ meta_TA_AAC_X360, /* tri-ace AAC (Star Ocean 4, End of Eternity, Infinite Undiscovery) */ meta_TA_AAC_PS3, /* tri-ace AAC (Star Ocean International, Resonance of Fate) */ + meta_PS3_MTA2, /* Metal Gear Solid 4 MTA2 */ #ifdef VGM_USE_VORBIS meta_OGG_VORBIS, /* Ogg Vorbis */ From 2c1dafa1a08b30fd70e97f90d7fbac4cc5f5f90c Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 18 May 2017 19:17:19 +0200 Subject: [PATCH 05/17] Add missing exts --- src/formats.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/formats.c b/src/formats.c index f7f05094..78e9599c 100644 --- a/src/formats.c +++ b/src/formats.c @@ -145,6 +145,7 @@ static const char* extension_list[] = { "kovs", "kraw", + "laac", //fake extension, for tri-Ace/FFmpeg "leg", "lmp4", //fake extension, for looping "logg", //fake extension, for looping @@ -158,6 +159,7 @@ static const char* extension_list[] = { "mca", "mcg", "mds", + "mdsp", "mi4", "mib", "mic", From 9488ba32c7b961e818eddfe41332e43827c6ce65 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 18 May 2017 19:55:00 +0200 Subject: [PATCH 06/17] test.exe: add "-F" option to loop + play stream's end instead of fading --- src/vgmstream.c | 37 ++++++++++++++++++++++++++++++++----- src/vgmstream.h | 8 ++++++-- test/test.c | 34 ++++++++++++++++++++++------------ 3 files changed, 60 insertions(+), 19 deletions(-) diff --git a/src/vgmstream.c b/src/vgmstream.c index 01d772b4..a628819e 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -869,12 +869,31 @@ void close_vgmstream(VGMSTREAM * vgmstream) { free(vgmstream); } +/* calculate samples based on player's config */ int32_t get_vgmstream_play_samples(double looptimes, double fadeseconds, double fadedelayseconds, VGMSTREAM * vgmstream) { if (vgmstream->loop_flag) { - return vgmstream->loop_start_sample+(vgmstream->loop_end_sample-vgmstream->loop_start_sample)*looptimes+(fadedelayseconds+fadeseconds)*vgmstream->sample_rate; - } else return vgmstream->num_samples; + if (fadeseconds < 0) { /* a bit hack-y to avoid signature change */ + /* Continue playing the file normally after looping, instead of fading. + * Most files cut abruply after the loop, but some do have proper endings. + * With looptimes = 1 this option should give the same output vs loop disabled */ + int loop_count = (int)looptimes; /* no half loops allowed */ + vgmstream->loop_target = loop_count; + return vgmstream->loop_start_sample + + (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * loop_count + + (vgmstream->num_samples - vgmstream->loop_end_sample); + } + else { + return vgmstream->loop_start_sample + + (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * looptimes + + (fadedelayseconds + fadeseconds) * vgmstream->sample_rate; + } + } + else { + return vgmstream->num_samples; + } } +/* decode data into sample buffer */ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { switch (vgmstream->layout_type) { case layout_interleave: @@ -1788,13 +1807,21 @@ int vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMST return samples_to_do; } -/* return 1 if we just looped */ +/* loop if end sample is reached, and return 1 if we did loop */ int vgmstream_do_loop(VGMSTREAM * vgmstream) { - /*if (vgmstream->loop_flag) return 0;*/ + /*if (!vgmstream->loop_flag) return 0;*/ - /* is this the loop end? */ + /* is this the loop end? = new loop, continue from loop_start_sample */ if (vgmstream->current_sample==vgmstream->loop_end_sample) { + /* disable looping if target count reached and continue normally + * (only needed with the "play stream end after looping N times" option enabled) */ + vgmstream->loop_count++; + if (vgmstream->loop_target && vgmstream->loop_target == vgmstream->loop_count) { + vgmstream->loop_flag = 0; /* could be improved but works ok */ + return 0; + } + /* against everything I hold sacred, preserve adpcm * history through loop for certain types */ if (vgmstream->meta_type == meta_DSP_STD || diff --git a/src/vgmstream.h b/src/vgmstream.h index d6e72a45..a605850c 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -728,8 +728,6 @@ typedef struct { off_t next_block_offset; /* offset of header of the next block */ int block_count; /* count of "semi" block in total block */ - int hit_loop; /* have we seen the loop yet? */ - /* loop layout (saved values) */ int32_t loop_sample; /* saved from current_sample, should be loop_start_sample... */ int32_t loop_samples_into_block;/* saved from samples_into_block */ @@ -737,6 +735,12 @@ typedef struct { size_t loop_block_size; /* saved from current_block_size */ off_t loop_next_block_offset; /* saved from next_block_offset */ + /* loop internals */ + int hit_loop; /* have we seen the loop yet? */ + /* counters for "loop + play end of the stream instead of fading" (not used/needed otherwise) */ + int loop_count; /* number of complete loops (1=looped once) */ + int loop_target; /* max loops before continuing with the stream end */ + /* decoder specific */ int codec_endian; /* little/big endian marker; name is left vague but usually means big endian */ diff --git a/test/test.c b/test/test.c index de986812..4a969885 100644 --- a/test/test.c +++ b/test/test.c @@ -36,7 +36,7 @@ void usage(const char * name) { "Options:\n" " -o outfile.wav: name of output .wav file, default is dump.wav\n" " -l loop count: loop count, default 2.0\n" - " -f fade time: fade time (seconds), default 10.0\n" + " -f fade time: fade time (seconds) after N loops, default 10.0\n" " -d fade delay: fade delay (seconds, default 0.0\n" " -i: ignore looping information and play the whole stream once\n" " -p: output to stdout (for piping into another program)\n" @@ -46,11 +46,12 @@ void usage(const char * name) { " -x: decode and print adxencd command line to encode as ADX\n" " -g: decode and print oggenc command line to encode as OGG\n" " -b: decode and print batch variable commands\n" - " -L: append a smpl chunk and create a looping wav\n" + " -L: append a smpl chunk and create a looping wav\n" " -e: force end-to-end looping\n" " -E: force end-to-end looping even if file has real loop points\n" " -r outfile2.wav: output a second time after resetting\n" " -2 N: only output the Nth (first is 0) set of stereo channels\n" + " -F: don't fade after N loops and play the rest of the stream\n" ,name); } @@ -73,15 +74,16 @@ int main(int argc, char ** argv) { int metaonly = 0; int adxencd = 0; int oggenc = 0; - int lwav = 0; + int lwav = 0; int batchvar = 0; int only_stereo = -1; double loop_count = 2.0; double fade_seconds = 10.0; double fade_delay_seconds = 0.0; - int32_t bytecount; + int fade_ignore = 0; + int32_t bytecount; - while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeLEr:gb2:")) != -1) { + while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeLEFr:gb2:")) != -1) { switch (opt) { case 'o': outfilename = optarg; @@ -127,14 +129,17 @@ int main(int argc, char ** argv) { really_force_loop = 1; break; case 'L': - lwav = 1; - break; + lwav = 1; + break; case 'r': reset_outfilename = optarg; break; case '2': only_stereo = atoi(optarg); break; + case 'F': + fade_ignore = 1; + break; default: usage(argv[0]); return 1; @@ -263,6 +268,11 @@ int main(int argc, char ** argv) { return 1; } + /* signal ignore fade for get_vgmstream_play_samples */ + if (loop_count && fade_ignore) { + fade_seconds = -1.0; + } + len = get_vgmstream_play_samples(loop_count,fade_seconds,fade_delay_seconds,s); if (!play && !adxencd && !oggenc && !batchvar) printf("samples to play: %d (%.4lf seconds)\n",len,(double)len/s->sample_rate); fade_samples = fade_seconds * s->sample_rate; @@ -273,10 +283,10 @@ int main(int argc, char ** argv) { } else { make_wav_header((uint8_t*)buf, len, s->sample_rate, s->channels); } - if (lwav && s->loop_flag) { // Adding space for smpl chunk at end + if (lwav && s->loop_flag) { // Adding space for smpl chunk at end bytecount = get_32bitLE((uint8_t*)buf + 4); put_32bitLE((uint8_t*)buf + 4, bytecount + 0x44); - } + } fwrite(buf,1,0x2c,outfile); /* decode forever */ @@ -325,9 +335,9 @@ int main(int argc, char ** argv) { } } - if (lwav && s->loop_flag) { // Writing smpl chuck - make_smpl_chunk((uint8_t*)buf, s->loop_start_sample, s->loop_end_sample); - fwrite(buf,1,0x44,outfile); + if (lwav && s->loop_flag) { // Writing smpl chuck + make_smpl_chunk((uint8_t*)buf, s->loop_start_sample, s->loop_end_sample); + fwrite(buf,1,0x44,outfile); } fclose(outfile); outfile = NULL; From a903072a11360d1243ca42a532743ab8f715af92 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 18 May 2017 21:00:42 +0200 Subject: [PATCH 07/17] Added XPEC's .XAU IMA-ADPCM support [Beat Down (Xbox)] + looping (PS2) --- src/formats.c | 2 +- src/meta/meta.h | 2 +- src/meta/ps2_xau.c | 91 ++++++++++++++++++++++++++-------------------- src/vgmstream.c | 2 +- src/vgmstream.h | 2 +- 5 files changed, 56 insertions(+), 43 deletions(-) diff --git a/src/formats.c b/src/formats.c index 78e9599c..c9c438be 100644 --- a/src/formats.c +++ b/src/formats.c @@ -795,7 +795,7 @@ static const meta_info meta_info_list[] = { {meta_DSP_CABELAS, "Cabelas games dsp header"}, {meta_PS2_LPCM, "LPCM header"}, {meta_PS2_VMS, "VMS Header"}, - {meta_PS2_XAU, "XAU Header"}, + {meta_XAU, "XPEC XAU header"}, {meta_GH3_BAR, "Guitar Hero III Mobile .bar"}, {meta_FFW, "Freedom Fighters BGM header"}, {meta_DSP_DSPW, "DSPW dsp header"}, diff --git a/src/meta/meta.h b/src/meta/meta.h index 3cdb2839..d5a60fbf 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -541,7 +541,7 @@ VGMSTREAM * init_vgmstream_dsp_bdsp(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_ps2_vms(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_ps2_xau(STREAMFILE* streamFile); +VGMSTREAM * init_vgmstream_xau(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_gh3_bar(STREAMFILE* streamFile); diff --git a/src/meta/ps2_xau.c b/src/meta/ps2_xau.c index 434a43b7..06d80de6 100644 --- a/src/meta/ps2_xau.c +++ b/src/meta/ps2_xau.c @@ -1,67 +1,80 @@ #include "meta.h" #include "../util.h" +#include "../coding/coding.h" -/* XAU (Spectral Force Chronicle [SLPM-65967]) */ -VGMSTREAM * init_vgmstream_ps2_xau(STREAMFILE *streamFile) -{ +/* XAU - XPEC Entertainment sound format (Beat Down PS2/Xbox, Spectral Force Chronicle [SLPM-65967]) */ +VGMSTREAM * init_vgmstream_xau(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; off_t start_offset; - - int loop_flag = 0; - int channel_count; + int loop_flag, channel_count, type, loop_start, loop_end; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("xau",filename_extension(filename))) goto fail; + /* check extension */ + if (!check_extensions(streamFile, "xau")) + goto fail; /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x58415500) + if (read_32bitBE(0x00,streamFile) != 0x58415500) /* "XAU\0" "*/ + goto fail; + if (read_32bitLE(0x08,streamFile) != 0x40) /* header start */ goto fail; - loop_flag = 0; + /* 0x04: version? (0x100) */ + type = read_32bitBE(0x0c, streamFile); + loop_start = read_32bitLE(0x10, streamFile); + loop_end = read_32bitLE(0x14, streamFile); + loop_flag = (loop_end > 0); + channel_count = read_8bit(0x18,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_32bitBE(0x50, streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = ((read_32bitBE(0x4C, streamFile) * channel_count)/ 16 / channel_count * 28); + vgmstream->meta_type = meta_XAU; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x8000; - vgmstream->meta_type = meta_PS2_XAU; + /* miniheader over a common header with some tweaks, so we'll simplify parsing */ + switch(type) { + case 0x50533200: /* "PS2\0" */ + if (read_32bitBE(0x40,streamFile) != 0x56414770) goto fail; /* "VAGp" */ - /* 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; + start_offset = 0x800; + vgmstream->sample_rate = read_32bitBE(0x50, streamFile); + vgmstream->num_samples = ps_bytes_to_samples(read_32bitBE(0x4C,streamFile) * channel_count, channel_count); + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset + vgmstream->interleave_block_size * i; + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x8000; - } - } + break; + case 0x58420000: /* "XB\0\0" */ + if (read_32bitBE(0x40,streamFile) != 0x52494646) goto fail; /* "RIFF" */ + + start_offset = 0x70; + vgmstream->sample_rate = read_32bitLE(0x58, streamFile); + vgmstream->num_samples = ms_ima_bytes_to_samples(read_32bitLE(0x6c, streamFile), read_16bitLE(0x60, streamFile), channel_count); + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; + /* there is also a "smpl" chunk at the end, same as loop_start/end */ + + vgmstream->coding_type = coding_XBOX; + vgmstream->layout_type = layout_none; + + break; + default: + goto fail; + } + + + 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/vgmstream.c b/src/vgmstream.c index a628819e..dfe32aa8 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -292,7 +292,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_ps2_lpcm, init_vgmstream_dsp_bdsp, init_vgmstream_ps2_vms, - init_vgmstream_ps2_xau, + init_vgmstream_xau, init_vgmstream_gh3_bar, init_vgmstream_ffw, init_vgmstream_dsp_dspw, diff --git a/src/vgmstream.h b/src/vgmstream.h index a605850c..70187a4f 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -549,7 +549,7 @@ typedef enum { meta_PS2_LPCM, /* Ah! My Goddess */ meta_DSP_BDSP, /* Ah! My Goddess */ meta_PS2_VMS, /* Autobahn Raser - Police Madness */ - meta_PS2_XAU, /* Spectral Force Chronicle */ + meta_XAU, /* XPEC Entertainment (Beat Down (PS2 Xbox), Spectral Force Chronicle (PS2)) */ meta_GH3_BAR, /* Guitar Hero III Mobile .bar */ meta_FFW, /* Freedom Fighters [NGC] */ meta_DSP_DSPW, /* Sengoku Basara 3 [WII] */ From 30afc09255e5468eccf660c473b9d7bd9f163f21 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 18 May 2017 21:03:14 +0200 Subject: [PATCH 08/17] Rename ps2_xau.c to xau.c --- src/libvgmstream.vcproj | 8 ++++---- src/libvgmstream.vcxproj | 2 +- src/libvgmstream.vcxproj.filters | 6 +++--- src/meta/{ps2_xau.c => xau.c} | 0 4 files changed, 8 insertions(+), 8 deletions(-) rename src/meta/{ps2_xau.c => xau.c} (100%) diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 8059d0f6..f017f036 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -946,10 +946,6 @@ RelativePath=".\meta\ps2_xa30.c" > - - @@ -1206,6 +1202,10 @@ RelativePath=".\meta\x360_tra.c" > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 2d76ac07..f101e173 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -341,7 +341,6 @@ - @@ -391,6 +390,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 160078f5..e6bc4e8c 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -571,9 +571,6 @@ meta\Source Files - - meta\Source Files - meta\Source Files @@ -727,6 +724,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files diff --git a/src/meta/ps2_xau.c b/src/meta/xau.c similarity index 100% rename from src/meta/ps2_xau.c rename to src/meta/xau.c From 0bab6ddf50b7754f8be196999f58eb47535f8fe6 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 18 May 2017 22:14:32 +0200 Subject: [PATCH 09/17] Fixed Crackdown X360 XWB variation; adjusted XWB XMA looping --- src/meta/xwb.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/meta/xwb.c b/src/meta/xwb.c index 5cf0c58f..1fbe9b1d 100644 --- a/src/meta/xwb.c +++ b/src/meta/xwb.c @@ -14,7 +14,8 @@ #define XACT2_1_MAX 38 /* Prey (v38) */ // v39 too? #define XACT2_2_MAX 41 /* Blue Dragon (v40) */ #define XACT3_0_MAX 46 /* Ninja Blade (t43 v42), Persona 4 Ultimax NESSICA (t45 v43) */ -#define XACT_TECHLAND 0x10000 /* Sniper Ghost Warrior, Nail'd (PS3/X360) */ +#define XACT_TECHLAND 0x10000 /* Sniper Ghost Warrior, Nail'd (PS3/X360), equivalent to XACT3_0 */ +#define XACT_CRACKDOWN 0x87 /* Crackdown 1, equivalent to XACT2_2 */ static const int wma_avg_bps_index[7] = { 12000, 24000, 4000, 6000, 8000, 20000, 2500 @@ -92,6 +93,10 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) { /* read main header (WAVEBANKHEADER) */ xwb.version = read_32bit(0x04, streamFile); /* XACT3: 0x04=tool version, 0x08=header version */ + /* Crackdown 1 X360, essentially XACT2 but may have split header in some cases */ + if (xwb.version == XACT_CRACKDOWN) + xwb.version = XACT2_2_MAX; + /* read segment offsets (SEGIDX) */ if (xwb.version <= XACT1_0_MAX) { xwb.streams = read_32bit(0x0c, streamFile); @@ -306,7 +311,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) { xwb.loop_end_sample = msd.loop_end_sample; // todo fix properly (XWB loop_start/end seem to count padding samples while XMA1 RIFF doesn't) - //this doesn't seem ok because can fall within 0 to 512 (ie.- first frame) + //this doesn't seem ok because can fall within 0 to 512 (ie.- first frame, 384) //if (xwb.loop_start_sample) xwb.loop_start_sample -= 512; //if (xwb.loop_end_sample) xwb.loop_end_sample -= 512; @@ -314,6 +319,11 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) { // (in rare cases this causes a glitch in FFmpeg since it has a bug where it's missing some samples) xwb.num_samples += 64 + 512; } + else if ((xwb.codec == XMA1 || xwb.codec == XMA2) && xwb.loop_flag) { + /* seems to be needed by some edge cases, ex. Crackdown */ + //add padding, see above + xwb.num_samples += 64 + 512; + } /* build the VGMSTREAM */ From 860156be7986753a156049b8548b4e5994e4dd3a Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 18 May 2017 22:35:48 +0200 Subject: [PATCH 10/17] Update file types to match formats.c --- fb2k/foo_vgmstream.cpp | 75 ++++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/fb2k/foo_vgmstream.cpp b/fb2k/foo_vgmstream.cpp index b7adbb93..72ebd663 100644 --- a/fb2k/foo_vgmstream.cpp +++ b/fb2k/foo_vgmstream.cpp @@ -400,48 +400,57 @@ DECLARE_COMPONENT_VERSION(APP_NAME,PLUGIN_VERSION,PLUGIN_DESCRIPTION); VALIDATE_COMPONENT_FILENAME("foo_input_vgmstream.dll"); // Registered file types, to associate an extension with foobar2000 in Windows. -// Accepted types go in input_vgmstream::g_is_our_path; both lists don't need to match. -// todo do we really want to associate every single vgmstream format? +// Accepted file types go in formats.c and are checked in input_vgmstream::g_is_our_path. +// Both lists don't need to match, formats.c is what matters here. +// (do we really want to associate every single vgmstream format?) // // these are declared statically, and if anyone has a better idea i'd like to hear it - josh. DECLARE_MULTIPLE_FILE_TYPE("2DX9 Audio File (*.2DX9)", 2dx9); DECLARE_MULTIPLE_FILE_TYPE("2PFS Audio File (*.2PFS)", 2pfs); +//"aac", //common, also tri-Ace's +DECLARE_MULTIPLE_FILE_TYPE("AA3 Audio File (*.AA3)", aa3); DECLARE_MULTIPLE_FILE_TYPE("AAAP Audio File (*.AAAP)", aaap); DECLARE_MULTIPLE_FILE_TYPE("AAX Audio File (*.AAX)", aax); - +//"ac3", //FFmpeg, not parsed //common? +DECLARE_MULTIPLE_FILE_TYPE("ACE Audio File (*.ACE)", ace); DECLARE_MULTIPLE_FILE_TYPE("ACM Audio File (*.ACM)", acm); -DECLARE_MULTIPLE_FILE_TYPE("ADPCM Audio File (*.ADPCM)", adpcm); DECLARE_MULTIPLE_FILE_TYPE("ADM Audio File (*.ADM)", adm); DECLARE_MULTIPLE_FILE_TYPE("ADP Audio File (*.ADP)", adp); -DECLARE_MULTIPLE_FILE_TYPE("PS2 ADS Audio File (*.ADS)", ads); +DECLARE_MULTIPLE_FILE_TYPE("ADPCM Audio File (*.ADPCM)", adpcm); +DECLARE_MULTIPLE_FILE_TYPE("ADS Audio File (*.ADS)", ads); DECLARE_MULTIPLE_FILE_TYPE("ADX Audio File (*.ADX)", adx); DECLARE_MULTIPLE_FILE_TYPE("AFC Audio File (*.AFC)", afc); DECLARE_MULTIPLE_FILE_TYPE("AGSC Audio File (*.AGSC)", agsc); DECLARE_MULTIPLE_FILE_TYPE("AHX Audio File (*.AHX)", ahx); DECLARE_MULTIPLE_FILE_TYPE("AIFC Audio File (*.AIFC)", aifc); +DECLARE_MULTIPLE_FILE_TYPE("AIFCL Audio File (*.AIFCL)", aifcl); +//"aiff", //common DECLARE_MULTIPLE_FILE_TYPE("AIX Audio File (*.AIX)", aix); DECLARE_MULTIPLE_FILE_TYPE("AKB Audio File (*.AKB)", akb); DECLARE_MULTIPLE_FILE_TYPE("AMTS Audio File (*.AMTS)", amts); DECLARE_MULTIPLE_FILE_TYPE("AS4 Audio File (*.AS4)", as4); DECLARE_MULTIPLE_FILE_TYPE("ASD Audio File (*.ASD)", asd); DECLARE_MULTIPLE_FILE_TYPE("ASF Audio File (*.ASF)", asf); -DECLARE_MULTIPLE_FILE_TYPE("AST Audio File (*.AST)", ast); DECLARE_MULTIPLE_FILE_TYPE("ASR Audio File (*.ASR)", asr); DECLARE_MULTIPLE_FILE_TYPE("ASS Audio File (*.ASS)", ass); +DECLARE_MULTIPLE_FILE_TYPE("AST Audio File (*.AST)", ast); DECLARE_MULTIPLE_FILE_TYPE("ATRAC3plus Audio File (*.AT3)", at3); DECLARE_MULTIPLE_FILE_TYPE("AUD Audio File (*.AUD)", aud); DECLARE_MULTIPLE_FILE_TYPE("AUS Audio File (*.AUS)", aus); -DECLARE_MULTIPLE_FILE_TYPE("BAKA Audio File (*.BAKA)", baka); +DECLARE_MULTIPLE_FILE_TYPE("B1S Audio File (*.B1S)", b1s); DECLARE_MULTIPLE_FILE_TYPE("BAF Audio File (*.BAF)", baf); +DECLARE_MULTIPLE_FILE_TYPE("BAKA Audio File (*.BAKA)", baka); DECLARE_MULTIPLE_FILE_TYPE("BAR Audio File (*.BAR)", bar); DECLARE_MULTIPLE_FILE_TYPE("BCSTM Audio File (*.BCSTM)", bcstm); DECLARE_MULTIPLE_FILE_TYPE("BCWAV Audio File (*.BCWAV)", bcwav); +DECLARE_MULTIPLE_FILE_TYPE("BDSP Audio File (*.BDSP)", bdsp); DECLARE_MULTIPLE_FILE_TYPE("BFSTM Audio File (*.BFSTM)", bfstm); DECLARE_MULTIPLE_FILE_TYPE("BFWAV Audio File (*.BFWAV)", bfwav); DECLARE_MULTIPLE_FILE_TYPE("BFWAV Audio File [2] (*.BFWAV)", bfwavnsmbu); DECLARE_MULTIPLE_FILE_TYPE("BG00 Audio File (*.BG00)", bg00); +DECLARE_MULTIPLE_FILE_TYPE("BGM Audio File (*.BGM)", bgm); DECLARE_MULTIPLE_FILE_TYPE("BGW Audio File (*.BGW)", bgw); DECLARE_MULTIPLE_FILE_TYPE("BH2PCM Audio File (*.BH2PCM)", bh2pcm); DECLARE_MULTIPLE_FILE_TYPE("BIK Audio File (*.BIK)", bik); @@ -469,10 +478,12 @@ DECLARE_MULTIPLE_FILE_TYPE("CFN Audio File (*.CFN)", cfn); DECLARE_MULTIPLE_FILE_TYPE("CKD Audio File (*.CKD)", ckd); DECLARE_MULTIPLE_FILE_TYPE("CNK Audio File (*.CNK)", cnk); DECLARE_MULTIPLE_FILE_TYPE("CPS Audio File (*.CPS)", cps); +DECLARE_MULTIPLE_FILE_TYPE("CXS Audio File (*.CXS)", cxs); +DECLARE_MULTIPLE_FILE_TYPE("DBM Audio File (*.DBM)", dbm); DECLARE_MULTIPLE_FILE_TYPE("DCS Audio File (*.DCS)", dcs); -DECLARE_MULTIPLE_FILE_TYPE("DE2 Audio File (*.DE2)", de2); DECLARE_MULTIPLE_FILE_TYPE("DDSP Audio File (*.DDSP)", ddsp); +DECLARE_MULTIPLE_FILE_TYPE("DE2 Audio File (*.DE2)", de2); DECLARE_MULTIPLE_FILE_TYPE("DMSG Audio File (*.DMSG)", dmsg); DECLARE_MULTIPLE_FILE_TYPE("DSP Audio File (*.DSP)", dsp); DECLARE_MULTIPLE_FILE_TYPE("DSPW Audio File (*.DSPW)", dspw); @@ -485,8 +496,10 @@ DECLARE_MULTIPLE_FILE_TYPE("EMFF Audio File (*.EMFF)", emff); DECLARE_MULTIPLE_FILE_TYPE("ENTH Audio File (*.ENTH)", enth); DECLARE_MULTIPLE_FILE_TYPE("FAG Audio File (*.FAG)", fag); +DECLARE_MULTIPLE_FILE_TYPE("FFW Audio File (*.FFW)", ffw); DECLARE_MULTIPLE_FILE_TYPE("FILP Audio File (*.FILP)", filp); DECLARE_MULTIPLE_FILE_TYPE("FSB Audio File (*.FSB)", fsb); +DECLARE_MULTIPLE_FILE_TYPE("FWAV Audio File (*.FWAV)", fwav); DECLARE_MULTIPLE_FILE_TYPE("G1L Audio File (*.G1L)", g1l); DECLARE_MULTIPLE_FILE_TYPE("GBTS Audio File (*.GBTS)", gbts); @@ -497,6 +510,7 @@ DECLARE_MULTIPLE_FILE_TYPE("GCW Audio File (*.GCW)", gcw); DECLARE_MULTIPLE_FILE_TYPE("GENH Audio File (*.GENH)", genh); DECLARE_MULTIPLE_FILE_TYPE("GMS Audio File (*.GMS)", gms); DECLARE_MULTIPLE_FILE_TYPE("GSB Audio File (*.GSB)", gsb); +DECLARE_MULTIPLE_FILE_TYPE("GSB Audio File (*.GTD)", gtd); DECLARE_MULTIPLE_FILE_TYPE("HCA Audio File (*.HCA)", hca); DECLARE_MULTIPLE_FILE_TYPE("HGC1 Audio File (*.HGC1)", hgc1); @@ -506,11 +520,13 @@ DECLARE_MULTIPLE_FILE_TYPE("HALPST Audio File (*.HPS)", hps); DECLARE_MULTIPLE_FILE_TYPE("HSF Audio File (*.HSF)", hsf); DECLARE_MULTIPLE_FILE_TYPE("HWAS Audio File (*.HWAS)", hwas); +DECLARE_MULTIPLE_FILE_TYPE("IAB Audio File (*.IAB)", iab); +DECLARE_MULTIPLE_FILE_TYPE("IADP Audio File (*.IADP)", iadp); DECLARE_MULTIPLE_FILE_TYPE("IDSP Audio File (*.IDSP)", idsp); DECLARE_MULTIPLE_FILE_TYPE("IDVI Audio File (*.IDVI)", idvi); DECLARE_MULTIPLE_FILE_TYPE("IKM Audio File (*.IKM)", ikm); DECLARE_MULTIPLE_FILE_TYPE("ILD Audio File (*.ILD)", ild); -DECLARE_MULTIPLE_FILE_TYPE("PS2 RAW Interleaved PCM (*.INT)", int); +DECLARE_MULTIPLE_FILE_TYPE("INT Audio File (*.INT)", int); DECLARE_MULTIPLE_FILE_TYPE("ISD Audio File (*.ISD)", isd); DECLARE_MULTIPLE_FILE_TYPE("ISWS Audio File (*.ISWS)", isws); DECLARE_MULTIPLE_FILE_TYPE("IVAUD Audio File (*.IVAUD)", ivaud); @@ -526,9 +542,10 @@ DECLARE_MULTIPLE_FILE_TYPE("KHV Audio File (*.KHV)", khv); DECLARE_MULTIPLE_FILE_TYPE("KOVS Audio File (*.KOVS)", kovs); DECLARE_MULTIPLE_FILE_TYPE("KRAW Audio File (*.KRAW)", kraw); +DECLARE_MULTIPLE_FILE_TYPE("LAAC Audio File (*.LAAC)", laac); DECLARE_MULTIPLE_FILE_TYPE("LEG Audio File (*.LEG)", leg); -DECLARE_MULTIPLE_FILE_TYPE("LOGG Audio File (*.LOGG)", logg); DECLARE_MULTIPLE_FILE_TYPE("LMP4 Audio File (*.LMP4)", lmp4); +DECLARE_MULTIPLE_FILE_TYPE("LOGG Audio File (*.LOGG)", logg); DECLARE_MULTIPLE_FILE_TYPE("LPCM Audio File (*.LPCM)", lpcm); DECLARE_MULTIPLE_FILE_TYPE("LPS Audio File (*.LPS)", lps); DECLARE_MULTIPLE_FILE_TYPE("LSF Audio File (*.LSF)", lsf); @@ -540,17 +557,19 @@ DECLARE_MULTIPLE_FILE_TYPE("MCA Audio File (*.MCA)", mca); DECLARE_MULTIPLE_FILE_TYPE("MCG Audio File (*.MCG)", mcg); DECLARE_MULTIPLE_FILE_TYPE("MDS Audio File (*.MDS)", mds); DECLARE_MULTIPLE_FILE_TYPE("MDSP Audio File (*.MDSP)", mdsp); -DECLARE_MULTIPLE_FILE_TYPE("PS2 MI4 Audio File (*.MI4)", mi4); -DECLARE_MULTIPLE_FILE_TYPE("PS2 MIB Audio File (*.MIB)", mib); -DECLARE_MULTIPLE_FILE_TYPE("PS2 MIC Audio File (*.MIC)", mic); +DECLARE_MULTIPLE_FILE_TYPE("MI4 Audio File (*.MI4)", mi4); +DECLARE_MULTIPLE_FILE_TYPE("MIB Audio File (*.MIB)", mib); +DECLARE_MULTIPLE_FILE_TYPE("MIC Audio File (*.MIC)", mic); DECLARE_MULTIPLE_FILE_TYPE("MIHB Audio File (*.MIHB)", mihb); DECLARE_MULTIPLE_FILE_TYPE("MNSTR Audio File (*.MNSTR)", mnstr); +//"mp4", //common DECLARE_MULTIPLE_FILE_TYPE("MPDSP Audio File (*.MPDSP)", mpdsp); DECLARE_MULTIPLE_FILE_TYPE("MPDS Audio File (*.MPDS)", mpds); DECLARE_MULTIPLE_FILE_TYPE("MSA Audio File (*.MSA)", msa); DECLARE_MULTIPLE_FILE_TYPE("MSF Audio File (*.MSF)", msf); DECLARE_MULTIPLE_FILE_TYPE("MSS Audio File (*.MSS)", mss); DECLARE_MULTIPLE_FILE_TYPE("MSVP Audio File (*.MSVP)", msvp); +DECLARE_MULTIPLE_FILE_TYPE("MTA2 Audio File (*.MTA2)", mta2); DECLARE_MULTIPLE_FILE_TYPE("MTAF Audio File (*.MTAF)", mtaf); DECLARE_MULTIPLE_FILE_TYPE("MUS Playlist File (*.MUS)", mus); DECLARE_MULTIPLE_FILE_TYPE("MUSC Audio File (*.MUSC)", musc); @@ -561,11 +580,14 @@ DECLARE_MULTIPLE_FILE_TYPE("MYSPD Audio File (*.MYSPD)", myspd); DECLARE_MULTIPLE_FILE_TYPE("NDP Audio File (*.NDP)", ndp); DECLARE_MULTIPLE_FILE_TYPE("NGCA Audio File (*.NGCA)", ngca); -DECLARE_MULTIPLE_FILE_TYPE("PS2 NPSF Audio File (*.NPSF)", npsf); +DECLARE_MULTIPLE_FILE_TYPE("NPS Audio File (*.NPS)", nps); +DECLARE_MULTIPLE_FILE_TYPE("NPSF Audio File (*.NPSF)", npsf); DECLARE_MULTIPLE_FILE_TYPE("NUS3BANK Audio File (*.NUS3BANK)", nus3bank); DECLARE_MULTIPLE_FILE_TYPE("NWA Audio File (*.NWA)", nwa); +//"ogg", //common DECLARE_MULTIPLE_FILE_TYPE("OGL Audio File (*.OGL)", ogl); +DECLARE_MULTIPLE_FILE_TYPE("OMA Audio File (*.OMA)", oma); DECLARE_MULTIPLE_FILE_TYPE("OMU Audio File (*.OMU)", omu); DECLARE_MULTIPLE_FILE_TYPE("OTM Audio File (*.OTM)", otm); @@ -597,7 +619,7 @@ DECLARE_MULTIPLE_FILE_TYPE("RWAV Audio File (*.RWAV)", rwav); DECLARE_MULTIPLE_FILE_TYPE("RWS Audio File (*.RWS)", rws); DECLARE_MULTIPLE_FILE_TYPE("RWSD Audio File (*.RWSD)", rwsd); DECLARE_MULTIPLE_FILE_TYPE("RWX Audio File (*.RWX)", rwx); -DECLARE_MULTIPLE_FILE_TYPE("PS2 RXWS File (*.RXW)", rxw); +DECLARE_MULTIPLE_FILE_TYPE("RXWS File (*.RXW)", rxw); DECLARE_MULTIPLE_FILE_TYPE("S14 Audio File (*.S14)", s14); DECLARE_MULTIPLE_FILE_TYPE("SAB Audio File (*.SAB)", sab); @@ -629,19 +651,22 @@ DECLARE_MULTIPLE_FILE_TYPE("SPM Audio File (*.SPM)", spm); DECLARE_MULTIPLE_FILE_TYPE("SPS Audio File (*.SPS)", sps); DECLARE_MULTIPLE_FILE_TYPE("SPSD Audio File (*.SPSD)", spsd); DECLARE_MULTIPLE_FILE_TYPE("SPW Audio File (*.SPW)", spw); -DECLARE_MULTIPLE_FILE_TYPE("PS2 SS2 Audio File (*.SS2)", ss2); +DECLARE_MULTIPLE_FILE_TYPE("SS2 Audio File (*.SS2)", ss2); DECLARE_MULTIPLE_FILE_TYPE("SS3 Audio File (*.SS3)", ss3); DECLARE_MULTIPLE_FILE_TYPE("SS7 Audio File (*.SS7)", ss7); DECLARE_MULTIPLE_FILE_TYPE("SSM Audio File (*.SSM)", ssm); DECLARE_MULTIPLE_FILE_TYPE("SSS Audio File (*.SSS)", sss); DECLARE_MULTIPLE_FILE_TYPE("STER Audio File (*.STER)", ster); +DECLARE_MULTIPLE_FILE_TYPE("STH Audio File (*.STH)", sth); +//"stm", //common DECLARE_MULTIPLE_FILE_TYPE("STMA Audio File (*.STMA)", stma); DECLARE_MULTIPLE_FILE_TYPE("STR Audio File (*.STR)", str); DECLARE_MULTIPLE_FILE_TYPE("STRM Audio File (*.STRM)", strm); -DECLARE_MULTIPLE_FILE_TYPE("PS2 EXST Audio File (*.STS)", sts); +DECLARE_MULTIPLE_FILE_TYPE("STS Audio File (*.STS)", sts); DECLARE_MULTIPLE_FILE_TYPE("STX Audio File (*.STX)", stx); -DECLARE_MULTIPLE_FILE_TYPE("PS2 SVAG Audio File (*.SVAG)", svag); +DECLARE_MULTIPLE_FILE_TYPE("SVAG Audio File (*.SVAG)", svag); DECLARE_MULTIPLE_FILE_TYPE("SVS Audio File (*.SVS)", svs); +DECLARE_MULTIPLE_FILE_TYPE("SWAG Audio File (*.SWAG)", swag); DECLARE_MULTIPLE_FILE_TYPE("SWAV Audio File (*.SWAV)", swav); DECLARE_MULTIPLE_FILE_TYPE("SWD Audio File (*.SWD)", swd); DECLARE_MULTIPLE_FILE_TYPE("SXD Audio File (*.SXD)", sxd); @@ -651,6 +676,7 @@ DECLARE_MULTIPLE_FILE_TYPE("TEC Audio File (*.TEC)", tec); DECLARE_MULTIPLE_FILE_TYPE("THP Audio File (*.THP)", thp); DECLARE_MULTIPLE_FILE_TYPE("TK1 Audio File (*.TK1)", tk1); DECLARE_MULTIPLE_FILE_TYPE("TK5 Audio File (*.TK5)", tk5); +DECLARE_MULTIPLE_FILE_TYPE("TRA Audio File (*.TRA)", tra); DECLARE_MULTIPLE_FILE_TYPE("TUN Audio File (*.TUN)", tun); DECLARE_MULTIPLE_FILE_TYPE("TYDSP Audio File (*.TYDSP)", tydsp); @@ -658,6 +684,7 @@ DECLARE_MULTIPLE_FILE_TYPE("UM3 Audio File (*.UM3)", um3); DECLARE_MULTIPLE_FILE_TYPE("VAG Audio File (*.VAG)", vag); DECLARE_MULTIPLE_FILE_TYPE("VAS Audio File (*.VAS)", vas); +DECLARE_MULTIPLE_FILE_TYPE("VAS Audio File (*.VAS)", vawx); DECLARE_MULTIPLE_FILE_TYPE("VB Audio File (*.VB)", vb); DECLARE_MULTIPLE_FILE_TYPE("VBK Audio File (*.VBK)", vbk); DECLARE_MULTIPLE_FILE_TYPE("VGS Audio File (*.VGS)", vgs); @@ -673,8 +700,9 @@ DECLARE_MULTIPLE_FILE_TYPE("WAA Audio File (*.WAA)", waa); DECLARE_MULTIPLE_FILE_TYPE("WAC Audio File (*.WAC)", wac); DECLARE_MULTIPLE_FILE_TYPE("WAD Audio File (*.WAD)", wad); DECLARE_MULTIPLE_FILE_TYPE("WAM Audio File (*.WAM)", wam); -DECLARE_MULTIPLE_FILE_TYPE("WAVM Audio File (*.WAVM)", wavm); DECLARE_MULTIPLE_FILE_TYPE("WAS Audio File (*.WAS)", was); +//"wav", //common +DECLARE_MULTIPLE_FILE_TYPE("WAVM Audio File (*.WAVM)", wavm); DECLARE_MULTIPLE_FILE_TYPE("WEM Audio File (*.WEM)", wem); DECLARE_MULTIPLE_FILE_TYPE("WII Audio File (*.WII)", wii); DECLARE_MULTIPLE_FILE_TYPE("WMUS Audio File (*.WMUS)", wmus); @@ -684,9 +712,10 @@ DECLARE_MULTIPLE_FILE_TYPE("WSD Audio File (*.WSD)", wsd); DECLARE_MULTIPLE_FILE_TYPE("WSI Audio File (*.WSI)", wsi); DECLARE_MULTIPLE_FILE_TYPE("WVS Audio File (*.WVS)", wvs); -DECLARE_MULTIPLE_FILE_TYPE("PSX CD-XA File (*.XA)", xa); +DECLARE_MULTIPLE_FILE_TYPE("XA File (*.XA)", xa); DECLARE_MULTIPLE_FILE_TYPE("XA2 Audio File (*.XA2)", xa2); DECLARE_MULTIPLE_FILE_TYPE("XA30 Audio File (*.XA30)", xa30); +DECLARE_MULTIPLE_FILE_TYPE("XAG Audio File (*.XAG)", xag); DECLARE_MULTIPLE_FILE_TYPE("XAU Audio File (*.XAU)", xau); DECLARE_MULTIPLE_FILE_TYPE("XMA Audio File (*.XMA)", xma); DECLARE_MULTIPLE_FILE_TYPE("XMA2 Audio File (*.XMA2)", xma2); @@ -698,6 +727,10 @@ DECLARE_MULTIPLE_FILE_TYPE("XVAG Audio File (*.XVAG)", xvag); DECLARE_MULTIPLE_FILE_TYPE("XVAS Audio File (*.XVAS)", xvas); DECLARE_MULTIPLE_FILE_TYPE("XWAV Audio File (*.XWAV)", xwav); DECLARE_MULTIPLE_FILE_TYPE("XWB Audio File (*.XWB)", xwb); +DECLARE_MULTIPLE_FILE_TYPE("XWM Audio File (*.XWM)", xwm); +DECLARE_MULTIPLE_FILE_TYPE("XWMA Audio File (*.XWMA)", xwma); +DECLARE_MULTIPLE_FILE_TYPE("XWS Audio File (*.XWS)", xws); +DECLARE_MULTIPLE_FILE_TYPE("XWV Audio File (*.XWV)", xwv); DECLARE_MULTIPLE_FILE_TYPE("YDSP Audio File (*.YDSP)", ydsp); DECLARE_MULTIPLE_FILE_TYPE("YMF Audio File (*.YMF)", ymf); @@ -705,4 +738,4 @@ DECLARE_MULTIPLE_FILE_TYPE("YMF Audio File (*.YMF)", ymf); DECLARE_MULTIPLE_FILE_TYPE("ZSD Audio File (*.ZSD)", zsd); DECLARE_MULTIPLE_FILE_TYPE("ZWDSP Audio File (*.ZWDSP)", zwdsp); -DECLARE_MULTIPLE_FILE_TYPE("vgmstream Audio File (*.VGMSTREAM)", vgmstream); +DECLARE_MULTIPLE_FILE_TYPE("VGMSTREAM Audio File (*.VGMSTREAM)", vgmstream); From 25e9d1bcde1436e511e5d57f1f3db91a3378f1aa Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 18 May 2017 23:03:55 +0200 Subject: [PATCH 11/17] Move file types registers to foo_filetypes.h to clarify/simplify --- fb2k/foo_filetypes.h | 355 +++++++++++++++++++++++ fb2k/foo_input_vgmstream.vcxproj | 1 + fb2k/foo_input_vgmstream.vcxproj.filters | 3 + fb2k/foo_vgmstream.cpp | 342 +--------------------- fb2k/foo_vgmstream.h | 8 +- 5 files changed, 362 insertions(+), 347 deletions(-) create mode 100644 fb2k/foo_filetypes.h diff --git a/fb2k/foo_filetypes.h b/fb2k/foo_filetypes.h new file mode 100644 index 00000000..2af141d0 --- /dev/null +++ b/fb2k/foo_filetypes.h @@ -0,0 +1,355 @@ +#ifndef _FOO_FILETYPES_H_ +#define _FOO_FILETYPES_H_ + + +#define DECLARE_MULTIPLE_FILE_TYPE(NAME,EXTENSION) \ + namespace { \ + static input_file_type_impl g_filetype_instance_##EXTENSION(NAME,"*." #EXTENSION ,true); \ + static service_factory_single_ref_t g_filetype_service##EXTENSION(g_filetype_instance_##EXTENSION); \ + } + + +// Registered file types, to associate an extension with foobar2000 in Windows. +// Accepted file types go in formats.c and are checked in input_vgmstream::g_is_our_path. +// Both lists don't need to match, formats.c is what really matters +// (ie. we won't need to associate every single vgmstream format). + +// these are declared statically, and if anyone has a better idea i'd like to hear it - josh. + +DECLARE_MULTIPLE_FILE_TYPE("2DX9 Audio File (*.2DX9)", 2dx9); +DECLARE_MULTIPLE_FILE_TYPE("2PFS Audio File (*.2PFS)", 2pfs); + +//"aac", //common, also tri-Ace's +DECLARE_MULTIPLE_FILE_TYPE("AA3 Audio File (*.AA3)", aa3); +DECLARE_MULTIPLE_FILE_TYPE("AAAP Audio File (*.AAAP)", aaap); +DECLARE_MULTIPLE_FILE_TYPE("AAX Audio File (*.AAX)", aax); +//"ac3", //FFmpeg, not parsed //common? +DECLARE_MULTIPLE_FILE_TYPE("ACE Audio File (*.ACE)", ace); +DECLARE_MULTIPLE_FILE_TYPE("ACM Audio File (*.ACM)", acm); +DECLARE_MULTIPLE_FILE_TYPE("ADM Audio File (*.ADM)", adm); +DECLARE_MULTIPLE_FILE_TYPE("ADP Audio File (*.ADP)", adp); +DECLARE_MULTIPLE_FILE_TYPE("ADPCM Audio File (*.ADPCM)", adpcm); +DECLARE_MULTIPLE_FILE_TYPE("ADS Audio File (*.ADS)", ads); +DECLARE_MULTIPLE_FILE_TYPE("ADX Audio File (*.ADX)", adx); +DECLARE_MULTIPLE_FILE_TYPE("AFC Audio File (*.AFC)", afc); +DECLARE_MULTIPLE_FILE_TYPE("AGSC Audio File (*.AGSC)", agsc); +DECLARE_MULTIPLE_FILE_TYPE("AHX Audio File (*.AHX)", ahx); +DECLARE_MULTIPLE_FILE_TYPE("AIFC Audio File (*.AIFC)", aifc); +DECLARE_MULTIPLE_FILE_TYPE("AIFCL Audio File (*.AIFCL)", aifcl); +//"aiff", //common +DECLARE_MULTIPLE_FILE_TYPE("AIX Audio File (*.AIX)", aix); +DECLARE_MULTIPLE_FILE_TYPE("AKB Audio File (*.AKB)", akb); +DECLARE_MULTIPLE_FILE_TYPE("AMTS Audio File (*.AMTS)", amts); +DECLARE_MULTIPLE_FILE_TYPE("AS4 Audio File (*.AS4)", as4); +DECLARE_MULTIPLE_FILE_TYPE("ASD Audio File (*.ASD)", asd); +DECLARE_MULTIPLE_FILE_TYPE("ASF Audio File (*.ASF)", asf); +DECLARE_MULTIPLE_FILE_TYPE("ASR Audio File (*.ASR)", asr); +DECLARE_MULTIPLE_FILE_TYPE("ASS Audio File (*.ASS)", ass); +DECLARE_MULTIPLE_FILE_TYPE("AST Audio File (*.AST)", ast); +DECLARE_MULTIPLE_FILE_TYPE("ATRAC3plus Audio File (*.AT3)", at3); +DECLARE_MULTIPLE_FILE_TYPE("AUD Audio File (*.AUD)", aud); +DECLARE_MULTIPLE_FILE_TYPE("AUS Audio File (*.AUS)", aus); + +DECLARE_MULTIPLE_FILE_TYPE("B1S Audio File (*.B1S)", b1s); +DECLARE_MULTIPLE_FILE_TYPE("BAF Audio File (*.BAF)", baf); +DECLARE_MULTIPLE_FILE_TYPE("BAKA Audio File (*.BAKA)", baka); +DECLARE_MULTIPLE_FILE_TYPE("BAR Audio File (*.BAR)", bar); +DECLARE_MULTIPLE_FILE_TYPE("BCSTM Audio File (*.BCSTM)", bcstm); +DECLARE_MULTIPLE_FILE_TYPE("BCWAV Audio File (*.BCWAV)", bcwav); +DECLARE_MULTIPLE_FILE_TYPE("BDSP Audio File (*.BDSP)", bdsp); +DECLARE_MULTIPLE_FILE_TYPE("BFSTM Audio File (*.BFSTM)", bfstm); +DECLARE_MULTIPLE_FILE_TYPE("BFWAV Audio File (*.BFWAV)", bfwav); +DECLARE_MULTIPLE_FILE_TYPE("BFWAV Audio File [2] (*.BFWAV)", bfwavnsmbu); +DECLARE_MULTIPLE_FILE_TYPE("BG00 Audio File (*.BG00)", bg00); +DECLARE_MULTIPLE_FILE_TYPE("BGM Audio File (*.BGM)", bgm); +DECLARE_MULTIPLE_FILE_TYPE("BGW Audio File (*.BGW)", bgw); +DECLARE_MULTIPLE_FILE_TYPE("BH2PCM Audio File (*.BH2PCM)", bh2pcm); +DECLARE_MULTIPLE_FILE_TYPE("BIK Audio File (*.BIK)", bik); +DECLARE_MULTIPLE_FILE_TYPE("BIKA Audio File (*.BIKA)", bika); +DECLARE_MULTIPLE_FILE_TYPE("BIK2 Audio File (*.BIK2)", bik2); +DECLARE_MULTIPLE_FILE_TYPE("BIK2A Audio File (*.BIK2A)", bik2a); +DECLARE_MULTIPLE_FILE_TYPE("BK2 Audio File (*.BK2)", bk2); +DECLARE_MULTIPLE_FILE_TYPE("BK2A Audio File (*.BK2A)", bk2a); +DECLARE_MULTIPLE_FILE_TYPE("BMDX Audio File (*.BMDX)", bmdx); +DECLARE_MULTIPLE_FILE_TYPE("BMS Audio File (*.BMS)", bms); +DECLARE_MULTIPLE_FILE_TYPE("KLBS Audio File (*.BNK)", bnk); +DECLARE_MULTIPLE_FILE_TYPE("BNS Audio File (*.BNS)", bns); +DECLARE_MULTIPLE_FILE_TYPE("BNSF Audio File (*.BNSF)", bnsf); +DECLARE_MULTIPLE_FILE_TYPE("BO2 Audio File (*.BO2)", bo2); +DECLARE_MULTIPLE_FILE_TYPE("BRSTM Audio File (*.BRSTM)", brstm); +DECLARE_MULTIPLE_FILE_TYPE("BRSTM Audio File [2] (*.BRSTM)", brstmspm); +DECLARE_MULTIPLE_FILE_TYPE("BTSND Audio File (*.BTSND)", btsnd); +DECLARE_MULTIPLE_FILE_TYPE("BVG Audio File (*.BVG)", bvg); + +DECLARE_MULTIPLE_FILE_TYPE("CAF Audio File (*.CAF)", caf); +DECLARE_MULTIPLE_FILE_TYPE("CAPDSP Audio File (*.CAPDSP)", capdsp); +DECLARE_MULTIPLE_FILE_TYPE("CBD2 Audio File (*.CBD2)", cbd2); +DECLARE_MULTIPLE_FILE_TYPE("CCC Audio File (*.CCC)", ccc); +DECLARE_MULTIPLE_FILE_TYPE("CFN Audio File (*.CFN)", cfn); +DECLARE_MULTIPLE_FILE_TYPE("CKD Audio File (*.CKD)", ckd); +DECLARE_MULTIPLE_FILE_TYPE("CNK Audio File (*.CNK)", cnk); +DECLARE_MULTIPLE_FILE_TYPE("CPS Audio File (*.CPS)", cps); +DECLARE_MULTIPLE_FILE_TYPE("CXS Audio File (*.CXS)", cxs); + +DECLARE_MULTIPLE_FILE_TYPE("DBM Audio File (*.DBM)", dbm); +DECLARE_MULTIPLE_FILE_TYPE("DCS Audio File (*.DCS)", dcs); +DECLARE_MULTIPLE_FILE_TYPE("DDSP Audio File (*.DDSP)", ddsp); +DECLARE_MULTIPLE_FILE_TYPE("DE2 Audio File (*.DE2)", de2); +DECLARE_MULTIPLE_FILE_TYPE("DMSG Audio File (*.DMSG)", dmsg); +DECLARE_MULTIPLE_FILE_TYPE("DSP Audio File (*.DSP)", dsp); +DECLARE_MULTIPLE_FILE_TYPE("DSPW Audio File (*.DSPW)", dspw); +DECLARE_MULTIPLE_FILE_TYPE("DTK Audio File (*.DTK)", dtk); +DECLARE_MULTIPLE_FILE_TYPE("DVI Audio File (*.DVI)", dvi); +DECLARE_MULTIPLE_FILE_TYPE("DXH Audio File (*.DXH)", dxh); + +DECLARE_MULTIPLE_FILE_TYPE("EAM Audio File (*.EAM)", eam); +DECLARE_MULTIPLE_FILE_TYPE("EMFF Audio File (*.EMFF)", emff); +DECLARE_MULTIPLE_FILE_TYPE("ENTH Audio File (*.ENTH)", enth); + +DECLARE_MULTIPLE_FILE_TYPE("FAG Audio File (*.FAG)", fag); +DECLARE_MULTIPLE_FILE_TYPE("FFW Audio File (*.FFW)", ffw); +DECLARE_MULTIPLE_FILE_TYPE("FILP Audio File (*.FILP)", filp); +DECLARE_MULTIPLE_FILE_TYPE("FSB Audio File (*.FSB)", fsb); +DECLARE_MULTIPLE_FILE_TYPE("FWAV Audio File (*.FWAV)", fwav); + +DECLARE_MULTIPLE_FILE_TYPE("G1L Audio File (*.G1L)", g1l); +DECLARE_MULTIPLE_FILE_TYPE("GBTS Audio File (*.GBTS)", gbts); +DECLARE_MULTIPLE_FILE_TYPE("GCA Audio File (*.GCA)", gca); +DECLARE_MULTIPLE_FILE_TYPE("GCM Audio File (*.GCM)", gcm); +DECLARE_MULTIPLE_FILE_TYPE("GCUB Audio File (*.GCUB)", gcub); +DECLARE_MULTIPLE_FILE_TYPE("GCW Audio File (*.GCW)", gcw); +DECLARE_MULTIPLE_FILE_TYPE("GENH Audio File (*.GENH)", genh); +DECLARE_MULTIPLE_FILE_TYPE("GMS Audio File (*.GMS)", gms); +DECLARE_MULTIPLE_FILE_TYPE("GSB Audio File (*.GSB)", gsb); +DECLARE_MULTIPLE_FILE_TYPE("GSB Audio File (*.GTD)", gtd); + +DECLARE_MULTIPLE_FILE_TYPE("HCA Audio File (*.HCA)", hca); +DECLARE_MULTIPLE_FILE_TYPE("HGC1 Audio File (*.HGC1)", hgc1); +DECLARE_MULTIPLE_FILE_TYPE("HIS Audio File (*.HIS)", his); +DECLARE_MULTIPLE_FILE_TYPE("HLWAV Audio File (*.HLWAV)", hlwav); +DECLARE_MULTIPLE_FILE_TYPE("HALPST Audio File (*.HPS)", hps); +DECLARE_MULTIPLE_FILE_TYPE("HSF Audio File (*.HSF)", hsf); +DECLARE_MULTIPLE_FILE_TYPE("HWAS Audio File (*.HWAS)", hwas); + +DECLARE_MULTIPLE_FILE_TYPE("IAB Audio File (*.IAB)", iab); +DECLARE_MULTIPLE_FILE_TYPE("IADP Audio File (*.IADP)", iadp); +DECLARE_MULTIPLE_FILE_TYPE("IDSP Audio File (*.IDSP)", idsp); +DECLARE_MULTIPLE_FILE_TYPE("IDVI Audio File (*.IDVI)", idvi); +DECLARE_MULTIPLE_FILE_TYPE("IKM Audio File (*.IKM)", ikm); +DECLARE_MULTIPLE_FILE_TYPE("ILD Audio File (*.ILD)", ild); +DECLARE_MULTIPLE_FILE_TYPE("INT Audio File (*.INT)", int); +DECLARE_MULTIPLE_FILE_TYPE("ISD Audio File (*.ISD)", isd); +DECLARE_MULTIPLE_FILE_TYPE("ISWS Audio File (*.ISWS)", isws); +DECLARE_MULTIPLE_FILE_TYPE("IVAUD Audio File (*.IVAUD)", ivaud); +DECLARE_MULTIPLE_FILE_TYPE("IVAG Audio File (*.IVAG)", ivag); +DECLARE_MULTIPLE_FILE_TYPE("IVB Audio File (*.IVB)", ivb); + +DECLARE_MULTIPLE_FILE_TYPE("JOE Audio File (*.JOE)", joe); +DECLARE_MULTIPLE_FILE_TYPE("JSTM Audio File (*.JSTM)", jstm); + +DECLARE_MULTIPLE_FILE_TYPE("KCES Audio File (*.KCES)", kces); +DECLARE_MULTIPLE_FILE_TYPE("KCEY Audio File (*.KCEY)", kcey); +DECLARE_MULTIPLE_FILE_TYPE("KHV Audio File (*.KHV)", khv); +DECLARE_MULTIPLE_FILE_TYPE("KOVS Audio File (*.KOVS)", kovs); +DECLARE_MULTIPLE_FILE_TYPE("KRAW Audio File (*.KRAW)", kraw); + +DECLARE_MULTIPLE_FILE_TYPE("LAAC Audio File (*.LAAC)", laac); +DECLARE_MULTIPLE_FILE_TYPE("LEG Audio File (*.LEG)", leg); +DECLARE_MULTIPLE_FILE_TYPE("LMP4 Audio File (*.LMP4)", lmp4); +DECLARE_MULTIPLE_FILE_TYPE("LOGG Audio File (*.LOGG)", logg); +DECLARE_MULTIPLE_FILE_TYPE("LPCM Audio File (*.LPCM)", lpcm); +DECLARE_MULTIPLE_FILE_TYPE("LPS Audio File (*.LPS)", lps); +DECLARE_MULTIPLE_FILE_TYPE("LSF Audio File (*.LSF)", lsf); +DECLARE_MULTIPLE_FILE_TYPE("LWAV Audio File (*.LWAV)", lwav); + +DECLARE_MULTIPLE_FILE_TYPE("MATX Audio File (*.MATX)", matx); +DECLARE_MULTIPLE_FILE_TYPE("MC3 Audio File (*.MC3)", mc3); +DECLARE_MULTIPLE_FILE_TYPE("MCA Audio File (*.MCA)", mca); +DECLARE_MULTIPLE_FILE_TYPE("MCG Audio File (*.MCG)", mcg); +DECLARE_MULTIPLE_FILE_TYPE("MDS Audio File (*.MDS)", mds); +DECLARE_MULTIPLE_FILE_TYPE("MDSP Audio File (*.MDSP)", mdsp); +DECLARE_MULTIPLE_FILE_TYPE("MI4 Audio File (*.MI4)", mi4); +DECLARE_MULTIPLE_FILE_TYPE("MIB Audio File (*.MIB)", mib); +DECLARE_MULTIPLE_FILE_TYPE("MIC Audio File (*.MIC)", mic); +DECLARE_MULTIPLE_FILE_TYPE("MIHB Audio File (*.MIHB)", mihb); +DECLARE_MULTIPLE_FILE_TYPE("MNSTR Audio File (*.MNSTR)", mnstr); +//"mp4", //common +DECLARE_MULTIPLE_FILE_TYPE("MPDSP Audio File (*.MPDSP)", mpdsp); +DECLARE_MULTIPLE_FILE_TYPE("MPDS Audio File (*.MPDS)", mpds); +DECLARE_MULTIPLE_FILE_TYPE("MSA Audio File (*.MSA)", msa); +DECLARE_MULTIPLE_FILE_TYPE("MSF Audio File (*.MSF)", msf); +DECLARE_MULTIPLE_FILE_TYPE("MSS Audio File (*.MSS)", mss); +DECLARE_MULTIPLE_FILE_TYPE("MSVP Audio File (*.MSVP)", msvp); +DECLARE_MULTIPLE_FILE_TYPE("MTA2 Audio File (*.MTA2)", mta2); +DECLARE_MULTIPLE_FILE_TYPE("MTAF Audio File (*.MTAF)", mtaf); +DECLARE_MULTIPLE_FILE_TYPE("MUS Playlist File (*.MUS)", mus); +DECLARE_MULTIPLE_FILE_TYPE("MUSC Audio File (*.MUSC)", musc); +DECLARE_MULTIPLE_FILE_TYPE("MUSX Audio File (*.MUSX)", musx); +DECLARE_MULTIPLE_FILE_TYPE("MWV Audio File (*.MWV)", mwv); +DECLARE_MULTIPLE_FILE_TYPE("MxSt Audio File (*.MxSt)", mxst); +DECLARE_MULTIPLE_FILE_TYPE("MYSPD Audio File (*.MYSPD)", myspd); + +DECLARE_MULTIPLE_FILE_TYPE("NDP Audio File (*.NDP)", ndp); +DECLARE_MULTIPLE_FILE_TYPE("NGCA Audio File (*.NGCA)", ngca); +DECLARE_MULTIPLE_FILE_TYPE("NPS Audio File (*.NPS)", nps); +DECLARE_MULTIPLE_FILE_TYPE("NPSF Audio File (*.NPSF)", npsf); +DECLARE_MULTIPLE_FILE_TYPE("NUS3BANK Audio File (*.NUS3BANK)", nus3bank); +DECLARE_MULTIPLE_FILE_TYPE("NWA Audio File (*.NWA)", nwa); + +//"ogg", //common +DECLARE_MULTIPLE_FILE_TYPE("OGL Audio File (*.OGL)", ogl); +DECLARE_MULTIPLE_FILE_TYPE("OMA Audio File (*.OMA)", oma); +DECLARE_MULTIPLE_FILE_TYPE("OMU Audio File (*.OMU)", omu); +DECLARE_MULTIPLE_FILE_TYPE("OTM Audio File (*.OTM)", otm); + +DECLARE_MULTIPLE_FILE_TYPE("P2BT Audio File (*.P2BT)", p2bt); +DECLARE_MULTIPLE_FILE_TYPE("P3D Audio File (*.P3D)", p3d); +DECLARE_MULTIPLE_FILE_TYPE("PAST Audio File (*.PAST)", past); +DECLARE_MULTIPLE_FILE_TYPE("PCM Audio File (*.PCM)", pcm); +DECLARE_MULTIPLE_FILE_TYPE("PDT Audio File (*.PDT)", pdt); +DECLARE_MULTIPLE_FILE_TYPE("PNB Audio File (*.PNB)", pnb); +DECLARE_MULTIPLE_FILE_TYPE("PONA Audio File (*.PONA)", pona); +DECLARE_MULTIPLE_FILE_TYPE("POS Audio File (*.POS)", pos); +DECLARE_MULTIPLE_FILE_TYPE("PS2STM Audio File (*.PS2STM)", ps2stm); +DECLARE_MULTIPLE_FILE_TYPE("PSH Audio File (*.PSH)", psh); +DECLARE_MULTIPLE_FILE_TYPE("PSND Audio File (*.PSND)", psnd); +DECLARE_MULTIPLE_FILE_TYPE("PSW Audio File (*.PSW)", psw); + +DECLARE_MULTIPLE_FILE_TYPE("RAK Audio File (*.RAK)", rak); +DECLARE_MULTIPLE_FILE_TYPE("RAS Audio File (*.RAS)", ras); +DECLARE_MULTIPLE_FILE_TYPE("RAW Audio File (*.RAW)", raw); +DECLARE_MULTIPLE_FILE_TYPE("RKV Audio File (*.RKV)", rkv); +DECLARE_MULTIPLE_FILE_TYPE("RND Audio File (*.RND)", rnd); +DECLARE_MULTIPLE_FILE_TYPE("RRDS Audio File (*.RRDS)", rrds); +DECLARE_MULTIPLE_FILE_TYPE("RSD Audio File (*.RSD)", rsd); +DECLARE_MULTIPLE_FILE_TYPE("RSF Audio File (*.RSF)", rsf); +DECLARE_MULTIPLE_FILE_TYPE("RSTM Audio File (*.RSTM)", rstm); +DECLARE_MULTIPLE_FILE_TYPE("RVWS Audio File (*.RSTM)", rvws); +DECLARE_MULTIPLE_FILE_TYPE("RWAR Audio File (*.RWSD)", rwar); +DECLARE_MULTIPLE_FILE_TYPE("RWAV Audio File (*.RWAV)", rwav); +DECLARE_MULTIPLE_FILE_TYPE("RWS Audio File (*.RWS)", rws); +DECLARE_MULTIPLE_FILE_TYPE("RWSD Audio File (*.RWSD)", rwsd); +DECLARE_MULTIPLE_FILE_TYPE("RWX Audio File (*.RWX)", rwx); +DECLARE_MULTIPLE_FILE_TYPE("RXWS File (*.RXW)", rxw); + +DECLARE_MULTIPLE_FILE_TYPE("S14 Audio File (*.S14)", s14); +DECLARE_MULTIPLE_FILE_TYPE("SAB Audio File (*.SAB)", sab); +DECLARE_MULTIPLE_FILE_TYPE("SAD Audio File (*.SAD)", sad); +DECLARE_MULTIPLE_FILE_TYPE("SAP Audio File (*.SAP)", sap); +DECLARE_MULTIPLE_FILE_TYPE("SC Audio File (*.SC)", sc); +DECLARE_MULTIPLE_FILE_TYPE("SCD Audio File (*.SCD)", scd); +DECLARE_MULTIPLE_FILE_TYPE("SCK Audio File (*.SCK)", sck); +DECLARE_MULTIPLE_FILE_TYPE("SD9 Audio File (*.SD9)", sd9); +DECLARE_MULTIPLE_FILE_TYPE("SDT Audio File (*.SDT)", sdt); +DECLARE_MULTIPLE_FILE_TYPE("SEG Audio File (*.SEG)", seg); +DECLARE_MULTIPLE_FILE_TYPE("SF0 Audio File (*.SF0)", sf0); +DECLARE_MULTIPLE_FILE_TYPE("SFL Audio File (*.SFL)", sfl); +DECLARE_MULTIPLE_FILE_TYPE("SFS Audio File (*.SFS)", sfs); +DECLARE_MULTIPLE_FILE_TYPE("SFX Audio File (*.SFX)", sfx); +DECLARE_MULTIPLE_FILE_TYPE("SGB Audio File (*.SGB)", sgb); +DECLARE_MULTIPLE_FILE_TYPE("SGD Audio File (*.SGD)", sgd); +DECLARE_MULTIPLE_FILE_TYPE("SGX Audio File (*.SGX)", sgx); +DECLARE_MULTIPLE_FILE_TYPE("SL3 Audio File (*.SL3)", sl3); +DECLARE_MULTIPLE_FILE_TYPE("SLI Audio File (*.SLI)", sli); +DECLARE_MULTIPLE_FILE_TYPE("SMP Audio File (*.SMP)", smp); +DECLARE_MULTIPLE_FILE_TYPE("SMPL Audio File (*.SMPL)", smpl); +DECLARE_MULTIPLE_FILE_TYPE("SND Audio File (*.SND)", snd); +DECLARE_MULTIPLE_FILE_TYPE("SNDS Audio File (*.SNDS)", snds); +DECLARE_MULTIPLE_FILE_TYPE("SNG Audio File (*.SNG)", sng); +DECLARE_MULTIPLE_FILE_TYPE("SNS Audio File (*.SNS)", sns); +DECLARE_MULTIPLE_FILE_TYPE("SPD Audio File (*.SPD)", spd); +DECLARE_MULTIPLE_FILE_TYPE("SPM Audio File (*.SPM)", spm); +DECLARE_MULTIPLE_FILE_TYPE("SPS Audio File (*.SPS)", sps); +DECLARE_MULTIPLE_FILE_TYPE("SPSD Audio File (*.SPSD)", spsd); +DECLARE_MULTIPLE_FILE_TYPE("SPW Audio File (*.SPW)", spw); +DECLARE_MULTIPLE_FILE_TYPE("SS2 Audio File (*.SS2)", ss2); +DECLARE_MULTIPLE_FILE_TYPE("SS3 Audio File (*.SS3)", ss3); +DECLARE_MULTIPLE_FILE_TYPE("SS7 Audio File (*.SS7)", ss7); +DECLARE_MULTIPLE_FILE_TYPE("SSM Audio File (*.SSM)", ssm); +DECLARE_MULTIPLE_FILE_TYPE("SSS Audio File (*.SSS)", sss); +DECLARE_MULTIPLE_FILE_TYPE("STER Audio File (*.STER)", ster); +DECLARE_MULTIPLE_FILE_TYPE("STH Audio File (*.STH)", sth); +//"stm", //common +DECLARE_MULTIPLE_FILE_TYPE("STMA Audio File (*.STMA)", stma); +DECLARE_MULTIPLE_FILE_TYPE("STR Audio File (*.STR)", str); +DECLARE_MULTIPLE_FILE_TYPE("STRM Audio File (*.STRM)", strm); +DECLARE_MULTIPLE_FILE_TYPE("STS Audio File (*.STS)", sts); +DECLARE_MULTIPLE_FILE_TYPE("STX Audio File (*.STX)", stx); +DECLARE_MULTIPLE_FILE_TYPE("SVAG Audio File (*.SVAG)", svag); +DECLARE_MULTIPLE_FILE_TYPE("SVS Audio File (*.SVS)", svs); +DECLARE_MULTIPLE_FILE_TYPE("SWAG Audio File (*.SWAG)", swag); +DECLARE_MULTIPLE_FILE_TYPE("SWAV Audio File (*.SWAV)", swav); +DECLARE_MULTIPLE_FILE_TYPE("SWD Audio File (*.SWD)", swd); +DECLARE_MULTIPLE_FILE_TYPE("SXD Audio File (*.SXD)", sxd); +DECLARE_MULTIPLE_FILE_TYPE("SXD2 Audio File (*.SXD2)", sxd2); + +DECLARE_MULTIPLE_FILE_TYPE("TEC Audio File (*.TEC)", tec); +DECLARE_MULTIPLE_FILE_TYPE("THP Audio File (*.THP)", thp); +DECLARE_MULTIPLE_FILE_TYPE("TK1 Audio File (*.TK1)", tk1); +DECLARE_MULTIPLE_FILE_TYPE("TK5 Audio File (*.TK5)", tk5); +DECLARE_MULTIPLE_FILE_TYPE("TRA Audio File (*.TRA)", tra); +DECLARE_MULTIPLE_FILE_TYPE("TUN Audio File (*.TUN)", tun); +DECLARE_MULTIPLE_FILE_TYPE("TYDSP Audio File (*.TYDSP)", tydsp); + +DECLARE_MULTIPLE_FILE_TYPE("UM3 Audio File (*.UM3)", um3); + +DECLARE_MULTIPLE_FILE_TYPE("VAG Audio File (*.VAG)", vag); +DECLARE_MULTIPLE_FILE_TYPE("VAS Audio File (*.VAS)", vas); +DECLARE_MULTIPLE_FILE_TYPE("VAS Audio File (*.VAS)", vawx); +DECLARE_MULTIPLE_FILE_TYPE("VB Audio File (*.VB)", vb); +DECLARE_MULTIPLE_FILE_TYPE("VBK Audio File (*.VBK)", vbk); +DECLARE_MULTIPLE_FILE_TYPE("VGS Audio File (*.VGS)", vgs); +DECLARE_MULTIPLE_FILE_TYPE("VGV Audio File (*.VGV)", vgv); +DECLARE_MULTIPLE_FILE_TYPE("VIG Audio File (*.VIG)", vig); +DECLARE_MULTIPLE_FILE_TYPE("VMS Audio File (*.VMS)", vms); +DECLARE_MULTIPLE_FILE_TYPE("VOI Audio File (*.VOI)", voi); +DECLARE_MULTIPLE_FILE_TYPE("VPK Audio File (*.VPK)", vpk); +DECLARE_MULTIPLE_FILE_TYPE("VS Audio File (*.VS)", vs); +DECLARE_MULTIPLE_FILE_TYPE("VSF Audio File (*.VSF)", vsf); + +DECLARE_MULTIPLE_FILE_TYPE("WAA Audio File (*.WAA)", waa); +DECLARE_MULTIPLE_FILE_TYPE("WAC Audio File (*.WAC)", wac); +DECLARE_MULTIPLE_FILE_TYPE("WAD Audio File (*.WAD)", wad); +DECLARE_MULTIPLE_FILE_TYPE("WAM Audio File (*.WAM)", wam); +DECLARE_MULTIPLE_FILE_TYPE("WAS Audio File (*.WAS)", was); +//"wav", //common +DECLARE_MULTIPLE_FILE_TYPE("WAVM Audio File (*.WAVM)", wavm); +DECLARE_MULTIPLE_FILE_TYPE("WEM Audio File (*.WEM)", wem); +DECLARE_MULTIPLE_FILE_TYPE("WII Audio File (*.WII)", wii); +DECLARE_MULTIPLE_FILE_TYPE("WMUS Audio File (*.WMUS)", wmus); +DECLARE_MULTIPLE_FILE_TYPE("WP2 Audio File (*.WP2)", wp2); +DECLARE_MULTIPLE_FILE_TYPE("WPD Audio File (*.WPD)", wpd); +DECLARE_MULTIPLE_FILE_TYPE("WSD Audio File (*.WSD)", wsd); +DECLARE_MULTIPLE_FILE_TYPE("WSI Audio File (*.WSI)", wsi); +DECLARE_MULTIPLE_FILE_TYPE("WVS Audio File (*.WVS)", wvs); + +DECLARE_MULTIPLE_FILE_TYPE("XA File (*.XA)", xa); +DECLARE_MULTIPLE_FILE_TYPE("XA2 Audio File (*.XA2)", xa2); +DECLARE_MULTIPLE_FILE_TYPE("XA30 Audio File (*.XA30)", xa30); +DECLARE_MULTIPLE_FILE_TYPE("XAG Audio File (*.XAG)", xag); +DECLARE_MULTIPLE_FILE_TYPE("XAU Audio File (*.XAU)", xau); +DECLARE_MULTIPLE_FILE_TYPE("XMA Audio File (*.XMA)", xma); +DECLARE_MULTIPLE_FILE_TYPE("XMA2 Audio File (*.XMA2)", xma2); +DECLARE_MULTIPLE_FILE_TYPE("XMU Audio File (*.XMU)", xmu); +DECLARE_MULTIPLE_FILE_TYPE("XNB Audio File (*.XNB)", xnb); +DECLARE_MULTIPLE_FILE_TYPE("XSF Audio File (*.XSF)", xsf); +DECLARE_MULTIPLE_FILE_TYPE("XSS Audio File (*.XSS)", xss); +DECLARE_MULTIPLE_FILE_TYPE("XVAG Audio File (*.XVAG)", xvag); +DECLARE_MULTIPLE_FILE_TYPE("XVAS Audio File (*.XVAS)", xvas); +DECLARE_MULTIPLE_FILE_TYPE("XWAV Audio File (*.XWAV)", xwav); +DECLARE_MULTIPLE_FILE_TYPE("XWB Audio File (*.XWB)", xwb); +DECLARE_MULTIPLE_FILE_TYPE("XWM Audio File (*.XWM)", xwm); +DECLARE_MULTIPLE_FILE_TYPE("XWMA Audio File (*.XWMA)", xwma); +DECLARE_MULTIPLE_FILE_TYPE("XWS Audio File (*.XWS)", xws); +DECLARE_MULTIPLE_FILE_TYPE("XWV Audio File (*.XWV)", xwv); + +DECLARE_MULTIPLE_FILE_TYPE("YDSP Audio File (*.YDSP)", ydsp); +DECLARE_MULTIPLE_FILE_TYPE("YMF Audio File (*.YMF)", ymf); + +DECLARE_MULTIPLE_FILE_TYPE("ZSD Audio File (*.ZSD)", zsd); +DECLARE_MULTIPLE_FILE_TYPE("ZWDSP Audio File (*.ZWDSP)", zwdsp); + +DECLARE_MULTIPLE_FILE_TYPE("VGMSTREAM Audio File (*.VGMSTREAM)", vgmstream); + + +#endif /*_FOO_FILETYPES_H_ */ diff --git a/fb2k/foo_input_vgmstream.vcxproj b/fb2k/foo_input_vgmstream.vcxproj index 0763e5b6..7beb8c41 100644 --- a/fb2k/foo_input_vgmstream.vcxproj +++ b/fb2k/foo_input_vgmstream.vcxproj @@ -162,6 +162,7 @@ + diff --git a/fb2k/foo_input_vgmstream.vcxproj.filters b/fb2k/foo_input_vgmstream.vcxproj.filters index 654200e4..e95e0f46 100644 --- a/fb2k/foo_input_vgmstream.vcxproj.filters +++ b/fb2k/foo_input_vgmstream.vcxproj.filters @@ -21,6 +21,9 @@ Header Files + + Header Files + Header Files diff --git a/fb2k/foo_vgmstream.cpp b/fb2k/foo_vgmstream.cpp index 72ebd663..3f4393fd 100644 --- a/fb2k/foo_vgmstream.cpp +++ b/fb2k/foo_vgmstream.cpp @@ -20,6 +20,7 @@ extern "C" { #include "../src/vgmstream.h" } #include "foo_vgmstream.h" +#include "foo_filetypes.h" #ifndef VERSION #include "../version.h" @@ -399,343 +400,4 @@ static input_singletrack_factory_t g_input_vgmstream_factory; DECLARE_COMPONENT_VERSION(APP_NAME,PLUGIN_VERSION,PLUGIN_DESCRIPTION); VALIDATE_COMPONENT_FILENAME("foo_input_vgmstream.dll"); -// Registered file types, to associate an extension with foobar2000 in Windows. -// Accepted file types go in formats.c and are checked in input_vgmstream::g_is_our_path. -// Both lists don't need to match, formats.c is what matters here. -// (do we really want to associate every single vgmstream format?) -// -// these are declared statically, and if anyone has a better idea i'd like to hear it - josh. -DECLARE_MULTIPLE_FILE_TYPE("2DX9 Audio File (*.2DX9)", 2dx9); -DECLARE_MULTIPLE_FILE_TYPE("2PFS Audio File (*.2PFS)", 2pfs); - -//"aac", //common, also tri-Ace's -DECLARE_MULTIPLE_FILE_TYPE("AA3 Audio File (*.AA3)", aa3); -DECLARE_MULTIPLE_FILE_TYPE("AAAP Audio File (*.AAAP)", aaap); -DECLARE_MULTIPLE_FILE_TYPE("AAX Audio File (*.AAX)", aax); -//"ac3", //FFmpeg, not parsed //common? -DECLARE_MULTIPLE_FILE_TYPE("ACE Audio File (*.ACE)", ace); -DECLARE_MULTIPLE_FILE_TYPE("ACM Audio File (*.ACM)", acm); -DECLARE_MULTIPLE_FILE_TYPE("ADM Audio File (*.ADM)", adm); -DECLARE_MULTIPLE_FILE_TYPE("ADP Audio File (*.ADP)", adp); -DECLARE_MULTIPLE_FILE_TYPE("ADPCM Audio File (*.ADPCM)", adpcm); -DECLARE_MULTIPLE_FILE_TYPE("ADS Audio File (*.ADS)", ads); -DECLARE_MULTIPLE_FILE_TYPE("ADX Audio File (*.ADX)", adx); -DECLARE_MULTIPLE_FILE_TYPE("AFC Audio File (*.AFC)", afc); -DECLARE_MULTIPLE_FILE_TYPE("AGSC Audio File (*.AGSC)", agsc); -DECLARE_MULTIPLE_FILE_TYPE("AHX Audio File (*.AHX)", ahx); -DECLARE_MULTIPLE_FILE_TYPE("AIFC Audio File (*.AIFC)", aifc); -DECLARE_MULTIPLE_FILE_TYPE("AIFCL Audio File (*.AIFCL)", aifcl); -//"aiff", //common -DECLARE_MULTIPLE_FILE_TYPE("AIX Audio File (*.AIX)", aix); -DECLARE_MULTIPLE_FILE_TYPE("AKB Audio File (*.AKB)", akb); -DECLARE_MULTIPLE_FILE_TYPE("AMTS Audio File (*.AMTS)", amts); -DECLARE_MULTIPLE_FILE_TYPE("AS4 Audio File (*.AS4)", as4); -DECLARE_MULTIPLE_FILE_TYPE("ASD Audio File (*.ASD)", asd); -DECLARE_MULTIPLE_FILE_TYPE("ASF Audio File (*.ASF)", asf); -DECLARE_MULTIPLE_FILE_TYPE("ASR Audio File (*.ASR)", asr); -DECLARE_MULTIPLE_FILE_TYPE("ASS Audio File (*.ASS)", ass); -DECLARE_MULTIPLE_FILE_TYPE("AST Audio File (*.AST)", ast); -DECLARE_MULTIPLE_FILE_TYPE("ATRAC3plus Audio File (*.AT3)", at3); -DECLARE_MULTIPLE_FILE_TYPE("AUD Audio File (*.AUD)", aud); -DECLARE_MULTIPLE_FILE_TYPE("AUS Audio File (*.AUS)", aus); - -DECLARE_MULTIPLE_FILE_TYPE("B1S Audio File (*.B1S)", b1s); -DECLARE_MULTIPLE_FILE_TYPE("BAF Audio File (*.BAF)", baf); -DECLARE_MULTIPLE_FILE_TYPE("BAKA Audio File (*.BAKA)", baka); -DECLARE_MULTIPLE_FILE_TYPE("BAR Audio File (*.BAR)", bar); -DECLARE_MULTIPLE_FILE_TYPE("BCSTM Audio File (*.BCSTM)", bcstm); -DECLARE_MULTIPLE_FILE_TYPE("BCWAV Audio File (*.BCWAV)", bcwav); -DECLARE_MULTIPLE_FILE_TYPE("BDSP Audio File (*.BDSP)", bdsp); -DECLARE_MULTIPLE_FILE_TYPE("BFSTM Audio File (*.BFSTM)", bfstm); -DECLARE_MULTIPLE_FILE_TYPE("BFWAV Audio File (*.BFWAV)", bfwav); -DECLARE_MULTIPLE_FILE_TYPE("BFWAV Audio File [2] (*.BFWAV)", bfwavnsmbu); -DECLARE_MULTIPLE_FILE_TYPE("BG00 Audio File (*.BG00)", bg00); -DECLARE_MULTIPLE_FILE_TYPE("BGM Audio File (*.BGM)", bgm); -DECLARE_MULTIPLE_FILE_TYPE("BGW Audio File (*.BGW)", bgw); -DECLARE_MULTIPLE_FILE_TYPE("BH2PCM Audio File (*.BH2PCM)", bh2pcm); -DECLARE_MULTIPLE_FILE_TYPE("BIK Audio File (*.BIK)", bik); -DECLARE_MULTIPLE_FILE_TYPE("BIKA Audio File (*.BIKA)", bika); -DECLARE_MULTIPLE_FILE_TYPE("BIK2 Audio File (*.BIK2)", bik2); -DECLARE_MULTIPLE_FILE_TYPE("BIK2A Audio File (*.BIK2A)", bik2a); -DECLARE_MULTIPLE_FILE_TYPE("BK2 Audio File (*.BK2)", bk2); -DECLARE_MULTIPLE_FILE_TYPE("BK2A Audio File (*.BK2A)", bk2a); -DECLARE_MULTIPLE_FILE_TYPE("BMDX Audio File (*.BMDX)", bmdx); -DECLARE_MULTIPLE_FILE_TYPE("BMS Audio File (*.BMS)", bms); -DECLARE_MULTIPLE_FILE_TYPE("KLBS Audio File (*.BNK)", bnk); -DECLARE_MULTIPLE_FILE_TYPE("BNS Audio File (*.BNS)", bns); -DECLARE_MULTIPLE_FILE_TYPE("BNSF Audio File (*.BNSF)", bnsf); -DECLARE_MULTIPLE_FILE_TYPE("BO2 Audio File (*.BO2)", bo2); -DECLARE_MULTIPLE_FILE_TYPE("BRSTM Audio File (*.BRSTM)", brstm); -DECLARE_MULTIPLE_FILE_TYPE("BRSTM Audio File [2] (*.BRSTM)", brstmspm); -DECLARE_MULTIPLE_FILE_TYPE("BTSND Audio File (*.BTSND)", btsnd); -DECLARE_MULTIPLE_FILE_TYPE("BVG Audio File (*.BVG)", bvg); - -DECLARE_MULTIPLE_FILE_TYPE("CAF Audio File (*.CAF)", caf); -DECLARE_MULTIPLE_FILE_TYPE("CAPDSP Audio File (*.CAPDSP)", capdsp); -DECLARE_MULTIPLE_FILE_TYPE("CBD2 Audio File (*.CBD2)", cbd2); -DECLARE_MULTIPLE_FILE_TYPE("CCC Audio File (*.CCC)", ccc); -DECLARE_MULTIPLE_FILE_TYPE("CFN Audio File (*.CFN)", cfn); -DECLARE_MULTIPLE_FILE_TYPE("CKD Audio File (*.CKD)", ckd); -DECLARE_MULTIPLE_FILE_TYPE("CNK Audio File (*.CNK)", cnk); -DECLARE_MULTIPLE_FILE_TYPE("CPS Audio File (*.CPS)", cps); -DECLARE_MULTIPLE_FILE_TYPE("CXS Audio File (*.CXS)", cxs); - -DECLARE_MULTIPLE_FILE_TYPE("DBM Audio File (*.DBM)", dbm); -DECLARE_MULTIPLE_FILE_TYPE("DCS Audio File (*.DCS)", dcs); -DECLARE_MULTIPLE_FILE_TYPE("DDSP Audio File (*.DDSP)", ddsp); -DECLARE_MULTIPLE_FILE_TYPE("DE2 Audio File (*.DE2)", de2); -DECLARE_MULTIPLE_FILE_TYPE("DMSG Audio File (*.DMSG)", dmsg); -DECLARE_MULTIPLE_FILE_TYPE("DSP Audio File (*.DSP)", dsp); -DECLARE_MULTIPLE_FILE_TYPE("DSPW Audio File (*.DSPW)", dspw); -DECLARE_MULTIPLE_FILE_TYPE("DTK Audio File (*.DTK)", dtk); -DECLARE_MULTIPLE_FILE_TYPE("DVI Audio File (*.DVI)", dvi); -DECLARE_MULTIPLE_FILE_TYPE("DXH Audio File (*.DXH)", dxh); - -DECLARE_MULTIPLE_FILE_TYPE("EAM Audio File (*.EAM)", eam); -DECLARE_MULTIPLE_FILE_TYPE("EMFF Audio File (*.EMFF)", emff); -DECLARE_MULTIPLE_FILE_TYPE("ENTH Audio File (*.ENTH)", enth); - -DECLARE_MULTIPLE_FILE_TYPE("FAG Audio File (*.FAG)", fag); -DECLARE_MULTIPLE_FILE_TYPE("FFW Audio File (*.FFW)", ffw); -DECLARE_MULTIPLE_FILE_TYPE("FILP Audio File (*.FILP)", filp); -DECLARE_MULTIPLE_FILE_TYPE("FSB Audio File (*.FSB)", fsb); -DECLARE_MULTIPLE_FILE_TYPE("FWAV Audio File (*.FWAV)", fwav); - -DECLARE_MULTIPLE_FILE_TYPE("G1L Audio File (*.G1L)", g1l); -DECLARE_MULTIPLE_FILE_TYPE("GBTS Audio File (*.GBTS)", gbts); -DECLARE_MULTIPLE_FILE_TYPE("GCA Audio File (*.GCA)", gca); -DECLARE_MULTIPLE_FILE_TYPE("GCM Audio File (*.GCM)", gcm); -DECLARE_MULTIPLE_FILE_TYPE("GCUB Audio File (*.GCUB)", gcub); -DECLARE_MULTIPLE_FILE_TYPE("GCW Audio File (*.GCW)", gcw); -DECLARE_MULTIPLE_FILE_TYPE("GENH Audio File (*.GENH)", genh); -DECLARE_MULTIPLE_FILE_TYPE("GMS Audio File (*.GMS)", gms); -DECLARE_MULTIPLE_FILE_TYPE("GSB Audio File (*.GSB)", gsb); -DECLARE_MULTIPLE_FILE_TYPE("GSB Audio File (*.GTD)", gtd); - -DECLARE_MULTIPLE_FILE_TYPE("HCA Audio File (*.HCA)", hca); -DECLARE_MULTIPLE_FILE_TYPE("HGC1 Audio File (*.HGC1)", hgc1); -DECLARE_MULTIPLE_FILE_TYPE("HIS Audio File (*.HIS)", his); -DECLARE_MULTIPLE_FILE_TYPE("HLWAV Audio File (*.HLWAV)", hlwav); -DECLARE_MULTIPLE_FILE_TYPE("HALPST Audio File (*.HPS)", hps); -DECLARE_MULTIPLE_FILE_TYPE("HSF Audio File (*.HSF)", hsf); -DECLARE_MULTIPLE_FILE_TYPE("HWAS Audio File (*.HWAS)", hwas); - -DECLARE_MULTIPLE_FILE_TYPE("IAB Audio File (*.IAB)", iab); -DECLARE_MULTIPLE_FILE_TYPE("IADP Audio File (*.IADP)", iadp); -DECLARE_MULTIPLE_FILE_TYPE("IDSP Audio File (*.IDSP)", idsp); -DECLARE_MULTIPLE_FILE_TYPE("IDVI Audio File (*.IDVI)", idvi); -DECLARE_MULTIPLE_FILE_TYPE("IKM Audio File (*.IKM)", ikm); -DECLARE_MULTIPLE_FILE_TYPE("ILD Audio File (*.ILD)", ild); -DECLARE_MULTIPLE_FILE_TYPE("INT Audio File (*.INT)", int); -DECLARE_MULTIPLE_FILE_TYPE("ISD Audio File (*.ISD)", isd); -DECLARE_MULTIPLE_FILE_TYPE("ISWS Audio File (*.ISWS)", isws); -DECLARE_MULTIPLE_FILE_TYPE("IVAUD Audio File (*.IVAUD)", ivaud); -DECLARE_MULTIPLE_FILE_TYPE("IVAG Audio File (*.IVAG)", ivag); -DECLARE_MULTIPLE_FILE_TYPE("IVB Audio File (*.IVB)", ivb); - -DECLARE_MULTIPLE_FILE_TYPE("JOE Audio File (*.JOE)", joe); -DECLARE_MULTIPLE_FILE_TYPE("JSTM Audio File (*.JSTM)", jstm); - -DECLARE_MULTIPLE_FILE_TYPE("KCES Audio File (*.KCES)", kces); -DECLARE_MULTIPLE_FILE_TYPE("KCEY Audio File (*.KCEY)", kcey); -DECLARE_MULTIPLE_FILE_TYPE("KHV Audio File (*.KHV)", khv); -DECLARE_MULTIPLE_FILE_TYPE("KOVS Audio File (*.KOVS)", kovs); -DECLARE_MULTIPLE_FILE_TYPE("KRAW Audio File (*.KRAW)", kraw); - -DECLARE_MULTIPLE_FILE_TYPE("LAAC Audio File (*.LAAC)", laac); -DECLARE_MULTIPLE_FILE_TYPE("LEG Audio File (*.LEG)", leg); -DECLARE_MULTIPLE_FILE_TYPE("LMP4 Audio File (*.LMP4)", lmp4); -DECLARE_MULTIPLE_FILE_TYPE("LOGG Audio File (*.LOGG)", logg); -DECLARE_MULTIPLE_FILE_TYPE("LPCM Audio File (*.LPCM)", lpcm); -DECLARE_MULTIPLE_FILE_TYPE("LPS Audio File (*.LPS)", lps); -DECLARE_MULTIPLE_FILE_TYPE("LSF Audio File (*.LSF)", lsf); -DECLARE_MULTIPLE_FILE_TYPE("LWAV Audio File (*.LWAV)", lwav); - -DECLARE_MULTIPLE_FILE_TYPE("MATX Audio File (*.MATX)", matx); -DECLARE_MULTIPLE_FILE_TYPE("MC3 Audio File (*.MC3)", mc3); -DECLARE_MULTIPLE_FILE_TYPE("MCA Audio File (*.MCA)", mca); -DECLARE_MULTIPLE_FILE_TYPE("MCG Audio File (*.MCG)", mcg); -DECLARE_MULTIPLE_FILE_TYPE("MDS Audio File (*.MDS)", mds); -DECLARE_MULTIPLE_FILE_TYPE("MDSP Audio File (*.MDSP)", mdsp); -DECLARE_MULTIPLE_FILE_TYPE("MI4 Audio File (*.MI4)", mi4); -DECLARE_MULTIPLE_FILE_TYPE("MIB Audio File (*.MIB)", mib); -DECLARE_MULTIPLE_FILE_TYPE("MIC Audio File (*.MIC)", mic); -DECLARE_MULTIPLE_FILE_TYPE("MIHB Audio File (*.MIHB)", mihb); -DECLARE_MULTIPLE_FILE_TYPE("MNSTR Audio File (*.MNSTR)", mnstr); -//"mp4", //common -DECLARE_MULTIPLE_FILE_TYPE("MPDSP Audio File (*.MPDSP)", mpdsp); -DECLARE_MULTIPLE_FILE_TYPE("MPDS Audio File (*.MPDS)", mpds); -DECLARE_MULTIPLE_FILE_TYPE("MSA Audio File (*.MSA)", msa); -DECLARE_MULTIPLE_FILE_TYPE("MSF Audio File (*.MSF)", msf); -DECLARE_MULTIPLE_FILE_TYPE("MSS Audio File (*.MSS)", mss); -DECLARE_MULTIPLE_FILE_TYPE("MSVP Audio File (*.MSVP)", msvp); -DECLARE_MULTIPLE_FILE_TYPE("MTA2 Audio File (*.MTA2)", mta2); -DECLARE_MULTIPLE_FILE_TYPE("MTAF Audio File (*.MTAF)", mtaf); -DECLARE_MULTIPLE_FILE_TYPE("MUS Playlist File (*.MUS)", mus); -DECLARE_MULTIPLE_FILE_TYPE("MUSC Audio File (*.MUSC)", musc); -DECLARE_MULTIPLE_FILE_TYPE("MUSX Audio File (*.MUSX)", musx); -DECLARE_MULTIPLE_FILE_TYPE("MWV Audio File (*.MWV)", mwv); -DECLARE_MULTIPLE_FILE_TYPE("MxSt Audio File (*.MxSt)", mxst); -DECLARE_MULTIPLE_FILE_TYPE("MYSPD Audio File (*.MYSPD)", myspd); - -DECLARE_MULTIPLE_FILE_TYPE("NDP Audio File (*.NDP)", ndp); -DECLARE_MULTIPLE_FILE_TYPE("NGCA Audio File (*.NGCA)", ngca); -DECLARE_MULTIPLE_FILE_TYPE("NPS Audio File (*.NPS)", nps); -DECLARE_MULTIPLE_FILE_TYPE("NPSF Audio File (*.NPSF)", npsf); -DECLARE_MULTIPLE_FILE_TYPE("NUS3BANK Audio File (*.NUS3BANK)", nus3bank); -DECLARE_MULTIPLE_FILE_TYPE("NWA Audio File (*.NWA)", nwa); - -//"ogg", //common -DECLARE_MULTIPLE_FILE_TYPE("OGL Audio File (*.OGL)", ogl); -DECLARE_MULTIPLE_FILE_TYPE("OMA Audio File (*.OMA)", oma); -DECLARE_MULTIPLE_FILE_TYPE("OMU Audio File (*.OMU)", omu); -DECLARE_MULTIPLE_FILE_TYPE("OTM Audio File (*.OTM)", otm); - -DECLARE_MULTIPLE_FILE_TYPE("P2BT Audio File (*.P2BT)", p2bt); -DECLARE_MULTIPLE_FILE_TYPE("P3D Audio File (*.P3D)", p3d); -DECLARE_MULTIPLE_FILE_TYPE("PAST Audio File (*.PAST)", past); -DECLARE_MULTIPLE_FILE_TYPE("PCM Audio File (*.PCM)", pcm); -DECLARE_MULTIPLE_FILE_TYPE("PDT Audio File (*.PDT)", pdt); -DECLARE_MULTIPLE_FILE_TYPE("PNB Audio File (*.PNB)", pnb); -DECLARE_MULTIPLE_FILE_TYPE("PONA Audio File (*.PONA)", pona); -DECLARE_MULTIPLE_FILE_TYPE("POS Audio File (*.POS)", pos); -DECLARE_MULTIPLE_FILE_TYPE("PS2STM Audio File (*.PS2STM)", ps2stm); -DECLARE_MULTIPLE_FILE_TYPE("PSH Audio File (*.PSH)", psh); -DECLARE_MULTIPLE_FILE_TYPE("PSND Audio File (*.PSND)", psnd); -DECLARE_MULTIPLE_FILE_TYPE("PSW Audio File (*.PSW)", psw); - -DECLARE_MULTIPLE_FILE_TYPE("RAK Audio File (*.RAK)", rak); -DECLARE_MULTIPLE_FILE_TYPE("RAS Audio File (*.RAS)", ras); -DECLARE_MULTIPLE_FILE_TYPE("RAW Audio File (*.RAW)", raw); -DECLARE_MULTIPLE_FILE_TYPE("RKV Audio File (*.RKV)", rkv); -DECLARE_MULTIPLE_FILE_TYPE("RND Audio File (*.RND)", rnd); -DECLARE_MULTIPLE_FILE_TYPE("RRDS Audio File (*.RRDS)", rrds); -DECLARE_MULTIPLE_FILE_TYPE("RSD Audio File (*.RSD)", rsd); -DECLARE_MULTIPLE_FILE_TYPE("RSF Audio File (*.RSF)", rsf); -DECLARE_MULTIPLE_FILE_TYPE("RSTM Audio File (*.RSTM)", rstm); -DECLARE_MULTIPLE_FILE_TYPE("RVWS Audio File (*.RSTM)", rvws); -DECLARE_MULTIPLE_FILE_TYPE("RWAR Audio File (*.RWSD)", rwar); -DECLARE_MULTIPLE_FILE_TYPE("RWAV Audio File (*.RWAV)", rwav); -DECLARE_MULTIPLE_FILE_TYPE("RWS Audio File (*.RWS)", rws); -DECLARE_MULTIPLE_FILE_TYPE("RWSD Audio File (*.RWSD)", rwsd); -DECLARE_MULTIPLE_FILE_TYPE("RWX Audio File (*.RWX)", rwx); -DECLARE_MULTIPLE_FILE_TYPE("RXWS File (*.RXW)", rxw); - -DECLARE_MULTIPLE_FILE_TYPE("S14 Audio File (*.S14)", s14); -DECLARE_MULTIPLE_FILE_TYPE("SAB Audio File (*.SAB)", sab); -DECLARE_MULTIPLE_FILE_TYPE("SAD Audio File (*.SAD)", sad); -DECLARE_MULTIPLE_FILE_TYPE("SAP Audio File (*.SAP)", sap); -DECLARE_MULTIPLE_FILE_TYPE("SC Audio File (*.SC)", sc); -DECLARE_MULTIPLE_FILE_TYPE("SCD Audio File (*.SCD)", scd); -DECLARE_MULTIPLE_FILE_TYPE("SCK Audio File (*.SCK)", sck); -DECLARE_MULTIPLE_FILE_TYPE("SD9 Audio File (*.SD9)", sd9); -DECLARE_MULTIPLE_FILE_TYPE("SDT Audio File (*.SDT)", sdt); -DECLARE_MULTIPLE_FILE_TYPE("SEG Audio File (*.SEG)", seg); -DECLARE_MULTIPLE_FILE_TYPE("SF0 Audio File (*.SF0)", sf0); -DECLARE_MULTIPLE_FILE_TYPE("SFL Audio File (*.SFL)", sfl); -DECLARE_MULTIPLE_FILE_TYPE("SFS Audio File (*.SFS)", sfs); -DECLARE_MULTIPLE_FILE_TYPE("SFX Audio File (*.SFX)", sfx); -DECLARE_MULTIPLE_FILE_TYPE("SGB Audio File (*.SGB)", sgb); -DECLARE_MULTIPLE_FILE_TYPE("SGD Audio File (*.SGD)", sgd); -DECLARE_MULTIPLE_FILE_TYPE("SGX Audio File (*.SGX)", sgx); -DECLARE_MULTIPLE_FILE_TYPE("SL3 Audio File (*.SL3)", sl3); -DECLARE_MULTIPLE_FILE_TYPE("SLI Audio File (*.SLI)", sli); -DECLARE_MULTIPLE_FILE_TYPE("SMP Audio File (*.SMP)", smp); -DECLARE_MULTIPLE_FILE_TYPE("SMPL Audio File (*.SMPL)", smpl); -DECLARE_MULTIPLE_FILE_TYPE("SND Audio File (*.SND)", snd); -DECLARE_MULTIPLE_FILE_TYPE("SNDS Audio File (*.SNDS)", snds); -DECLARE_MULTIPLE_FILE_TYPE("SNG Audio File (*.SNG)", sng); -DECLARE_MULTIPLE_FILE_TYPE("SNS Audio File (*.SNS)", sns); -DECLARE_MULTIPLE_FILE_TYPE("SPD Audio File (*.SPD)", spd); -DECLARE_MULTIPLE_FILE_TYPE("SPM Audio File (*.SPM)", spm); -DECLARE_MULTIPLE_FILE_TYPE("SPS Audio File (*.SPS)", sps); -DECLARE_MULTIPLE_FILE_TYPE("SPSD Audio File (*.SPSD)", spsd); -DECLARE_MULTIPLE_FILE_TYPE("SPW Audio File (*.SPW)", spw); -DECLARE_MULTIPLE_FILE_TYPE("SS2 Audio File (*.SS2)", ss2); -DECLARE_MULTIPLE_FILE_TYPE("SS3 Audio File (*.SS3)", ss3); -DECLARE_MULTIPLE_FILE_TYPE("SS7 Audio File (*.SS7)", ss7); -DECLARE_MULTIPLE_FILE_TYPE("SSM Audio File (*.SSM)", ssm); -DECLARE_MULTIPLE_FILE_TYPE("SSS Audio File (*.SSS)", sss); -DECLARE_MULTIPLE_FILE_TYPE("STER Audio File (*.STER)", ster); -DECLARE_MULTIPLE_FILE_TYPE("STH Audio File (*.STH)", sth); -//"stm", //common -DECLARE_MULTIPLE_FILE_TYPE("STMA Audio File (*.STMA)", stma); -DECLARE_MULTIPLE_FILE_TYPE("STR Audio File (*.STR)", str); -DECLARE_MULTIPLE_FILE_TYPE("STRM Audio File (*.STRM)", strm); -DECLARE_MULTIPLE_FILE_TYPE("STS Audio File (*.STS)", sts); -DECLARE_MULTIPLE_FILE_TYPE("STX Audio File (*.STX)", stx); -DECLARE_MULTIPLE_FILE_TYPE("SVAG Audio File (*.SVAG)", svag); -DECLARE_MULTIPLE_FILE_TYPE("SVS Audio File (*.SVS)", svs); -DECLARE_MULTIPLE_FILE_TYPE("SWAG Audio File (*.SWAG)", swag); -DECLARE_MULTIPLE_FILE_TYPE("SWAV Audio File (*.SWAV)", swav); -DECLARE_MULTIPLE_FILE_TYPE("SWD Audio File (*.SWD)", swd); -DECLARE_MULTIPLE_FILE_TYPE("SXD Audio File (*.SXD)", sxd); -DECLARE_MULTIPLE_FILE_TYPE("SXD2 Audio File (*.SXD2)", sxd2); - -DECLARE_MULTIPLE_FILE_TYPE("TEC Audio File (*.TEC)", tec); -DECLARE_MULTIPLE_FILE_TYPE("THP Audio File (*.THP)", thp); -DECLARE_MULTIPLE_FILE_TYPE("TK1 Audio File (*.TK1)", tk1); -DECLARE_MULTIPLE_FILE_TYPE("TK5 Audio File (*.TK5)", tk5); -DECLARE_MULTIPLE_FILE_TYPE("TRA Audio File (*.TRA)", tra); -DECLARE_MULTIPLE_FILE_TYPE("TUN Audio File (*.TUN)", tun); -DECLARE_MULTIPLE_FILE_TYPE("TYDSP Audio File (*.TYDSP)", tydsp); - -DECLARE_MULTIPLE_FILE_TYPE("UM3 Audio File (*.UM3)", um3); - -DECLARE_MULTIPLE_FILE_TYPE("VAG Audio File (*.VAG)", vag); -DECLARE_MULTIPLE_FILE_TYPE("VAS Audio File (*.VAS)", vas); -DECLARE_MULTIPLE_FILE_TYPE("VAS Audio File (*.VAS)", vawx); -DECLARE_MULTIPLE_FILE_TYPE("VB Audio File (*.VB)", vb); -DECLARE_MULTIPLE_FILE_TYPE("VBK Audio File (*.VBK)", vbk); -DECLARE_MULTIPLE_FILE_TYPE("VGS Audio File (*.VGS)", vgs); -DECLARE_MULTIPLE_FILE_TYPE("VGV Audio File (*.VGV)", vgv); -DECLARE_MULTIPLE_FILE_TYPE("VIG Audio File (*.VIG)", vig); -DECLARE_MULTIPLE_FILE_TYPE("VMS Audio File (*.VMS)", vms); -DECLARE_MULTIPLE_FILE_TYPE("VOI Audio File (*.VOI)", voi); -DECLARE_MULTIPLE_FILE_TYPE("VPK Audio File (*.VPK)", vpk); -DECLARE_MULTIPLE_FILE_TYPE("VS Audio File (*.VS)", vs); -DECLARE_MULTIPLE_FILE_TYPE("VSF Audio File (*.VSF)", vsf); - -DECLARE_MULTIPLE_FILE_TYPE("WAA Audio File (*.WAA)", waa); -DECLARE_MULTIPLE_FILE_TYPE("WAC Audio File (*.WAC)", wac); -DECLARE_MULTIPLE_FILE_TYPE("WAD Audio File (*.WAD)", wad); -DECLARE_MULTIPLE_FILE_TYPE("WAM Audio File (*.WAM)", wam); -DECLARE_MULTIPLE_FILE_TYPE("WAS Audio File (*.WAS)", was); -//"wav", //common -DECLARE_MULTIPLE_FILE_TYPE("WAVM Audio File (*.WAVM)", wavm); -DECLARE_MULTIPLE_FILE_TYPE("WEM Audio File (*.WEM)", wem); -DECLARE_MULTIPLE_FILE_TYPE("WII Audio File (*.WII)", wii); -DECLARE_MULTIPLE_FILE_TYPE("WMUS Audio File (*.WMUS)", wmus); -DECLARE_MULTIPLE_FILE_TYPE("WP2 Audio File (*.WP2)", wp2); -DECLARE_MULTIPLE_FILE_TYPE("WPD Audio File (*.WPD)", wpd); -DECLARE_MULTIPLE_FILE_TYPE("WSD Audio File (*.WSD)", wsd); -DECLARE_MULTIPLE_FILE_TYPE("WSI Audio File (*.WSI)", wsi); -DECLARE_MULTIPLE_FILE_TYPE("WVS Audio File (*.WVS)", wvs); - -DECLARE_MULTIPLE_FILE_TYPE("XA File (*.XA)", xa); -DECLARE_MULTIPLE_FILE_TYPE("XA2 Audio File (*.XA2)", xa2); -DECLARE_MULTIPLE_FILE_TYPE("XA30 Audio File (*.XA30)", xa30); -DECLARE_MULTIPLE_FILE_TYPE("XAG Audio File (*.XAG)", xag); -DECLARE_MULTIPLE_FILE_TYPE("XAU Audio File (*.XAU)", xau); -DECLARE_MULTIPLE_FILE_TYPE("XMA Audio File (*.XMA)", xma); -DECLARE_MULTIPLE_FILE_TYPE("XMA2 Audio File (*.XMA2)", xma2); -DECLARE_MULTIPLE_FILE_TYPE("XMU Audio File (*.XMU)", xmu); -DECLARE_MULTIPLE_FILE_TYPE("XNB Audio File (*.XNB)", xnb); -DECLARE_MULTIPLE_FILE_TYPE("XSF Audio File (*.XSF)", xsf); -DECLARE_MULTIPLE_FILE_TYPE("XSS Audio File (*.XSS)", xss); -DECLARE_MULTIPLE_FILE_TYPE("XVAG Audio File (*.XVAG)", xvag); -DECLARE_MULTIPLE_FILE_TYPE("XVAS Audio File (*.XVAS)", xvas); -DECLARE_MULTIPLE_FILE_TYPE("XWAV Audio File (*.XWAV)", xwav); -DECLARE_MULTIPLE_FILE_TYPE("XWB Audio File (*.XWB)", xwb); -DECLARE_MULTIPLE_FILE_TYPE("XWM Audio File (*.XWM)", xwm); -DECLARE_MULTIPLE_FILE_TYPE("XWMA Audio File (*.XWMA)", xwma); -DECLARE_MULTIPLE_FILE_TYPE("XWS Audio File (*.XWS)", xws); -DECLARE_MULTIPLE_FILE_TYPE("XWV Audio File (*.XWV)", xwv); - -DECLARE_MULTIPLE_FILE_TYPE("YDSP Audio File (*.YDSP)", ydsp); -DECLARE_MULTIPLE_FILE_TYPE("YMF Audio File (*.YMF)", ymf); - -DECLARE_MULTIPLE_FILE_TYPE("ZSD Audio File (*.ZSD)", zsd); -DECLARE_MULTIPLE_FILE_TYPE("ZWDSP Audio File (*.ZWDSP)", zwdsp); - -DECLARE_MULTIPLE_FILE_TYPE("VGMSTREAM Audio File (*.VGMSTREAM)", vgmstream); +#include "foo_filetypes.h" diff --git a/fb2k/foo_vgmstream.h b/fb2k/foo_vgmstream.h index a99498d7..c2112715 100644 --- a/fb2k/foo_vgmstream.h +++ b/fb2k/foo_vgmstream.h @@ -75,10 +75,4 @@ STREAMFILE * open_foo_streamfile_buffer_by_file(service_ptr_t m_file,const STREAMFILE * open_foo_streamfile_buffer(const char * const filename, size_t buffersize, abort_callback * p_abort, t_filestats * stats); STREAMFILE * open_foo_streamfile(const char * const filename, abort_callback * p_abort, t_filestats * stats); - -#define DECLARE_MULTIPLE_FILE_TYPE(NAME,EXTENSION) \ - namespace { static input_file_type_impl g_filetype_instance_##EXTENSION(NAME,"*." #EXTENSION ,true); \ - static service_factory_single_ref_t g_filetype_service##EXTENSION(g_filetype_instance_##EXTENSION); } - - -#endif +#endif /*_FOO_VGMSTREAM_*/ From 4263533ba987a9b7cf6303f048594f3a1897d602 Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 19 May 2017 17:21:22 +0200 Subject: [PATCH 12/17] Move FFmpeg code from ffmpeg.c to ffmpeg_decoder.c for consistency --- src/coding/coding.h | 4 + src/coding/ffmpeg_decoder.c | 486 ++++++++++++++++++++++++++++++++++-- src/meta/akb.c | 2 +- src/meta/ffmpeg.c | 466 +--------------------------------- src/meta/meta.h | 9 +- src/meta/mp4.c | 3 +- src/meta/sgxd.c | 2 +- 7 files changed, 476 insertions(+), 496 deletions(-) diff --git a/src/coding/coding.h b/src/coding/coding.h index 9cbc24db..da20e0ec 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -204,9 +204,13 @@ void free_at3plus(maiatrac3plus_codec_data *data); #ifdef VGM_USE_FFMPEG /* ffmpeg_decoder */ +ffmpeg_codec_data * init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size); +ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size); + void decode_ffmpeg(VGMSTREAM *stream, sample * outbuf, int32_t samples_to_do, int channels); void reset_ffmpeg(VGMSTREAM *vgmstream); void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample); +void free_ffmpeg(ffmpeg_codec_data *data); void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples); #endif diff --git a/src/coding/ffmpeg_decoder.c b/src/coding/ffmpeg_decoder.c index d6d6376d..0947c5db 100644 --- a/src/coding/ffmpeg_decoder.c +++ b/src/coding/ffmpeg_decoder.c @@ -1,7 +1,34 @@ -#include "../vgmstream.h" +#include "coding.h" #ifdef VGM_USE_FFMPEG +/* internal sizes, can be any value */ +#define FFMPEG_DEFAULT_BUFFER_SIZE 2048 +#define FFMPEG_DEFAULT_IO_BUFFER_SIZE 128 * 1024 + + +static volatile int g_ffmpeg_initialized = 0; + + +/* ******************************************** */ +/* INTERNAL UTILS */ +/* ******************************************** */ + +/* Global FFmpeg init */ +static void g_init_ffmpeg() { + if (g_ffmpeg_initialized == 1) { + while (g_ffmpeg_initialized < 2); /* active wait for lack of a better way */ + } + else if (g_ffmpeg_initialized == 0) { + g_ffmpeg_initialized = 1; + av_log_set_flags(AV_LOG_SKIP_REPEATED); + av_log_set_level(AV_LOG_ERROR); + av_register_all(); + g_ffmpeg_initialized = 2; + } +} + +/* converts codec's samples (can be in any format, ex. Ogg's float32) to PCM16 */ static void convert_audio(sample *outbuf, const uint8_t *inbuf, int sampleCount, int bitsPerSample, int floatingPoint) { int s; switch (bitsPerSample) { @@ -59,15 +86,390 @@ static void convert_audio(sample *outbuf, const uint8_t *inbuf, int sampleCount, } } +/** + * Special patching for FFmpeg's buggy seek code. + * + * To seek with avformat_seek_file/av_seek_frame, FFmpeg's demuxers can implement read_seek2 (newest API) + * or read_seek (older API), with various search modes. If none are available it will use seek_frame_generic, + * which manually reads frame by frame until the selected timestamp. However, the prev frame will be consumed + * (so after seeking to 0 next av_read_frame will actually give the second frame and so on). + * + * Fortunately seek_frame_generic can use an index to find the correct position. This function reads the + * first frame/packet and sets up index to timestamp 0. This ensures faulty demuxers will seek to 0 correctly. + * Some formats may not seek to 0 even with this, though. + */ +static int init_seek(ffmpeg_codec_data * data) { + int ret, ts_index, found_first = 0; + int64_t ts = 0; + int64_t pos = 0; /* offset */ + int size = 0; /* coded size */ + int distance = 0; /* always? */ + + AVStream * stream; + AVPacket * pkt; + + stream = data->formatCtx->streams[data->streamIndex]; + pkt = data->lastReadPacket; + + /* read_seek shouldn't need this index, but direct access to FFmpeg's internals is no good */ + /* if (data->formatCtx->iformat->read_seek || data->formatCtx->iformat->read_seek2) + return 0; */ + + /* some formats already have a proper index (e.g. M4A) */ + ts_index = av_index_search_timestamp(stream, ts, AVSEEK_FLAG_ANY); + if (ts_index>=0) + goto test_seek; + + + /* find the first + second packets to get pos/size */ + while (1) { + av_packet_unref(pkt); + ret = av_read_frame(data->formatCtx, pkt); + if (ret < 0) + break; + if (pkt->stream_index != data->streamIndex) + continue; /* ignore non-selected streams */ + + if (!found_first) { /* first found */ + found_first = 1; + pos = pkt->pos; + ts = pkt->dts; + continue; + } else { /* second found */ + size = pkt->pos - pos; /* coded, pkt->size is decoded size */ + break; + } + } + if (!found_first) + goto fail; + + /* in rare cases there is only one packet */ + /* if (size == 0) { size = data_end - pos; } */ /* no easy way to know, ignore (most formats don's need size) */ + + /* some formats (XMA1) don't seem to have packet.dts, pretend it's 0 */ + if (ts == INT64_MIN) + ts = 0; + + /* Some streams start with negative DTS (observed in Ogg). For Ogg seeking to negative or 0 doesn't alter the output. + * It does seem seeking before decoding alters a bunch of (inaudible) +-1 lower bytes though. */ + VGM_ASSERT(ts != 0, "FFMPEG: negative start_ts (%li)\n", (long)ts); + if (ts != 0) + ts = 0; + + /* add index 0 */ + ret = av_add_index_entry(stream, pos, ts, size, distance, AVINDEX_KEYFRAME); + if ( ret < 0 ) + return ret; + + +test_seek: + /* seek to 0 test / move back to beginning, since we just consumed packets */ + ret = avformat_seek_file(data->formatCtx, data->streamIndex, ts, ts, ts, AVSEEK_FLAG_ANY); + if ( ret < 0 ) + return ret; /* we can't even reset_vgmstream the file */ + + avcodec_flush_buffers(data->codecCtx); + + return 0; + +fail: + return -1; +} + + +/* ******************************************** */ +/* AVIO CALLBACKS */ +/* ******************************************** */ + +/* AVIO callback: read stream, skipping external headers if needed */ +static int ffmpeg_read(void *opaque, uint8_t *buf, int buf_size) { + ffmpeg_codec_data *data = (ffmpeg_codec_data *) opaque; + uint64_t offset = data->offset; + int max_to_copy = 0; + int ret; + + if (data->header_insert_block) { + if (offset < data->header_size) { + max_to_copy = (int)(data->header_size - offset); + if (max_to_copy > buf_size) { + max_to_copy = buf_size; + } + memcpy(buf, data->header_insert_block + offset, max_to_copy); + buf += max_to_copy; + buf_size -= max_to_copy; + offset += max_to_copy; + if (!buf_size) { + data->offset = offset; + return max_to_copy; + } + } + offset -= data->header_size; + } + + /* when "fake" size is smaller than "real" size we need to make sure bytes_read (ret) is clamped; + * it confuses FFmpeg in rare cases (STREAMFILE may have valid data after size) */ + if (offset + buf_size > data->size + data->header_size) { + buf_size = data->size - offset; /* header "read" is manually inserted later */ + } + + ret = read_streamfile(buf, offset + data->start, buf_size, data->streamfile); + if (ret > 0) { + offset += ret; + if (data->header_insert_block) { + ret += max_to_copy; + } + } + + if (data->header_insert_block) { + offset += data->header_size; + } + + data->offset = offset; + return ret; +} + +/* AVIO callback: write stream not needed */ +static int ffmpeg_write(void *opaque, uint8_t *buf, int buf_size) { + return -1; +} + +/* AVIO callback: seek stream, skipping external headers if needed */ +static int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) { + ffmpeg_codec_data *data = (ffmpeg_codec_data *) opaque; + int ret = 0; + + if (whence & AVSEEK_SIZE) { + return data->size + data->header_size; + } + whence &= ~(AVSEEK_SIZE | AVSEEK_FORCE); + /* false offsets, on reads data->start will be added */ + switch (whence) { + case SEEK_SET: + break; + + case SEEK_CUR: + offset += data->offset; + break; + + case SEEK_END: + offset += data->size; + if (data->header_insert_block) + offset += data->header_size; + break; + } + + /* clamp offset; fseek returns 0 when offset > size, too */ + if (offset > data->size + data->header_size) { + offset = data->size + data->header_size; + } + + data->offset = offset; + return ret; +} + + +/* ******************************************** */ +/* MAIN INIT/DECODER */ +/* ******************************************** */ + +/** + * Manually init FFmpeg, from an offset. + * Used if the stream has internal data recognized by FFmpeg. + */ +ffmpeg_codec_data * init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size) { + return init_ffmpeg_header_offset(streamFile, NULL, 0, start, size); +} + +/** + * Manually init FFmpeg, from a fake header / offset. + * + * Takes a fake header, to trick FFmpeg into demuxing/decoding the stream. + * This header will be seamlessly inserted before 'start' offset, and total filesize will be 'header_size' + 'size'. + * The header buffer will be copied and memory-managed internally. + */ +ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size) { + char filename[PATH_LIMIT]; + ffmpeg_codec_data * data; + int errcode, i; + + int streamIndex, streamCount; + AVStream *stream; + AVCodecParameters *codecPar; + + AVRational tb; + + + /* basic setup */ + g_init_ffmpeg(); + + data = ( ffmpeg_codec_data * ) calloc(1, sizeof(ffmpeg_codec_data)); + if (!data) return NULL; + + streamFile->get_name( streamFile, filename, sizeof(filename) ); + + data->streamfile = streamFile->open(streamFile, filename, STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!data->streamfile) goto fail; + + data->start = start; + data->size = size; + + + /* insert fake header to trick FFmpeg into demuxing/decoding the stream */ + if (header_size > 0) { + data->header_size = header_size; + data->header_insert_block = av_memdup(header, header_size); + if (!data->header_insert_block) goto fail; + } + + /* setup IO, attempt to autodetect format and gather some info */ + data->buffer = av_malloc(FFMPEG_DEFAULT_IO_BUFFER_SIZE); + if (!data->buffer) goto fail; + + data->ioCtx = avio_alloc_context(data->buffer, FFMPEG_DEFAULT_IO_BUFFER_SIZE, 0, data, ffmpeg_read, ffmpeg_write, ffmpeg_seek); + if (!data->ioCtx) goto fail; + + data->formatCtx = avformat_alloc_context(); + if (!data->formatCtx) goto fail; + + data->formatCtx->pb = data->ioCtx; + + if ((errcode = avformat_open_input(&data->formatCtx, "", NULL, NULL)) < 0) goto fail; /* autodetect */ + + if ((errcode = avformat_find_stream_info(data->formatCtx, NULL)) < 0) goto fail; + + + /* find valid audio stream inside */ + streamIndex = -1; + streamCount = 0; /* audio streams only */ + + for (i = 0; i < data->formatCtx->nb_streams; ++i) { + stream = data->formatCtx->streams[i]; + codecPar = stream->codecpar; + if (streamIndex < 0 && codecPar->codec_type == AVMEDIA_TYPE_AUDIO) { + streamIndex = i; /* select first audio stream found */ + } else { + stream->discard = AVDISCARD_ALL; /* disable demuxing unneded streams */ + } + if (codecPar->codec_type == AVMEDIA_TYPE_AUDIO) + streamCount++; + } + + if (streamIndex < 0) goto fail; + + data->streamIndex = streamIndex; + stream = data->formatCtx->streams[streamIndex]; + data->streamCount = streamCount; + + + /* prepare codec and frame/packet buffers */ + data->codecCtx = avcodec_alloc_context3(NULL); + if (!data->codecCtx) goto fail; + + if ((errcode = avcodec_parameters_to_context(data->codecCtx, codecPar)) < 0) goto fail; + + av_codec_set_pkt_timebase(data->codecCtx, stream->time_base); + + data->codec = avcodec_find_decoder(data->codecCtx->codec_id); + if (!data->codec) goto fail; + + if ((errcode = avcodec_open2(data->codecCtx, data->codec, NULL)) < 0) goto fail; + + data->lastDecodedFrame = av_frame_alloc(); + if (!data->lastDecodedFrame) goto fail; + av_frame_unref(data->lastDecodedFrame); + + data->lastReadPacket = malloc(sizeof(AVPacket)); + if (!data->lastReadPacket) goto fail; + av_new_packet(data->lastReadPacket, 0); + + data->readNextPacket = 1; + data->bytesConsumedFromDecodedFrame = INT_MAX; + + + /* other setup */ + data->sampleRate = data->codecCtx->sample_rate; + data->channels = data->codecCtx->channels; + data->floatingPoint = 0; + + switch (data->codecCtx->sample_fmt) { + case AV_SAMPLE_FMT_U8: + case AV_SAMPLE_FMT_U8P: + data->bitsPerSample = 8; + break; + + case AV_SAMPLE_FMT_S16: + case AV_SAMPLE_FMT_S16P: + data->bitsPerSample = 16; + break; + + case AV_SAMPLE_FMT_S32: + case AV_SAMPLE_FMT_S32P: + data->bitsPerSample = 32; + break; + + case AV_SAMPLE_FMT_FLT: + case AV_SAMPLE_FMT_FLTP: + data->bitsPerSample = 32; + data->floatingPoint = 1; + break; + + case AV_SAMPLE_FMT_DBL: + case AV_SAMPLE_FMT_DBLP: + data->bitsPerSample = 64; + data->floatingPoint = 1; + break; + + default: + goto fail; + } + + data->bitrate = (int)(data->codecCtx->bit_rate); + data->endOfStream = 0; + data->endOfAudio = 0; + + /* try to guess frames/samples (duration isn't always set) */ + tb.num = 1; tb.den = data->codecCtx->sample_rate; + data->totalSamples = av_rescale_q(stream->duration, stream->time_base, tb); + if (data->totalSamples < 0) + data->totalSamples = 0; /* caller must consider this */ + + data->blockAlign = data->codecCtx->block_align; + data->frameSize = data->codecCtx->frame_size; + if(data->frameSize == 0) /* some formats don't set frame_size but can get on request, and vice versa */ + data->frameSize = av_get_audio_frame_duration(data->codecCtx,0); + + /* setup decode buffer */ + data->sampleBufferBlock = FFMPEG_DEFAULT_BUFFER_SIZE; + data->sampleBuffer = av_malloc( data->sampleBufferBlock * (data->bitsPerSample / 8) * data->channels ); + if (!data->sampleBuffer) + goto fail; + + + /* setup decent seeking for faulty formats */ + errcode = init_seek(data); + if (errcode < 0) goto fail; + + /* expose start samples to be skipped (encoder delay, usually added by MDCT-based encoders like AAC/MP3/ATRAC3/XMA/etc) + * get after init_seek because some demuxers like AAC only fill skip_samples for the first packet */ + if (stream->start_skip_samples) /* samples to skip in the first packet */ + data->skipSamples = stream->start_skip_samples; + else if (stream->skip_samples) /* samples to skip in any packet (first in this case), used sometimes instead (ex. AAC) */ + data->skipSamples = stream->skip_samples; + + return data; + +fail: + free_ffmpeg(data); + + return NULL; +} + +/* decode samples of any kind of FFmpeg format */ void decode_ffmpeg(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, int channels) { ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data; - int bytesPerSample; - int bytesPerFrame; - int frameSize; - - int bytesToRead; - int bytesRead; + int bytesPerSample, bytesPerFrame, frameSize; + int bytesToRead, bytesRead; uint8_t *targetBuf; @@ -78,10 +480,7 @@ void decode_ffmpeg(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, int bytesConsumedFromDecodedFrame; - int readNextPacket; - int endOfStream; - int endOfAudio; - + int readNextPacket, endOfStream, endOfAudio; int framesReadNow; @@ -114,12 +513,7 @@ void decode_ffmpeg(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, /* keep reading and decoding packets until the requested number of samples (in bytes) */ while (bytesRead < bytesToRead) { - int planeSize; - int planar; - int dataSize; - int toConsume; - int errcode; - + int planeSize, planar, dataSize, toConsume, errcode; /* size of previous frame */ dataSize = av_samples_get_buffer_size(&planeSize, codecCtx->channels, lastDecodedFrame->nb_samples, codecCtx->sample_fmt, 1); @@ -231,10 +625,10 @@ void decode_ffmpeg(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, end: framesReadNow = bytesRead / frameSize; - // Convert the audio + /* Convert the audio */ convert_audio(outbuf, data->sampleBuffer, framesReadNow * channels, data->bitsPerSample, data->floatingPoint); - // Output the state back to the structure + /* Output the state back to the structure */ data->bytesConsumedFromDecodedFrame = bytesConsumedFromDecodedFrame; data->readNextPacket = readNextPacket; data->endOfStream = endOfStream; @@ -242,6 +636,10 @@ end: } +/* ******************************************** */ +/* UTILS */ +/* ******************************************** */ + void reset_ffmpeg(VGMSTREAM *vgmstream) { ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data; @@ -268,7 +666,6 @@ void reset_ffmpeg(VGMSTREAM *vgmstream) { } } - void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample) { ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data; int64_t ts; @@ -297,6 +694,55 @@ void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample) { } } +void free_ffmpeg(ffmpeg_codec_data *data) { + if (data == NULL) + return; + + if (data->lastReadPacket) { + av_packet_unref(data->lastReadPacket); + free(data->lastReadPacket); + data->lastReadPacket = NULL; + } + if (data->lastDecodedFrame) { + av_free(data->lastDecodedFrame); + data->lastDecodedFrame = NULL; + } + if (data->codecCtx) { + avcodec_close(data->codecCtx); + avcodec_free_context(&(data->codecCtx)); + data->codecCtx = NULL; + } + if (data->formatCtx) { + avformat_close_input(&(data->formatCtx)); + data->formatCtx = NULL; + } + if (data->ioCtx) { + // buffer passed in is occasionally freed and replaced. + // the replacement must be freed as well. + data->buffer = data->ioCtx->buffer; + av_free(data->ioCtx); + data->ioCtx = NULL; + } + if (data->buffer) { + av_free(data->buffer); + data->buffer = NULL; + } + if (data->sampleBuffer) { + av_free(data->sampleBuffer); + data->sampleBuffer = NULL; + } + if (data->header_insert_block) { + av_free(data->header_insert_block); + data->header_insert_block = NULL; + } + if (data->streamfile) { + close_streamfile(data->streamfile); + data->streamfile = NULL; + } + free(data); +} + + /** * Sets the number of samples to skip at the beginning of the stream, needed by some "gapless" formats. * (encoder delay, usually added by MDCT-based encoders like AAC/MP3/ATRAC3/XMA/etc to "set up" the decoder). diff --git a/src/meta/akb.c b/src/meta/akb.c index 7c34461c..8a22de08 100644 --- a/src/meta/akb.c +++ b/src/meta/akb.c @@ -1,5 +1,5 @@ -#include "../vgmstream.h" #include "meta.h" +#include "../coding/coding.h" #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) /* AKB (AAC only) - found in SQEX iOS games */ diff --git a/src/meta/ffmpeg.c b/src/meta/ffmpeg.c index 022f8a9e..87c8662e 100644 --- a/src/meta/ffmpeg.c +++ b/src/meta/ffmpeg.c @@ -1,41 +1,11 @@ -#include "../vgmstream.h" #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" #ifdef VGM_USE_FFMPEG -/* internal sizes, can be any value */ -#define FFMPEG_DEFAULT_BUFFER_SIZE 2048 -#define FFMPEG_DEFAULT_IO_BUFFER_SIZE 128 * 1024 - -static int init_seek(ffmpeg_codec_data * data); - - -static volatile int g_ffmpeg_initialized = 0; - -/* - * Global FFmpeg init - */ -static void g_init_ffmpeg() -{ - if (g_ffmpeg_initialized == 1) - { - while (g_ffmpeg_initialized < 2); - } - else if (g_ffmpeg_initialized == 0) - { - g_ffmpeg_initialized = 1; - av_log_set_flags(AV_LOG_SKIP_REPEATED); - av_log_set_level(AV_LOG_ERROR); - av_register_all(); - g_ffmpeg_initialized = 2; - } -} - - /** * Generic init FFmpeg and vgmstream for any file supported by FFmpeg. - * Always called by vgmstream when trying to identify the file type (if the player allows it). + * Called by vgmstream when trying to identify the file type (if the player allows it). */ VGMSTREAM * init_vgmstream_ffmpeg(STREAMFILE *streamFile) { return init_vgmstream_ffmpeg_offset( streamFile, 0, streamFile->get_size(streamFile) ); @@ -105,436 +75,4 @@ fail: return NULL; } - -/** - * AVIO callback: read stream, skipping external headers if needed - */ -static int ffmpeg_read(void *opaque, uint8_t *buf, int buf_size) -{ - ffmpeg_codec_data *data = (ffmpeg_codec_data *) opaque; - uint64_t offset = data->offset; - int max_to_copy = 0; - int ret; - - if (data->header_insert_block) { - if (offset < data->header_size) { - max_to_copy = (int)(data->header_size - offset); - if (max_to_copy > buf_size) { - max_to_copy = buf_size; - } - memcpy(buf, data->header_insert_block + offset, max_to_copy); - buf += max_to_copy; - buf_size -= max_to_copy; - offset += max_to_copy; - if (!buf_size) { - data->offset = offset; - return max_to_copy; - } - } - offset -= data->header_size; - } - - /* when "fake" size is smaller than "real" size we need to make sure bytes_read (ret) is clamped; - * it confuses FFmpeg in rare cases (STREAMFILE may have valid data after size) */ - if (offset + buf_size > data->size + data->header_size) { - buf_size = data->size - offset; /* header "read" is manually inserted later */ - } - - ret = read_streamfile(buf, offset + data->start, buf_size, data->streamfile); - if (ret > 0) { - offset += ret; - if (data->header_insert_block) { - ret += max_to_copy; - } - } - - if (data->header_insert_block) { - offset += data->header_size; - } - - data->offset = offset; - return ret; -} - -/** - * AVIO callback: write stream not needed - */ -static int ffmpeg_write(void *opaque, uint8_t *buf, int buf_size) -{ - return -1; -} - -/** - * AVIO callback: seek stream, skipping external headers if needed - */ -static int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) -{ - ffmpeg_codec_data *data = (ffmpeg_codec_data *) opaque; - int ret = 0; - - if (whence & AVSEEK_SIZE) { - return data->size + data->header_size; - } - whence &= ~(AVSEEK_SIZE | AVSEEK_FORCE); - /* false offsets, on reads data->start will be added */ - switch (whence) { - case SEEK_SET: - break; - - case SEEK_CUR: - offset += data->offset; - break; - - case SEEK_END: - offset += data->size; - if (data->header_insert_block) - offset += data->header_size; - break; - } - - /* clamp offset; fseek returns 0 when offset > size, too */ - if (offset > data->size + data->header_size) { - offset = data->size + data->header_size; - } - - data->offset = offset; - return ret; -} - - -/** - * Manually init FFmpeg, from an offset. - * Can be used if the stream has an extra header over data recognized by FFmpeg. - */ -ffmpeg_codec_data * init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size) { - return init_ffmpeg_header_offset(streamFile, NULL, 0, start, size); -} - - -/** - * Manually init FFmpeg, from a fake header / offset. - * - * Can take a fake header, to trick FFmpeg into demuxing/decoding the stream. - * This header will be seamlessly inserted before 'start' offset, and total filesize will be 'header_size' + 'size'. - * The header buffer will be copied and memory-managed internally. - */ -ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size) { - char filename[PATH_LIMIT]; - - ffmpeg_codec_data * data; - - int errcode, i; - - int streamIndex, streamCount; - AVStream *stream; - AVCodecParameters *codecPar; - - AVRational tb; - - - /* basic setup */ - g_init_ffmpeg(); - - data = ( ffmpeg_codec_data * ) calloc(1, sizeof(ffmpeg_codec_data)); - if (!data) return NULL; - - streamFile->get_name( streamFile, filename, sizeof(filename) ); - - data->streamfile = streamFile->open(streamFile, filename, STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!data->streamfile) goto fail; - - data->start = start; - data->size = size; - - - /* insert fake header to trick FFmpeg into demuxing/decoding the stream */ - if (header_size > 0) { - data->header_size = header_size; - data->header_insert_block = av_memdup(header, header_size); - if (!data->header_insert_block) goto fail; - } - - /* setup IO, attempt to autodetect format and gather some info */ - data->buffer = av_malloc(FFMPEG_DEFAULT_IO_BUFFER_SIZE); - if (!data->buffer) goto fail; - - data->ioCtx = avio_alloc_context(data->buffer, FFMPEG_DEFAULT_IO_BUFFER_SIZE, 0, data, ffmpeg_read, ffmpeg_write, ffmpeg_seek); - if (!data->ioCtx) goto fail; - - data->formatCtx = avformat_alloc_context(); - if (!data->formatCtx) goto fail; - - data->formatCtx->pb = data->ioCtx; - - if ((errcode = avformat_open_input(&data->formatCtx, "", NULL, NULL)) < 0) goto fail; /* autodetect */ - - if ((errcode = avformat_find_stream_info(data->formatCtx, NULL)) < 0) goto fail; - - - /* find valid audio stream inside */ - streamIndex = -1; - streamCount = 0; /* audio streams only */ - - for (i = 0; i < data->formatCtx->nb_streams; ++i) { - stream = data->formatCtx->streams[i]; - codecPar = stream->codecpar; - if (streamIndex < 0 && codecPar->codec_type == AVMEDIA_TYPE_AUDIO) { - streamIndex = i; /* select first audio stream found */ - } else { - stream->discard = AVDISCARD_ALL; /* disable demuxing unneded streams */ - } - if (codecPar->codec_type == AVMEDIA_TYPE_AUDIO) - streamCount++; - } - - if (streamIndex < 0) goto fail; - - data->streamIndex = streamIndex; - stream = data->formatCtx->streams[streamIndex]; - data->streamCount = streamCount; - - - /* prepare codec and frame/packet buffers */ - data->codecCtx = avcodec_alloc_context3(NULL); - if (!data->codecCtx) goto fail; - - if ((errcode = avcodec_parameters_to_context(data->codecCtx, codecPar)) < 0) goto fail; - - av_codec_set_pkt_timebase(data->codecCtx, stream->time_base); - - data->codec = avcodec_find_decoder(data->codecCtx->codec_id); - if (!data->codec) goto fail; - - if ((errcode = avcodec_open2(data->codecCtx, data->codec, NULL)) < 0) goto fail; - - data->lastDecodedFrame = av_frame_alloc(); - if (!data->lastDecodedFrame) goto fail; - av_frame_unref(data->lastDecodedFrame); - - data->lastReadPacket = malloc(sizeof(AVPacket)); - if (!data->lastReadPacket) goto fail; - av_new_packet(data->lastReadPacket, 0); - - data->readNextPacket = 1; - data->bytesConsumedFromDecodedFrame = INT_MAX; - - - /* other setup */ - data->sampleRate = data->codecCtx->sample_rate; - data->channels = data->codecCtx->channels; - data->floatingPoint = 0; - - switch (data->codecCtx->sample_fmt) { - case AV_SAMPLE_FMT_U8: - case AV_SAMPLE_FMT_U8P: - data->bitsPerSample = 8; - break; - - case AV_SAMPLE_FMT_S16: - case AV_SAMPLE_FMT_S16P: - data->bitsPerSample = 16; - break; - - case AV_SAMPLE_FMT_S32: - case AV_SAMPLE_FMT_S32P: - data->bitsPerSample = 32; - break; - - case AV_SAMPLE_FMT_FLT: - case AV_SAMPLE_FMT_FLTP: - data->bitsPerSample = 32; - data->floatingPoint = 1; - break; - - case AV_SAMPLE_FMT_DBL: - case AV_SAMPLE_FMT_DBLP: - data->bitsPerSample = 64; - data->floatingPoint = 1; - break; - - default: - goto fail; - } - - data->bitrate = (int)(data->codecCtx->bit_rate); - data->endOfStream = 0; - data->endOfAudio = 0; - - /* try to guess frames/samples (duration isn't always set) */ - tb.num = 1; tb.den = data->codecCtx->sample_rate; - data->totalSamples = av_rescale_q(stream->duration, stream->time_base, tb); - if (data->totalSamples < 0) - data->totalSamples = 0; /* caller must consider this */ - - data->blockAlign = data->codecCtx->block_align; - data->frameSize = data->codecCtx->frame_size; - if(data->frameSize == 0) /* some formats don't set frame_size but can get on request, and vice versa */ - data->frameSize = av_get_audio_frame_duration(data->codecCtx,0); - - /* setup decode buffer */ - data->sampleBufferBlock = FFMPEG_DEFAULT_BUFFER_SIZE; - data->sampleBuffer = av_malloc( data->sampleBufferBlock * (data->bitsPerSample / 8) * data->channels ); - if (!data->sampleBuffer) - goto fail; - - - /* setup decent seeking for faulty formats */ - errcode = init_seek(data); - if (errcode < 0) goto fail; - - /* expose start samples to be skipped (encoder delay, usually added by MDCT-based encoders like AAC/MP3/ATRAC3/XMA/etc) - * get after init_seek because some demuxers like AAC only fill skip_samples for the first packet */ - if (stream->start_skip_samples) /* samples to skip in the first packet */ - data->skipSamples = stream->start_skip_samples; - else if (stream->skip_samples) /* samples to skip in any packet (first in this case), used sometimes instead (ex. AAC) */ - data->skipSamples = stream->skip_samples; - - return data; - -fail: - free_ffmpeg(data); - - return NULL; -} - - -/** - * Special patching for FFmpeg's buggy seek code. - * - * To seek with avformat_seek_file/av_seek_frame, FFmpeg's demuxers can implement read_seek2 (newest API) - * or read_seek (older API), with various search modes. If none are available it will use seek_frame_generic, - * which manually reads frame by frame until the selected timestamp. However, the prev frame will be consumed - * (so after seeking to 0 next av_read_frame will actually give the second frame and so on). - * - * Fortunately seek_frame_generic can use an index to find the correct position. This function reads the - * first frame/packet and sets up index to timestamp 0. This ensures faulty demuxers will seek to 0 correctly. - * Some formats may not seek to 0 even with this, though. - */ -static int init_seek(ffmpeg_codec_data * data) { - int ret, ts_index, found_first = 0; - int64_t ts = 0; - int64_t pos = 0; /* offset */ - int size = 0; /* coded size */ - int distance = 0; /* always? */ - - AVStream * stream; - AVPacket * pkt; - - stream = data->formatCtx->streams[data->streamIndex]; - pkt = data->lastReadPacket; - - /* read_seek shouldn't need this index, but direct access to FFmpeg's internals is no good */ - /* if (data->formatCtx->iformat->read_seek || data->formatCtx->iformat->read_seek2) - return 0; */ - - /* some formats already have a proper index (e.g. M4A) */ - ts_index = av_index_search_timestamp(stream, ts, AVSEEK_FLAG_ANY); - if (ts_index>=0) - goto test_seek; - - - /* find the first + second packets to get pos/size */ - while (1) { - av_packet_unref(pkt); - ret = av_read_frame(data->formatCtx, pkt); - if (ret < 0) - break; - if (pkt->stream_index != data->streamIndex) - continue; /* ignore non-selected streams */ - - if (!found_first) { /* first found */ - found_first = 1; - pos = pkt->pos; - ts = pkt->dts; - continue; - } else { /* second found */ - size = pkt->pos - pos; /* coded, pkt->size is decoded size */ - break; - } - } - if (!found_first) - goto fail; - - /* in rare cases there is only one packet */ - /* if (size == 0) { size = data_end - pos; } */ /* no easy way to know, ignore (most formats don's need size) */ - - /* some formats (XMA1) don't seem to have packet.dts, pretend it's 0 */ - if (ts == INT64_MIN) - ts = 0; - - /* Some streams start with negative DTS (observed in Ogg). For Ogg seeking to negative or 0 doesn't alter the output. - * It does seem seeking before decoding alters a bunch of (inaudible) +-1 lower bytes though. */ - VGM_ASSERT(ts != 0, "FFMPEG: negative start_ts (%li)\n", (long)ts); - if (ts != 0) - ts = 0; - - /* add index 0 */ - ret = av_add_index_entry(stream, pos, ts, size, distance, AVINDEX_KEYFRAME); - if ( ret < 0 ) - return ret; - - -test_seek: - /* seek to 0 test / move back to beginning, since we just consumed packets */ - ret = avformat_seek_file(data->formatCtx, data->streamIndex, ts, ts, ts, AVSEEK_FLAG_ANY); - if ( ret < 0 ) - return ret; /* we can't even reset_vgmstream the file */ - - avcodec_flush_buffers(data->codecCtx); - - return 0; - - -fail: - return -1; -} - - -void free_ffmpeg(ffmpeg_codec_data *data) { - if (data == NULL) - return; - - if (data->lastReadPacket) { - av_packet_unref(data->lastReadPacket); - free(data->lastReadPacket); - data->lastReadPacket = NULL; - } - if (data->lastDecodedFrame) { - av_free(data->lastDecodedFrame); - data->lastDecodedFrame = NULL; - } - if (data->codecCtx) { - avcodec_close(data->codecCtx); - avcodec_free_context(&(data->codecCtx)); - data->codecCtx = NULL; - } - if (data->formatCtx) { - avformat_close_input(&(data->formatCtx)); - data->formatCtx = NULL; - } - if (data->ioCtx) { - // buffer passed in is occasionally freed and replaced. - // the replacement must be freed as well. - data->buffer = data->ioCtx->buffer; - av_free(data->ioCtx); - data->ioCtx = NULL; - } - if (data->buffer) { - av_free(data->buffer); - data->buffer = NULL; - } - if (data->sampleBuffer) { - av_free(data->sampleBuffer); - data->sampleBuffer = NULL; - } - if (data->header_insert_block) { - av_free(data->header_insert_block); - data->header_insert_block = NULL; - } - if (data->streamfile) { - close_streamfile(data->streamfile); - data->streamfile = NULL; - } - free(data); -} #endif diff --git a/src/meta/meta.h b/src/meta/meta.h index d5a60fbf..1e259634 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -121,21 +121,14 @@ VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile); #ifdef VGM_USE_FFMPEG -ffmpeg_codec_data * init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size); -ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size); - -void free_ffmpeg(ffmpeg_codec_data *data); - -VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size); - VGMSTREAM * init_vgmstream_ffmpeg(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size); VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE * streamFile); #endif #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) VGMSTREAM * init_vgmstream_mp4_aac(STREAMFILE * streamFile); - VGMSTREAM * init_vgmstream_mp4_aac_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size); VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile); diff --git a/src/meta/mp4.c b/src/meta/mp4.c index 2bbf3ca2..ee8e56c7 100644 --- a/src/meta/mp4.c +++ b/src/meta/mp4.c @@ -1,6 +1,5 @@ -#include "../vgmstream.h" #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" #ifdef VGM_USE_MP4V2 void* mp4_file_open( const char* name, MP4FileMode mode ) diff --git a/src/meta/sgxd.c b/src/meta/sgxd.c index 5e5e0f3b..6c5f1a78 100644 --- a/src/meta/sgxd.c +++ b/src/meta/sgxd.c @@ -1,5 +1,5 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" /* utils to fix AT3 looping */ From 2f21b830747d6e2ffc6e740ef011355cb4d1a7fc Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 19 May 2017 17:44:15 +0200 Subject: [PATCH 13/17] Add number of streams/block size description tags --- fb2k/foo_vgmstream.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/fb2k/foo_vgmstream.cpp b/fb2k/foo_vgmstream.cpp index 3f4393fd..8137a31a 100644 --- a/fb2k/foo_vgmstream.cpp +++ b/fb2k/foo_vgmstream.cpp @@ -188,6 +188,26 @@ void input_vgmstream::get_info(file_info & p_info,abort_callback & p_abort ) { p_info.info_set("metadata source", temp); } + pos = description.find_first("number of streams: "); + if (pos != pfc::infinite_size) + { + pos += strlen("number of streams: "); + eos = description.find_first('\n', pos); + if (eos == pfc::infinite_size) eos = description.length(); + temp.set_string(description + pos, eos - pos); + p_info.info_set("number of streams", temp); + } + + pos = description.find_first("block size: "); + if (pos != pfc::infinite_size) + { + pos += strlen("block size: "); + eos = description.find_first('\n', pos); + if (eos == pfc::infinite_size) eos = description.length(); + temp.set_string(description + pos, eos - pos); + p_info.info_set("block size", temp); + } + p_info.set_length(((double)length_in_ms)/1000); } From 94b3854a87ff4f561a7a8214a4efa9d9c1b9a6b4 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 20 May 2017 01:26:57 +0200 Subject: [PATCH 14/17] Fixed some PS2 .AST [Naval Ops Warship Gunner (PS2)] --- src/meta/ps2_ast.c | 97 ++++++++++++++++------------------------------ 1 file changed, 34 insertions(+), 63 deletions(-) diff --git a/src/meta/ps2_ast.c b/src/meta/ps2_ast.c index 6acbb7cd..3c9ef56b 100644 --- a/src/meta/ps2_ast.c +++ b/src/meta/ps2_ast.c @@ -1,91 +1,62 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* AST */ +/* AST - from Koei and Marvelous games (same internal dev?) */ VGMSTREAM * init_vgmstream_ps2_ast(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; off_t start_offset; + int loop_flag, channel_count, variant_type; - int loop_flag = 0; - int channel_count; - int variant_type; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("ast",filename_extension(filename))) goto fail; + /* check extension */ + if (!check_extensions(streamFile,"ast")) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x41535400) /* "AST\0" */ goto fail; - /* determine variant */ - if (read_32bitBE(0x10,streamFile) == 0) - { - variant_type = 1; - } - else - { - variant_type = 2; - } - + /* determine variant (after 0x10 is garbage/code data in type 1 until 0x800, but consistent in all songs) */ + if (read_32bitBE(0x10,streamFile) == 0x00000000 || read_32bitBE(0x10,streamFile) == 0x20002000) { + variant_type = 1; /* Koei: P.T.O. IV (0x00000000), Naval Ops: Warship Gunner (0x20002000) */ + channel_count = 2; + } + else { + variant_type = 2; /* Marvelous: Katekyoo Hitman Reborn! Dream Hyper Battle!, Binchou-tan: Shiawasegoyomi */ + channel_count = read_32bitLE(0x0C,streamFile); + } loop_flag = 0; - channel_count = 2; - /* build the VGMSTREAM */ + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - if (variant_type == 1) - { - start_offset = 0x800; - channel_count = 2; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x04,streamFile); - vgmstream->num_samples = (read_32bitLE(0x0C,streamFile)-start_offset)*28/16/channel_count; - vgmstream->interleave_block_size = read_32bitLE(0x08,streamFile); - loop_flag = 0; - } - else if (variant_type == 2) - { - start_offset = 0x100; - channel_count = read_32bitLE(0x0C,streamFile); - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x08,streamFile); - vgmstream->num_samples = (read_32bitLE(0x04,streamFile)-start_offset)*28/16/channel_count; - vgmstream->interleave_block_size = read_32bitLE(0x10,streamFile); - } - else - { + /* fill in the vital statistics */ + if (variant_type == 1) { + start_offset = 0x800; + vgmstream->sample_rate = read_32bitLE(0x04,streamFile); + vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x0C,streamFile)-start_offset,channel_count); + vgmstream->interleave_block_size = read_32bitLE(0x08,streamFile); + } + else if (variant_type == 2) { + start_offset = 0x100; + vgmstream->sample_rate = read_32bitLE(0x08,streamFile); + vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x04,streamFile)-start_offset,channel_count); + vgmstream->interleave_block_size = read_32bitLE(0x10,streamFile); + } + else { goto fail; } vgmstream->layout_type = layout_interleave; - vgmstream->coding_type = coding_PSX; - vgmstream->meta_type = meta_PS2_AST; + vgmstream->coding_type = coding_PSX; + vgmstream->meta_type = meta_PS2_AST; - /* 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; - - } - } + 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; } From 6a922be61359aa279788b86b7470dce9a3dc95e0 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 20 May 2017 18:00:27 +0200 Subject: [PATCH 15/17] Fix encoder delay/skip samples in: SCD/SGXD/RIFF/MSF ATRAC3/p, SGXD AC3 --- src/meta/ps3_msf.c | 26 ++++++--- src/meta/riff.c | 19 +++++-- src/meta/sgxd.c | 133 +++++++++++++++----------------------------- src/meta/sqex_scd.c | 31 ++++++----- 4 files changed, 91 insertions(+), 118 deletions(-) diff --git a/src/meta/ps3_msf.c b/src/meta/ps3_msf.c index 226f07e7..18e52a37 100644 --- a/src/meta/ps3_msf.c +++ b/src/meta/ps3_msf.c @@ -34,7 +34,7 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) { /* byte flags, not in MSFv1 or v2 * 0x01/02/04/08: loop marker 0/1/2/3 - * 0x10: "resample" loop option (may be active with no 0x01 flag set) + * 0x10: resample options (force 44/48khz) * 0x20: VBR MP3 * 0x40: joint stereo MP3 (apparently interleaved stereo for other formats) * 0x80+: (none/reserved) */ @@ -104,17 +104,19 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) { case 0x6: { /* ATRAC3 high (132 kbps, frame size 192) */ ffmpeg_codec_data *ffmpeg_data = NULL; uint8_t buf[100]; - int32_t bytes, block_size, encoder_delay, joint_stereo, max_samples; + int32_t bytes, block_size, encoder_delay, joint_stereo; block_size = (codec_id==4 ? 0x60 : (codec_id==5 ? 0x98 : 0xC0)) * vgmstream->channels; - encoder_delay = 0x0; //todo MSF encoder delay (around 440-450*2) - max_samples = atrac3_bytes_to_samples(data_size, block_size); - joint_stereo = codec_id==4; /* interleaved joint stereo (ch must be even) */ + joint_stereo = (codec_id==4); /* interleaved joint stereo (ch must be even) */ + /* MSF skip samples: from tests with MSEnc and real files (ex. TTT2 eddy.msf v43, v01 demos) seems like 1162 is consistent. + * Atelier Rorona bt_normal01 needs it to properly skip the beginning garbage but usually doesn't matter. + * (note that encoder may add a fade-in with looping/resampling enabled but should be skipped) */ + encoder_delay = 1162; + vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_size) - encoder_delay; if (vgmstream->sample_rate==0xFFFFFFFF) /* some MSFv1 (Digi World SP) */ vgmstream->sample_rate = 44100;//voice tracks seems to use 44khz, not sure about other tracks - /* make a fake riff so FFmpeg can parse the ATRAC3 */ bytes = ffmpeg_make_riff_atrac3(buf, 100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay); if (bytes <= 0) goto fail; @@ -124,10 +126,16 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) { vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; - vgmstream->num_samples = max_samples; + + /* manually set skip_samples if FFmpeg didn't do it */ + if (ffmpeg_data->skipSamples <= 0) { + ffmpeg_set_skip_samples(ffmpeg_data, encoder_delay); + } + + /* MSF loop/sample values are offsets so trickier to adjust the skip_samples but this seems correct */ if (loop_flag) { - vgmstream->loop_start_sample = atrac3_bytes_to_samples(loop_start, block_size); - vgmstream->loop_end_sample = atrac3_bytes_to_samples(loop_end, block_size); + vgmstream->loop_start_sample = atrac3_bytes_to_samples(loop_start, block_size) /* - encoder_delay*/; + vgmstream->loop_end_sample = atrac3_bytes_to_samples(loop_end, block_size) - encoder_delay; } break; diff --git a/src/meta/riff.c b/src/meta/riff.c index 78241431..3eafe01c 100644 --- a/src/meta/riff.c +++ b/src/meta/riff.c @@ -174,7 +174,6 @@ int read_fmt(int big_endian, case 0xFFFE: /* WAVEFORMATEXTENSIBLE / ATRAC3plus */ #endif /* defined */ fmt->coding_type = coding_FFmpeg; - fmt->block_size = 2048; fmt->interleave = 0; break; #endif /* VGM_USE_FFMPEG */ @@ -408,10 +407,20 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { if ( !ffmpeg_data ) goto fail; sample_count = ffmpeg_data->totalSamples; /* fact_sample_count */ - /* the encoder introduces some garbage (usually silent) samples to skip before the stream - * loop values include the skip samples but fact_sample_count doesn't; add them back to fix some edge loops */ - if (fact_sample_skip > 0) - sample_count += fact_sample_skip; + + if (at3) { + /* the encoder introduces some garbage (not always silent) samples to skip before the stream */ + /* manually set skip_samples if FFmpeg didn't do it */ + if (ffmpeg_data->skipSamples <= 0) { + ffmpeg_set_skip_samples(ffmpeg_data, fact_sample_skip); + } + + /* RIFF loop/sample values are absolute (with skip samples), adjust */ + if (loop_flag) { + loop_start_offset -= ffmpeg_data->skipSamples; + loop_end_offset -= ffmpeg_data->skipSamples; + } + } } break; #endif diff --git a/src/meta/sgxd.c b/src/meta/sgxd.c index 6c5f1a78..2ed824ca 100644 --- a/src/meta/sgxd.c +++ b/src/meta/sgxd.c @@ -2,48 +2,27 @@ #include "../coding/coding.h" -/* utils to fix AT3 looping */ -typedef struct { - int32_t fact_samples; - int32_t loop_start_sample; - int32_t loop_end_sample; - int32_t skip_samples; -} at3_riff_info; -static int get_at3_riff_info(at3_riff_info* info, STREAMFILE *streamFile, int32_t offset); - - -/* Sony's SGB+SGH / SGD / SGX (variations of the same format) - * PS3: Genji (SGX only), Folklore, Afrika, Tokyo Jungle - * PSP: Brave Story, Sarugetchu Sarusaru Daisakusen, Kurohyo 1/2 - * - * Contains header + chunks, usually: - * WAVE: stream(s) header of ADPCM, AC3, ATRAC3plus, etc - * NAME: stream name(s) - * WSUR, WMRK, BUSS: unknown - * RGND, SEQD: unknown (related to SE) - * Then data, containing the original header if applicable (ex. AT3 RIFF). - * The SGXD header has priority over it (ex. some ATRAC3plus files have 48000 while the data RIFF 44100) - */ +/* SGXD - Sony/SCEI's format (SGB+SGH / SGD / SGX), found in: + * PS3: Genji, Folklore, Afrika (Short VAG), Tokyo Jungle + * PSP: Brave Story, Sarugetchu Sarusaru Daisakusen, Kurohyo 1/2, Pathwork Heroes */ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; STREAMFILE * streamHeader = NULL; - off_t start_offset, data_offset, chunk_offset; size_t data_size; int is_sgx, is_sgb; int loop_flag, channels, type; int sample_rate, num_samples, loop_start_sample, loop_end_sample; - int target_stream = 0, total_streams; /* check extension, case insensitive */ + /* .sgx: header+data (Genji), .sgd: header+data, .sgh/sgd: header/data */ if (!check_extensions(streamFile,"sgx,sgd,sgb")) goto fail; is_sgx = check_extensions(streamFile,"sgx"); is_sgb = check_extensions(streamFile,"sgb"); - //is_sgd = check_extensions(streamFile,"sgd"); /* SGB+SGH: use SGH as header; otherwise use the current file as header */ if (is_sgb) { @@ -69,14 +48,15 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) { } + /* typical chunks: WAVE, NAME (strings), RGND, SEQD (related to SFX), WSUR, WMKR, BUSS */ /* WAVE chunk (size 0x10 + files * 0x38 + optional padding) */ - /* 0x04 SGX: unknown; SGD/SGH: chunk length, 0x08 null */ if (is_sgx) { /* position after chunk+size */ if (read_32bitBE(0x10,streamHeader) != 0x57415645) goto fail; /* "WAVE" */ chunk_offset = 0x18; } else { if (!find_chunk_le(streamHeader, 0x57415645,0x10,0, &chunk_offset,NULL)) goto fail; /* "WAVE" */ } + /* 0x04 SGX: unknown; SGD/SGH: chunk length, 0x08 null */ /* check multi-streams (usually only SE containers; Puppeteer) */ total_streams = read_32bitLE(chunk_offset+0x04,streamHeader); @@ -107,7 +87,7 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) { data_size = read_32bitLE(chunk_offset+0x2c,streamHeader); /* stream size (without padding) / interleave (for type3) */ if (is_sgx) { - stream_offset = 0x0; /* TODO unknown (not seen multi SGX) */ + stream_offset = 0x0; } else{ stream_offset = read_32bitLE(chunk_offset+0x30,streamHeader); } @@ -128,41 +108,53 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) { vgmstream->num_streams = total_streams; vgmstream->meta_type = meta_SGXD; + /* needs -1 to match RIFF AT3's loop chunk + * (maybe SGXD = "loop before this sample" rather than "loop after this sample" as expected by vgmstream) */ + if (vgmstream->loop_end_sample > 0) + vgmstream->loop_end_sample -= 1; + switch (type) { - case 0x03: /* PSX ADPCM */ + case 0x03: /* PS-ADPCM */ vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_interleave; if (is_sgx || is_sgb) { vgmstream->interleave_block_size = 0x10; - } else { //todo this only seems to happen with SFX + } else { /* this only seems to happen with SFX */ vgmstream->interleave_block_size = data_size; } break; #ifdef VGM_USE_FFMPEG - case 0x04: { /* ATRAC3plus */ - at3_riff_info info; - ffmpeg_codec_data *ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, data_size); + case 0x04: { /* ATRAC3plus */ + ffmpeg_codec_data *ffmpeg_data; + + /* internally has a RIFF header; but the SGXD header / sample rate has priority over it (may not match) */ + 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; - /* manually fix looping due to FFmpeg bugs */ - if (loop_flag && get_at3_riff_info(&info, streamFile, start_offset)) { - if (vgmstream->num_samples == info.fact_samples) { /* use if looks normal */ - /* todo use "skip samples"; for now we just use absolute loop values */ - vgmstream->loop_start_sample = info.loop_start_sample; - vgmstream->loop_end_sample = info.loop_end_sample; - vgmstream->num_samples += info.skip_samples; /* to ensure it always reaches loop_end */ + /* manually read skip_samples if FFmpeg didn't do it */ + if (ffmpeg_data->skipSamples <= 0) { + off_t chunk_offset; + size_t chunk_size, fact_skip_samples = 0; + if (!find_chunk_le(streamFile, 0x66616374,start_offset+0xc,0, &chunk_offset,&chunk_size)) /* find "fact" */ + goto fail; + if (chunk_size == 0x8) { + fact_skip_samples = read_32bitLE(chunk_offset+0x4, streamFile); + } else if (chunk_size == 0xc) { + fact_skip_samples = read_32bitLE(chunk_offset+0x8, streamFile); } + ffmpeg_set_skip_samples(ffmpeg_data, fact_skip_samples); } + /* SGXD loop/sample values are relative (without skip samples) vs RIFF (with skip samples), no need to adjust */ break; } #endif - case 0x05: /* Short VAG ADPCM */ + case 0x05: /* Short PS-ADPCM */ vgmstream->coding_type = coding_PSX_cfg; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x4; @@ -170,13 +162,23 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) { break; #ifdef VGM_USE_FFMPEG - case 0x06: { /* AC3 */ - ffmpeg_codec_data *ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, data_size); + case 0x06: { /* AC3 */ + ffmpeg_codec_data *ffmpeg_data; + + 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; + /* manually set skip_samples if FFmpeg didn't do it */ + if (ffmpeg_data->skipSamples <= 0) { + /* PS3 AC3 consistently has 256 encoder delay samples, and there are ~1000-2000 samples after num_samples. + * Skipping them marginally improves full loops in some Tokyo Jungle tracks (ex. a_1.sgd). */ + ffmpeg_set_skip_samples(ffmpeg_data, 256); + } + /* SGXD loop/sample values are relative (without skip samples), no need to adjust */ + break; } #endif @@ -197,50 +199,3 @@ fail: close_vgmstream(vgmstream); return NULL; } - - - -/** - * AT3 RIFF headers have a "skip samples at the beginning" value that the decoder should use, - * and absolute loop values. However the SGXD header loop values assume those samples are skipped. - * - * FFmpeg doesn't support/export this, so we have to manually get the absolute values to fix looping. - */ -static int get_at3_riff_info(at3_riff_info* info, STREAMFILE *streamFile, int32_t offset) { - off_t chunk_offset; - size_t chunk_size; - - memset(info, 0, sizeof(at3_riff_info)); - - if (read_32bitBE(offset+0x0,streamFile)!=0x52494646 /* "RIFF" */ - && read_32bitBE(offset+0x8,streamFile)!=0x57415645 ) /* "WAVE" */ - goto fail; - - /*"smpl"*/ - if (!find_chunk_le(streamFile, 0x736D706C,offset+0xc,0, &chunk_offset,&chunk_size)) goto fail; - if (read_32bitLE(chunk_offset+0x1C, streamFile)==0 - || read_32bitLE(chunk_offset+0x24+0x4, streamFile)!=0 ) - goto fail; - info->loop_start_sample = read_32bitLE(chunk_offset+0x1C+0x8+0x8, streamFile); - info->loop_end_sample = read_32bitLE(chunk_offset+0x1C+0x8+0xc,streamFile); - - /*"fact"*/ - if (!find_chunk_le(streamFile, 0x66616374,offset+0xc,0, &chunk_offset,&chunk_size)) goto fail; - if (chunk_size == 0x8) { - info->fact_samples = read_32bitLE(chunk_offset+0x0, streamFile); - info->skip_samples = read_32bitLE(chunk_offset+0x4, streamFile); - } else if (chunk_size == 0xc) { - info->fact_samples = read_32bitLE(chunk_offset+0x0, streamFile); - info->skip_samples = read_32bitLE(chunk_offset+0x8, streamFile); - } else { - goto fail; - } - - /* found */ - return 1; - -fail: - /* not found */ - return 0; - -} diff --git a/src/meta/sqex_scd.c b/src/meta/sqex_scd.c index b44ee2f5..17784a21 100644 --- a/src/meta/sqex_scd.c +++ b/src/meta/sqex_scd.c @@ -1,6 +1,5 @@ #include "meta.h" #include "../coding/coding.h" -#include "../util.h" /* Square-Enix SCD (FF XIII, XIV) */ @@ -358,7 +357,6 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) { int32_t bytes; /* post_meta_offset+0x00: fmt0x166 header (BE), post_meta_offset+0x34: seek table */ - bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, post_meta_offset,0x34, stream_size, streamFile, 1); if (bytes <= 0) goto fail; @@ -378,30 +376,33 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) { /* ATRAC3plus */ /* Lord of Arcana (PSP) */ { ffmpeg_codec_data *ffmpeg_data = NULL; - off_t chunk_offset; - size_t chunk_size, fact_sample_skip = 0; - /* full riff header at start_offset/post_meta_offset (same) */ + /* full RIFF header at start_offset/post_meta_offset (same) */ ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size); if (!ffmpeg_data) goto fail; vgmstream->codec_data = ffmpeg_data; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; - vgmstream->num_samples = ffmpeg_data->totalSamples; + vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact samples */ vgmstream->loop_start_sample = loop_start; vgmstream->loop_end_sample = loop_end; - /* manually find encoder_delay to adjust samples since it's not properly used by FFmpeg */ - if (!find_chunk_le(streamFile, 0x66616374,start_offset+0xc,0, &chunk_offset,&chunk_size)) goto fail; /*"fact"*/ - if (chunk_size == 0x8) { - fact_sample_skip = read_32bitLE(chunk_offset+0x4, streamFile); - } else if (chunk_size == 0xc) { - fact_sample_skip = read_32bitLE(chunk_offset+0x8, streamFile); + /* manually read skip_samples if FFmpeg didn't do it */ + if (ffmpeg_data->skipSamples <= 0) { + off_t chunk_offset; + size_t chunk_size, fact_skip_samples = 0; + if (!find_chunk_le(streamFile, 0x66616374,start_offset+0xc,0, &chunk_offset,&chunk_size)) /* find "fact" */ + goto fail; + if (chunk_size == 0x8) { + fact_skip_samples = read_32bitLE(chunk_offset+0x4, streamFile); + } else if (chunk_size == 0xc) { + fact_skip_samples = read_32bitLE(chunk_offset+0x8, streamFile); + } + ffmpeg_set_skip_samples(ffmpeg_data, fact_skip_samples); } - vgmstream->num_samples += fact_sample_skip; - vgmstream->loop_start_sample += fact_sample_skip; - vgmstream->loop_end_sample += fact_sample_skip; + /* SCD loop/sample values are relative (without skip samples) vs RIFF (with skip samples), no need to adjust */ + } break; From 0c7ff41c11f6784d9e1b9ebd3382b71959217f0b Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 20 May 2017 18:07:06 +0200 Subject: [PATCH 16/17] Add new -F test.exe option to the readme --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index b5650835..62ed32a7 100644 --- a/readme.txt +++ b/readme.txt @@ -43,6 +43,7 @@ Options: -E: force end-to-end looping even if file has real loop points -r outfile2.wav: output a second time after resetting -2 N: only output the Nth (first is 0) set of stereo channels + -F: don't fade after N loops and play the rest of the stream Typical usage would be: test -o happy.wav happy.adx From 25bc0f29fd79d59f36104641525e7627322d7cf8 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 20 May 2017 18:18:27 +0200 Subject: [PATCH 17/17] Remove duplicate foobar #include --- fb2k/foo_vgmstream.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/fb2k/foo_vgmstream.cpp b/fb2k/foo_vgmstream.cpp index 8137a31a..2ed7b962 100644 --- a/fb2k/foo_vgmstream.cpp +++ b/fb2k/foo_vgmstream.cpp @@ -419,5 +419,3 @@ static input_singletrack_factory_t g_input_vgmstream_factory; DECLARE_COMPONENT_VERSION(APP_NAME,PLUGIN_VERSION,PLUGIN_DESCRIPTION); VALIDATE_COMPONENT_FILENAME("foo_input_vgmstream.dll"); - -#include "foo_filetypes.h"