diff --git a/fb2k/foo_filetypes.h b/fb2k/foo_filetypes.h index 4c21659b..657d20a9 100644 --- a/fb2k/foo_filetypes.h +++ b/fb2k/foo_filetypes.h @@ -40,6 +40,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("AIFCL", aifcl); VGMSTREAM_DECLARE_FILE_TYPE("AIX", aix); VGMSTREAM_DECLARE_FILE_TYPE("AKB", akb); VGMSTREAM_DECLARE_FILE_TYPE("AMTS", amts); +VGMSTREAM_DECLARE_FILE_TYPE("AO", ao); VGMSTREAM_DECLARE_FILE_TYPE("AS4", as4); VGMSTREAM_DECLARE_FILE_TYPE("ASD", asd); VGMSTREAM_DECLARE_FILE_TYPE("ASF", asf); @@ -92,6 +93,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("CNK", cnk); VGMSTREAM_DECLARE_FILE_TYPE("CPS", cps); VGMSTREAM_DECLARE_FILE_TYPE("CXS", cxs); +VGMSTREAM_DECLARE_FILE_TYPE("DA", da); VGMSTREAM_DECLARE_FILE_TYPE("DBM", dbm); VGMSTREAM_DECLARE_FILE_TYPE("DCS", dcs); VGMSTREAM_DECLARE_FILE_TYPE("DDSP", ddsp); @@ -142,6 +144,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("ILD", ild); VGMSTREAM_DECLARE_FILE_TYPE("INT", int); VGMSTREAM_DECLARE_FILE_TYPE("ISD", isd); VGMSTREAM_DECLARE_FILE_TYPE("ISWS", isws); +VGMSTREAM_DECLARE_FILE_TYPE("ITL", itl); VGMSTREAM_DECLARE_FILE_TYPE("IVAUD", ivaud); VGMSTREAM_DECLARE_FILE_TYPE("IVAG", ivag); VGMSTREAM_DECLARE_FILE_TYPE("IVB", ivb); diff --git a/src/formats.c b/src/formats.c index 7764ab40..658bc7b5 100644 --- a/src/formats.c +++ b/src/formats.c @@ -33,6 +33,7 @@ static const char* extension_list[] = { "aix", "akb", "amts", //fake extension (to be removed) + "ao", //txth/reserved [Cloudphobia (PC)] "as4", "asd", "asf", @@ -85,6 +86,7 @@ static const char* extension_list[] = { "cps", "cxs", + "da", "dbm", "dcs", "ddsp", @@ -135,6 +137,7 @@ static const char* extension_list[] = { "int", "isd", "isws", + "itl", //txth/reserved [Charinko Hero (GC)] "ivaud", "ivag", "ivb", @@ -660,7 +663,7 @@ static const meta_info meta_info_list[] = { {meta_RIFF_WAVE_smpl, "RIFF WAVE header with sample looping info"}, {meta_RIFX_WAVE, "RIFX WAVE header"}, {meta_RIFX_WAVE_smpl, "RIFX WAVE header with sample looping info"}, - {meta_XNBm, "XNBm header"}, + {meta_XNB, "Microsoft XNA Game Studio 4.0 header"}, {meta_PCM_SCD, "PCM file with custom header (SCD)"}, {meta_PCM_PS2, "PCM file with custom header (PS2)"}, {meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV Header"}, diff --git a/src/meta/riff.c b/src/meta/riff.c index e0ac857c..e3933e4f 100644 --- a/src/meta/riff.c +++ b/src/meta/riff.c @@ -2,6 +2,7 @@ #include "../coding/coding.h" #include "../layout/layout.h" #include "../util.h" +#include /* Resource Interchange File Format */ @@ -262,7 +263,8 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("wav",filename_extension(filename)) && - strcasecmp("lwav",filename_extension(filename)) + strcasecmp("lwav",filename_extension(filename)) && + strcasecmp("da",filename_extension(filename)) /* SD Gundam - Over Galaxian, The Great Battle VI (PS) */ #ifndef VGM_USE_FFMPEG && strcasecmp("sgb",filename_extension(filename)) /* SGB has proper support with FFmpeg in sgxd */ #endif @@ -835,79 +837,66 @@ fail: return NULL; } -/* XNBm (Windows 7 Phone) */ +//todo move +/* XNB - Microsoft XNA Game Studio 4.0 format */ VGMSTREAM * init_vgmstream_xnbm(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; + off_t start_offset; + int loop_flag = 0, version, flags, num_samples = 0; + size_t xnb_size, data_size; struct riff_fmt_chunk fmt; - off_t file_size = -1; - int sample_count = 0; - off_t start_offset = -1; - - int loop_flag = 0; -#if 0 - long loop_start_ms = -1; - long loop_end_ms = -1; - off_t loop_start_offset = -1; - off_t loop_end_offset = -1; -#endif - - uint32_t xnbm_size; - uint32_t data_size = 0; /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("xnb",filename_extension(filename))) - { + if ( !check_extensions(streamFile,"xnb")) goto fail; - } /* check header */ - if ((uint32_t)read_32bitBE(0,streamFile)!=0x584E426d) /* "XNBm" */ - goto fail; - /* check version? */ - if ((uint32_t)read_16bitLE(4,streamFile)!=5) + if ((read_32bitBE(0,streamFile) & 0xFFFFFF00) != 0x584E4200) /* "XNB" */ goto fail; + /* 0x04: platform: ‘w’ = Microsoft Windows, ‘m’ = Windows Phone 7, ‘x’ = Xbox 360, 'a' = Android */ - xnbm_size = read_32bitLE(6,streamFile); - file_size = get_streamfile_size(streamFile); + version = read_8bit(0x04,streamFile); + if (version != 5) goto fail; /* XNA 4.0 only */ - /* check for tructated XNBm */ - if (file_size < xnbm_size) goto fail; + flags = read_8bit(0x05,streamFile); + if (flags & 0x80) goto fail; /* compressed with XMemCompress, not public */ + //if (flags & 0x01) goto fail; /* XMA flag? */ - /* read through chunks to verify format and find metadata */ + /* "check for truncated XNB" (???) */ + xnb_size = read_32bitLE(0x06,streamFile); + if (get_streamfile_size(streamFile) < xnb_size) goto fail; + + /* XNB contains "type reader" class references to parse "shared resource" data (can be any implemented filetype) */ { - off_t current_chunk = 0xa; /* start with first chunk */ - int id_string_len; + char reader_name[255+1]; + off_t current_chunk = 0xa; + int reader_string_len; uint32_t fmt_chunk_size; + const char * type_sound = "Microsoft.Xna.Framework.Content.SoundEffectReader"; /* partial "fmt" chunk or XMA */ + //const char * type_song = "Microsoft.Xna.Framework.Content.SongReader"; /* just references a companion .wma */ - /* flag? count of strings? */ - if (read_8bit(current_chunk ++, streamFile) != 1) - goto fail; - - /* string length */ - id_string_len = read_8bit(current_chunk ++, streamFile); - - /* skip string */ - /* may want to check this ID "Microsoft.Xna.Framework.Content.SoundEffectReader" */ - current_chunk += id_string_len; - - /* ???? */ - if (read_32bitLE(current_chunk, streamFile) != 0) - goto fail; - current_chunk += 4; - - /* ???? */ - if (read_8bit(current_chunk ++, streamFile) != 0) - goto fail; - - /* flag? count of chunks? */ + /* type reader count, accept only one for now */ if (read_8bit(current_chunk++, streamFile) != 1) goto fail; - /* fmt size */ + reader_string_len = read_8bit(current_chunk++, streamFile); /* doesn't count null */ + if (reader_string_len > 255) goto fail; + + /* check SoundEffect type string */ + if (read_string(reader_name,reader_string_len+1,current_chunk,streamFile) != reader_string_len) + goto fail; + if ( strcmp(reader_name, type_sound) != 0 ) + goto fail; + current_chunk += reader_string_len + 1; + current_chunk += 4; /* reader version */ + + /* shared resource count */ + if (read_8bit(current_chunk++, streamFile) != 1) + goto fail; + + /* shared resource: partial "fmt" chunk */ fmt_chunk_size = read_32bitLE(current_chunk, streamFile); current_chunk += 4; @@ -918,10 +907,8 @@ VGMSTREAM * init_vgmstream_xnbm(STREAMFILE *streamFile) { 0, /* sns == false */ 0)) /* mwv == false */ goto fail; - current_chunk += fmt_chunk_size; - /* data size! */ data_size = read_32bitLE(current_chunk, streamFile); current_chunk += 4; @@ -930,40 +917,40 @@ VGMSTREAM * init_vgmstream_xnbm(STREAMFILE *streamFile) { switch (fmt.coding_type) { case coding_PCM16LE: - sample_count = data_size/2/fmt.channel_count; + num_samples = pcm_bytes_to_samples(data_size, fmt.channel_count, 16); break; case coding_PCM8_U_int: - sample_count = data_size/fmt.channel_count; + num_samples = pcm_bytes_to_samples(data_size, fmt.channel_count, 8); break; case coding_MSADPCM: - sample_count = msadpcm_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count); + num_samples = msadpcm_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count); break; case coding_MS_IMA: - sample_count = (data_size / fmt.block_size) * (fmt.block_size - 4 * fmt.channel_count) * 2 / fmt.channel_count + + num_samples = (data_size / fmt.block_size) * (fmt.block_size - 4 * fmt.channel_count) * 2 / fmt.channel_count + ((data_size % fmt.block_size) ? (data_size % fmt.block_size - 4 * fmt.channel_count) * 2 / fmt.channel_count : 0); break; default: + VGM_LOG("XNB: unknown codec 0x%x\n", fmt.coding_type); goto fail; } - /* build the VGMSTREAM */ + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(fmt.channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - vgmstream->num_samples = sample_count; + vgmstream->num_samples = num_samples; vgmstream->sample_rate = fmt.sample_rate; + vgmstream->meta_type = meta_XNB; vgmstream->coding_type = fmt.coding_type; - vgmstream->layout_type = layout_none; if (fmt.channel_count > 1) { switch (fmt.coding_type) { case coding_PCM8_U_int: case coding_MS_IMA: case coding_MSADPCM: - // use layout_none from above + vgmstream->layout_type = layout_none; break; default: vgmstream->layout_type = layout_interleave; @@ -971,40 +958,24 @@ VGMSTREAM * init_vgmstream_xnbm(STREAMFILE *streamFile) { } } - vgmstream->interleave_block_size = fmt.interleave; switch (fmt.coding_type) { case coding_MSADPCM: case coding_MS_IMA: - // override interleave_block_size with frame size vgmstream->interleave_block_size = fmt.block_size; break; default: - // use interleave from above + vgmstream->interleave_block_size = fmt.interleave; break; } - vgmstream->meta_type = meta_XNBm; - /* open the file, set up each channel */ - { - int i; - - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename, - STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) goto fail; - - for (i=0;ich[i].streamfile = vgmstream->ch[0].streamfile; - vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset = - start_offset+i*fmt.interleave; - } - } + if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) ) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } diff --git a/src/vgmstream.h b/src/vgmstream.h index c765f797..90c4da86 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -479,7 +479,7 @@ typedef enum { meta_RIFF_WAVE_SNS, /* .sns RIFF */ meta_RIFX_WAVE, /* RIFX, for big-endian WAVs */ meta_RIFX_WAVE_smpl, /* RIFX w/ loop data in smpl chunk */ - meta_XNBm, /* XNBm, which has a RIFF fmt chunk */ + meta_XNB, /* XNA Game Studio 4.0 */ meta_PC_MXST, /* Lego Island MxSt */ meta_PC_SOB_SAB, /* Worms 4 Mayhem SOB+SAB file */ meta_NWA, /* Visual Art's NWA */