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); 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 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/coding/coding.h b/src/coding/coding.h index 92efe52d..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); @@ -87,14 +83,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 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 */ 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/header.c b/src/header.c new file mode 100644 index 00000000..e51c27db --- /dev/null +++ b/src/header.c @@ -0,0 +1,187 @@ +#include +#include "header.h" +#include "vgmstream.h" +#include "streamfile.h" +#include "streamtypes.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)); + + { + 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->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; + } + else { + vgmstream->ch[ch].channel_start_offset = + vgmstream->ch[ch].offset = start_offset + + vgmstream->interleave_block_size*ch; + } + } + } + + + 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..8c94dd93 --- /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, const char * cmpexts); + +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/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 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 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 */ { 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/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/bgw.c b/src/meta/bgw.c index 841d95d6..5eb0489e 100644 --- a/src/meta/bgw.c +++ b/src/meta/bgw.c @@ -1,140 +1,179 @@ #include "meta.h" #include "../util.h" +#include "../header.h" -/* BGW (FF XI) */ +/** + * BGW - Final Fantasy XI (PC) music files. + * + * 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; + int channel_count, loop_flag = 0; - /* 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; - if (loop_flag) { - vgmstream->loop_start_sample = (loop_start-1)*16; - vgmstream->loop_end_sample = vgmstream->num_samples; + vgmstream->meta_type = meta_FFXI_BGW; + 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 3: /* ATRAC3 (encrypted) */ + default: + goto fail; } - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 9; - vgmstream->meta_type = meta_FFXI_BGW; /* 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 */ +/** + * SPW (SEWave), PlayOnline viewer for Final Fantasy XI (PC) + */ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; + 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 */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("spw",filename_extension(filename))) goto fail; + /* 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_FFXI; - 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->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; } - vgmstream->layout_type = layout_interleave; - 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; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } 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/fsb.c b/src/meta/fsb.c index 165d6d88..fe1bed06 100644 --- a/src/meta/fsb.c +++ b/src/meta/fsb.c @@ -1,825 +1,407 @@ #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 * init_vgmstream_fsb(STREAMFILE *streamFile) { + return init_vgmstream_fsb_offset(streamFile, 0x0); +} + +/* 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) { + if (read_32bitBE(0x00,streamFile) != 0x00574156) /* "\0WAV" */ + return NULL; + return init_vgmstream_fsb_offset(streamFile, 0x10); +} + +VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - - int fsb4_format; + off_t start_offset, h_off, s_off; + size_t custom_data_offset; 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; + FSB_HEADER fsbh; + + /* check extensions */ + if ( !header_check_extensions(streamFile, "fsb,wii") ) + goto fail; + + h_off = offset; /* 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; + 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; - 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; + /* 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 - 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; + /* 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 - channel_count = (uint16_t)read_16bitLE(0x6E,streamFile); + start_offset = offset + fsbh.hdrsize + fsbh.shdrsize; + custom_data_offset = offset + fsbh.hdrsize + fsbh.shdrsize_min; /* DSP coefs, seek tables, etc */ + + /* 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); /* (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"); /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); + vgmstream = allocate_vgmstream(fsbh.numchannels,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->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; + + /* 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; + + mpeg_data = init_mpeg_codec_data(streamFile, start_offset, vgmstream->sample_rate, vgmstream->channels, &mpeg_coding_type, NULL, NULL); + if (!mpeg_data) goto fail; + + vgmstream->codec_data = mpeg_data; + 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"); + + /* 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); + } + +#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 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_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_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); + //VGM_LOG("FSB FSOUND_IMAADPCM found\n"); +#if 0 + if (fsbh.numchannels > 2) { /* Blade Kitten 5.1 */ + vgmstream->coding_type = coding_XBOX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x12 * 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 */ } - 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); + 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 ? */ } - 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); - } } } - + + /* 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 */ - { - 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; - } - } - } + 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; } - - -/* FSB4 with "WAV" Header, found in "Deadly Creatures (WII)" - 16 byte "WAV" header which holds the filesize...*/ -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; -} - - -// FSB3 & FSB4 MPEG TEST -VGMSTREAM * init_vgmstream_fsb_mpeg(STREAMFILE *streamFile) { -#ifdef VGM_USE_MPEG - 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) == 0x46534233) /* "FSB3" */ - { - fsb_mainheader_len = 0x18; - } - else if (read_32bitBE(0x00,streamFile) == 0x46534234) /* "FSB4" */ - { - fsb_mainheader_len = 0x30; - } - 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)); - - 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; - - /* 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; - - /* 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; - -#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 - 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 diff --git a/src/meta/fsb5.c b/src/meta/fsb5.c index 8ffde4e5..240bd55c 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; @@ -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 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/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/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; 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); 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/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; diff --git a/src/util.h b/src/util.h index 9fbf7f00..7e72c828 100644 --- a/src/util.h +++ b/src/util.h @@ -72,4 +72,24 @@ 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) +#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 + #endif diff --git a/src/vgmstream.c b/src/vgmstream.c index 82e8c955..dba4476d 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, @@ -455,7 +451,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; @@ -1028,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: @@ -1159,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: @@ -1188,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 @@ -1428,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, @@ -1449,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: @@ -1767,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 { @@ -1977,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"); @@ -2620,18 +2588,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 +3135,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..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 */ @@ -328,11 +326,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) */ 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