From 0f2627f8da3c02a4c02adb9cbc0a7a578a38619e Mon Sep 17 00:00:00 2001 From: bnnm Date: Tue, 27 Dec 2016 14:28:12 +0100 Subject: [PATCH 01/21] Added VGM_DEBUG_OUTPUT flag to define debug logging utils --- src/util.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/util.h b/src/util.h index 9fbf7f00..1e1bcf01 100644 --- a/src/util.h +++ b/src/util.h @@ -72,4 +72,21 @@ void concatn(int length, char * dst, const char * src); void concatn_doublenull(int length, char * dst, const char * src); void concatn_fitting_doublenull(int length, char * dst, const char * src); + +/* Simple stdout logging for debugging and regression testing purposes. + * Needs C99 variadic macros. */ +#ifdef VGM_DEBUG_OUTPUT + +#define VGM_ASSERT(condition, ...) \ + do { if (condition) printf(__VA_ARGS__); } while (0) +#define VGM_LOG(...) \ + do { printf(__VA_ARGS__); } while (0) + +#else + +#define VGM_ASSERT(condition,fmt, ...) /* nothing */ +#define VGM_LOG(...) /* nothing */ + +#endif + #endif From 1be0f5f03dd5224082fd3be3eb0f67e600e98391 Mon Sep 17 00:00:00 2001 From: bnnm Date: Tue, 27 Dec 2016 14:28:52 +0100 Subject: [PATCH 02/21] Added external EXTRA_CFLAGS/LDFLAGS --- test/Makefile.mingw | 4 ++-- winamp/Makefile | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Makefile.mingw b/test/Makefile.mingw index 94bde73d..752f0654 100644 --- a/test/Makefile.mingw +++ b/test/Makefile.mingw @@ -22,8 +22,8 @@ endif # config export SHELL = /bin/sh -export CFLAGS=-Wall -O3 $(MPEG_CC) -DVGM_USE_G7221 -DVGM_USE_G719 $(MAT3P_CC) -DVAR_ARRAYS -I../ext_includes $(FFMPEG_CC) -export LDFLAGS=-L../src -L../ext_libs -lvgmstream -lvorbis $(MPEG_LD) -lg7221_decode -lg719_decode $(MAT3P_LD) -lm $(FFMPEG_LD) +export CFLAGS=-Wall -O3 $(MPEG_CC) -DVGM_USE_G7221 -DVGM_USE_G719 $(MAT3P_CC) $(FFMPEG_CC) -DVAR_ARRAYS -I../ext_includes $(EXTRA_CFLAGS) +export LDFLAGS=-L../src -L../ext_libs -lvgmstream -lvorbis $(MPEG_LD) -lg7221_decode -lg719_decode $(MAT3P_LD) $(FFMPEG_LD) -lm $(EXTRA_LDFLAGS) #export CC=i586-mingw32msvc-gcc #export AR=i586-mingw32msvc-ar #export STRIP=i586-mingw32msvc-strip diff --git a/winamp/Makefile b/winamp/Makefile index 76c67195..6817686c 100644 --- a/winamp/Makefile +++ b/winamp/Makefile @@ -22,8 +22,8 @@ endif # config export SHELL = /bin/sh -export CFLAGS=-Wall -O3 $(MPEG_CC) -DVGM_USE_G7221 -DVGM_USE_G719 $(MAT3P_CC) -DWIN32 -DUSE_ALLOCA -I../ext_includes $(FFMPEG_CC) -export LDFLAGS=-L../src -L../ext_libs -lvgmstream -lvorbis $(MPEG_LD) -lg7221_decode -lg719_decode $(MAT3P_LD) -lm $(FFMPEG_LD) +export CFLAGS=-Wall -O3 $(MPEG_CC) -DVGM_USE_G7221 -DVGM_USE_G719 $(MAT3P_CC) $(FFMPEG_CC) -DUSE_ALLOCA -DWIN32 -I../ext_includes $(EXTRA_CFLAGS) +export LDFLAGS=-L../src -L../ext_libs -lvgmstream -lvorbis $(MPEG_LD) -lg7221_decode -lg719_decode $(MAT3P_LD) $(FFMPEG_LD) -lm $(EXTRA_LDFLAGS) export CC=i586-mingw32msvc-gcc export AR=i586-mingw32msvc-ar export STRIP=i586-mingw32msvc-strip From e6b6a34a6750c44d75797db38617d8c85a14dd74 Mon Sep 17 00:00:00 2001 From: bnnm Date: Tue, 27 Dec 2016 14:30:45 +0100 Subject: [PATCH 03/21] Removed unused layouts --- src/layout/layout.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/layout/layout.h b/src/layout/layout.h index 599e9353..f5a8efde 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -68,12 +68,8 @@ void dsp_bdsp_block_update(off_t block_offset, VGMSTREAM * vgmstream); void tra_block_update(off_t block_offset, VGMSTREAM * vgmstream); -void mtaf_block_update(off_t block_offset, VGMSTREAM * vgmstream); - void ps2_iab_block_update(off_t block_offset, VGMSTREAM * vgmstream); void ps2_strlr_block_update(off_t block_offset, VGMSTREAM * vgmstream); -void ps2_mtaf_block_update(off_t block_ofset, VGMSTREAM * vgmstream); - #endif From 08a1a50ccb2192d8b7fcf07566d7c18443fdcdd2 Mon Sep 17 00:00:00 2001 From: bnnm Date: Tue, 27 Dec 2016 14:35:23 +0100 Subject: [PATCH 04/21] Fixed regression/segfault in multistream .mtaf [MGS3]; cleanup Apparently some MTAF ripped with an old tool contain block data, and a previous change attempted to support them. This broke multistream MTAF (block header starts with 0x01, and frame header starts with 0x00, but also 0x01 in multistreams). Those MTAF should be re-ripped without blocks. --- src/coding/mtaf_decoder.c | 110 ++++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 47 deletions(-) diff --git a/src/coding/mtaf_decoder.c b/src/coding/mtaf_decoder.c index d631476b..50e27672 100644 --- a/src/coding/mtaf_decoder.c +++ b/src/coding/mtaf_decoder.c @@ -3,6 +3,8 @@ #include "coding.h" #include "../util.h" +#define MTAF_BLOCK_SUPPORT 0 + // 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. @@ -81,62 +83,79 @@ static int16_t step_size[32][16] = { 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; - unsigned long cur_off = stream->offset; + off_t cur_off = stream->offset; int i; - int c = channel%2; - int16_t init_idx; - int16_t init_hist; + int c = channel%2; /* global channel to stream channel */ int32_t hist = stream->adpcm_history1_16; - int step_idx = stream->adpcm_step_index; - - //printf("channel %d: first_sample = %d, stream->offset = 0x%lx, cur_off = 0x%lx init_idx = %d\n", channel, first_sample, (unsigned long)stream->offset, cur_off, init_idx); + int32_t step_idx = stream->adpcm_step_index; + uint8_t byte = 0; -#if 0 - if (init_idx < 0 || init_idx > 31) { - fprintf(stderr, "step idx out of range at 0x%lx ch %d\n", cur_off, c); - exit(1); - } - if (0 != read_16bitLE(cur_off+10+c*4, stream->streamfile)) { - fprintf(stderr, "exp. zero after hist at 0x%lx ch %d\n", cur_off, c); - exit(1); + +#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 - first_sample = first_sample%0x100; - - if (first_sample%0x100 == 0) { - while (read_8bit(cur_off, stream->streamfile) != 0) { - cur_off += 16; - } - - stream->offset = cur_off; + first_sample = first_sample % 0x100; - init_idx = read_16bitLE(cur_off+4+c*2, stream->streamfile); - init_hist = read_16bitLE(cur_off+8+c*4, stream->streamfile); - - hist = init_hist; + /* read header when we hit a new frame every 0x100 samples */ + if (first_sample == 0) { + int32_t init_idx, init_hist; -#if 0 - if (step_idx != init_idx) { - fprintf(stderr, "step_idx does not match at 0x%lx, %d!=%d\n",cur_off,step_idx, init_idx); - exit(1); + /* 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); + + /* avoid index out of range in corrupt files */ + if (init_idx < 0) { + init_idx = 0; + } else if (init_idx > 31) { + init_idx = 31; } -#endif + step_idx = init_idx; + hist = init_hist; } for (i=first_sample,sample_count=0; istreamfile); - if (i%2!=1) - { - // low nibble first - nibble = byte&0xf; - } - else - { - // high nibble last + uint8_t nibble; + + if (i%2 != 1) { /* low nibble first */ + byte = read_8bit(cur_off + 0x10 + 0x80*c + i/2, stream->streamfile); + nibble = byte & 0x0f; + } else { /* high nibble last */ nibble = byte >> 4; } @@ -145,12 +164,9 @@ void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, outbuf[sample_count] = hist; step_idx += index_table[nibble]; - if (step_idx < 0) - { + if (step_idx < 0) { /* clip step */ step_idx = 0; - } - if (step_idx > 31) - { + } else if (step_idx > 31) { step_idx = 31; } } /* end sample loop */ From e06ddd0076ea534e6116c8b324f656281e075fd8 Mon Sep 17 00:00:00 2001 From: bnnm Date: Tue, 27 Dec 2016 16:33:10 +0100 Subject: [PATCH 05/21] Fixed minor compiler warnings (unused/uninitialized vars) --- src/meta/bcstm.c | 26 +++++++++++++++----------- src/meta/bfstm.c | 26 ++++++++++++++------------ src/meta/bfwav.c | 4 ++-- src/meta/btsnd.c | 1 - src/meta/fsb5.c | 2 +- src/meta/g1l.c | 2 +- src/meta/ngc_dsp_std.c | 4 ++-- src/meta/ps3_klbs.c | 4 ++-- 8 files changed, 37 insertions(+), 32 deletions(-) diff --git a/src/meta/bcstm.c b/src/meta/bcstm.c index 91b23ef1..54307f73 100644 --- a/src/meta/bcstm.c +++ b/src/meta/bcstm.c @@ -7,8 +7,7 @@ VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) { coding_t coding_type; - off_t info_offset, seek_offset, data_offset, regn_offset, pdat_offset; - size_t info_size, seek_size, data_size, regn_size, pdat_size; + off_t info_offset = 0, seek_offset = 0, data_offset = 0; uint16_t temp_id; int codec_number; int channel_count; @@ -35,23 +34,23 @@ VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) { switch(temp_id) { case 0x4000: info_offset = read_32bitLE(0x18 + i * 0xc, streamFile); - info_size = read_32bitLE(0x1c + i * 0xc, streamFile); + /* size_t info_size = read_32bitLE(0x1c + i * 0xc, streamFile); */ break; case 0x4001: seek_offset = read_32bitLE(0x18 + i * 0xc, streamFile); - seek_size = read_32bitLE(0x1c + i * 0xc, streamFile); + /* size_t seek_size = read_32bitLE(0x1c + i * 0xc, streamFile); */ break; case 0x4002: data_offset = read_32bitLE(0x18 + i * 0xc, streamFile); - data_size = read_32bitLE(0x1c + i * 0xc, streamFile); + /* size_t data_size = read_32bitLE(0x1c + i * 0xc, streamFile); */ break; case 0x4003: - regn_offset = read_32bitLE(0x18 + i * 0xc, streamFile); - regn_size = read_32bitLE(0x1c + i * 0xc, streamFile); + /* off_t regn_offset = read_32bitLE(0x18 + i * 0xc, streamFile); */ + /* size_t regn_size = read_32bitLE(0x1c + i * 0xc, streamFile); */ break; case 0x4004: - pdat_offset = read_32bitLE(0x18 + i * 0xc, streamFile); - pdat_size = read_32bitLE(0x1c + i * 0xc, streamFile); + /* off_t pdat_offset = read_32bitLE(0x18 + i * 0xc, streamFile); */ + /* size_t pdat_size = read_32bitLE(0x1c + i * 0xc, streamFile); */ break; default: break; @@ -62,6 +61,7 @@ VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) { /* check type details */ + if (info_offset == 0) goto fail; codec_number = read_8bit(info_offset + 0x20, streamFile); loop_flag = read_8bit(info_offset + 0x21, streamFile); channel_count = read_8bit(info_offset + 0x22, streamFile); @@ -74,6 +74,7 @@ VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) { coding_type = coding_PCM16LE; break; case 2: + if (seek_offset == 0) goto fail; if ((uint32_t)read_32bitBE(seek_offset, streamFile) != 0x5345454B) { /* "SEEK" If this header doesn't exist, assuming that the file is IMA */ ima = 1; coding_type = coding_INT_IMA; @@ -157,10 +158,13 @@ VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) { } } - if (ima) // No SEEK (ADPC) header, so just start where the SEEK header is supposed to be. + if (ima) { // No SEEK (ADPC) header, so just start where the SEEK header is supposed to be. + if (seek_offset == 0) goto fail; start_offset = seek_offset; - else + } else { + if (data_offset == 0) goto fail; start_offset = data_offset + 0x20; + } diff --git a/src/meta/bfstm.c b/src/meta/bfstm.c index 75189de8..449abea8 100644 --- a/src/meta/bfstm.c +++ b/src/meta/bfstm.c @@ -8,8 +8,7 @@ VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) { coding_t coding_type; - off_t info_offset, seek_offset, data_offset, regn_offset, pdat_offset; - size_t info_size, seek_size, data_size, regn_size, pdat_size; + off_t info_offset = 0, seek_offset = 0, data_offset = 0; uint16_t temp_id; int codec_number; int channel_count; @@ -17,7 +16,6 @@ VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) { int i, j; int ima = 0; off_t start_offset; - int founddata; off_t tempoffset1; int section_count; @@ -39,23 +37,23 @@ VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) { switch(temp_id) { case 0x4000: info_offset = read_32bitBE(0x18 + i * 0xc, streamFile); - info_size = read_32bitBE(0x1c + i * 0xc, streamFile); + /* size_t info_size = read_32bitBE(0x1c + i * 0xc, streamFile); */ break; case 0x4001: seek_offset = read_32bitBE(0x18 + i * 0xc, streamFile); - seek_size = read_32bitBE(0x1c + i * 0xc, streamFile); + /* size_t seek_size = read_32bitBE(0x1c + i * 0xc, streamFile); */ break; case 0x4002: data_offset = read_32bitBE(0x18 + i * 0xc, streamFile); - data_size = read_32bitBE(0x1c + i * 0xc, streamFile); + /* size_t data_size = read_32bitBE(0x1c + i * 0xc, streamFile); */ break; case 0x4003: - regn_offset = read_32bitBE(0x18 + i * 0xc, streamFile); - regn_size = read_32bitBE(0x1c + i * 0xc, streamFile); + /* off_t regn_offset = read_32bitBE(0x18 + i * 0xc, streamFile); */ + /* size_t regn_size = read_32bitBE(0x1c + i * 0xc, streamFile); */ break; case 0x4004: - pdat_offset = read_32bitBE(0x18 + i * 0xc, streamFile); - pdat_size = read_32bitBE(0x1c + i * 0xc, streamFile); + /* off_t pdat_offset = read_32bitBE(0x18 + i * 0xc, streamFile); */ + /* size_t pdat_size = read_32bitBE(0x1c + i * 0xc, streamFile); */ break; default: break; @@ -63,6 +61,7 @@ VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) { } + if (info_offset == 0) goto fail; if ((uint32_t)read_32bitBE(info_offset, streamFile) != 0x494E464F) /* "INFO" */ goto fail; @@ -152,10 +151,13 @@ VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) { } } - if (ima) // No SEEK (ADPC) header, so just start where the SEEK header is supposed to be. + if (ima) { // No SEEK (ADPC) header, so just start where the SEEK header is supposed to be. + if (seek_offset == 0) goto fail; start_offset = seek_offset; - else + } else { + if (data_offset == 0) goto fail; start_offset = data_offset + 0x20; + } diff --git a/src/meta/bfwav.c b/src/meta/bfwav.c index 12f0eec4..a02f09e2 100644 --- a/src/meta/bfwav.c +++ b/src/meta/bfwav.c @@ -7,7 +7,7 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) { coding_t coding_type; - int ima = 0; + /*int ima = 0;*/ int nsmbu_flag = 0; int32_t(*read_32bit)(off_t, STREAMFILE*) = read_32bitBE; int16_t(*read_16bit)(off_t, STREAMFILE*) = read_16bitBE; @@ -149,4 +149,4 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) { fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; -} \ No newline at end of file +} diff --git a/src/meta/btsnd.c b/src/meta/btsnd.c index e27803ef..b0afa30f 100644 --- a/src/meta/btsnd.c +++ b/src/meta/btsnd.c @@ -8,7 +8,6 @@ Wii U boot sound file for each game/app. VGMSTREAM * init_vgmstream_btsnd(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; - coding_t coding_type; int channel_count = 2; int loop_flag; off_t start_offset = 0x8; diff --git a/src/meta/fsb5.c b/src/meta/fsb5.c index 8ffde4e5..805f796b 100644 --- a/src/meta/fsb5.c +++ b/src/meta/fsb5.c @@ -15,7 +15,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) { int NumSamples; int ChannelCount; int SampleRate; - int DSPInfoStart; + int DSPInfoStart = 0; int SampleHeaderStart, SampleHeaderLength, NameTableLength, SampleDataLength, CodingID, SampleMode; int ExtraFlag, ExtraFlagStart, ExtraFlagType, ExtraFlagSize, ExtraFlagEnd; diff --git a/src/meta/g1l.c b/src/meta/g1l.c index 17d9dd2a..7e659fe6 100644 --- a/src/meta/g1l.c +++ b/src/meta/g1l.c @@ -7,7 +7,7 @@ VGMSTREAM * init_vgmstream_g1l(STREAMFILE *streamFile) { coding_t coding_type; - off_t head_offset; + /*off_t head_offset;*/ int channel_count; int loop_flag; diff --git a/src/meta/ngc_dsp_std.c b/src/meta/ngc_dsp_std.c index 5693e0be..778c59d3 100644 --- a/src/meta/ngc_dsp_std.c +++ b/src/meta/ngc_dsp_std.c @@ -2686,9 +2686,9 @@ VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile) { goto fail; if (header.loop_flag) { - off_t loop_off; +// off_t loop_off; /* check loop predictor/scale */ - loop_off = header.loop_start_offset/16*8; +// loop_off = header.loop_start_offset/16*8; /* Retro doesn't seem to abide by this */ // if (header.loop_ps != (uint8_t)read_8bit(current_offset + start_offset+loop_off,streamFile)) // goto fail; diff --git a/src/meta/ps3_klbs.c b/src/meta/ps3_klbs.c index 405138e6..0951945b 100644 --- a/src/meta/ps3_klbs.c +++ b/src/meta/ps3_klbs.c @@ -10,8 +10,8 @@ VGMSTREAM * init_vgmstream_ps3_klbs(STREAMFILE *streamFile) size_t fileLength; off_t readOffset = 0; off_t start_offset; - off_t loop_start_offset; - off_t loop_end_offset; + off_t loop_start_offset = 0; + off_t loop_end_offset = 0; uint8_t testBuffer[0x10]; int loop_flag = 0; From 2807d2fbaba472adde004f9934aaf374744e5a4d Mon Sep 17 00:00:00 2001 From: bnnm Date: Tue, 27 Dec 2016 17:13:22 +0100 Subject: [PATCH 06/21] Fixed minor compiler warnings --- ext_libs/clHCA.c | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/ext_libs/clHCA.c b/ext_libs/clHCA.c index a9e7ab8c..c2935d60 100644 --- a/ext_libs/clHCA.c +++ b/ext_libs/clHCA.c @@ -14,6 +14,7 @@ //-------------------------------------------------- // インライン関数 //-------------------------------------------------- +#if 0 static inline unsigned short get_le16(unsigned short v_){const unsigned char *v=(const unsigned char *)&v_;unsigned short r=v[1];r<<=8;r|=v[0];return r;} static inline unsigned short get_be16(unsigned short v_){const unsigned char *v=(const unsigned char *)&v_;unsigned short r=v[0];r<<=8;r|=v[1];return r;} static inline unsigned int get_be24(unsigned int v_){const unsigned char *v=(const unsigned char *)&v_;unsigned int r=v[0];r<<=8;r|=v[1];r<<=8;r|=v[2];return r;}; @@ -21,7 +22,6 @@ static inline unsigned int get_le32(unsigned int v_){const unsigned char *v=(con static inline unsigned int get_be32(unsigned int v_){const unsigned char *v=(const unsigned char *)&v_;unsigned int r=v[0];r<<=8;r|=v[1];r<<=8;r|=v[2];r<<=8;r|=v[3];return r;} static inline float get_bef32(float v_){union{float f;unsigned int i;}v;v.f=v_;v.i=get_be32(v.i);return v.f;} -#if 0 static union { unsigned int i; unsigned char c[4]; } g_is_le = {1}; static inline unsigned short swap_u16(unsigned short v){unsigned short r=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;return r;} static inline unsigned short swap_u32(unsigned int v){unsigned int r=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;return r;} @@ -191,9 +191,11 @@ static void clHCA_destructor(clHCA *hca) //-------------------------------------------------- // HCAチェック //-------------------------------------------------- +#if 0 static int clHCA_CheckFile(void *data,unsigned int size){ - return (data&&size>=4&&(get_le32(*(unsigned int *)data)&0x7F7F7F7F)==0x00414348); + return (data&&size>=4&&(get_be32(*(unsigned int *)data)&0x7F7F7F7F)==0x48434100);/*'HCA\0'*/ } +#endif //-------------------------------------------------- // チェックサム @@ -366,7 +368,7 @@ static int clHCA_PrintInfo(const char *filenameHCA){ } // HCA - if(size>=sizeof(stHeader) && (clData_CheckBit(&d,32)&0x7F7F7F7F)=='HCA\0'){ + if(size>=sizeof(stHeader) && (clData_CheckBit(&d,32)&0x7F7F7F7F)==0x48434100){/*'HCA\0'*/ clData_AddBit(&d,32); _version=clData_GetBit(&d,16); _dataOffset=clData_GetBit(&d,16); @@ -380,7 +382,7 @@ static int clHCA_PrintInfo(const char *filenameHCA){ } // fmt - if(size>=sizeof(stFormat) && (clData_CheckBit(&d, 32)&0x7F7F7F7F)=='fmt\0'){ + if(size>=sizeof(stFormat) && (clData_CheckBit(&d, 32)&0x7F7F7F7F)==0x666D7400){/*'fmt\0'*/ clData_AddBit(&d,32); _channelCount=clData_GetBit(&d,8); _samplingRate=clData_GetBit(&d,24); @@ -408,7 +410,7 @@ static int clHCA_PrintInfo(const char *filenameHCA){ } // comp - if(size>=sizeof(stCompress) && (clData_CheckBit(&d, 32)&0x7F7F7F7F)=='comp'){ + if(size>=sizeof(stCompress) && (clData_CheckBit(&d, 32)&0x7F7F7F7F)==0x636F6D70){/*'comp'*/ clData_AddBit(&d,32); _blockSize=clData_GetBit(&d,16); _comp_r01=clData_GetBit(&d,8); @@ -443,7 +445,7 @@ static int clHCA_PrintInfo(const char *filenameHCA){ } // dec - else if(size>=sizeof(stDecode) && (clData_CheckBit(&d, 32)&0x7F7F7F7F)=='dec\0'){ + else if(size>=sizeof(stDecode) && (clData_CheckBit(&d, 32)&0x7F7F7F7F)==0x64656300){/*'dec\0'*/ unsigned char count1,count2,enableCount2; clData_AddBit(&d, 32); _blockSize=clData_GetBit(&d,16); @@ -482,7 +484,7 @@ static int clHCA_PrintInfo(const char *filenameHCA){ } // vbr - if(size>=sizeof(stVBR) && (clData_CheckBit(&d,32)&0x7F7F7F7F)=='vbr\0'){ + if(size>=sizeof(stVBR) && (clData_CheckBit(&d,32)&0x7F7F7F7F)==0x76627200){/*'vbr\0'*/ clData_AddBit(&d, 32); _vbr_r01=clData_GetBit(&d,16); _vbr_r02=clData_GetBit(&d,16); @@ -502,7 +504,7 @@ static int clHCA_PrintInfo(const char *filenameHCA){ } // ath - if(size>=6 && (clData_CheckBit(&d,32)&0x7F7F7F7F)=='ath\0'){ + if(size>=6 && (clData_CheckBit(&d,32)&0x7F7F7F7F)==0x61746800){/*'ath\0'*/ clData_AddBit(&d,32); _ath_type=clData_GetBit(&d,16); printf("ATHタイプ:%d ※v2.0から廃止されています。\n",_ath_type); @@ -514,7 +516,7 @@ static int clHCA_PrintInfo(const char *filenameHCA){ } // loop - if(size>=sizeof(stLoop) && (clData_CheckBit(&d,32)&0x7F7F7F7F)=='loop'){ + if(size>=sizeof(stLoop) && (clData_CheckBit(&d,32)&0x7F7F7F7F)==0x6C6F6F70){/*'loop'*/ clData_AddBit(&d, 32); _loopStart=clData_GetBit(&d,32); _loopEnd=clData_GetBit(&d,32); @@ -531,7 +533,7 @@ static int clHCA_PrintInfo(const char *filenameHCA){ } // ciph - if(size>=6 && (clData_CheckBit(&d, 32)&0x7F7F7F7F)=='ciph'){ + if(size>=6 && (clData_CheckBit(&d, 32)&0x7F7F7F7F)==0x63697068){/*'ciph'*/ clData_AddBit(&d,32); _ciph_type=clData_GetBit(&d,16); switch(_ciph_type){ @@ -547,7 +549,7 @@ static int clHCA_PrintInfo(const char *filenameHCA){ } // rva - if(size>=sizeof(stRVA) && (clData_CheckBit(&d,32)&0x7F7F7F7F)=='rva\0'){ + if(size>=sizeof(stRVA) && (clData_CheckBit(&d,32)&0x7F7F7F7F)==0x72766100){/*'rva\0'*/ union { unsigned int i; float f; } v; clData_AddBit(&d,32); v.i=clData_GetBit(&d,32); @@ -557,7 +559,7 @@ static int clHCA_PrintInfo(const char *filenameHCA){ } // comm - if(size>=5 && (clData_CheckBit(&d,32)&0x7F7F7F7F)=='comm'){ + if(size>=5 && (clData_CheckBit(&d,32)&0x7F7F7F7F)==0x636F6D6D){/*'comm'*/ int i; clData_AddBit(&d,32); _comm_len=clData_GetBit(&d,8); @@ -758,7 +760,7 @@ int clHCA_DecodeToWavefile_Decode(clHCA *hca,void *fp1,void *fp2,unsigned int ad int clHCA_isOurFile0(const void *data){ clData d; clData_constructor(&d, data, 8); - if((clData_CheckBit(&d,32)&0x7F7F7F7F)=='HCA\0'){ + if((clData_CheckBit(&d,32)&0x7F7F7F7F)==0x48434100){/*'HCA\0'*/ clData_AddBit(&d,32+16); return clData_CheckBit(&d,16); } @@ -1067,7 +1069,7 @@ int clHCA_Decode(clHCA *hca,void *data,unsigned int size,unsigned int address){ if(size_version=clData_GetBit(&d,16); hca->_dataOffset=clData_GetBit(&d,16); @@ -1080,7 +1082,7 @@ int clHCA_Decode(clHCA *hca,void *data,unsigned int size,unsigned int address){ } // fmt - if(size>=sizeof(stFormat) && (clData_CheckBit(&d,32)&0x7F7F7F7F)=='fmt\0'){ + if(size>=sizeof(stFormat) && (clData_CheckBit(&d,32)&0x7F7F7F7F)==0x666D7400){/*'fmt\0'*/ clData_AddBit(&d,32); hca->_channelCount=clData_GetBit(&d,8); hca->_samplingRate=clData_GetBit(&d,24); @@ -1095,7 +1097,7 @@ int clHCA_Decode(clHCA *hca,void *data,unsigned int size,unsigned int address){ } // comp - if(size>=sizeof(stCompress) && (clData_CheckBit(&d,32)&0x7F7F7F7F)=='comp'){ + if(size>=sizeof(stCompress) && (clData_CheckBit(&d,32)&0x7F7F7F7F)==0x636F6D70){/*'comp'*/ clData_AddBit(&d,32); hca->_blockSize=clData_GetBit(&d,16); hca->_comp_r01=clData_GetBit(&d,8); @@ -1113,7 +1115,7 @@ int clHCA_Decode(clHCA *hca,void *data,unsigned int size,unsigned int address){ } // dec - else if(size>=sizeof(stDecode) && (clData_CheckBit(&d,32)&0x7F7F7F7F)=='dec\0'){ + else if(size>=sizeof(stDecode) && (clData_CheckBit(&d,32)&0x7F7F7F7F)==0x64656300){/*'dec\0'*/ unsigned char count1,count2,enableCount2; clData_AddBit(&d,32); hca->_blockSize=clData_GetBit(&d,16); @@ -1137,7 +1139,7 @@ int clHCA_Decode(clHCA *hca,void *data,unsigned int size,unsigned int address){ } // vbr - if(size>=sizeof(stVBR) && (clData_CheckBit(&d,32)&0x7F7F7F7F)=='vbr\0'){ + if(size>=sizeof(stVBR) && (clData_CheckBit(&d,32)&0x7F7F7F7F)==0x76627200){/*'vbr\0'*/ clData_AddBit(&d,32); hca->_vbr_r01=clData_GetBit(&d,16); hca->_vbr_r02=clData_GetBit(&d,16); @@ -1148,7 +1150,7 @@ int clHCA_Decode(clHCA *hca,void *data,unsigned int size,unsigned int address){ } // ath - if(size>=6 && (clData_CheckBit(&d,32)&0x7F7F7F7F)=='ath\0'){ + if(size>=6 && (clData_CheckBit(&d,32)&0x7F7F7F7F)==0x61746800){/*'ath\0'*/ clData_AddBit(&d,32); hca->_ath_type=clData_GetBit(&d,16); }else{ @@ -1156,7 +1158,7 @@ int clHCA_Decode(clHCA *hca,void *data,unsigned int size,unsigned int address){ } // loop - if(size>=sizeof(stLoop) && (clData_CheckBit(&d,32)&0x7F7F7F7F)=='loop'){ + if(size>=sizeof(stLoop) && (clData_CheckBit(&d,32)&0x7F7F7F7F)==0x6C6F6F70){/*'loop'*/ clData_AddBit(&d,32); hca->_loopStart=clData_GetBit(&d,32); hca->_loopEnd=clData_GetBit(&d,32); @@ -1174,7 +1176,7 @@ int clHCA_Decode(clHCA *hca,void *data,unsigned int size,unsigned int address){ } // ciph - if(size>=6 && (clData_CheckBit(&d,32)&0x7F7F7F7F)=='ciph'){ + if(size>=6 && (clData_CheckBit(&d,32)&0x7F7F7F7F)==0x63697068){/*'ciph'*/ clData_AddBit(&d,32); hca->_ciph_type=clData_GetBit(&d,16); if(!(hca->_ciph_type==0||hca->_ciph_type==1||hca->_ciph_type==0x38))return -1; @@ -1184,7 +1186,7 @@ int clHCA_Decode(clHCA *hca,void *data,unsigned int size,unsigned int address){ } // rva - if(size>=sizeof(stRVA) && (clData_CheckBit(&d,32)&0x7F7F7F7F)=='rva\0'){ + if(size>=sizeof(stRVA) && (clData_CheckBit(&d,32)&0x7F7F7F7F)==0x72766100){/*'rva\0'*/ union { unsigned int i; float f; } v; clData_AddBit(&d,32); v.i=clData_GetBit(&d,32); @@ -1195,7 +1197,7 @@ int clHCA_Decode(clHCA *hca,void *data,unsigned int size,unsigned int address){ } // comm - if(size>=5 && (clData_CheckBit(&d,32)&0x7F7F7F7F)=='comm'){ + if(size>=5 && (clData_CheckBit(&d,32)&0x7F7F7F7F)==0x636F6D6D){/*'comm'*/ void * newmem; unsigned int i; clData_AddBit(&d,32); From ad3b08168150e43e50e14c2a8a6737c1c55f0c6a Mon Sep 17 00:00:00 2001 From: bnnm Date: Tue, 27 Dec 2016 23:18:41 +0100 Subject: [PATCH 07/21] Fix possible segfault --- src/meta/ps3_msf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meta/ps3_msf.c b/src/meta/ps3_msf.c index 7fbf617b..169aab64 100644 --- a/src/meta/ps3_msf.c +++ b/src/meta/ps3_msf.c @@ -228,7 +228,7 @@ fail: #ifdef VGM_USE_FFMPEG if (ffmpeg_data) { free_ffmpeg(ffmpeg_data); - vgmstream->codec_data = NULL; + if (vgmstream) vgmstream->codec_data = NULL; } #endif if (vgmstream) close_vgmstream(vgmstream); From 790bb79cc9bd11a4cd9d4c1a1975a1a2147c6409 Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 28 Dec 2016 01:38:56 +0100 Subject: [PATCH 08/21] Allow to disable mpg123 stderr output for recoverable MPEGs (FSBs) --- src/coding/coding.h | 9 +++------ src/coding/mpeg_decoder.c | 7 +++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/coding/coding.h b/src/coding/coding.h index 92efe52d..d6c092c0 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -87,14 +87,11 @@ void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); #ifdef VGM_USE_MPEG -void decode_fake_mpeg2_l2(VGMSTREAMCHANNEL * stream, - mpeg_codec_data * data, - sample * outbuf, int32_t samples_to_do); mpeg_codec_data *init_mpeg_codec_data(STREAMFILE *streamfile, off_t start_offset, long given_sample_rate, int given_channels, coding_t *coding_type, int * actual_sample_rate, int * actual_channels); +void decode_fake_mpeg2_l2(VGMSTREAMCHANNEL * stream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do); +void decode_mpeg(VGMSTREAMCHANNEL * stream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels); long mpeg_bytes_to_samples(long bytes, const struct mpg123_frameinfo *mi); -void decode_mpeg(VGMSTREAMCHANNEL * stream, - mpeg_codec_data * data, - sample * outbuf, int32_t samples_to_do, int channels); +void mpeg_set_error_logging(mpeg_codec_data * data, int enable); #endif #ifdef VGM_USE_G7221 diff --git a/src/coding/mpeg_decoder.c b/src/coding/mpeg_decoder.c index 921287b8..e571dad6 100644 --- a/src/coding/mpeg_decoder.c +++ b/src/coding/mpeg_decoder.c @@ -226,4 +226,11 @@ long mpeg_bytes_to_samples(long bytes, const struct mpg123_frameinfo *mi) { return (int64_t)bytes * mi->rate * 8 / (mi->bitrate * 1000); } + +/** + * disables/enables stderr output, useful for MPEG known to contain recoverable errors + */ +void mpeg_set_error_logging(mpeg_codec_data * data, int enable) { + mpg123_param(data->m, MPG123_ADD_FLAGS, MPG123_QUIET, !enable); +} #endif From d4f45eaaee42033744fe5a06b32047996feb093c Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 28 Dec 2016 11:39:56 +0100 Subject: [PATCH 09/21] Moved debug FSB5 MPEG from fsb.c to fsb5.c --- src/meta/fsb5.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/src/meta/fsb5.c b/src/meta/fsb5.c index 805f796b..240bd55c 100644 --- a/src/meta/fsb5.c +++ b/src/meta/fsb5.c @@ -298,3 +298,155 @@ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; } + +#if 0 +// FSB5 MPEG +VGMSTREAM * init_vgmstream_fsb5_mpeg(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[PATH_LIMIT]; + off_t start_offset; + int channel_count, channels, loop_flag, fsb_mainheader_len, fsb_subheader_len, FSBFlag, rate; + long sample_rate = 0, num_samples = 0; + uint16_t mp3ID; + +#ifdef VGM_USE_MPEG + mpeg_codec_data *mpeg_data = NULL; + coding_t mpeg_coding_type = coding_MPEG1_L3; +#endif + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("fsb",filename_extension(filename))) goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) == 0x46534235) /* "FSB5" */ + { + fsb_mainheader_len = 0x3C; + } + else + { + goto fail; + } + + //fsb_subheader_len = read_16bitLE(fsb_mainheader_len,streamFile); + + /* "Check if the FSB is used as conatiner or as single file" */ + if (read_32bitBE(0x04,streamFile) != 0x01000000) + goto fail; + +#if 0 + /* Check channel count, multi-channel not supported and will be refused */ + if ((read_16bitLE(0x6E,streamFile) != 0x2) && + (read_16bitLE(0x6E,streamFile) != 0x1)) + goto fail; +#endif + + start_offset = fsb_mainheader_len+fsb_subheader_len+0x10; + + /* Check the MPEG Sync Header */ + mp3ID = read_16bitBE(start_offset,streamFile); + if ((mp3ID&0xFFE0) != 0xFFE0) + goto fail; + + channel_count = read_16bitLE(fsb_mainheader_len+0x3E,streamFile); + if (channel_count != 1 && channel_count != 2) + goto fail; + + FSBFlag = read_32bitLE(fsb_mainheader_len+0x30,streamFile); + if (FSBFlag&0x2 || FSBFlag&0x4 || FSBFlag&0x6) + loop_flag = 1; + + num_samples = (read_32bitLE(fsb_mainheader_len+0x2C,streamFile)); + +#ifdef VGM_USE_MPEG + mpeg_data = init_mpeg_codec_data(streamFile, start_offset, -1, -1, &mpeg_coding_type, &rate, &channels); // -1 to not check sample rate or channels + if (!mpeg_data) goto fail; + + //channel_count = channels; + sample_rate = rate; + +#else + // reject if no MPEG support + goto fail; +#endif + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = num_samples; + vgmstream->channels = channel_count; + + /* Still WIP */ + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitLE(fsb_mainheader_len+0x28,streamFile); + vgmstream->loop_end_sample = read_32bitLE(fsb_mainheader_len+0x2C,streamFile); + } + vgmstream->meta_type = meta_FSB_MPEG; + +#ifdef VGM_USE_MPEG + /* NOTE: num_samples seems to be quite wrong for MPEG */ + vgmstream->codec_data = mpeg_data; + vgmstream->layout_type = layout_mpeg; + vgmstream->coding_type = mpeg_coding_type; +#else + // reject if no MPEG support + goto fail; +#endif + + +#if 0 + if (loop_flag) { + vgmstream->loop_start_sample = read_32bitBE(0x18,streamFile)/960*1152; + vgmstream->loop_end_sample = read_32bitBE(0x1C,streamFile)/960*1152; + } +#endif + + /* open the file for reading */ + { + int i; + STREAMFILE * file; + if(vgmstream->layout_type == layout_interleave) + { + 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; + } + } + +#ifdef VGM_USE_MPEG + else if(vgmstream->layout_type == layout_mpeg) { + for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,MPEG_BUFFER_SIZE); + vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset=start_offset; + } + + } +#endif + else { goto fail; } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: +#ifdef VGM_USE_MPEG + if (mpeg_data) { + mpg123_delete(mpeg_data->m); + free(mpeg_data); + + if (vgmstream) { + vgmstream->codec_data = NULL; + } + } +#endif + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} +#endif From fa31aa2cd77f97358840c80fdac8388253348a64 Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 28 Dec 2016 16:14:44 +0100 Subject: [PATCH 10/21] Fixed wrong meta --- src/meta/2dx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meta/2dx.c b/src/meta/2dx.c index ebe39903..3993fa39 100644 --- a/src/meta/2dx.c +++ b/src/meta/2dx.c @@ -41,7 +41,7 @@ VGMSTREAM * init_vgmstream_2dx(STREAMFILE *streamFile) { vgmstream->num_samples = read_32bitLE(0x66,streamFile); vgmstream->layout_type = layout_none; vgmstream->interleave_block_size = read_16bitLE(0x38,streamFile); - vgmstream->meta_type = meta_2DX; + vgmstream->meta_type = meta_2DX9; /* open the file for reading */ { From 9bd2003218d2304da520f48117f7b689b214e115 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 29 Dec 2016 01:46:49 +0100 Subject: [PATCH 11/21] Fix minor warning --- src/vgmstream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vgmstream.c b/src/vgmstream.c index 82e8c955..2aab59ed 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -455,7 +455,7 @@ void reset_vgmstream(VGMSTREAM * vgmstream) { #endif if (vgmstream->coding_type==coding_CRI_HCA) { hca_codec_data *data = vgmstream->codec_data; - clHCA *hca = (clHCA *)(data + 1); + /*clHCA *hca = (clHCA *)(data + 1);*/ data->curblock = 0; data->sample_ptr = clHCA_samplesPerBlock; data->samples_discard = 0; From ad660177c41d53631225c19b07b38d550852811f Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 29 Dec 2016 13:24:24 +0100 Subject: [PATCH 12/21] New utils for common/repetitive actions in stream headers Meant to be more specialized than util.c (the main difference is that header.c includes VGMSTREAM and may define other struts), used mainly in metas --- src/Makefile | 2 +- src/Makefile.unix.am | 4 +- src/header.c | 197 +++++++++++++++++++++++++++++++ src/header.h | 22 ++++ src/libvgmstream.vcproj | 8 ++ src/libvgmstream.vcxproj | 2 + src/libvgmstream.vcxproj.filters | 6 + 7 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 src/header.c create mode 100644 src/header.h diff --git a/src/Makefile b/src/Makefile index d344912f..0168a93d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -311,7 +311,7 @@ META_OBJS=meta/adx_header.o \ EXT_LIBS = ../ext_libs/clHCA.o -OBJECTS=vgmstream.o streamfile.o util.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS) $(EXT_LIBS) +OBJECTS=vgmstream.o streamfile.o util.o header.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS) $(EXT_LIBS) libvgmstream.a: $(OBJECTS) $(AR) crs libvgmstream.a $(OBJECTS) diff --git a/src/Makefile.unix.am b/src/Makefile.unix.am index 9bd5446f..bb1f9164 100644 --- a/src/Makefile.unix.am +++ b/src/Makefile.unix.am @@ -4,8 +4,8 @@ AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir) AM_MAKEFLAGS=-f Makefile.unix libvgmstream_la_LDFLAGS = coding/libcoding.la layout/liblayout.la meta/libmeta.la -libvgmstream_la_SOURCES = vgmstream.c util.c streamfile.c ../ext_libs/clHCA.c +libvgmstream_la_SOURCES = vgmstream.c util.c streamfile.c header.c ../ext_libs/clHCA.c SUBDIRS = coding layout meta -EXTRA_DIST = pstdint.h streamfile.h streamtypes.h util.h vgmstream.h +EXTRA_DIST = pstdint.h streamfile.h streamtypes.h util.h header.h vgmstream.h diff --git a/src/header.c b/src/header.c new file mode 100644 index 00000000..7712be94 --- /dev/null +++ b/src/header.c @@ -0,0 +1,197 @@ +#include +#include "vgmstream.h" +#include "streamfile.h" +#include "util.h" + +/** + * checks if the stream filename is one of the extensions (comma-separated, ex. "adx" or "adx,aix") + * + * returns 0 on failure + */ +int header_check_extensions(STREAMFILE *streamFile, const char * cmpexts) { + char filename[PATH_LIMIT]; + const char * ext = NULL; + const char * cmpext = NULL; + size_t ext_len; + + streamFile->get_name(streamFile,filename,sizeof(filename)); + ext = filename_extension(filename); + ext_len = strlen(ext); + + cmpext = cmpexts; + do { + if (strncasecmp(ext,cmpext, ext_len)==0 ) + return 1; + cmpext = strstr(cmpext, ","); + if (cmpext != NULL) + cmpext = cmpext + 1; /* skip comma */ + } while (cmpext != NULL); + + return 0; +} + + +/** + * opens a stream at offset + * + * returns 0 on failure + */ +int header_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t start_offset) { + STREAMFILE * file; + char filename[PATH_LIMIT]; + int ch; + + streamFile->get_name(streamFile,filename,sizeof(filename)); + + +#if 0 + /* there is no appreciable difference using this */ + if (vgmstream->layout_type == layout_mpeg) { + for (ch=0; ch < vgmstream->channels; ch++) { + vgmstream->ch[ch].streamfile = streamFile->open(streamFile,filename,MPEG_BUFFER_SIZE); + vgmstream->ch[ch].channel_start_offset= vgmstream->ch[ch].offset=start_offset; + } + } + else +#endif + { + file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!file) return 0; + + for (ch=0; ch < vgmstream->channels; ch++) { + vgmstream->ch[ch].streamfile = file; + + if (vgmstream->coding_type == coding_MS_IMA + || vgmstream->coding_type == coding_XBOX) { /*todo not needed?*/ + /* both IMA channels work with same bytes */ + vgmstream->ch[ch].channel_start_offset = + vgmstream->ch[ch].offset = start_offset; + } + else { + vgmstream->ch[ch].channel_start_offset = + vgmstream->ch[ch].offset = start_offset + + vgmstream->interleave_block_size*ch; + } + /*todo if interleave and ch > 0 and layout none don't change offset? */ + } + } + + + return 1; +} + + +/** + * Copies a XMA2 riff to buf + * + * returns number of bytes in buf or -1 when buf is not big enough + */ +int header_make_riff_xma2(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_count, int block_size) { + uint16_t codec_XMA2 = 0x0166; + size_t riff_size = 4+4+ 4 + 0x3c + 4+4; + size_t bytecount; + uint32_t streams = 0; + uint32_t speakers = 0; /* see audiodefs.h */ + + if (buf_size < riff_size) + return -1; + + bytecount = sample_count * channels * sizeof(sample); + + /* untested (no support for > 2ch xma for now) */ + switch (channels) { + case 1: + streams = 1; + speakers = 0x00000004; /* FC */ + break; + case 2: + streams = 1; + speakers = 0x00000001 | 0x00000002; /* FL FR */ + break; + case 3: + streams = 3; + speakers = 0x00000001 | 0x00000002 | 0x00000004; /* FL FC FR */ + break; + case 4: + streams = 2; + speakers = 0x00000001 | 0x00000002 | 0x00000010 | 0x00000020; /* FL FR BL BR */ + break; + case 5: + streams = 3; + speakers = 0x00000001 | 0x00000002 | 0x00000010 | 0x00000020 | 0x00000004; /* FL C FR BL BR*/ + break; + case 6: + streams = 3; + speakers = 0x00000001 | 0x00000002 | 0x00000010 | 0x00000020 | 0x00000200 | 0x00000400; /* FL FR BL BR SL SR */ + break; + default: + streams = 1; + speakers = 0x80000000; + break; + } + + /*memset(buf,0, sizeof(uint8_t) * fmt_size);*/ + + memcpy(buf+0x00, "RIFF", 4); + put_32bitLE(buf+0x04, (int32_t)(riff_size-4-4 + data_size)); /* riff size */ + memcpy(buf+0x08, "WAVE", 4); + + memcpy(buf+0x0c, "fmt ", 4); + put_32bitLE(buf+0x10, 0x34);/*size*/ + put_16bitLE(buf+0x14, codec_XMA2); + put_16bitLE(buf+0x16, channels); + put_32bitLE(buf+0x18, sample_rate); + put_32bitLE(buf+0x1c, sample_rate*channels*sizeof(sample)); /* average bytes per second (wrong) */ + put_16bitLE(buf+0x20, (int16_t)(channels*sizeof(sample))); /* block align */ + put_16bitLE(buf+0x22, sizeof(sample)*8); /* bits per sample */ + + put_16bitLE(buf+0x24, 0x22); /* extra data size */ + put_16bitLE(buf+0x26, streams); /* number of streams */ + put_32bitLE(buf+0x28, speakers); /* speaker position */ + put_32bitLE(buf+0x2c, bytecount); /* PCM samples */ + put_32bitLE(buf+0x30, block_size); /* XMA block size */ + /* (looping values not set, expected to be handled externally) */ + put_32bitLE(buf+0x34, 0); /* play begin */ + put_32bitLE(buf+0x38, 0); /* play length */ + put_32bitLE(buf+0x3c, 0); /* loop begin */ + put_32bitLE(buf+0x40, 0); /* loop length */ + put_8bit(buf+0x44, 0); /* loop count */ + put_8bit(buf+0x45, 4); /* encoder version */ + put_16bitLE(buf+0x46, block_count); /* blocks count = entried in seek table */ + + memcpy(buf+0x48, "data", 4); + put_32bitLE(buf+0x4c, data_size); /* data size */ + + return riff_size; +} + + +/** + * reads DSP coefs built in the streamfile + */ +void header_dsp_read_coefs_be(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t offset, off_t spacing) { + int ch, i; + /* get ADPCM coefs */ + for (ch=0; ch < vgmstream->channels; ch++) { + for (i=0; i < 16; i++) { + vgmstream->ch[ch].adpcm_coef[i] = + read_16bitBE(offset + ch*spacing + i*2, streamFile); + } + } +} + + +#if 0 +/** + * Converts a data offset (without headers) to sample, so full datasize would be num_samples + * + * return -1 on failure + */ +int data_offset_to_samples(layout_t layout, int channels, size_t interleave, size_t data_offset) { + // todo get samples per block + // VAG: datasize * 28 / 16 / channels; + // IMA: (datasize / 0x24 / channels) * ((0x24-4)*2);//0x24 = interleave? + // DSP: datasize / 8 / channel_count * 14; +} + +#endif diff --git a/src/header.h b/src/header.h new file mode 100644 index 00000000..e8fe2de7 --- /dev/null +++ b/src/header.h @@ -0,0 +1,22 @@ +/* + * header.h - utilities for common/repetitive actions in stream headers (more complex than those in util.h) + */ + +#ifndef _HEADER_H_ +#define _HEADER_H_ + +#include "util.h" +#include "streamfile.h" +#include "vgmstream.h" + + +int header_check_extensions(STREAMFILE *streamFile, char * extensions); + +int header_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t start_offset); + +int header_make_riff_xma2(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_count, int block_size);; + +void header_dsp_read_coefs_be(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t offset, off_t spacing); + + +#endif /* _HEADER_H_ */ diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index f70e207d..85463f6a 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -147,6 +147,10 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + @@ -169,6 +173,10 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 21f3f199..3216a50a 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -82,6 +82,7 @@ + @@ -138,6 +139,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 8a6cbc9e..5ff7d1cd 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -47,6 +47,9 @@ + + Header Files + Header Files @@ -82,6 +85,9 @@ + + Source Files + Source Files From c042878a1b4fdb852f7da6664890166c259e767e Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 29 Dec 2016 13:27:10 +0100 Subject: [PATCH 13/21] One more debug util --- src/util.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util.h b/src/util.h index 1e1bcf01..7e72c828 100644 --- a/src/util.h +++ b/src/util.h @@ -81,11 +81,14 @@ void concatn_fitting_doublenull(int length, char * dst, const char * src); do { if (condition) printf(__VA_ARGS__); } while (0) #define VGM_LOG(...) \ do { printf(__VA_ARGS__); } while (0) +#define VGM_LOGF() \ + do { printf("%s:%i '%s'\n", __FILE__, __LINE__, __func__); } while (0) #else #define VGM_ASSERT(condition,fmt, ...) /* nothing */ #define VGM_LOG(...) /* nothing */ +#define VGM_LOGF(...) /* nothing */ #endif From 6c82a508efd4fc9c2569e53137d6a368e0f4948e Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 29 Dec 2016 14:06:57 +0100 Subject: [PATCH 14/21] Redone FSB1-4: improved XMA/MPEG, bugs, looping Now parses FMOD's flags correctly and should work for all versions. There are still some problems with IMA ADPCM which also happened before. --- src/meta/fsb.c | 1120 +++++++++++++++-------------------------------- src/meta/meta.h | 8 +- src/vgmstream.c | 20 +- src/vgmstream.h | 6 +- 4 files changed, 358 insertions(+), 796 deletions(-) diff --git a/src/meta/fsb.c b/src/meta/fsb.c index 165d6d88..411cd1ca 100644 --- a/src/meta/fsb.c +++ b/src/meta/fsb.c @@ -1,825 +1,405 @@ #include "meta.h" #include "../coding/coding.h" #include "../util.h" +#include "../header.h" -/* FSB1 */ -VGMSTREAM * init_vgmstream_fsb1(STREAMFILE *streamFile) { +#define FAKE_RIFF_BUFFER_SIZE 100 - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; +static VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset); - /* int fsb1_included_files; */ - int fsb1_format; - int loop_flag = 0; - int channel_count; +/* ************************************************************************************************************ + * FSB defines, copied from the public spec (https://www.fmod.org/questions/question/forum-4928/) + * The format is mostly compatible for FSB1/2/3/4, but not FSB5. Headers always use LE. A FSB contains + * main header + sample header(s) + raw data. In multistreams N sample headers are stored (and + * if the BASICHEADERS flag is set, all headers but the first use HEADER_BASIC = numsamples + datasize) + * ************************************************************************************************************ */ +/* These flags are used for FMOD_FSB_HEADER::mode */ +#define FMOD_FSB_SOURCE_FORMAT 0x00000001 /* all samples stored in their original compressed format */ +#define FMOD_FSB_SOURCE_BASICHEADERS 0x00000002 /* samples should use the basic header structure */ +#define FMOD_FSB_SOURCE_ENCRYPTED 0x00000004 /* all sample data is encrypted */ +#define FMOD_FSB_SOURCE_BIGENDIANPCM 0x00000008 /* pcm samples have been written out in big-endian format */ +#define FMOD_FSB_SOURCE_NOTINTERLEAVED 0x00000010 /* Sample data is not interleaved. */ +#define FMOD_FSB_SOURCE_MPEG_PADDED 0x00000020 /* Mpeg frames are now rounded up to the nearest 2 bytes for normal sounds, or 16 bytes for multichannel. */ +#define FMOD_FSB_SOURCE_MPEG_PADDED4 0x00000040 /* Mpeg frames are now rounded up to the nearest 4 bytes for normal sounds, or 16 bytes for multichannel. */ - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("fsb",filename_extension(filename))) goto fail; +/* These flags are used for FMOD_FSB_HEADER::version */ +#define FMOD_FSB_VERSION_3_0 0x00030000 /* FSB version 3.0 */ +#define FMOD_FSB_VERSION_3_1 0x00030001 /* FSB version 3.1 */ +#define FMOD_FSB_VERSION_4_0 0x00040000 /* FSB version 4.0 */ - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x46534231) /* "FSB1" */ - goto fail; - - /* "Check if the FSB is used as - conatiner or as single file" */ - if (read_32bitBE(0x04,streamFile) != 0x01000000) - goto fail; +/* FMOD 3 defines. These flags are used for FMOD_FSB_SAMPLE_HEADER::mode */ +#define FSOUND_LOOP_OFF 0x00000001 /* For non looping samples. */ +#define FSOUND_LOOP_NORMAL 0x00000002 /* For forward looping samples. */ +#define FSOUND_LOOP_BIDI 0x00000004 /* For bidirectional looping samples. (no effect if in hardware). */ +#define FSOUND_8BITS 0x00000008 /* For 8 bit samples. */ +#define FSOUND_16BITS 0x00000010 /* For 16 bit samples. */ +#define FSOUND_MONO 0x00000020 /* For mono samples. */ +#define FSOUND_STEREO 0x00000040 /* For stereo samples. */ +#define FSOUND_UNSIGNED 0x00000080 /* For user created source data containing unsigned samples. */ +#define FSOUND_SIGNED 0x00000100 /* For user created source data containing signed data. */ +#define FSOUND_MPEG 0x00000200 /* For MPEG layer 2/3 data. */ +#define FSOUND_CHANNELMODE_ALLMONO 0x00000400 /* Sample is a collection of mono channels. */ +#define FSOUND_CHANNELMODE_ALLSTEREO 0x00000800 /* Sample is a collection of stereo channel pairs */ +#define FSOUND_HW3D 0x00001000 /* Attempts to make samples use 3d hardware acceleration. (if the card supports it) */ +#define FSOUND_2D 0x00002000 /* Tells software (not hardware) based sample not to be included in 3d processing. */ +#define FSOUND_SYNCPOINTS_NONAMES 0x00004000 /* Specifies that syncpoints are present with no names */ +#define FSOUND_DUPLICATE 0x00008000 /* This subsound is a duplicate of the previous one i.e. it uses the same sample data but w/different mode bits */ +#define FSOUND_CHANNELMODE_PROTOOLS 0x00010000 /* Sample is 6ch and uses L C R LS RS LFE standard. */ +#define FSOUND_MPEGACCURATE 0x00020000 /* For FSOUND_Stream_Open - for accurate FSOUND_Stream_GetLengthMs/FSOUND_Stream_SetTime. WARNING, see FSOUND_Stream_Open for inital opening time performance issues. */ +#define FSOUND_HW2D 0x00080000 /* 2D hardware sounds. allows hardware specific effects */ +#define FSOUND_3D 0x00100000 /* 3D software sounds */ +#define FSOUND_32BITS 0x00200000 /* For 32 bit (float) samples. */ +#define FSOUND_IMAADPCM 0x00400000 /* Contents are stored compressed as IMA ADPCM */ +#define FSOUND_VAG 0x00800000 /* For PS2 only - Contents are compressed as Sony VAG format */ +#define FSOUND_XMA 0x01000000 /* For Xbox360 only - Contents are compressed as XMA format */ +#define FSOUND_GCADPCM 0x02000000 /* For Gamecube only - Contents are compressed as Gamecube DSP-ADPCM format */ +#define FSOUND_MULTICHANNEL 0x04000000 /* For PS2 and Gamecube only - Contents are interleaved into a multi-channel (more than stereo) format */ +#define FSOUND_OGG 0x08000000 /* For vorbis encoded ogg data */ +#define FSOUND_CELT 0x08000000 /* For vorbis encoded ogg data */ +#define FSOUND_MPEG_LAYER3 0x10000000 /* Data is in MP3 format. */ +#define FSOUND_MPEG_LAYER2 0x00040000 /* Data is in MP2 format. */ +#define FSOUND_LOADMEMORYIOP 0x20000000 /* For PS2 only - "name" will be interpreted as a pointer to data for streaming and samples. The address provided will be an IOP address */ +#define FSOUND_IMAADPCMSTEREO 0x20000000 /* Signify IMA ADPCM is actually stereo not two interleaved mono */ +#define FSOUND_IGNORETAGS 0x40000000 /* Skips id3v2 etc tag checks when opening a stream, to reduce seek/read overhead when opening files (helps with CD performance) */ +#define FSOUND_SYNCPOINTS 0x80000000 /* Specifies that syncpoints are present */ - loop_flag = 0; - channel_count = 2; +/* These flags are used for FMOD_FSB_SAMPLE_HEADER::mode */ +#define FSOUND_CHANNELMODE_MASK (FSOUND_CHANNELMODE_ALLMONO | FSOUND_CHANNELMODE_ALLSTEREO | FSOUND_CHANNELMODE_PROTOOLS) +#define FSOUND_CHANNELMODE_DEFAULT 0x00000000 /* Determine channel assignment automatically from channel count. */ +#define FSOUND_CHANNELMODE_RESERVED 0x00000C00 - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; +#define FSOUND_NORMAL (FSOUND_16BITS | FSOUND_SIGNED | FSOUND_MONO) - /* This will be tricky ;o) */ - fsb1_format = read_32bitBE(0x44,streamFile); - switch (fsb1_format) { - case 0x40008800: /* PS2 (Operation Genesis) */ - case 0x41008800: /* PS2 (Operation Genesis) */ - vgmstream->coding_type = coding_PSX; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x10; - vgmstream->num_samples = (read_32bitLE(0x34,streamFile))*28/16/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = read_32bitLE(0x30,streamFile); - } - break; - default: - goto fail; +#define FSB_SAMPLE_DATA_ALIGN 32 - } - /* fill in the vital statistics */ - start_offset = 0x50; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x38,streamFile); - vgmstream->meta_type = meta_FSB1; - - /* 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; +/* simplified struct based on the original definitions */ +typedef struct { + /* main header */ + uint32_t id; + int32_t numsamples; /* number of samples(streams) in the file */ + uint32_t shdrsize; /* size in bytes of all of the sample headers including extended information */ + uint32_t datasize; /* size in bytes of compressed sample data */ + /* main header: FSB 3/3.1/4 */ + uint32_t version; /* extended fsb version */ + uint32_t flags; /* flags that apply to all samples(streams) in the fsb */ + /* sample header */ + uint32_t lengthsamples; + uint32_t lengthcompressedbytes; + uint32_t loopstart; + uint32_t loopend; + uint32_t mode; + int32_t deffreq; + uint16_t numchannels; + /* extra */ + uint32_t hdrsize; + uint32_t shdrsize_min; + meta_t meta_type; +} FSB_HEADER; - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - -/* FSB3.0 and FSB3.1 */ -VGMSTREAM * init_vgmstream_fsb3(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - int fsb_headerlen; - int channel_count; - int loop_flag = 0; - int FSBFlag = 0; - int i, c; - off_t start_offset; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - - if (strcasecmp("fsb",filename_extension(filename))) - goto fail; - - /* check header for "FSB3" string */ - if (read_32bitBE(0x00,streamFile) != 0x46534233) - goto fail; - - /* "Check if the FSB is used as conatiner or as single file" */ - if (read_32bitLE(0x04,streamFile) != 0x1) - goto fail; - - /* Check if we're dealing with a FSB3.0 file */ - if ((read_32bitBE(0x10,streamFile) != 0x00000300) && - ((read_32bitBE(0x10,streamFile) != 0x01000300))) - goto fail; - - channel_count = read_16bitLE(0x56,streamFile); - fsb_headerlen = read_32bitLE(0x08,streamFile); - - FSBFlag = read_32bitLE(0x48,streamFile); - - if (FSBFlag&0x2 || FSBFlag&0x4 || FSBFlag&0x6) - loop_flag = 1; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - start_offset = fsb_headerlen+0x18; - vgmstream->sample_rate = (read_32bitLE(0x4C, streamFile)); - - - // Get the Decoder - if (FSBFlag&0x00000100) - { // Ignore format and treat as RAW PCM - vgmstream->coding_type = coding_PCM16LE; - if (channel_count == 1) - { - vgmstream->layout_type = layout_none; - } - else if (channel_count > 1) - { - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x2; - } - } - else if (FSBFlag&0x00400000) - { // XBOX IMA - vgmstream->coding_type = coding_XBOX; - vgmstream->layout_type = layout_none; - } - else if (FSBFlag&0x00800000) - { // PS2 ADPCM - vgmstream->coding_type = coding_PSX; - if (channel_count == 1) - { - vgmstream->layout_type = layout_none; - } - else if (channel_count > 1) - { - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x10; - } - } - else if (FSBFlag&0x02000000) - { // Nintendo DSP - vgmstream->coding_type = coding_NGC_DSP; - if (channel_count == 1) - { - vgmstream->layout_type = layout_none; - } - else if (channel_count > 1) - { - vgmstream->layout_type = layout_interleave_byte; - vgmstream->interleave_block_size = 2; - } - // read coeff(s), DSP only - for (c=0;cch[c].adpcm_coef[i]=read_16bitBE(0x68+c*0x2e +i*2,streamFile); - } - } - } - else goto fail; - - vgmstream->num_samples = read_32bitLE(0x38,streamFile); - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(0x40,streamFile); - vgmstream->loop_end_sample = read_32bitLE(0x44,streamFile); - } - - - if (read_32bitBE(0x10,streamFile) == 0x00000300) - { - vgmstream->meta_type = meta_FSB3_0; - } - else if (read_32bitBE(0x10,streamFile) == 0x01000300) - { - vgmstream->meta_type = meta_FSB3_1; - } - - /* 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; - - if (vgmstream->coding_type == coding_XBOX) { - /* xbox interleaving is a little odd */ - vgmstream->ch[i].channel_start_offset=start_offset; - } else { - vgmstream->ch[i].channel_start_offset= - start_offset+vgmstream->interleave_block_size*i; - } - vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset; - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} +/* ********************************************************************************** */ /* FSB4 */ -VGMSTREAM * init_vgmstream_fsb4(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int fsb4_format; - int loop_flag = 0; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("fsb",filename_extension(filename)) && - strcasecmp("wii",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x46534234) /* "FSB4" */ - goto fail; - - /* "Check if the FSB is used as - conatiner or as single file" */ - if (read_32bitBE(0x04,streamFile) != 0x01000000) - goto fail; - - if (read_32bitBE(0x60,streamFile) == 0x40008800 || - read_32bitBE(0x60,streamFile) == 0x40000802 || - read_32bitBE(0x60,streamFile) == 0x40100802 || - read_32bitBE(0x60,streamFile) == 0x000040A0 || - read_32bitBE(0x60,streamFile) == 0x40004020) { - loop_flag = 1; - } else { - loop_flag = 0; - } - -#if 0 - if (read_32bitBE(0x60,streamFile) != 0x20000882 && - read_32bitBE(0x60,streamFile) != 0x20100002 && - read_32bitBE(0x60,streamFile) != 0x20100882 && - read_32bitBE(0x60,streamFile) != 0x20100802 && - read_32bitBE(0x60,streamFile) != 0x20100082 && - read_32bitBE(0x60,streamFile) != 0x20000802) { - channel_count = 2; - } else { - channel_count = 1; - } -#endif - - channel_count = (uint16_t)read_16bitLE(0x6E,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x64,streamFile); - fsb4_format = read_32bitBE(0x60,streamFile); - switch (fsb4_format) { - /* PC Blade Kitten */ - case 0x40004020: - case 0x20004000: - case 0x00004020: - case 0x000040A0: - vgmstream->coding_type = coding_MS_IMA; - vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = 0x24*vgmstream->channels; - vgmstream->num_samples = (read_32bitLE(0x54,streamFile)/0x24/vgmstream->channels)*((0x24-4)*2); - //vgmstream->num_samples = read_32bitLE(0x50,streamFile); - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(0x58,streamFile); - vgmstream->loop_end_sample = read_32bitLE(0x5C,streamFile); - } - break; - /* PS2 (Spider Man - Web of Shadows), Speed Racer */ - case 0x40008800: - case 0x20008800: // Silent Hill: Shattered Memories - vgmstream->coding_type = coding_PSX; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x10; - vgmstream->num_samples = (read_32bitLE(0x54,streamFile))*28/16/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = read_32bitLE(0x50,streamFile); - } - break; - /* de Blob 2*/ - case 0x00000886: - /* WII (de Blob, Night at the Museum) */ - case 0x40000802: - case 0x40000882: - case 0x40100802: - case 0x40200802: - case 0x00000802: - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = read_32bitLE(0x50,streamFile); - } - - if (read_32bitLE(0x14,streamFile)==0x20 || - read_32bitLE(0x14,streamFile)==0x22 || - read_32bitLE(0x14,streamFile)==0x00) - { - /* Night at the Museum */ - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_interleave_byte; - vgmstream->interleave_block_size = 2; - } - else if (read_32bitLE(0x14,streamFile)==0x10 || - read_32bitLE(0x14,streamFile)==0x30) - { - /* de Blob, NatM sfx */ - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = read_32bitLE(0x54,streamFile)/channel_count; - } - else if (read_32bitLE(0x14,streamFile)==0x40) { - /* M. Night Shamylan The Last Airbender */ - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_interleave_byte; - vgmstream->interleave_block_size = 2; - - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(0x58,streamFile); - } - } - else goto fail; - - vgmstream->num_samples = (read_32bitLE(0x54,streamFile)/8/channel_count*14); - break; - - /* Night at the Museum */ - case 0x20000882: - case 0x20000802: - case 0x20100002: - case 0x20100882: - case 0x20100802: - case 0x20100082: - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_none; - vgmstream->num_samples = (read_32bitLE(0x54,streamFile)/8/channel_count*14); - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = read_32bitLE(0x50,streamFile); - } - break; - - /* Rocket Knight (PC) */ - case 0x10000000: /* Dead Space (iOS) */ - case 0x50210000: - case 0x30210000: - case 0x30011000: - case 0x20005000: - case 0x30011080: - case 0x30211000: - case 0x40005020: - case 0x20204000: - case 0x40204020: - case 0x50011000: - case 0x20205000: - case 0x30610080: - case 0x50210080: /* Another Century's Episode R (PS3) */ - case 0x50010800: /* Toy Story 3 (PS3) */ - vgmstream->coding_type = coding_PCM16LE; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x2; - vgmstream->num_samples = (read_32bitLE(0x5C,streamFile)); - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(0x58,streamFile); - vgmstream->loop_end_sample = read_32bitLE(0x5C,streamFile); - } - break; - default: - goto fail; - } - - start_offset = read_32bitLE(0x08,streamFile)+0x30; - - vgmstream->meta_type = meta_FSB4; - - if (vgmstream->coding_type == coding_NGC_DSP) { - int c,i; - for (c=0;cch[c].adpcm_coef[i] = - read_16bitBE(0x80+c*0x2e + i*2,streamFile); - } - } - } - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - - if (vgmstream->coding_type == coding_MS_IMA) { - // both IMA channels work with same bytes - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset; - } else { - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - } - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; +VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) { + return init_vgmstream_fsb_offset(streamFile, 0x0); } - -/* FSB4 with "WAV" Header, found in "Deadly Creatures (WII)" - 16 byte "WAV" header which holds the filesize...*/ +/* FSB4 with "\0WAV" Header, found in Deadly Creatures (Wii) + * 16 byte header which holds the filesize + * (unsure if this is from a proper rip) */ VGMSTREAM * init_vgmstream_fsb4_wav(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - int loop_flag; - int channel_count; - int fsb_headerlength; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("fsb",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x00574156) /* 0x0\"WAV" */ - goto fail; - if (read_32bitBE(0x10,streamFile) != 0x46534234) /* "FSB4" */ - goto fail; - - channel_count = (uint16_t)read_16bitLE(0x7E,streamFile); - - if (channel_count > 2) { - goto fail; - } - - loop_flag = (read_32bitBE(0x70,streamFile) == 0x40000802); - fsb_headerlength = read_32bitLE(0x18,streamFile); - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = fsb_headerlength + 0x40; - vgmstream->sample_rate = read_32bitLE(0x74,streamFile); - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_interleave_byte; - vgmstream->interleave_block_size = 0x2; - vgmstream->num_samples = (read_32bitLE(0x64,streamFile)/8/channel_count*14); - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = read_32bitLE(0x60,streamFile); - } - - vgmstream->meta_type = meta_FSB4_WAV; - - if (vgmstream->coding_type == coding_NGC_DSP) { - int i; - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x90+i*2,streamFile); - } - if (vgmstream->channels == 2) { - for (i=0;i<16;i++) { - vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0xBE + i*2,streamFile); - } - } - } - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; + if (read_32bitBE(0x00,streamFile) != 0x00574156) /* "\0WAV" */ + return NULL; + return init_vgmstream_fsb_offset(streamFile, 0x10); } - -// FSB3 & FSB4 MPEG TEST -VGMSTREAM * init_vgmstream_fsb_mpeg(STREAMFILE *streamFile) { -#ifdef VGM_USE_MPEG +VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - int channel_count, channels, loop_flag, fsb_mainheader_len, fsb_subheader_len, FSBFlag, rate; - long sample_rate = 0, num_samples = 0; - uint16_t mp3ID; + off_t start_offset, h_off, s_off; + size_t custom_data_offset; + int loop_flag = 0; -#ifdef VGM_USE_MPEG - mpeg_codec_data *mpeg_data = NULL; - coding_t mpeg_coding_type = coding_MPEG1_L3; -#endif + FSB_HEADER fsbh; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("fsb",filename_extension(filename))) goto fail; + /* check extensions */ + if ( !header_check_extensions(streamFile, "fsb,wii") ) + goto fail; + + h_off = offset; /* check header */ - if (read_32bitBE(0x00,streamFile) == 0x46534233) /* "FSB3" */ - { - fsb_mainheader_len = 0x18; - } - else if (read_32bitBE(0x00,streamFile) == 0x46534234) /* "FSB4" */ - { - fsb_mainheader_len = 0x30; - } - else - { - goto fail; - } + fsbh.id = read_32bitBE(offset+0x00,streamFile); + if (fsbh.id == 0x46534231) { /* "FSB1" (somewhat different from other fsbs) */ + fsbh.meta_type = meta_FSB1; + fsbh.hdrsize = 0x10; + fsbh.shdrsize_min = 0x40; - fsb_subheader_len = read_16bitLE(fsb_mainheader_len,streamFile); - - /* "Check if the FSB is used as conatiner or as single file" */ - if (read_32bitBE(0x04,streamFile) != 0x01000000) + /* main header */ + fsbh.numsamples = read_32bitLE(h_off+0x04,streamFile); + fsbh.datasize = read_32bitLE(h_off+0x08,streamFile); + fsbh.shdrsize = 0x40; + fsbh.version = 0; + fsbh.flags = 0; + + s_off = offset+fsbh.hdrsize; + /* sample header */ + /* 0x00:name(len=0x20) */ + fsbh.lengthsamples = read_32bitLE(s_off+0x20,streamFile); + fsbh.lengthcompressedbytes = read_32bitLE(s_off+0x24,streamFile); + fsbh.deffreq = read_32bitLE(s_off+0x28,streamFile); + /* 0x2c:? 0x2e:? 0x30:? 0x32:? */ + fsbh.mode = read_32bitLE(s_off+0x34,streamFile); + fsbh.loopstart = read_32bitLE(s_off+0x38,streamFile); + fsbh.loopend = read_32bitLE(s_off+0x3c,streamFile); + + fsbh.numchannels = (fsbh.mode & FSOUND_STEREO) ? 2 : 1; + if (fsbh.loopend > fsbh.lengthsamples) /* this seems common... */ + fsbh.lengthsamples = fsbh.loopend; + } + else { /* other FSBs (common/extended format) */ + if (fsbh.id == 0x46534232) { /* "FSB2" */ + fsbh.meta_type = meta_FSB2; + fsbh.hdrsize = 0x10; + fsbh.shdrsize_min = 0x40; /* guessed */ + } else if (fsbh.id == 0x46534233) { /* "FSB3" */ + fsbh.meta_type = meta_FSB3; + fsbh.hdrsize = 0x18; + fsbh.shdrsize_min = 0x40; + } else if (fsbh.id == 0x46534234) { /* "FSB4" */ + fsbh.meta_type = meta_FSB4; + fsbh.hdrsize = 0x30; + fsbh.shdrsize_min = 0x50; + } else { + goto fail; + } + + /* main header */ + fsbh.numsamples = read_32bitLE(h_off+0x04,streamFile); + fsbh.shdrsize = read_32bitLE(h_off+0x08,streamFile); + fsbh.datasize = read_32bitLE(h_off+0x0c,streamFile); + if (fsbh.hdrsize > 0x10) { + fsbh.version = read_32bitLE(h_off+0x10,streamFile); + fsbh.flags = read_32bitLE(h_off+0x14,streamFile); + /* FSB4: 0x18:hash 0x20:guid */ + } else { + fsbh.version = 0; + fsbh.flags = 0; + } + + if (fsbh.version == FMOD_FSB_VERSION_3_1) { + fsbh.shdrsize_min = 0x50; + } else if (fsbh.version != 0 /* FSB2 */ + && fsbh.version != FMOD_FSB_VERSION_3_0 + && fsbh.version != FMOD_FSB_VERSION_4_0) { + goto fail; + } + + if (fsbh.shdrsize < fsbh.shdrsize_min) goto fail; + + s_off = offset+fsbh.hdrsize; + /* sample header */ + /* 0x00:size 0x02:name(len=size) */ + fsbh.lengthsamples = read_32bitLE(s_off+0x20,streamFile); + fsbh.lengthcompressedbytes = read_32bitLE(s_off+0x24,streamFile); + fsbh.loopstart = read_32bitLE(s_off+0x28,streamFile); + fsbh.loopend = read_32bitLE(s_off+0x2c,streamFile); + fsbh.mode = read_32bitLE(s_off+0x30,streamFile); + fsbh.deffreq = read_32bitLE(s_off+0x34,streamFile); + /* 0x38:defvol 0x3a:defpan 0x3c:defpri */ + fsbh.numchannels = read_16bitLE(s_off+0x3e,streamFile); + /* FSB3.1/4: 0x40:mindistance 0x44:maxdistance 0x48:varfreq/size_32bits 0x4c:varvol 0x4e:fsbh.varpan */ + /* 0x50:extended_data (of size_32bits, when fsbh.shdrsize > 0x50) */ + } + + /* FSB header ok, check other stuff */ + if (fsbh.numsamples != 1) { /* multistream */ + VGM_LOG("FSB numsamples > 1 found\n"); goto fail; - + } + /* XOR encryption for some FSB4 */ + if (fsbh.flags & FMOD_FSB_SOURCE_ENCRYPTED) { + VGM_LOG("FSB ENCRYPTED found\n"); + goto fail; + } #if 0 - /* Check channel count, multi-channel not supported and will be refused */ - if ((read_16bitLE(0x6E,streamFile) != 0x2) && - (read_16bitLE(0x6E,streamFile) != 0x1)) + /* sometimes there is garbage at the end or missing bytes? (Guitar Hero Wii) */ + if (fsbh.hdrsize + fsbh.shdrsize + fsbh.datasize != streamFile->get_size(streamFile) - offset) { + VGM_LOG("FSB wrong head/datasize found\n"); goto fail; + } #endif - start_offset = fsb_mainheader_len+fsb_subheader_len+0x10; - - /* Check the MPEG Sync Header */ - mp3ID = read_16bitBE(start_offset,streamFile); - if ((mp3ID&0xFFE0) != 0xFFE0) - goto fail; + start_offset = offset + fsbh.hdrsize + fsbh.shdrsize; + custom_data_offset = offset + fsbh.hdrsize + fsbh.shdrsize_min; /* DSP coefs, seek tables, etc */ - channel_count = read_16bitLE(fsb_mainheader_len+0x3E,streamFile); - if (channel_count != 1 && channel_count != 2) - goto fail; - - FSBFlag = read_32bitLE(fsb_mainheader_len+0x30,streamFile); - if (FSBFlag&0x2 || FSBFlag&0x4 || FSBFlag&0x6) - loop_flag = 1; - - num_samples = (read_32bitLE(fsb_mainheader_len+0x2C,streamFile)); - - mpeg_data = init_mpeg_codec_data(streamFile, start_offset, -1, -1, &mpeg_coding_type, &rate, &channels); // -1 to not check sample rate or channels - if (!mpeg_data) goto fail; - - //channel_count = channels; - sample_rate = rate; + /* Loops by default unless disabled (sometimes may add FSOUND_LOOP_NORMAL). Often streams + * repeat over and over (some tracks that shouldn't do this based on the flags, no real way to identify them). */ + loop_flag = !(fsbh.mode & FSOUND_LOOP_OFF); + /* ping-pong looping = no looping? (forward > reverse > forward) */ + VGM_ASSERT(fsbh.mode & FSOUND_LOOP_BIDI, "FSB BIDI looping found\n"); /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); + vgmstream = allocate_vgmstream(fsbh.numchannels,loop_flag); if (!vgmstream) goto fail; - vgmstream->sample_rate = sample_rate; - vgmstream->num_samples = num_samples; - vgmstream->channels = channel_count; - - /* Still WIP */ - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(fsb_mainheader_len+0x28,streamFile); - vgmstream->loop_end_sample = read_32bitLE(fsb_mainheader_len+0x2C,streamFile); - } - vgmstream->meta_type = meta_FSB_MPEG; + vgmstream->sample_rate = fsbh.deffreq; + vgmstream->num_samples = fsbh.lengthsamples; + vgmstream->loop_start_sample = fsbh.loopstart; + vgmstream->loop_end_sample = fsbh.loopend; + vgmstream->meta_type = fsbh.meta_type; - /* NOTE: num_samples seems to be quite wrong for MPEG */ - vgmstream->codec_data = mpeg_data; - vgmstream->layout_type = layout_mpeg; - vgmstream->coding_type = mpeg_coding_type; + /* parse format */ + if (fsbh.mode & FSOUND_MPEG) { + /* FSB3: ?; FSB4: Shatter, Way of the Samurai 3/4, Forza Horizon 1/2, Dragon Age Origins */ +#if defined(VGM_USE_MPEG) + mpeg_codec_data *mpeg_data = NULL; + coding_t mpeg_coding_type; -#if 0 - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitBE(0x18,streamFile)/960*1152; - vgmstream->loop_end_sample = read_32bitBE(0x1C,streamFile)/960*1152; - } -#endif - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - if(vgmstream->layout_type == layout_interleave) - { - 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; - } - } - - else if(vgmstream->layout_type == layout_mpeg) { - for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,MPEG_BUFFER_SIZE); - vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset=start_offset; - } - - } - else { goto fail; } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (mpeg_data) { - mpg123_delete(mpeg_data->m); - free(mpeg_data); - - if (vgmstream) { - vgmstream->codec_data = NULL; - } - } - if (vgmstream) close_vgmstream(vgmstream); -#endif - return NULL; -} - -#if 0 -// FSB5 MPEG -VGMSTREAM * init_vgmstream_fsb5_mpeg(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - int channel_count, channels, loop_flag, fsb_mainheader_len, fsb_subheader_len, FSBFlag, rate; - long sample_rate = 0, num_samples = 0; - uint16_t mp3ID; - -#ifdef VGM_USE_MPEG - mpeg_codec_data *mpeg_data = NULL; - coding_t mpeg_coding_type = coding_MPEG1_L3; -#endif - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("fsb",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) == 0x46534235) /* "FSB5" */ - { - fsb_mainheader_len = 0x3C; - } - else - { - goto fail; - } - - //fsb_subheader_len = read_16bitLE(fsb_mainheader_len,streamFile); - - /* "Check if the FSB is used as conatiner or as single file" */ - if (read_32bitBE(0x04,streamFile) != 0x01000000) - goto fail; - -#if 0 - /* Check channel count, multi-channel not supported and will be refused */ - if ((read_16bitLE(0x6E,streamFile) != 0x2) && - (read_16bitLE(0x6E,streamFile) != 0x1)) - goto fail; -#endif - - start_offset = fsb_mainheader_len+fsb_subheader_len+0x10; - - /* Check the MPEG Sync Header */ - mp3ID = read_16bitBE(start_offset,streamFile); - if ((mp3ID&0xFFE0) != 0xFFE0) - goto fail; - - channel_count = read_16bitLE(fsb_mainheader_len+0x3E,streamFile); - if (channel_count != 1 && channel_count != 2) - goto fail; - - FSBFlag = read_32bitLE(fsb_mainheader_len+0x30,streamFile); - if (FSBFlag&0x2 || FSBFlag&0x4 || FSBFlag&0x6) - loop_flag = 1; - - num_samples = (read_32bitLE(fsb_mainheader_len+0x2C,streamFile)); - -#ifdef VGM_USE_MPEG - mpeg_data = init_mpeg_codec_data(streamFile, start_offset, -1, -1, &mpeg_coding_type, &rate, &channels); // -1 to not check sample rate or channels + mpeg_data = init_mpeg_codec_data(streamFile, start_offset, vgmstream->sample_rate, vgmstream->channels, &mpeg_coding_type, NULL, NULL); if (!mpeg_data) goto fail; - //channel_count = channels; - sample_rate = rate; - -#else - // reject if no MPEG support - goto fail; -#endif - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - vgmstream->sample_rate = sample_rate; - vgmstream->num_samples = num_samples; - vgmstream->channels = channel_count; - - /* Still WIP */ - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(fsb_mainheader_len+0x28,streamFile); - vgmstream->loop_end_sample = read_32bitLE(fsb_mainheader_len+0x2C,streamFile); - } - vgmstream->meta_type = meta_FSB_MPEG; - -#ifdef VGM_USE_MPEG - /* NOTE: num_samples seems to be quite wrong for MPEG */ vgmstream->codec_data = mpeg_data; - vgmstream->layout_type = layout_mpeg; - vgmstream->coding_type = mpeg_coding_type; -#else - // reject if no MPEG support - goto fail; -#endif + vgmstream->coding_type = mpeg_coding_type; + vgmstream->layout_type = layout_mpeg; + /* struct mpg123_frameinfo mpeg_info; */ + /* if (MPG123_OK != mpg123_info(mpeg_data->m, &mpeg_info)) goto fail; */ + VGM_ASSERT(fsbh.mode & FSOUND_MPEG_LAYER2, "FSB FSOUND_MPEG_LAYER2 found\n"); + VGM_ASSERT(fsbh.mode & FSOUND_IGNORETAGS, "FSB FSOUND_IGNORETAGS found\n"); -#if 0 - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitBE(0x18,streamFile)/960*1152; - vgmstream->loop_end_sample = read_32bitBE(0x1C,streamFile)/960*1152; - } -#endif - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - if(vgmstream->layout_type == layout_interleave) - { - 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; - } + /* when these flags are set each MPEG frame is 0-padded at the end, and mpg123 will complain to stderr (but ignore them) + * no way to easily skip the padding so for now we'll just disable stderr output */ + if ((fsbh.flags & FMOD_FSB_SOURCE_MPEG_PADDED) || (fsbh.flags & FMOD_FSB_SOURCE_MPEG_PADDED4)) { + mpeg_set_error_logging(mpeg_data, 0); } -#ifdef VGM_USE_MPEG - else if(vgmstream->layout_type == layout_mpeg) { - for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,MPEG_BUFFER_SIZE); - vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset=start_offset; - } +#elif defined(VGM_USE_FFMPEG) + /* FFmpeg can't properly read FSB4 or FMOD's 0-padded MPEG data @ start_offset, this won't work */ + ffmpeg_codec_data *ffmpeg_data = NULL; - } + ffmpeg_data = init_ffmpeg_offset(streamFile, 0, streamFile->get_size(streamFile)); + if ( !ffmpeg_data ) goto fail; + vgmstream->codec_data = ffmpeg_data; + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; + +#else + VGM_LOG("FSB4 MPEG found\n"); + goto fail; #endif - else { goto fail; } } + else if (fsbh.mode & FSOUND_IMAADPCM) { /* (codec 0x69, Voxware Byte Aligned) */ + if (fsbh.mode & FSOUND_IMAADPCMSTEREO) { /* noninterleaved, true stereo IMA */ + /* FSB4: Shatter, Blade Kitten (PC), Hard Corps: Uprising (PS3) */ + vgmstream->coding_type = coding_XBOX; /* todo not always working in Hard Corps, interleave problem? */ + vgmstream->layout_type = layout_none; + //VGM_LOG("FSB FSOUND_IMAADPCMSTEREO found\n"); + } else { + /* FSB3: Bioshock (PC); FSB4: Blade Kitten (PC) */ + vgmstream->coding_type = coding_XBOX; + vgmstream->layout_type = layout_none; + //VGM_LOG("FSB FSOUND_IMAADPCM found\n"); +#if 0 + if (fsbh.numchannels > 2) { /* Blade Kitten 5.1 */ + vgmstream->coding_type = coding_MS_IMA; + vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = 0x24 * vgmstream->channels; + } +#endif + + } + } + else if (fsbh.mode & FSOUND_VAG) { + /* FSB1: Jurassic Park Operation Genesis + * FSB3: ?; FSB4: Spider Man Web of Shadows, Speed Racer, Silent Hill: Shattered Memories (PS2) */ + + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x10; + } + else if (fsbh.mode & FSOUND_XMA) { + /* FSB4: Xbox360 Armored Core V, Hard Corps, Halo Anniversary */ +#if defined(VGM_USE_FFMPEG) + ffmpeg_codec_data *ffmpeg_data = NULL; + uint8_t buf[FAKE_RIFF_BUFFER_SIZE]; + size_t bytes, block_size, block_count; + /* not accurate but not needed by FFmpeg */ + block_size = 2048; + block_count = fsbh.datasize / block_size; /* read_32bitLE(custom_data_offset +0x14) -1? */ + + /* make a fake riff so FFmpeg can parse the XMA2 */ + bytes = header_make_riff_xma2(buf, FAKE_RIFF_BUFFER_SIZE, fsbh.lengthsamples, fsbh.datasize, fsbh.numchannels, fsbh.deffreq, block_count, block_size); + if (bytes <= 0) + goto fail; + + ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,fsbh.datasize); + if ( !ffmpeg_data ) goto fail; + vgmstream->codec_data = ffmpeg_data; + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; + +#else + VGM_LOG("FSB XMA found\n"); + goto fail; +#endif + } + else if (fsbh.mode & FSOUND_GCADPCM) { + /* FSB3: ?; FSB4: de Blob (Wii), Night at the Museum, M. Night Shyamalan Avatar: The Last Airbender */ + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave_byte; + vgmstream->interleave_block_size = 0x2; + header_dsp_read_coefs_be(vgmstream, streamFile, custom_data_offset, 0x2e); + } + else if (fsbh.mode & FSOUND_OGG) { + /* FSB4: ? (possibly FMOD's custom ogg) */ + + VGM_LOG("FSB4 FSOUND_OGG found\n"); + goto fail; + } + else if (fsbh.mode & FSOUND_CELT) { + /* FSB4: ? (The Witcher 2?) */ + + VGM_LOG("FSB4 FSOUND_CELT found\n"); + goto fail; + } + else { /* PCM */ + if (fsbh.mode & FSOUND_8BITS) { + VGM_LOG("FSB FSOUND_8BITS found\n"); + if (fsbh.mode & FSOUND_UNSIGNED) { + vgmstream->coding_type = coding_PCM8_U; /* ? coding_PCM8_U_int */ + } else { /* FSOUND_SIGNED */ + vgmstream->coding_type = coding_PCM8; /* ? coding_PCM8_int / coding_PCM8_SB_int */ + } + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x1; + } else { /* Rocket Knight (PC), Another Century's Episode R (PS3), Toy Story 3 (Wii) */ + /* sometimes FSOUND_STEREO/FSOUND_MONO is not set (ex. Dead Space iOS), + * or only STEREO/MONO but not FSOUND_8BITS/FSOUND_16BITS is set */ + if (fsbh.flags & FMOD_FSB_SOURCE_BIGENDIANPCM) { + vgmstream->coding_type = coding_PCM16BE; + } else { + vgmstream->coding_type = coding_PCM16LE; /* ? coding_PCM16LE_int ? */ + } + vgmstream->layout_type = vgmstream->channels == 1 ? layout_none : layout_interleave; /* needed? */ + vgmstream->interleave_block_size = 0x2; + } + } + + /* full channel interleave, used in short streams (ex. de Blob Wii SFXs) */ + if (fsbh.numchannels > 1 && (fsbh.flags & FMOD_FSB_SOURCE_NOTINTERLEAVED)) { + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = fsbh.lengthcompressedbytes / fsbh.numchannels; + } + + + /* open the file for reading */ + if ( !header_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: -#ifdef VGM_USE_MPEG - if (mpeg_data) { - mpg123_delete(mpeg_data->m); - free(mpeg_data); - - if (vgmstream) { - vgmstream->codec_data = NULL; - } - } -#endif - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } -#endif diff --git a/src/meta/meta.h b/src/meta/meta.h index 1f32637d..fdb54f8d 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -182,18 +182,12 @@ VGMSTREAM * init_vgmstream_aus(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_rws(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_fsb1(STREAMFILE * streamFile); - -VGMSTREAM * init_vgmstream_fsb3(STREAMFILE * streamFile); - -VGMSTREAM * init_vgmstream_fsb4(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_fsb(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_fsb4_wav(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_fsb5(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_fsb_mpeg(STREAMFILE * streamFile); - VGMSTREAM * init_vgmstream_rwx(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_xwb(STREAMFILE * streamFile); diff --git a/src/vgmstream.c b/src/vgmstream.c index 2aab59ed..6bdb67fc 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -92,10 +92,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_hgc1, init_vgmstream_aus, init_vgmstream_rws, - init_vgmstream_fsb1, - // init_vgmstream_fsb2, - init_vgmstream_fsb3, - init_vgmstream_fsb4, + init_vgmstream_fsb, init_vgmstream_fsb4_wav, init_vgmstream_fsb5, init_vgmstream_rwx, @@ -300,7 +297,6 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_ngc_nst_dsp, init_vgmstream_baf, init_vgmstream_ps3_msf, - init_vgmstream_fsb_mpeg, init_vgmstream_nub_vag, init_vgmstream_ps3_past, init_vgmstream_ps3_sgdx, @@ -2620,18 +2616,15 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { case meta_FSB1: snprintf(temp,TEMPSIZE,"FMOD Sample Bank (FSB1) Header"); break; - case meta_FSB3_0: - snprintf(temp,TEMPSIZE,"FMOD Sample Bank (FSB3.0) Header"); + case meta_FSB2: + snprintf(temp,TEMPSIZE,"FMOD Sample Bank (FSB2) Header"); break; - case meta_FSB3_1: - snprintf(temp,TEMPSIZE,"FMOD Sample Bank (FSB3.1) Header"); + case meta_FSB3: + snprintf(temp,TEMPSIZE,"FMOD Sample Bank (FSB3) Header"); break; case meta_FSB4: snprintf(temp,TEMPSIZE,"FMOD Sample Bank (FSB4) Header"); break; - case meta_FSB4_WAV: - snprintf(temp,TEMPSIZE,"FMOD Sample Bank (FSB4) with additional 'WAV' Header"); - break; case meta_FSB5: snprintf(temp,TEMPSIZE,"FMOD Sample Bank (FSB5) Header"); break; @@ -3170,9 +3163,6 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { break; case meta_PS3_MSF: snprintf(temp,TEMPSIZE,"PS3 MSF header"); - break; - case meta_FSB_MPEG: - snprintf(temp,TEMPSIZE,"FSB MPEG header"); break; case meta_NUB_VAG: snprintf(temp,TEMPSIZE,"VAG (NUB) header"); diff --git a/src/vgmstream.h b/src/vgmstream.h index 58930651..105599ef 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -328,11 +328,9 @@ typedef enum { meta_AUS, /* Variuos Capcom Games */ meta_RWS, /* Variuos Konami Games */ meta_FSB1, /* FMOD Sample Bank, version 1 */ - meta_FSB3_0, /* FMOD Sample Bank, version 3.0 */ - meta_FSB3_1, /* FMOD Sample Bank, version 3.1 */ + meta_FSB2, /* FMOD Sample Bank, version 2 */ + meta_FSB3, /* FMOD Sample Bank, version 3.0/3.1 */ meta_FSB4, /* FMOD Sample Bank, version 4 */ - meta_FSB_MPEG, /* Just Test */ - meta_FSB4_WAV, /* FMOD Sample Bank, version 4 with "WAV" Header */ meta_FSB5, /* FMOD Sample Bank, version 5 */ meta_RWX, /* Air Force Delta Storm (XBOX) */ meta_XWB, /* King of Fighters (XBOX) */ From ee5a40224d9b2128a7bf0bd7d4398352e005000c Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 29 Dec 2016 23:34:21 +0100 Subject: [PATCH 15/21] Added PS ADPCM of configurable frame size (FF XI, Blur, Afrika) This fuses the FF XI/BSF/Short VAG decoder variants into a single one (FF XI alone has 4 possible frame sizes); also fixed FF XI sample rate and some cleanup. --- src/coding/coding.h | 6 +- src/coding/psx_decoder.c | 127 +++++++++------------------------------ src/meta/baf.c | 49 +++++++-------- src/meta/bgw.c | 117 ++++++++++++++++++------------------ src/meta/ps3_sgh_sgb.c | 2 +- src/vgmstream.c | 48 +++------------ src/vgmstream.h | 4 +- 7 files changed, 124 insertions(+), 229 deletions(-) diff --git a/src/coding/coding.h b/src/coding/coding.h index d6c092c0..4ae8420c 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -56,13 +56,9 @@ void decode_invert_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelsp void decode_psx_badflags(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); -void decode_ffxi_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); - -void decode_baf_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); - void decode_hevag_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); -void decode_short_vag_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_vag_adpcm_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size); void decode_xa(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void init_get_high_nibble(VGMSTREAM * vgmstream); diff --git a/src/coding/psx_decoder.c b/src/coding/psx_decoder.c index c8484269..81ab8e31 100644 --- a/src/coding/psx_decoder.c +++ b/src/coding/psx_decoder.c @@ -3,8 +3,7 @@ #include "../util.h" /* for some algos, maybe closer to the real thing */ -#define VAG_USE_INTEGER_TABLE 0 - +#define VAG_USE_INTEGER_TABLE 0 /* PS ADPCM table (precalculated divs) */ static const double VAG_f[5][2] = { @@ -14,6 +13,7 @@ static const double VAG_f[5][2] = { { 98.0 / 64.0 , -55.0 / 64.0 }, { 122.0 / 64.0 , -60.0 / 64.0 } }; +#if VAG_USE_INTEGER_TABLE /* PS ADPCM table */ static const int8_t VAG_coefs[5][2] = { { 0 , 0 }, @@ -22,7 +22,7 @@ static const int8_t VAG_coefs[5][2] = { { 98 , -55 }, { 122 , -60 } }; - +#endif /* PSVita ADPCM table */ static const int16_t HEVAG_coefs[128][4] = { @@ -294,84 +294,6 @@ void decode_psx_badflags(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel stream->adpcm_history2_32=hist2; } -/* FF XI's Vag-ish format */ -void decode_ffxi_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { - - int predict_nr, shift_factor, sample; - int32_t hist1=stream->adpcm_history1_32; - int32_t hist2=stream->adpcm_history2_32; - - short scale; - int i; - int32_t sample_count; - int32_t predictor; - - int framesin = first_sample/16; - - predict_nr = read_8bit(stream->offset+framesin*9,stream->streamfile) >> 4; - shift_factor = read_8bit(stream->offset+framesin*9,stream->streamfile) & 0xf; - first_sample = first_sample % 16; - - for (i=first_sample,sample_count=0; ioffset+(framesin*9)+1+i/2,stream->streamfile); - - sample=0; - - scale = ((i&1 ? - sample_byte >> 4 : - sample_byte & 0x0f)<<12); - -#if !VAG_USE_INTEGER_TABLE - predictor = - (int)((hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1])); -#else - predictor = - (hist1*VAG_coefs[predict_nr][0]+hist2*VAG_coefs[predict_nr][1])/64; -#endif - sample=(scale >> shift_factor) + predictor; - - outbuf[sample_count] = clamp16(sample); - hist2=hist1; - hist1=sample; - } - stream->adpcm_history1_32=hist1; - stream->adpcm_history2_32=hist2; -} - -void decode_baf_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { - - int predict_nr, shift_factor, sample; - int32_t hist1=stream->adpcm_history1_32; - int32_t hist2=stream->adpcm_history2_32; - - short scale; - int i; - int32_t sample_count; - - int framesin = first_sample/64; - - predict_nr = read_8bit(stream->offset+framesin*33,stream->streamfile) >> 4; - shift_factor = read_8bit(stream->offset+framesin*33,stream->streamfile) & 0xf; - - first_sample = first_sample % 64; - - for (i=first_sample,sample_count=0; ioffset+(framesin*33)+1+i/2,stream->streamfile); - - scale = ((i&1 ? - sample_byte >> 4 : - sample_byte & 0x0f)<<12); - - sample=(int)((scale >> shift_factor)+hist1*VAG_f[predict_nr][0]+hist2*VAG_f[predict_nr][1]); - - outbuf[sample_count] = clamp16(sample); - hist2=hist1; - hist1=sample; - } - stream->adpcm_history1_32=hist1; - stream->adpcm_history2_32=hist2; -} - /** * Sony's HEVAG (High Efficiency VAG) ADPCM, used in PSVita games (hardware decoded). @@ -442,11 +364,10 @@ void decode_hevag_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channels /** - * Short VAG ADPCM, found in PS3 Afrika (SGDX type 5). - * Uses 8 byte blocks and no flag. + * PS ADPCM of configurable size, with no flag. + * Found in PS3 Afrika (SGDX type 5) in size 4, FF XI in sizes 3/5/9/41, Blur and James Bond in size 33. */ -void decode_short_vag_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { - +void decode_vag_adpcm_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size) { uint8_t predict_nr, shift, byte; int16_t scale = 0; @@ -454,37 +375,45 @@ void decode_short_vag_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int chan int32_t hist1 = stream->adpcm_history1_32; int32_t hist2 = stream->adpcm_history2_32; - int i, sample_count; + int i, sample_count, bytes_per_frame, samples_per_frame; + const int header_size = 1; + bytes_per_frame = frame_size - header_size; + samples_per_frame = bytes_per_frame * 2; - int framesin = first_sample / 6; + int framesin = first_sample / samples_per_frame; - /* 2 byte header: predictor = 1st, shift = 2nd */ - byte = (uint8_t)read_8bit(stream->offset+framesin*8+0,stream->streamfile); + /* 1 byte header: predictor = 1st, shift = 2nd */ + byte = (uint8_t)read_8bit(stream->offset+framesin*frame_size+0,stream->streamfile); predict_nr = byte >> 4; shift = byte & 0x0f; - first_sample = first_sample % 6; + first_sample = first_sample % samples_per_frame; for (i = first_sample, sample_count = 0; i < first_sample + samples_to_do; i++, sample_count += channelspacing) { sample = 0; if (predict_nr < 5) { - - if (i & 1) {/* odd/even nibble */ - scale = byte >> 4; - } else { - byte = (uint8_t)read_8bit(stream->offset+(framesin*8)+1+i/2,stream->streamfile); + if (i%2 != 1) { /* low nibble first */ + byte = (uint8_t)read_8bit(stream->offset+(framesin*frame_size)+header_size+i/2,stream->streamfile); scale = (byte & 0x0f); + } else { /* high nibble last */ + scale = byte >> 4; } + scale = scale << 12; /* shift + sign extend (only if scale is int16_t) */ /*if (scale > 7) { scale = scale - 16; }*/ - scale = scale << 12; /* shift + sign extend only if scale is int16_t */ - - sample = (hist1 * VAG_coefs[predict_nr][0] + +#if VAG_USE_INTEGER_TABLE + sample = (scale >> shift) + + (hist1 * VAG_coefs[predict_nr][0] + hist2 * VAG_coefs[predict_nr][1] ) / 64; - sample = sample + (scale >> shift); + sample = sample + ; +#else + sample = (int)( (scale >> shift) + + (hist1 * VAG_f[predict_nr][0] + + hist2 * VAG_f[predict_nr][1]) ); +#endif } outbuf[sample_count] = clamp16(sample); diff --git a/src/meta/baf.c b/src/meta/baf.c index cbd57315..2eb7bfd3 100644 --- a/src/meta/baf.c +++ b/src/meta/baf.c @@ -1,36 +1,44 @@ #include "meta.h" #include "../util.h" +#include "../header.h" /* .BAF - Bizarre Creations (Blur, James Bond 007: Blood Stone, etc) */ VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t WAVE_size,DATA_size; + off_t WAVE_size, DATA_size; off_t start_offset; long sample_count; + int sample_rate; const int frame_size = 33; - const int frame_samples = 64; + const int frame_samples = (frame_size-1) * 2; int channels; int loop_flag = 0; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("baf",filename_extension(filename))) goto fail; + /* check extensions */ + if ( !header_check_extensions(streamFile, "baf") ) + goto fail; /* check WAVE */ - if (read_32bitBE(0,streamFile) != 0x57415645) goto fail; + if (read_32bitBE(0,streamFile) != 0x57415645) /* "WAVE" */ + goto fail; WAVE_size = read_32bitBE(4,streamFile); - if (WAVE_size != 0x4c) goto fail; + if (WAVE_size != 0x4c) /* && WAVE_size != 0x50*/ + goto fail; /* check for DATA after WAVE */ - if (read_32bitBE(WAVE_size,streamFile) != 0x44415441) goto fail; + if (read_32bitBE(WAVE_size,streamFile) != 0x44415441) /* "DATA"*/ + goto fail; /* check that WAVE size is data size */ DATA_size = read_32bitBE(0x30,streamFile); if (read_32bitBE(WAVE_size+4,streamFile)-8 != DATA_size) goto fail; + /*if (WAVE_size == 0x50) sample_count = DATA_size * frame_samples / frame_size / channels;*/ sample_count = read_32bitBE(0x44,streamFile); + /*if (WAVE_size == 0x50) sample_rate = read_32bitBE(0x3c,streamFile);*/ + sample_rate = read_32bitBE(0x40,streamFile); + /* unsure how to detect channel count, so use a hack */ channels = (long long)DATA_size / frame_size * frame_samples / sample_count; @@ -40,33 +48,22 @@ VGMSTREAM * init_vgmstream_baf(STREAMFILE *streamFile) { /* fill in the vital statistics */ start_offset = WAVE_size + 8; - vgmstream->sample_rate = read_32bitBE(0x40,streamFile); + vgmstream->sample_rate = sample_rate; vgmstream->num_samples = sample_count; - vgmstream->coding_type = coding_BAF_ADPCM; + vgmstream->coding_type = coding_VAG_ADPCM_cfg; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = frame_size; vgmstream->meta_type = meta_BAF; - /* open the file for reading by each channel */ - { - int i; - STREAMFILE *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; - - } - } + /* open the file for reading */ + if ( !header_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } diff --git a/src/meta/bgw.c b/src/meta/bgw.c index 841d95d6..cbe9f666 100644 --- a/src/meta/bgw.c +++ b/src/meta/bgw.c @@ -1,80 +1,93 @@ #include "meta.h" #include "../util.h" +#include "../header.h" -/* BGW (FF XI) */ +/* BGW (FF XI) + * + * Some info from POLUtils + */ VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; + uint32_t codec, filesize, blocksize, sample_rate; int32_t loop_start; + uint8_t block_align; + off_t start_offset; int loop_flag = 0; int channel_count; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("bgw",filename_extension(filename))) goto fail; - - /* "BGMStream" */ - if (read_32bitBE(0,streamFile) != 0x42474d53 || - read_32bitBE(4,streamFile) != 0x74726561 || - read_32bitBE(8,streamFile) != 0x6d000000 || - read_32bitBE(12,streamFile) != 0) goto fail; - - /* check file size with header value */ - if (read_32bitLE(0x10,streamFile) != get_streamfile_size(streamFile)) + /* check extensions */ + if ( !header_check_extensions(streamFile, "bgw") ) goto fail; - channel_count = read_8bit(0x2e,streamFile); + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x42474d53 || /* "BGMS" */ + read_32bitBE(0x04,streamFile) != 0x74726561 || /* "trea" */ + read_32bitBE(0x08,streamFile) != 0x6d000000 ) /* "m\0\0\0" */ + goto fail; + + codec = read_32bitLE(0x0c,streamFile); + filesize = read_32bitLE(0x10,streamFile); + /*file_id = read_32bitLE(0x14,streamFile);*/ + blocksize = read_32bitLE(0x18,streamFile); loop_start = read_32bitLE(0x1c,streamFile); + sample_rate = (read_32bitLE(0x20,streamFile) + read_32bitLE(0x24,streamFile)) & 0xFFFFFFFF; /* bizarrely obfuscated sample rate */ + start_offset = read_32bitLE(0x28,streamFile); + /*0x2c: unk (vol?) */ + /*0x2d: unk (0x10?) */ + channel_count = read_8bit(0x2e,streamFile); + block_align = read_8bit(0x2f,streamFile); + + + /* check file size with header value */ + if (filesize != get_streamfile_size(streamFile)) + goto fail; + loop_flag = (loop_start > 0); - + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ - start_offset = read_32bitLE(0x28,streamFile); - vgmstream->channels = channel_count; - vgmstream->sample_rate = 44100; - vgmstream->coding_type = coding_FFXI; - vgmstream->num_samples = read_32bitLE(0x18,streamFile)*16; + vgmstream->meta_type = meta_FFXI_BGW; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = blocksize * block_align; if (loop_flag) { - vgmstream->loop_start_sample = (loop_start-1)*16; + vgmstream->loop_start_sample = (loop_start-1) * block_align; vgmstream->loop_end_sample = vgmstream->num_samples; } - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 9; - vgmstream->meta_type = meta_FFXI_BGW; + switch (codec) { + case 0: { /* ADPCM */ + vgmstream->coding_type = coding_VAG_ADPCM_cfg; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = (block_align / 2) + 1; /* half, even if channels = 1 */ + break; + } + case 1: /* PCM */ + case 3: /* ATRAC3 (encrypted) */ + default: + goto fail; + } + + /* 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+i*9; - - } - } + if ( !header_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; } /* .spw (SEWave, PlayOnline viewer for FFXI), very similar to bgw */ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; off_t start_offset; int loop_flag = 0; @@ -82,8 +95,8 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) { int channel_count; /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("spw",filename_extension(filename))) goto fail; + if ( !header_check_extensions(streamFile, "spw") ) + goto fail; /* "SeWave" */ if (read_32bitBE(0,streamFile) != 0x53655761 || @@ -105,7 +118,7 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) { start_offset = read_32bitLE(0x24,streamFile); vgmstream->channels = channel_count; vgmstream->sample_rate = 44100; - vgmstream->coding_type = coding_FFXI; + vgmstream->coding_type = coding_VAG_ADPCM_cfg; vgmstream->num_samples = read_32bitLE(0x14,streamFile)*16; if (loop_flag) { vgmstream->loop_start_sample = (loop_start-1)*16; @@ -116,20 +129,10 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) { vgmstream->interleave_block_size = 9; vgmstream->meta_type = meta_FFXI_SPW; + /* 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+i*9; - - } - } + if ( !header_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; return vgmstream; diff --git a/src/meta/ps3_sgh_sgb.c b/src/meta/ps3_sgh_sgb.c index ce0ec106..e0a4cf29 100644 --- a/src/meta/ps3_sgh_sgb.c +++ b/src/meta/ps3_sgh_sgb.c @@ -195,7 +195,7 @@ VGMSTREAM * init_vgmstream_ps3_sgdx(STREAMFILE *streamFile) { } #endif case 0x05: /* Short VAG ADPCM */ - vgmstream->coding_type = coding_SHORT_VAG_ADPCM; + vgmstream->coding_type = coding_VAG_ADPCM_cfg; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x4; diff --git a/src/vgmstream.c b/src/vgmstream.c index 6bdb67fc..dba4476d 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1024,20 +1024,16 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_AICA: return 2; case coding_NGC_AFC: - case coding_FFXI: - return 16; case coding_PSX: case coding_PSX_badflags: case coding_invert_PSX: case coding_HEVAG_ADPCM: case coding_XA: return 28; - case coding_SHORT_VAG_ADPCM: - return 6; + case coding_VAG_ADPCM_cfg: + return (vgmstream->interleave_block_size - 1) * 2; /* decodes 1 byte into 2 bytes */ case coding_XBOX: case coding_INT_XBOX: - case coding_BAF_ADPCM: - return 64; case coding_EAXA: return 28; case coding_MAXIS_ADPCM: @@ -1155,16 +1151,14 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_SNDS_IMA: return 0; case coding_NGC_AFC: - case coding_FFXI: - return 9; case coding_PSX: case coding_PSX_badflags: case coding_HEVAG_ADPCM: case coding_invert_PSX: case coding_NDS_PROCYON: return 16; - case coding_SHORT_VAG_ADPCM: - return 4; + case coding_VAG_ADPCM_cfg: + return vgmstream->interleave_block_size; case coding_XA: return 14*vgmstream->channels; case coding_XBOX: @@ -1184,8 +1178,6 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { return 1; case coding_APPLE_IMA4: return 34; - case coding_BAF_ADPCM: - return 33; case coding_LSF: return 28; #ifdef VGM_USE_G7221 @@ -1424,20 +1416,6 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do); } break; - case coding_FFXI: - for (chan=0;chanchannels;chan++) { - decode_ffxi_adpcm(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); - } - break; - case coding_BAF_ADPCM: - for (chan=0;chanchannels;chan++) { - decode_baf_adpcm(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); - } - break; case coding_HEVAG_ADPCM: for (chan=0;chanchannels;chan++) { decode_hevag_adpcm(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, @@ -1445,11 +1423,11 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do); } break; - case coding_SHORT_VAG_ADPCM: + case coding_VAG_ADPCM_cfg: for (chan=0;chanchannels;chan++) { - decode_short_vag_adpcm(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + decode_vag_adpcm_configurable(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + samples_to_do, vgmstream->interleave_block_size); } break; case coding_XA: @@ -1763,7 +1741,7 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) { vgmstream->loop_ch[i].adpcm_history2_32 = vgmstream->ch[i].adpcm_history2_32; } } - /* todo preserve hevag, baf_adpcm, etc history? */ + /* todo preserve hevag/adjustable_vag_adpcm/others history? */ #ifdef DEBUG { @@ -1973,17 +1951,11 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { case coding_invert_PSX: snprintf(temp,TEMPSIZE,"BMDX \"encrypted\" Playstation 4-bit ADPCM"); break; - case coding_FFXI: - snprintf(temp,TEMPSIZE,"FFXI Playstation-ish 4-bit ADPCM"); - break; - case coding_BAF_ADPCM: - snprintf(temp,TEMPSIZE,"Bizarre Creations Playstation-ish 4-bit ADPCM"); - break; case coding_HEVAG_ADPCM: snprintf(temp,TEMPSIZE,"PSVita HEVAG ADPCM"); break; - case coding_SHORT_VAG_ADPCM: - snprintf(temp,TEMPSIZE,"Short VAG (SGXD type 5) ADPCM"); + case coding_VAG_ADPCM_cfg: + snprintf(temp,TEMPSIZE,"Playstation 4-bit ADPCM (configurable)"); break; case coding_XA: snprintf(temp,TEMPSIZE,"CD-ROM XA 4-bit ADPCM"); diff --git a/src/vgmstream.h b/src/vgmstream.h index 105599ef..bc11a34b 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -91,10 +91,8 @@ typedef enum { coding_PSX, /* PSX & PS2 ADPCM */ coding_invert_PSX, /* PSX ADPCM with some weirdness */ coding_PSX_badflags, /* with garbage in the flags byte */ - coding_FFXI, /* FF XI PSX-ish ADPCM */ - coding_BAF_ADPCM, /* Bizarre Creations PSX-ish ADPCM */ coding_HEVAG_ADPCM, /* PSVita games */ - coding_SHORT_VAG_ADPCM, /* SGXD type 5 (PS3 Afrika) */ + coding_VAG_ADPCM_cfg, /* VAG with configurable frame size: FF XI, SGXD type 5, Bizarre Creations */ coding_XA, /* PSX CD-XA */ coding_XBOX, /* XBOX IMA */ coding_INT_XBOX, /* XBOX 'real interleaved' IMA */ From 9d33b4258487f452a718c595c1e1e3c5f483ac14 Mon Sep 17 00:00:00 2001 From: bnnm Date: Mon, 2 Jan 2017 15:24:10 +0100 Subject: [PATCH 16/21] Improved SPW (PCM, sample rate) --- src/meta/bgw.c | 112 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 38 deletions(-) diff --git a/src/meta/bgw.c b/src/meta/bgw.c index cbe9f666..5eb0489e 100644 --- a/src/meta/bgw.c +++ b/src/meta/bgw.c @@ -2,7 +2,8 @@ #include "../util.h" #include "../header.h" -/* BGW (FF XI) +/** + * BGW - Final Fantasy XI (PC) music files. * * Some info from POLUtils */ @@ -13,8 +14,7 @@ VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) { uint8_t block_align; off_t start_offset; - int loop_flag = 0; - int channel_count; + int channel_count, loop_flag = 0; /* check extensions */ if ( !header_check_extensions(streamFile, "bgw") ) @@ -52,82 +52,119 @@ VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) { /* fill in the vital statistics */ vgmstream->meta_type = meta_FFXI_BGW; vgmstream->sample_rate = sample_rate; - vgmstream->num_samples = blocksize * block_align; - if (loop_flag) { - vgmstream->loop_start_sample = (loop_start-1) * block_align; - vgmstream->loop_end_sample = vgmstream->num_samples; - } switch (codec) { - case 0: { /* ADPCM */ + case 0: /* PS ADPCM */ vgmstream->coding_type = coding_VAG_ADPCM_cfg; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = (block_align / 2) + 1; /* half, even if channels = 1 */ + + vgmstream->num_samples = blocksize * block_align; + if (loop_flag) { + vgmstream->loop_start_sample = (loop_start-1) * block_align; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + break; - } - case 1: /* PCM */ + case 3: /* ATRAC3 (encrypted) */ default: goto fail; } - /* open the file for reading */ if ( !header_open_stream(vgmstream, streamFile, start_offset) ) goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: close_vgmstream(vgmstream); return NULL; } -/* .spw (SEWave, PlayOnline viewer for FFXI), very similar to bgw */ +/** + * SPW (SEWave), PlayOnline viewer for Final Fantasy XI (PC) + */ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; + uint32_t codec, filesize, blocksize, sample_rate; + int32_t loop_start; + uint8_t block_align; off_t start_offset; - int loop_flag = 0; - int32_t loop_start; - int channel_count; + int channel_count, loop_flag = 0; - /* check extension, case insensitive */ - if ( !header_check_extensions(streamFile, "spw") ) + /* check extensions */ + if ( !header_check_extensions(streamFile, "spw") ) goto fail; - /* "SeWave" */ - if (read_32bitBE(0,streamFile) != 0x53655761 || - read_32bitBE(4,streamFile) != 0x76650000) goto fail; + /* check header */ + if (read_32bitBE(0,streamFile) != 0x53655761 || /* "SeWa" */ + read_32bitBE(4,streamFile) != 0x76650000) /* "ve\0\0" */ + goto fail; /* check file size with header value */ if (read_32bitLE(0x8,streamFile) != get_streamfile_size(streamFile)) goto fail; - channel_count = read_8bit(0x2a,streamFile); + filesize = read_32bitLE(0x08,streamFile); + codec = read_32bitLE(0x0c,streamFile); + /*file_id = read_32bitLE(0x10,streamFile);*/ + blocksize = read_32bitLE(0x14,streamFile); loop_start = read_32bitLE(0x18,streamFile); + sample_rate = (read_32bitLE(0x1c,streamFile) + read_32bitLE(0x20,streamFile)) & 0xFFFFFFFF; /* bizarrely obfuscated sample rate */ + start_offset = read_32bitLE(0x24,streamFile); + /*0x2c: unk (0x00?) */ + /*0x2d: unk (0x00/01?) */ + channel_count = read_8bit(0x2a,streamFile); + block_align = read_8bit(0x2b,streamFile); + /*0x2c: unk (0x01 when PCM, 0x10 when VAG?) */ + + /* check file size with header value */ + if (filesize != get_streamfile_size(streamFile)) + goto fail; + loop_flag = (loop_start > 0); - + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ - start_offset = read_32bitLE(0x24,streamFile); - vgmstream->channels = channel_count; - vgmstream->sample_rate = 44100; - vgmstream->coding_type = coding_VAG_ADPCM_cfg; - vgmstream->num_samples = read_32bitLE(0x14,streamFile)*16; - if (loop_flag) { - vgmstream->loop_start_sample = (loop_start-1)*16; - vgmstream->loop_end_sample = vgmstream->num_samples; - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 9; vgmstream->meta_type = meta_FFXI_SPW; + vgmstream->sample_rate = sample_rate; + + switch (codec) { + case 0: /* PS ADPCM */ + vgmstream->coding_type = coding_VAG_ADPCM_cfg; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = (block_align / 2) + 1; /* half, even if channels = 1 */ + + vgmstream->num_samples = blocksize * block_align; + if (loop_flag) { + vgmstream->loop_start_sample = (loop_start-1) * block_align;; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + break; + + case 1: /* PCM */ + vgmstream->coding_type = coding_PCM16LE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x02; + + vgmstream->num_samples = blocksize; + if (loop_flag) { + vgmstream->loop_start_sample = (loop_start-1); + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + break; + default: + goto fail; + } /* open the file for reading */ @@ -136,8 +173,7 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) { return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } From a79cc5546b11a9e92a9035a8b3e6b36b1976654a Mon Sep 17 00:00:00 2001 From: bnnm Date: Mon, 2 Jan 2017 15:41:18 +0100 Subject: [PATCH 17/21] Fix a rare case of silence/0-read at the edge of some files This was only noticeable in some FFmpeg files, since it uses an IO buffer size that didn't align with foobar's. --- fb2k/foostream.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fb2k/foostream.cpp b/fb2k/foostream.cpp index 79855297..97312096 100644 --- a/fb2k/foostream.cpp +++ b/fb2k/foostream.cpp @@ -49,13 +49,14 @@ static size_t read_the_rest_foo(uint8_t * dest, off_t offset, size_t length, FOO streamfile->validsize=0; try { - if(offset >= streamfile->m_file->get_size(*streamfile->p_abort)) { + if(offset > streamfile->m_file->get_size(*streamfile->p_abort)) { /* Update offset at end of file */ streamfile->offset = streamfile->m_file->get_size(*streamfile->p_abort); return length_read; } streamfile->m_file->seek(offset,*streamfile->p_abort); - if (streamfile->m_file->is_eof(*streamfile->p_abort)) return length_read; + //if (streamfile->m_file->is_eof(*streamfile->p_abort)) /* allow edge case of offset=filesize */ + // return length_read; } catch (...) { streamfile->offset = streamfile->m_file->get_size(*streamfile->p_abort); #ifdef PROFILE_STREAMFILE From a77d4d21ceea8bbbf7680ad996ee4a7c0db92492 Mon Sep 17 00:00:00 2001 From: bnnm Date: Mon, 2 Jan 2017 15:42:26 +0100 Subject: [PATCH 18/21] Manually setting layout_none was not needed in mono PCM files --- src/meta/fsb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/meta/fsb.c b/src/meta/fsb.c index 411cd1ca..bece068a 100644 --- a/src/meta/fsb.c +++ b/src/meta/fsb.c @@ -301,9 +301,9 @@ VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) { //VGM_LOG("FSB FSOUND_IMAADPCM found\n"); #if 0 if (fsbh.numchannels > 2) { /* Blade Kitten 5.1 */ - vgmstream->coding_type = coding_MS_IMA; - vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = 0x24 * vgmstream->channels; + vgmstream->coding_type = coding_XBOX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x12 * vgmstream->channels; } #endif @@ -381,7 +381,7 @@ VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) { } else { vgmstream->coding_type = coding_PCM16LE; /* ? coding_PCM16LE_int ? */ } - vgmstream->layout_type = vgmstream->channels == 1 ? layout_none : layout_interleave; /* needed? */ + vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x2; } } From 6fa660c1a38d431576ccd953565e34105abe4750 Mon Sep 17 00:00:00 2001 From: bnnm Date: Mon, 2 Jan 2017 15:43:10 +0100 Subject: [PATCH 19/21] Define strncasecmp for MSC --- src/streamtypes.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/streamtypes.h b/src/streamtypes.h index 82146d06..3b2cca35 100644 --- a/src/streamtypes.h +++ b/src/streamtypes.h @@ -7,19 +7,24 @@ #define _STREAMTYPES_H #ifdef _MSC_VER + #if (_MSC_VER >= 1600) #include #else #include -#endif +#endif /* (_MSC_VER >= 1600) */ + #define inline _inline #define strcasecmp _stricmp +#define strncasecmp _strnicmp + #if (_MSC_VER < 1900) #define snprintf _snprintf -#endif +#endif /* (_MSC_VER < 1900) */ + #else #include -#endif +#endif /* _MSC_VER */ typedef int16_t sample; From aaf137817ce6e3ac556889f1a2b80ac6f71372d2 Mon Sep 17 00:00:00 2001 From: bnnm Date: Mon, 2 Jan 2017 17:03:49 +0100 Subject: [PATCH 20/21] IMA tweaks --- src/meta/fsb.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/meta/fsb.c b/src/meta/fsb.c index bece068a..fe1bed06 100644 --- a/src/meta/fsb.c +++ b/src/meta/fsb.c @@ -234,7 +234,7 @@ VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) { /* Loops by default unless disabled (sometimes may add FSOUND_LOOP_NORMAL). Often streams * repeat over and over (some tracks that shouldn't do this based on the flags, no real way to identify them). */ - loop_flag = !(fsbh.mode & FSOUND_LOOP_OFF); + loop_flag = !(fsbh.mode & FSOUND_LOOP_OFF); /* (fsbh.mode & FSOUND_LOOP_NORMAL) */ /* ping-pong looping = no looping? (forward > reverse > forward) */ VGM_ASSERT(fsbh.mode & FSOUND_LOOP_BIDI, "FSB BIDI looping found\n"); @@ -291,13 +291,15 @@ VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) { else if (fsbh.mode & FSOUND_IMAADPCM) { /* (codec 0x69, Voxware Byte Aligned) */ if (fsbh.mode & FSOUND_IMAADPCMSTEREO) { /* noninterleaved, true stereo IMA */ /* FSB4: Shatter, Blade Kitten (PC), Hard Corps: Uprising (PS3) */ - vgmstream->coding_type = coding_XBOX; /* todo not always working in Hard Corps, interleave problem? */ + vgmstream->coding_type = coding_MS_IMA; /* todo not always working in Hard Corps, interleave problem? */ vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = 0x24*vgmstream->channels; //VGM_LOG("FSB FSOUND_IMAADPCMSTEREO found\n"); } else { /* FSB3: Bioshock (PC); FSB4: Blade Kitten (PC) */ - vgmstream->coding_type = coding_XBOX; + vgmstream->coding_type = coding_MS_IMA; vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = 0x24*vgmstream->channels; //VGM_LOG("FSB FSOUND_IMAADPCM found\n"); #if 0 if (fsbh.numchannels > 2) { /* Blade Kitten 5.1 */ From 5b70e3688b469de2f85b043f5dee1fba52f52f4e Mon Sep 17 00:00:00 2001 From: bnnm Date: Mon, 2 Jan 2017 17:05:01 +0100 Subject: [PATCH 21/21] Adjusted .h and stream opener --- src/header.c | 20 +++++--------------- src/header.h | 2 +- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/header.c b/src/header.c index 7712be94..e51c27db 100644 --- a/src/header.c +++ b/src/header.c @@ -1,6 +1,8 @@ #include +#include "header.h" #include "vgmstream.h" #include "streamfile.h" +#include "streamtypes.h" #include "util.h" /** @@ -43,17 +45,6 @@ int header_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t star streamFile->get_name(streamFile,filename,sizeof(filename)); - -#if 0 - /* there is no appreciable difference using this */ - if (vgmstream->layout_type == layout_mpeg) { - for (ch=0; ch < vgmstream->channels; ch++) { - vgmstream->ch[ch].streamfile = streamFile->open(streamFile,filename,MPEG_BUFFER_SIZE); - vgmstream->ch[ch].channel_start_offset= vgmstream->ch[ch].offset=start_offset; - } - } - else -#endif { file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!file) return 0; @@ -61,9 +52,9 @@ int header_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t star for (ch=0; ch < vgmstream->channels; ch++) { vgmstream->ch[ch].streamfile = file; - if (vgmstream->coding_type == coding_MS_IMA - || vgmstream->coding_type == coding_XBOX) { /*todo not needed?*/ - /* both IMA channels work with same bytes */ + if (vgmstream->layout_type == layout_none + || vgmstream->layout_type == layout_mpeg) { /* no appreciable difference for mpeg */ + /* for some codecs like IMA where channels work with the same bytes */ vgmstream->ch[ch].channel_start_offset = vgmstream->ch[ch].offset = start_offset; } @@ -72,7 +63,6 @@ int header_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t star vgmstream->ch[ch].offset = start_offset + vgmstream->interleave_block_size*ch; } - /*todo if interleave and ch > 0 and layout none don't change offset? */ } } diff --git a/src/header.h b/src/header.h index e8fe2de7..8c94dd93 100644 --- a/src/header.h +++ b/src/header.h @@ -10,7 +10,7 @@ #include "vgmstream.h" -int header_check_extensions(STREAMFILE *streamFile, char * extensions); +int header_check_extensions(STREAMFILE *streamFile, const char * cmpexts); int header_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t start_offset);