diff --git a/BUILD.md b/BUILD.md index 6c0e02db..60b3f9e1 100644 --- a/BUILD.md +++ b/BUILD.md @@ -5,10 +5,11 @@ **GCC / Make**: In Windows this means one of these two somewhere in PATH: - MinGW-w64 (32bit version): https://sourceforge.net/projects/mingw-w64/ - Use this for easier standalone executables + - Latest online installer with any config should work (for example: gcc-7.2.0, i686, win32, sjlj). - MSYS2 with the MinGW-w64_shell (32bit) package: https://msys2.github.io/ **MSVC / Visual Studio**: Microsoft's Visual C++ and MSBuild, bundled in either: -- Visual Studio 2017: https://www.visualstudio.com/downloads/ +- Visual Studio (2015/2017/latest): https://www.visualstudio.com/downloads/ - Visual Studio Community should work (free, but must register after trial period) - Visual C++ Build Tools (no IDE): http://landinghub.visualstudio.com/visual-cpp-build-tools @@ -20,7 +21,7 @@ ### CLI (test.exe/vgmstream-cli) / Winamp plugin (in_vgmstream) / XMPlay plugin (xmp-vgmstream) **With GCC**: use the *./Makefile* in the root folder, see inside for options. For compilation flags check the *Makefile* in each folder. -You need to manually rebuild if you change a *.h* file (use *make clean*). +You may need to manually rebuild if you change a *.h* file (use *make clean*). In Linux, Makefiles can be used to cross-compile with the MingW headers, but may not be updated to generate native code at the moment. It should be fixable with some effort. Autotools should build it as vgmstream-cli instead (see the Audacious section). @@ -33,13 +34,15 @@ set PATH=C:\Program Files (x86)\mingw-w64\i686-5.4.0-win32-sjlj-rt_v5-rev0\mingw cd vgmstream mingw32-make.exe vgmstream_cli -f Makefile ^ - VGM_ENABLE_FFMPEG=1 VGM_ENABLE_MAIATRAC3PLUS=0 ^ + VGM_ENABLE_FFMPEG=1 ^ SHELL=sh.exe CC=gcc.exe AR=ar.exe STRIP=strip.exe DLLTOOL=dlltool.exe WINDRES=windres.exe ``` **With MSVC**: To build in Visual Studio, run *./init-build.bat*, open *./vgmstream_full.sln* and compile. To build from the command line, run *./build.bat*. -The build script will automatically handle obtaining dependencies and making the project changes listed in the foobar2000 section. +The build script will automatically handle obtaining dependencies and making the project changes listed in the foobar2000 section (you may need to get some PowerShell .NET packages). + +You can also call MSBuild directly in the command line (see the foobar2000 section for dependencies and examples) ### foobar2000 plugin (foo\_input\_vgmstream) Requires MSVC (foobar/SDK only links to MSVC C++ DLLs) and these dependencies: @@ -51,9 +54,31 @@ Requires MSVC (foobar/SDK only links to MSVC C++ DLLs) and these dependencies: The following project modifications are required: - For *foobar2000_ATL_helpers* add *../../../WTL/Include* to the compilers's *additional includes* -FDK-AAC/QAAC can be safely disabled by removing *VGM_USE_MP4V2* and *VGM_USE_FDKAAC* in the compiler/linker options and the project dependencies, MAIATRAC3 too, as FFmpeg is used instead to support their codecs. +FDK-AAC/QAAC can be safely disabled by removing *VGM_USE_MP4V2* and *VGM_USE_FDKAAC* in the compiler/linker options and the project dependencies, as FFmpeg is used instead to support their codecs. -You can also use the command line to compile with MSBuild, if you don't want to touch the .vcxproj files, register VS2017 after trial, or only have VC++/MSBuild tools. +You can also manually use the command line to compile with MSBuild, if you don't want to touch the .vcxproj files, register VS after trial, get PowerShell dependencies for the build script, or only have VC++/MSBuild tools. + +Windows CMD example for foobar2000: +``` +prompt $P$G$_$S +set PATH=C:\Program Files (x86)\Git\usr\bin;%PATH% +set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH% + +cd vgmstream + +set CL=/I"C:\projects\WTL\Include" +set LINK="C:\projects\foobar\foobar2000\shared\shared.lib" + +msbuild fb2k/foo_input_vgmstream.vcxproj ^ + /t:Clean + +msbuild fb2k/foo_input_vgmstream.vcxproj ^ + /t:Build ^ + /p:Platform=Win32 ^ + /p:PlatformToolset=v140 ^ + /p:Configuration=Release ^ + /p:DependenciesDir=../.. +``` ### Audacious plugin Requires the dev version of Audacious (and dependencies), automake/autoconf, and gcc/make (C++11). It must be compiled and installed into Audacious, where it should appear in the plugin list as "vgmstream". diff --git a/cli/test.vcxproj b/cli/test.vcxproj index a1a213e0..7554ea58 100644 --- a/cli/test.vcxproj +++ b/cli/test.vcxproj @@ -52,7 +52,9 @@ - + + ../dependencies + <_ProjectFileVersion>10.0.30319.1 AllRules.ruleset @@ -68,7 +70,7 @@ Disabled - ../ext_libs/Getopt;../ext_includes;../dependencies/qaac/mp4v2/include;../dependencies/fdk-aac/libSYS/include;../dependencies/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) + ../ext_libs/Getopt;../ext_includes;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) WIN32;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;_DEBUG;_WINDOWS;_CONSOLE;%(PreprocessorDefinitions) true EnableFastChecks @@ -94,7 +96,7 @@ - ../ext_libs/Getopt;../ext_includes;../dependencies/qaac/mp4v2/include;../dependencies/fdk-aac/libSYS/include;../dependencies/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) + ../ext_libs/Getopt;../ext_includes;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) WIN32;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;NDEBUG;_WINDOWS;_CONSOLE;%(PreprocessorDefinitions) MultiThreaded @@ -124,10 +126,10 @@ - + {308e2ad5-be31-4770-9441-a8d50f56895c} - + {86a064e2-c81b-4eee-8be0-a39a2e7c7c76} diff --git a/cli/vgmstream_cli.c b/cli/vgmstream_cli.c index 3d232fb1..06b17ed4 100644 --- a/cli/vgmstream_cli.c +++ b/cli/vgmstream_cli.c @@ -308,7 +308,7 @@ int main(int argc, char ** argv) { if (!play_sdtout && !print_adxencd && !print_oggenc && !print_batchvar) { printf("samples to play: %d (%.4lf seconds)\n", len_samples, (double)len_samples / vgmstream->sample_rate); } - fade_samples = fade_seconds * vgmstream->sample_rate; + fade_samples = (int32_t)(fade_seconds * vgmstream->sample_rate); if (loop_count > 0 && ignore_fade) { vgmstream->loop_target = (int)loop_count; @@ -356,7 +356,7 @@ int main(int argc, char ** argv) { if (samples_into_fade > 0) { double fadedness = (double)(fade_samples-samples_into_fade)/fade_samples; for (k = 0; k < vgmstream->channels; k++) { - buf[j*vgmstream->channels+k] = buf[j*vgmstream->channels+k]*fadedness; + buf[j*vgmstream->channels+k] = (sample)buf[j*vgmstream->channels+k]*fadedness; } } } @@ -423,7 +423,7 @@ int main(int argc, char ** argv) { if (samples_into_fade > 0) { double fadedness = (double)(fade_samples-samples_into_fade)/fade_samples; for (k = 0; k < vgmstream->channels; k++) { - buf[j*vgmstream->channels+k] = buf[j*vgmstream->channels+k]*fadedness; + buf[j*vgmstream->channels+k] = (sample)buf[j*vgmstream->channels+k]*fadedness; } } } diff --git a/fb2k/foo_input_vgmstream.vcxproj b/fb2k/foo_input_vgmstream.vcxproj index 35251c52..3026658a 100644 --- a/fb2k/foo_input_vgmstream.vcxproj +++ b/fb2k/foo_input_vgmstream.vcxproj @@ -52,7 +52,9 @@ - + + ../dependencies + <_ProjectFileVersion>10.0.30319.1 AllRules.ruleset @@ -68,7 +70,7 @@ Disabled - ..\dependencies\wtl\include;../ext_includes;..\dependencies\foobar\foobar2000\SDK;..\dependencies\foobar\foobar2000\shared;..\dependencies\foobar\foobar2000;../dependencies/qaac/mp4v2/include;../dependencies/fdk-aac/libSYS/include;../dependencies/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) + ../ext_includes;$(DependenciesDir)/WTL/Include;$(DependenciesDir)/foobar/foobar2000/SDK;$(DependenciesDir)/foobar/foobar2000/shared;$(DependenciesDir)/foobar/foobar2000;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) WIN32;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;_DEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks @@ -81,8 +83,8 @@ /d2notypeopt %(AdditionalOptions) - ../dependencies/foobar/foobar2000/shared/shared.lib;../ext_libs/libvorbis.lib;../ext_libs/libmpg123-0.lib;../ext_libs/libg7221_decode.lib;../ext_libs/libg719_decode.lib;../ext_libs/avcodec.lib;../ext_libs/avformat.lib;../ext_libs/avutil.lib;../ext_libs/swresample.lib;../ext_libs/libatrac9.lib;%(AdditionalDependencies) - ../dependencies/foobar/foobar2000/shared/shared.lib;%(AdditionalLibraryDirectories) + $(DependenciesDir)/foobar/foobar2000/shared/shared.lib;../ext_libs/libvorbis.lib;../ext_libs/libmpg123-0.lib;../ext_libs/libg7221_decode.lib;../ext_libs/libg719_decode.lib;../ext_libs/avcodec.lib;../ext_libs/avformat.lib;../ext_libs/avutil.lib;../ext_libs/swresample.lib;../ext_libs/libatrac9.lib;%(AdditionalDependencies) + $(DependenciesDir)/foobar/foobar2000/shared/shared.lib;%(AdditionalLibraryDirectories) %(DelayLoadDLLs) true @@ -95,7 +97,7 @@ - ..\dependencies\wtl\include;../ext_includes;..\dependencies\foobar\foobar2000\SDK;..\dependencies\foobar\foobar2000\shared;..\dependencies\foobar\foobar2000;../dependencies/qaac/mp4v2/include;../dependencies/fdk-aac/libSYS/include;../dependencies/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) + ../ext_includes;$(DependenciesDir)/WTL/Include;$(DependenciesDir)/foobar/foobar2000/SDK;$(DependenciesDir)/foobar/foobar2000/shared;$(DependenciesDir)/foobar/foobar2000;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) WIN32;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;NDEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) MultiThreaded @@ -107,8 +109,8 @@ /d2notypeopt - ../dependencies/foobar/foobar2000/shared/shared.lib;../ext_libs/libvorbis.lib;../ext_libs/libmpg123-0.lib;../ext_libs/libg7221_decode.lib;../ext_libs/libg719_decode.lib;../ext_libs/avcodec.lib;../ext_libs/avformat.lib;../ext_libs/avutil.lib;../ext_libs/swresample.lib;../ext_libs/libatrac9.lib;%(AdditionalDependencies) - ../dependencies/foobar/foobar2000/shared/shared.lib;%(AdditionalLibraryDirectories) + $(DependenciesDir)/foobar/foobar2000/shared/shared.lib;../ext_libs/libvorbis.lib;../ext_libs/libmpg123-0.lib;../ext_libs/libg7221_decode.lib;../ext_libs/libg719_decode.lib;../ext_libs/avcodec.lib;../ext_libs/avformat.lib;../ext_libs/avutil.lib;../ext_libs/swresample.lib;../ext_libs/libatrac9.lib;%(AdditionalDependencies) + $(DependenciesDir)/foobar/foobar2000/shared/shared.lib;%(AdditionalLibraryDirectories) %(IgnoreSpecificDefaultLibraries) %(DelayLoadDLLs) true @@ -137,25 +139,25 @@ - + {308e2ad5-be31-4770-9441-a8d50f56895c} - + {622e8b19-8109-4717-bd4d-9657aa78363e} - + {71ad2674-065b-48f5-b8b0-e1f9d3892081} - + {ee47764e-a202-4f85-a767-abdab4aff35f} - + {e8091321-d79d-4575-86ef-064ea1a4a20d} - + {ebfffb4e-261d-44d3-b89c-957b31a0bf9c} - + {86a064e2-c81b-4eee-8be0-a39a2e7c7c76} diff --git a/src/coding/coding_utils.c b/src/coding/coding_utils.c index d0cec7fc..937b608c 100644 --- a/src/coding/coding_utils.c +++ b/src/coding/coding_utils.c @@ -436,20 +436,19 @@ fail: static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int start_packet, int channels_per_packet, int bytes_per_packet, int samples_per_frame, int samples_per_subframe, int bits_frame_size) { int frames = 0, samples = 0, loop_start_frame = 0, loop_end_frame = 0, start_skip = 0, end_skip = 0; - uint32_t first_frame_b, packet_skip_count = 0, frame_size_b, packet_size_b, header_size_b; - uint64_t offset_b, packet_offset_b, frame_offset_b; - size_t size; + size_t first_frame_b, packet_skip_count = 0, frame_size_b, packet_size_b, header_size_b; + off_t offset_b, packet_offset_b, frame_offset_b; - uint32_t packet_size = bytes_per_packet; + size_t packet_size = bytes_per_packet; off_t offset = msd->data_offset; - uint32_t stream_offset_b = msd->data_offset * 8; + off_t max_offset = msd->data_offset + msd->data_size; + off_t stream_offset_b = msd->data_offset * 8; offset += start_packet * packet_size; - size = offset + msd->data_size; packet_size_b = packet_size * 8; /* read packets */ - while (offset < size) { + while (offset < max_offset) { offset_b = offset * 8; /* global offset in bits */ offset += packet_size; /* global offset in bytes */ @@ -678,7 +677,7 @@ void wmapro_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_ return; } samples_per_frame = wma_get_samples_per_frame(version, sample_rate, decode_flags); - bits_frame_size = floor(log(block_align) / log(2)) + 4; /* max bits needed to represent this block_align */ + bits_frame_size = (int)floor(log(block_align) / log(2)) + 4; /* max bits needed to represent this block_align */ samples_per_subframe = 0; /* not really needed WMAPro can't use loop subframes (complex subframe lengths) */ msd->xma_version = 0; /* signal it's not XMA */ @@ -705,7 +704,8 @@ void wma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_ali else { /* variable frames per packet (mini-header values) */ off_t offset = msd->data_offset; - while (offset < msd->data_size) { /* read packets (superframes) */ + off_t max_offset = msd->data_offset + msd->data_size; + while (offset < max_offset) { /* read packets (superframes) */ int packet_frames; uint8_t header = read_8bit(offset, streamFile); /* upper nibble: index; lower nibble: frames */ diff --git a/src/coding/pcm_decoder.c b/src/coding/pcm_decoder.c index 3e016f94..c2f3732f 100644 --- a/src/coding/pcm_decoder.c +++ b/src/coding/pcm_decoder.c @@ -177,7 +177,7 @@ void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac int sample_pcm; sample_float = (float*)&sample_int; - sample_pcm = floor((*sample_float) * 32767.f + .5f); + sample_pcm = (int)floor((*sample_float) * 32767.f + .5f); outbuf[sample_count] = clamp16(sample_pcm); } diff --git a/src/coding/vorbis_custom_decoder.c b/src/coding/vorbis_custom_decoder.c index 29d20a32..6048b767 100644 --- a/src/coding/vorbis_custom_decoder.c +++ b/src/coding/vorbis_custom_decoder.c @@ -180,7 +180,7 @@ static void pcm_convert_float_to_16(vorbis_custom_codec_data * data, sample * ou sample *ptr = outbuf + i; float *mono = pcm[i]; for (j = 0; j < samples_to_do; j++) { - int val = floor(mono[j] * 32767.f + .5f); + int val = (int)floor(mono[j] * 32767.f + .5f); if (val > 32767) val = 32767; if (val < -32768) val = -32768; diff --git a/src/coding/vorbis_custom_utils_wwise.c b/src/coding/vorbis_custom_utils_wwise.c index 73ee1508..8ff3c1d2 100644 --- a/src/coding/vorbis_custom_utils_wwise.c +++ b/src/coding/vorbis_custom_utils_wwise.c @@ -13,11 +13,11 @@ /* DEFS */ /* **************************************************************************** */ -static int build_header_identification(uint8_t * buf, size_t bufsize, int channels, int sample_rate, int blocksize_short, int blocksize_long); -static int build_header_comment(uint8_t * buf, size_t bufsize); -static int get_packet_header(STREAMFILE *streamFile, off_t offset, wwise_header_t header_type, int * granulepos, size_t * packet_size, int big_endian); -static int rebuild_packet(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian); -static int rebuild_setup(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian, int channels); +static size_t build_header_identification(uint8_t * buf, size_t bufsize, int channels, int sample_rate, int blocksize_short, int blocksize_long); +static size_t build_header_comment(uint8_t * buf, size_t bufsize); +static size_t get_packet_header(STREAMFILE *streamFile, off_t offset, wwise_header_t header_type, int * granulepos, size_t * packet_size, int big_endian); +static size_t rebuild_packet(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian); +static size_t rebuild_setup(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian, int channels); static int ww2ogg_generate_vorbis_packet(vgm_bitstream * ow, vgm_bitstream * iw, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian); static int ww2ogg_generate_vorbis_setup(vgm_bitstream * ow, vgm_bitstream * iw, vorbis_custom_codec_data * data, int channels, size_t packet_size, STREAMFILE *streamFile); @@ -126,7 +126,7 @@ fail: /* **************************************************************************** */ /* loads info from a wwise packet header */ -static int get_packet_header(STREAMFILE *streamFile, off_t offset, wwise_header_t header_type, int * granulepos, size_t * packet_size, int big_endian) { +static size_t get_packet_header(STREAMFILE *streamFile, off_t offset, wwise_header_t header_type, int * granulepos, size_t * packet_size, int big_endian) { int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE; int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE; @@ -153,7 +153,7 @@ static int get_packet_header(STREAMFILE *streamFile, off_t offset, wwise_header_ } /* Transforms a Wwise data packet into a real Vorbis one (depending on config) */ -static int rebuild_packet(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian) { +static size_t rebuild_packet(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian) { vgm_bitstream ow, iw; int rc, granulepos; size_t header_size, packet_size; @@ -196,7 +196,7 @@ fail: /* Transforms a Wwise setup packet into a real Vorbis one (depending on config). */ -static int rebuild_setup(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian, int channels) { +static size_t rebuild_setup(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian, int channels) { vgm_bitstream ow, iw; int rc, granulepos; size_t header_size, packet_size; @@ -238,8 +238,8 @@ fail: return 0; } -static int build_header_identification(uint8_t * buf, size_t bufsize, int channels, int sample_rate, int blocksize_0_exp, int blocksize_1_exp) { - int bytes = 0x1e; +static size_t build_header_identification(uint8_t * buf, size_t bufsize, int channels, int sample_rate, int blocksize_0_exp, int blocksize_1_exp) { + size_t bytes = 0x1e; uint8_t blocksizes; if (bytes > bufsize) return 0; @@ -260,8 +260,8 @@ static int build_header_identification(uint8_t * buf, size_t bufsize, int channe return bytes; } -static int build_header_comment(uint8_t * buf, size_t bufsize) { - int bytes = 0x19; +static size_t build_header_comment(uint8_t * buf, size_t bufsize) { + size_t bytes = 0x19; if (bytes > bufsize) return 0; diff --git a/src/formats.c b/src/formats.c index 0395c1b1..9bd66259 100644 --- a/src/formats.c +++ b/src/formats.c @@ -43,7 +43,9 @@ static const char* extension_list[] = { "ast", "at3", "at9", + "atsl", "atsl3", + "atsl4", "atx", "aud", "aus", @@ -237,6 +239,7 @@ static const char* extension_list[] = { "psnd", "psw", + "rac", //txth/reserved [Manhunt (Xbox)] "rak", "ras", "raw", @@ -351,6 +354,7 @@ static const char* extension_list[] = { "waa", "wac", "wad", + "waf", "wam", "was", //"wav", //common @@ -650,8 +654,8 @@ static const meta_info meta_info_list[] = { {meta_CFN, "tri-Crescendo CAF Header"}, {meta_PS2_VPK, "VPK Header"}, {meta_GENH, "GENH Generic Header"}, - {meta_DSP_SADB, "sadb header"}, - {meta_SADL, "sadl header"}, + {meta_DSP_SADB, "Procyon Studio SADB header"}, + {meta_SADL, "Procyon Studio SADL header"}, {meta_PS2_BMDX, "Beatmania .bmdx header"}, {meta_DSP_WSI, ".wsi header"}, {meta_AIFC, "Audio Interchange File Format AIFF-C"}, @@ -726,7 +730,7 @@ static const meta_info meta_info_list[] = { {meta_NGC_YMF, "YMF DSP Header"}, {meta_PS2_CCC, "CCC Header"}, {meta_PSX_FAG, "FAG Header"}, - {meta_PS2_MIHB, "Merged MIH+MIB"}, + {meta_PS2_MIHB, "MIH+MIB header"}, {meta_DSP_WII_MUS, "mus header"}, {meta_WII_SNG, "SNG DSP Header"}, {meta_RSD2VAG, "RSD2/VAG Header"}, @@ -792,8 +796,8 @@ static const meta_info meta_info_list[] = { {meta_ZSD, "ZSD Header"}, {meta_RedSpark, "RedSpark Header"}, {meta_PC_IVAUD, "assumed GTA IV Audio file by .ivaud extension"}, - {meta_DSP_WII_WSD, "Standard Nintendo DSP headers in .wsd"}, - {meta_WII_NDP, "Vertigo NDP Header"}, + {meta_DSP_WII_WSD, ".WSD header"}, + {meta_WII_NDP, "Icon Games NDP header"}, {meta_PS2_SPS, "Ape Escape 2 SPS Header"}, {meta_PS2_XA2_RRP, "Acclaim XA2 Header"}, {meta_NDS_HWAS, "Vicarious Visions HWAS header"}, @@ -812,7 +816,7 @@ static const meta_info meta_info_list[] = { {meta_MAXIS_XA, "Maxis XAI/XAJ Header"}, {meta_EXAKT_SC, "assumed Activision / EXAKT SC by extension"}, {meta_WII_BNS, "Nintendo BNS header"}, - {meta_WII_WAS, "WAS (iSWS) DSP header"}, + {meta_WII_WAS, "Sumo Digital iSWS header"}, {meta_XBOX_HLWAV, "Half Life 2 bgm header"}, {meta_STX, "Nintendo .stx header"}, {meta_MYSPD, "U-Sing .MYSPD header"}, @@ -822,7 +826,7 @@ static const meta_info meta_info_list[] = { {meta_DMSG, "RIFF/DMSGsegh header"}, {meta_PONA_3DO, "Policenauts BGM header"}, {meta_PONA_PSX, "Policenauts BGM header"}, - {meta_NGC_DSP_AAAP, "Double standard DSP header in 'AAAp'"}, + {meta_NGC_DSP_AAAP, "Acclaim Austin AAAp header"}, {meta_NGC_DSP_KONAMI, "Konami DSP header"}, {meta_PS2_STER, "STER Header"}, {meta_BNSF, "Namco Bandai BNSF header"}, @@ -835,12 +839,13 @@ static const meta_info meta_info_list[] = { {meta_PC_SMP, "Ghostbusters .smp Header"}, {meta_NGC_PDT, "PDT DSP header"}, {meta_NGC_BO2, "Blood Omen 2 DSP header"}, + {meta_DSP_DDSP, ".DDSP header"}, {meta_P3D, "Radical P3D header"}, {meta_PS2_TK1, "Tekken TK5STRM1 Header"}, {meta_PS2_ADSC, "ADSC Header"}, {meta_NGC_DSP_MPDS, "MPDS DSP header"}, - {meta_DSP_STR_IG, "Infogrames dual dsp header"}, - {meta_EA_SWVR, "Electronic Arts SWVR header"}, + {meta_DSP_STR_IG, "Infogrames .DSP header"}, + {meta_EA_SWVR, "Electronic Arts SWVR header"}, {meta_PS2_B1S, "B1S header"}, {meta_PS2_WAD, "WAD header"}, {meta_DSP_XIII, "XIII dsp header"}, @@ -852,7 +857,7 @@ static const meta_info meta_info_list[] = { {meta_XAU, "XPEC XAU header"}, {meta_GH3_BAR, "Guitar Hero III Mobile .bar"}, {meta_FFW, "Freedom Fighters BGM header"}, - {meta_DSP_DSPW, "DSPW dsp header"}, + {meta_DSP_DSPW, "Capcom DSPW header"}, {meta_PS2_JSTM, "JSTM Header"}, {meta_XVAG, "Sony XVAG header"}, {meta_PS3_CPS, "tri-Crescendo CPS Header"}, @@ -959,6 +964,7 @@ static const meta_info meta_info_list[] = { {meta_SQEX_SAB, "Square-Enix SAB header"}, {meta_SQEX_MAB, "Square-Enix MAB header"}, {meta_OGG_L2SD, "Ogg Vorbis (L2SD)"}, + {meta_WAF, "KID WAF header"}, #ifdef VGM_USE_MP4V2 {meta_MP4, "AAC header"}, diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 94fd9d95..74fe5834 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -277,7 +277,7 @@ > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 958a19b8..e648b0d5 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -43,7 +43,9 @@ - + + ../dependencies + <_ProjectFileVersion>10.0.30319.1 AllRules.ruleset @@ -56,7 +58,7 @@ Disabled - ../ext_includes;../dependencies/qaac/mp4v2/include;../dependencies/fdk-aac/libSYS/include;../dependencies/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) + ../ext_includes;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) WIN32;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_G719;VGM_USE_MP4V2;VGM_USE_FDKAAC;VGM_USE_ATRAC9;USE_ALLOCA;_DEBUG;_LIB;%(PreprocessorDefinitions) true EnableFastChecks @@ -70,7 +72,7 @@ - ../ext_includes;../dependencies/qaac/mp4v2/include;../dependencies/fdk-aac/libSYS/include;../dependencies/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) + ../ext_includes;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) _WIN32_WINNT=0x501;WIN32;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_G719;VGM_USE_MP4V2;VGM_USE_FDKAAC;VGM_USE_ATRAC9;USE_ALLOCA;NDEBUG;_LIB;%(PreprocessorDefinitions) MultiThreaded @@ -186,7 +188,7 @@ - + @@ -397,6 +399,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index d8543b19..902d34b9 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -169,7 +169,7 @@ meta\Source Files - + meta\Source Files @@ -781,6 +781,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files diff --git a/src/meta/atsl.c b/src/meta/atsl.c new file mode 100644 index 00000000..4bc0cd4c --- /dev/null +++ b/src/meta/atsl.c @@ -0,0 +1,129 @@ +#include "meta.h" +#include "../coding/coding.h" + +static STREAMFILE* setup_atsl_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext); +typedef enum { ATRAC3, ATRAC9, KOVS } atsl_codec; + +/* .ATSL - Koei Tecmo audio container [One Piece Pirate Warriors (PS3), Warriors All-Stars (PC)] */ +VGMSTREAM * init_vgmstream_atsl(STREAMFILE *streamFile) { + VGMSTREAM *vgmstream = NULL; + STREAMFILE *temp_streamFile = NULL; + int total_subsongs, target_subsong = streamFile->stream_index; + int type, big_endian = 0; + atsl_codec codec; + const char* fake_ext; + off_t subfile_offset; + size_t subfile_size, header_size; + int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; + + + /* check extensions + * .atsl: header id (for G1L extractions), .atsl3: PS3 games, .atsl4: PS4 games */ + if ( !check_extensions(streamFile,"atsl,atsl3,atsl4")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x4154534C) /* "ATSL" */ + goto fail; + + /* main header (LE) */ + header_size = read_32bitLE(0x04,streamFile); + /* 0x08/0c: flags?, 0x10: fixed? (0x03E8) */ + total_subsongs = read_32bitLE(0x14,streamFile); + /* 0x18: 0x28, or 0x30 (rarer) */ + /* 0x1c: null, 0x20: subheader size, 0x24/28: null */ + + //todo: sometimes entries are repeated/dummy and point to the first entry + if (target_subsong == 0) target_subsong = 1; + if (target_subsong > total_subsongs || total_subsongs <= 0) goto fail; + + + /* Type byte may be wrong (could need header id tests instead). + * Example flags at 0x08/0x0c: + * - 00010101 00020001 .atsl3 from One Piece Pirate Warriors (PS3)[ATRAC3] + * - 00000201 00020001 .atsl3 from Fist of North Star: Ken's Rage 2 (PS3)[ATRAC3] + * 00000301 00020101 (same) + * - 01040301 00060301 .atsl4 from Nobunaga's Ambition: Sphere of Influence (PS4)[ATRAC9] + * - 00060301 00040301 atsl in G1L from One Piece Pirate Warriors 3 (Vita)[ATRAC9] + * - 00060301 00010301 atsl in G1L from One Piece Pirate Warriors 3 (PC)[KOVS] + * - 000A0301 00010501 atsl in G1L from Warriors All-Stars (PC)[KOVS] + */ + type = read_8bit(0x0d, streamFile); + switch(type) { + case 0x01: + codec = KOVS; + fake_ext = "kvs"; + break; + case 0x02: + codec = ATRAC3; + fake_ext = "at3"; + big_endian = 1; + break; + case 0x04: + case 0x06: + codec = ATRAC9; + fake_ext = "at9"; + break; + default: + goto fail; + } + read_32bit = big_endian ? read_32bitBE : read_32bitLE; + + + /* entry header (machine endianness) */ + /* 0x00: id */ + subfile_offset = read_32bit(header_size + (target_subsong-1)*0x28 + 0x04,streamFile); + subfile_size = read_32bit(header_size + (target_subsong-1)*0x28 + 0x08,streamFile); + /* 0x08+: sample rate/num_samples/loop_start/etc, matching subfile header */ + /* some kind of seek/switch table follows (optional, found in .atsl3) */ + + temp_streamFile = setup_atsl_streamfile(streamFile, subfile_offset,subfile_size, fake_ext); + if (!temp_streamFile) goto fail; + + /* init the VGMSTREAM */ + switch(codec) { + case ATRAC3: + case ATRAC9: + vgmstream = init_vgmstream_riff(temp_streamFile); + if (!vgmstream) goto fail; + break; + case KOVS: + vgmstream = init_vgmstream_ogg_vorbis(temp_streamFile); + if (!vgmstream) goto fail; + break; + default: + goto fail; + } + + vgmstream->num_streams = total_subsongs; + + close_streamfile(temp_streamFile); + return vgmstream; + +fail: + close_streamfile(temp_streamFile); + close_vgmstream(vgmstream); + return NULL; +} + + +static STREAMFILE* setup_atsl_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext) { + STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL; + + /* setup subfile */ + new_streamFile = open_wrap_streamfile(streamFile); + if (!new_streamFile) goto fail; + temp_streamFile = new_streamFile; + + new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size); + if (!new_streamFile) goto fail; + temp_streamFile = new_streamFile; + + new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,fake_ext); + if (!new_streamFile) goto fail; + temp_streamFile = new_streamFile; + + return temp_streamFile; + +fail: + close_streamfile(temp_streamFile); + return NULL; +} diff --git a/src/meta/atsl3.c b/src/meta/atsl3.c deleted file mode 100644 index 722c3f77..00000000 --- a/src/meta/atsl3.c +++ /dev/null @@ -1,76 +0,0 @@ -#include "meta.h" -#include "../coding/coding.h" - -static STREAMFILE* setup_atsl3_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size); - -/* .ATSL3 - Koei Tecmo container of multiple .AT3 [One Piece Pirate Warriors (PS3)] */ -VGMSTREAM * init_vgmstream_atsl3(STREAMFILE *streamFile) { - VGMSTREAM *vgmstream = NULL; - STREAMFILE *temp_streamFile = NULL; - int total_subsongs, target_subsong = streamFile->stream_index; - off_t subfile_offset; - size_t subfile_size, header_size, entry_size; - - /* check extensions */ - if ( !check_extensions(streamFile,"atsl3")) - goto fail; - if (read_32bitBE(0x00,streamFile) != 0x4154534C) /* "ATSL" */ - goto fail; - - /* main header (LE) */ - header_size = read_32bitLE(0x04,streamFile); - /* 0x08/0c: flags?, 0x10: some size? */ - total_subsongs = read_32bitLE(0x14,streamFile); - entry_size = read_32bitLE(0x18,streamFile); - /* 0x1c: null, 0x20: subheader size, 0x24/28: null */ - - if (target_subsong == 0) target_subsong = 1; - if (target_subsong > total_subsongs || total_subsongs <= 0) goto fail; - - /* entry header (BE) */ - /* 0x00: id */ - subfile_offset = read_32bitBE(header_size + (target_subsong-1)*entry_size + 0x04,streamFile); - subfile_size = read_32bitBE(header_size + (target_subsong-1)*entry_size + 0x08,streamFile); - /* 0x08+: sample rate/num_samples/loop_start/etc, matching subfile header */ - /* some kind of seek/switch table follows */ - - temp_streamFile = setup_atsl3_streamfile(streamFile, subfile_offset,subfile_size); - if (!temp_streamFile) goto fail; - - /* init the VGMSTREAM */ - vgmstream = init_vgmstream_riff(temp_streamFile); - if (!vgmstream) goto fail; - vgmstream->num_streams = total_subsongs; - - close_streamfile(temp_streamFile); - return vgmstream; - -fail: - close_streamfile(temp_streamFile); - close_vgmstream(vgmstream); - return NULL; -} - - -static STREAMFILE* setup_atsl3_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size) { - STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL; - - /* setup subfile */ - new_streamFile = open_wrap_streamfile(streamFile); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; - - new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; - - new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"at3"); - if (!new_streamFile) goto fail; - temp_streamFile = new_streamFile; - - return temp_streamFile; - -fail: - close_streamfile(temp_streamFile); - return NULL; -} diff --git a/src/meta/awc.c b/src/meta/awc.c index ab73b6cd..6423e947 100644 --- a/src/meta/awc.c +++ b/src/meta/awc.c @@ -17,7 +17,7 @@ typedef struct { int block_chunk; off_t stream_offset; - off_t stream_size; + size_t stream_size; } awc_header; @@ -187,12 +187,15 @@ static int parse_awc_header(STREAMFILE* streamFile, awc_header* awc) { /* get stream tags */ for (i = 0; i < tag_count; i++) { - uint64_t tag_header, tag, size, offset; + uint64_t tag_header; + uint8_t tag; + size_t size; + off_t offset; tag_header = (uint64_t)read_64bit(off + 0x08*i,streamFile); - tag = (tag_header >> 56) & 0xFF; /* 8b */ - size = (tag_header >> 28) & 0x0FFFFFFF; /* 28b */ - offset = (tag_header >> 0) & 0x0FFFFFFF; /* 28b */ + tag = (uint8_t)((tag_header >> 56) & 0xFF); /* 8b */ + size = (size_t)((tag_header >> 28) & 0x0FFFFFFF); /* 28b */ + offset = (off_t)((tag_header >> 0) & 0x0FFFFFFF); /* 28b */ /* Tags are apparently part of a hash derived from a word ("data", "format", etc). * If music + 1ch, the header and data chunks can repeat for no reason (sometimes not even pointed). */ diff --git a/src/meta/g1l.c b/src/meta/g1l.c index 81b767d3..7c6e43d8 100644 --- a/src/meta/g1l.c +++ b/src/meta/g1l.c @@ -4,12 +4,12 @@ static VGMSTREAM * init_vgmstream_kt_wiibgm_offset(STREAMFILE *streamFile, off_t offset); -/* Koei Tecmo G1L - pack format, sometimes containing a single stream - * +/* Koei Tecmo G1L - container format, sometimes containing a single stream. * It probably makes more sense to extract it externally, it's here mainly for Hyrule Warriors */ VGMSTREAM * init_vgmstream_kt_g1l(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - int type, num_streams, target_stream = streamFile->stream_index; + int type; + int total_streams, target_stream = streamFile->stream_index; off_t stream_offset; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; @@ -22,30 +22,30 @@ VGMSTREAM * init_vgmstream_kt_g1l(STREAMFILE *streamFile) { && read_32bitBE(0x4, streamFile) != 0x30303030) /* "0000" (version?) */ goto fail; - if (read_32bitBE(0x0, streamFile) == 0x47314C5F ) { + if (read_32bitBE(0x0, streamFile) == 0x47314C5F) { read_32bit = read_32bitBE; } else { read_32bit = read_32bitLE; } - /* 0x08 filesize */ - /* 0x0c first file offset (same as 0x18) */ + /* 0x08: filesize, 0x0c: header size */ type = read_32bit(0x10,streamFile); - num_streams = read_32bit(0x14,streamFile); + total_streams = read_32bit(0x14,streamFile); if (target_stream==0) target_stream = 1; - if (target_stream < 0 || target_stream > num_streams || num_streams < 1) goto fail; + if (target_stream < 0 || target_stream > total_streams || total_streams < 1) goto fail; stream_offset = read_32bit(0x18 + 0x4*(target_stream-1),streamFile); - /* filesize = stream_offset - stream_next_offset*/ + //stream_size = stream_offset - stream_next_offset;//not ok, sometimes entries are unordered/repeats */ switch(type) { /* type may not be correct */ case 0x09: /* DSP (WiiBGM) from Hyrule Warriors (Wii U) */ vgmstream = init_vgmstream_kt_wiibgm_offset(streamFile, stream_offset); break; + case 0x06: /* ATRAC9 (RIFF) from One Piece Pirate Warriors 3 (Vita) */ case 0x01: /* ATRAC3plus (RIFF) from One Piece Pirate Warriors 2 (PS3) */ case 0x00: /* OGG (KOVS) from Romance Three Kindgoms 13 (PC)*/ - case 0x0A: /* OGG (KOVS) from Dragon Quest Heroes (PC)*/ + case 0x0A: /* OGG (KOVS) from Dragon Quest Heroes (PC), Bladestorm (PC) w/ single files */ default: goto fail; } diff --git a/src/meta/genh.c b/src/meta/genh.c index ea67480a..3b2b6ddd 100644 --- a/src/meta/genh.c +++ b/src/meta/genh.c @@ -195,7 +195,15 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { vgmstream->layout_type = layout_none; break; case coding_XBOX_IMA: - vgmstream->layout_type = layout_none; + if (genh.codec_mode == 1) { + if (!genh.interleave) goto fail; /* creates garbage */ + coding = coding_XBOX_IMA_int; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = genh.interleave; + } + else { + vgmstream->layout_type = layout_none; + } break; case coding_NGC_DTK: if (vgmstream->channels != 2) goto fail; @@ -367,14 +375,16 @@ static int parse_genh(STREAMFILE * streamFile, genh_header * genh) { genh->num_samples = read_32bitLE(0x40,streamFile); genh->skip_samples = read_32bitLE(0x44,streamFile); /* for FFmpeg based codecs */ genh->skip_samples_mode = read_8bit(0x48,streamFile); /* 0=autodetect, 1=force manual value @ 0x44 */ - if (genh->codec == ATRAC3 || genh->codec == ATRAC3PLUS) - genh->codec_mode = read_8bit(0x49,streamFile); /* 0=autodetect, 1=force joint stereo, 2=force full stereo */ - if (genh->codec == XMA1 || genh->codec == XMA2) - genh->codec_mode = read_8bit(0x4a,streamFile); /* 0=default (4ch = 2ch + 2ch), 1=single (4ch = 1ch + 1ch + 1ch + 1ch) */ + genh->codec_mode = read_8bit(0x4b,streamFile); + if ((genh->codec == ATRAC3 || genh->codec == ATRAC3PLUS) && genh->codec_mode==0) + genh->codec_mode = read_8bit(0x49,streamFile); + if ((genh->codec == XMA1 || genh->codec == XMA2) && genh->codec_mode==0) + genh->codec_mode = read_8bit(0x4a,streamFile); genh->data_size = read_32bitLE(0x50,streamFile); if (genh->data_size == 0) genh->data_size = get_streamfile_size(streamFile) - genh->start_offset; + genh->num_samples = genh->num_samples > 0 ? genh->num_samples : genh->loop_end_sample; genh->loop_flag = genh->loop_start_sample != -1; diff --git a/src/meta/meta.h b/src/meta/meta.h index 80dc0622..66a2618e 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -697,11 +697,13 @@ VGMSTREAM * init_vgmstream_fsb_encrypted(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_xwc(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_atsl3(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_atsl(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_sps_n1(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_atx(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_waf(STREAMFILE * streamFile); #endif /*_META_H*/ diff --git a/src/meta/ngc_dsp_std.c b/src/meta/ngc_dsp_std.c index dd9a58cd..3a8ffd93 100644 --- a/src/meta/ngc_dsp_std.c +++ b/src/meta/ngc_dsp_std.c @@ -28,55 +28,127 @@ struct dsp_header { int16_t block_size; }; -/* nonzero on failure */ +/* read the above struct; returns nonzero on failure */ static int read_dsp_header(struct dsp_header *header, off_t offset, STREAMFILE *file) { int i; uint8_t buf[0x4e]; /* usually padded out to 0x60 */ - if (read_streamfile(buf, offset, 0x4e, file) != 0x4e) return 1; - - header->sample_count = - get_32bitBE(buf+0x00); - header->nibble_count = - get_32bitBE(buf+0x04); - header->sample_rate = - get_32bitBE(buf+0x08); - header->loop_flag = - get_16bitBE(buf+0x0c); - header->format = - get_16bitBE(buf+0x0e); - header->loop_start_offset = - get_32bitBE(buf+0x10); - header->loop_end_offset = - get_32bitBE(buf+0x14); - header->ca = - get_32bitBE(buf+0x18); + if (read_streamfile(buf, offset, 0x4e, file) != 0x4e) + return 1; + header->sample_count = get_32bitBE(buf+0x00); + header->nibble_count = get_32bitBE(buf+0x04); + header->sample_rate = get_32bitBE(buf+0x08); + header->loop_flag = get_16bitBE(buf+0x0c); + header->format = get_16bitBE(buf+0x0e); + header->loop_start_offset = get_32bitBE(buf+0x10); + header->loop_end_offset = get_32bitBE(buf+0x14); + header->ca = get_32bitBE(buf+0x18); for (i=0; i < 16; i++) - header->coef[i] = - get_16bitBE(buf+0x1c+i*2); - header->gain = - get_16bitBE(buf+0x3c); - header->initial_ps = - get_16bitBE(buf+0x3e); - header->initial_hist1 = - get_16bitBE(buf+0x40); - header->initial_hist2 = - get_16bitBE(buf+0x42); - header->loop_ps = - get_16bitBE(buf+0x44); - header->loop_hist1 = - get_16bitBE(buf+0x46); - header->loop_hist2 = - get_16bitBE(buf+0x48); - header->channel_count = - get_16bitBE(buf+0x4a); - header->block_size = - get_16bitBE(buf+0x4c); - + header->coef[i] = get_16bitBE(buf+0x1c+i*0x2); + header->gain = get_16bitBE(buf+0x3c); + header->initial_ps = get_16bitBE(buf+0x3e); + header->initial_hist1 = get_16bitBE(buf+0x40); + header->initial_hist2 = get_16bitBE(buf+0x42); + header->loop_ps = get_16bitBE(buf+0x44); + header->loop_hist1 = get_16bitBE(buf+0x46); + header->loop_hist2 = get_16bitBE(buf+0x48); + header->channel_count = get_16bitBE(buf+0x4a); + header->block_size = get_16bitBE(buf+0x4c); return 0; } -/* the standard .dsp, as generated by DSPADPCM.exe */ +static void setup_vgmstream_dsp(VGMSTREAM* vgmstream, struct dsp_header* ch_header) { + int i, j; + + /* set coeffs and initial history (usually 0) */ + for (i = 0; i < vgmstream->channels; i++){ + for (j = 0; j < 16; j++) { + vgmstream->ch[i].adpcm_coef[j] = ch_header[i].coef[j]; + } + vgmstream->ch[i].adpcm_history1_16 = ch_header[i].initial_hist1; + vgmstream->ch[i].adpcm_history2_16 = ch_header[i].initial_hist2; + } +} + +static int dsp_load_header(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) { + int i; + + /* load standard dsp header per channel */ + for (i = 0; i < channels; i++) { + if (read_dsp_header(&ch_header[i], offset + i*spacing, streamFile)) + goto fail; + } + + return 1; +fail: + return 0; +} +static int check_dsp_format(struct dsp_header* ch_header, int channels) { + int i; + + /* check type==0 and gain==0 */ + for (i = 0; i < channels; i++) { + if (ch_header[i].format || ch_header[i].gain) + goto fail; + } + + return 1; +fail: + return 0; +} +static int check_dsp_samples(struct dsp_header* ch_header, int channels) { + int i; + + /* check for agreement between channels */ + for (i = 0; i < channels - 1; i++) { + if (ch_header[i].sample_count != ch_header[i+1].sample_count || + ch_header[i].nibble_count != ch_header[i+1].nibble_count || + ch_header[i].sample_rate != ch_header[i+1].sample_rate || + ch_header[i].loop_flag != ch_header[i+1].loop_flag || + ch_header[i].loop_start_offset != ch_header[i+1].loop_start_offset || + ch_header[i].loop_end_offset != ch_header[i+1].loop_end_offset ) { + goto fail; + } + } + + return 1; +fail: + return 0; +} +static int check_dsp_initial_ps(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) { + int i; + + /* check initial predictor/scale */ + for (i = 0; i < channels; i++) { + if (ch_header[i].initial_ps != (uint8_t)read_8bit(offset + i*spacing, streamFile)) + goto fail; + } + + return 1; +fail: + return 0; +} +static int check_dsp_loop_ps(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) { + int i; + + if (!ch_header[0].loop_flag) + return 1; + + /* check loop predictor/scale */ + for (i = 0; i < channels; i++) { + off_t loop_offset = ch_header[i].loop_start_offset / 16 * 8; + if (ch_header[i].loop_ps != (uint8_t)read_8bit(offset + i*spacing + loop_offset,streamFile)) + goto fail; + } + + return 1; +fail: + return 0; +} + +/* ********************************* */ + +/* the standard .dsp, as generated by DSPADPCM.exe */ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; @@ -523,7 +595,7 @@ VGMSTREAM * init_vgmstream_ngc_str(STREAMFILE *streamFile) { streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("str",filename_extension(filename))) goto fail; - /* always 0xFAAF0001 @ offset 0 */ + /* always 0xFAAF0001 @ offset 0 */ if (read_32bitBE(0x00,streamFile)!=0xFAAF0001) goto fail; /* build the VGMSTREAM */ @@ -535,9 +607,9 @@ VGMSTREAM * init_vgmstream_ngc_str(STREAMFILE *streamFile) { vgmstream->num_samples = read_32bitBE(0x08,streamFile); vgmstream->sample_rate = read_32bitBE(0x04,streamFile); - /* always loop to the beginning */ - vgmstream->loop_start_sample=0; - vgmstream->loop_end_sample=vgmstream->num_samples; + /* always loop to the beginning */ + vgmstream->loop_start_sample=0; + vgmstream->loop_end_sample=vgmstream->num_samples; vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_interleave; @@ -572,7 +644,6 @@ fail: /* a bunch of formats that are identical except for file extension, * but have different interleaves */ - VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; @@ -808,120 +879,60 @@ fail: return NULL; } - -/* sadb - .SAD files, two standard DSP headers */ +#define SADB_MAX_CHANNELS 2 +/* sadb - Procyon Studio header + interleaved dsp [Shiren the Wanderer 3 (Wii), Disaster: Day of Crisis (Wii)] */ VGMSTREAM * init_vgmstream_sadb(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - off_t start_offset; - off_t interleave; - - struct dsp_header ch0_header,ch1_header; - int i; + off_t start_offset, header_offset; + size_t header_spacing, interleave; int channel_count; + struct dsp_header ch_header[SADB_MAX_CHANNELS]; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("sad",filename_extension(filename))) goto fail; - - /* check header magic */ - if (read_32bitBE(0x0,streamFile) != 0x73616462) goto fail; /* "sadb" */ + /* check extension */ + if (!check_extensions(streamFile, "sad")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x73616462) /* "sadb" */ + goto fail; channel_count = read_8bit(0x32, streamFile); - if (channel_count != 1 && channel_count != 2) goto fail; - - if (read_dsp_header(&ch0_header, 0x80, streamFile)) goto fail; - if (channel_count == 2 && read_dsp_header(&ch1_header, 0xe0, streamFile)) goto fail; + if (channel_count > SADB_MAX_CHANNELS) goto fail; + header_offset = 0x80; + header_spacing = 0x60; start_offset = read_32bitBE(0x48,streamFile); - interleave = 16; + interleave = 0x10; - /* check initial predictor/scale */ - if (ch0_header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile)) - goto fail; - if (channel_count == 2 && ch1_header.initial_ps != (uint8_t)read_8bit(start_offset+interleave,streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain || - (channel_count == 2 &&(ch1_header.format || ch1_header.gain))) - goto fail; - - /* check for agreement */ - if ( channel_count == 2 &&( - ch0_header.sample_count != ch1_header.sample_count || - ch0_header.nibble_count != ch1_header.nibble_count || - ch0_header.sample_rate != ch1_header.sample_rate || - ch0_header.loop_flag != ch1_header.loop_flag || - ch0_header.loop_start_offset != ch1_header.loop_start_offset || - ch0_header.loop_end_offset != ch1_header.loop_end_offset - )) goto fail; - - if (ch0_header.loop_flag) { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/8/channel_count*8; - loop_off = (loop_off/interleave*interleave*channel_count) + (loop_off%interleave); - if (ch0_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) - goto fail; - if (channel_count == 2 && - ch1_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off+interleave,streamFile)) - goto fail; - } + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + //todo: loop check fails unless adjusted: + // loop_offset = (loop_offset / spacing * spacing * channels) + (loop_offset % spacing); + //if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; /* build the VGMSTREAM */ - - vgmstream = allocate_vgmstream(channel_count,ch0_header.loop_flag); + vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; + vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; - /* TODO: adjust for interleave? */ - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = channel_count == 2 ? layout_interleave : layout_none; - vgmstream->interleave_block_size = interleave; vgmstream->meta_type = meta_DSP_SADB; + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); - /* coeffs */ - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - if (channel_count == 2) - vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - - if (channel_count == 2) { - vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; - vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; - vgmstream->ch[1].streamfile = vgmstream->ch[0].streamfile; - } - - if (!vgmstream->ch[0].streamfile) goto fail; - /* open the file for reading */ - for (i=0;ich[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+i*interleave; - } - + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; return vgmstream; fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } @@ -1219,7 +1230,7 @@ fail: Lego Indiana Jones - The Original Adventures (Wii) Lego Indiana Jones 2 - The Adventure Continues (Wii) Lego Star Wars - The Complete Saga (Wii) - Lego The Lord of the Rings (Wii) + Lego The Lord of the Rings (Wii) The Chronicles of Narnia - Prince Caspian (Wii) */ VGMSTREAM * init_vgmstream_wii_idsp(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; @@ -1232,7 +1243,7 @@ VGMSTREAM * init_vgmstream_wii_idsp(STREAMFILE *streamFile) { /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if ((strcasecmp("gcm",filename_extension(filename))) && - (strcasecmp("idsp",filename_extension(filename)))) + (strcasecmp("idsp",filename_extension(filename)))) goto fail; /* check header magic */ @@ -1255,14 +1266,14 @@ VGMSTREAM * init_vgmstream_wii_idsp(STREAMFILE *streamFile) { start_offset = 0xe0; } - else if (read_32bitBE(0x4, streamFile) == 3 && //Lego The Lord of the Rings (Wii) - read_32bitBE(0x8, streamFile) == 0x12c) - { - if (read_dsp_header(&ch0_header, 0x20, streamFile)) goto fail; - if (read_dsp_header(&ch1_header, 0x80, streamFile)) goto fail; + else if (read_32bitBE(0x4, streamFile) == 3 && //Lego The Lord of the Rings (Wii) + read_32bitBE(0x8, streamFile) == 0x12c) + { + if (read_dsp_header(&ch0_header, 0x20, streamFile)) goto fail; + if (read_dsp_header(&ch1_header, 0x80, streamFile)) goto fail; - start_offset = 0xe0; - } + start_offset = 0xe0; + } else goto fail; interleave = read_32bitBE(0xc, streamFile); @@ -1350,551 +1361,220 @@ fail: return NULL; } -/* .wsd files, two DSP files stuck together */ -/* found in Phantom Brave Wii */ +#define WSD_MAX_CHANNELS 2 +/* .wsd - Custom heade + full interleaved dsp [Phantom Brave (Wii)] */ VGMSTREAM * init_vgmstream_wii_wsd(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - off_t channel_1_start, channel_2_start, channel_1_size, channel_2_size; - - struct dsp_header ch0_header,ch1_header; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("wsd",filename_extension(filename))) goto fail; - - /* read .wsd header */ - channel_1_start = read_32bitBE(0x0,streamFile); - channel_2_start = read_32bitBE(0x4,streamFile); - channel_1_size = read_32bitBE(0x8,streamFile); - channel_2_size = read_32bitBE(0xc,streamFile); - - /* check header */ - if (channel_1_size != channel_2_size) goto fail; - if (channel_1_start != 0x20) goto fail; - if (channel_1_size < 0x20 || channel_2_size < 0x20) goto fail; - if (channel_1_start + channel_1_size > channel_2_start) goto fail; - if (channel_2_start + channel_2_size > get_streamfile_size(streamFile)) - goto fail; - - /* get DSP headers */ - if (read_dsp_header(&ch0_header, channel_1_start, streamFile)) goto fail; - if (read_dsp_header(&ch1_header, channel_2_start, streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch0_header.initial_ps != - (uint8_t)read_8bit(channel_1_start + 0x60, streamFile)) - goto fail; - - if (ch1_header.initial_ps != - (uint8_t)read_8bit(channel_2_start + 0x60, streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain || - ch1_header.format || ch1_header.gain) - goto fail; - - /* check for agreement */ - if ( - ch0_header.sample_count != ch1_header.sample_count || - ch0_header.nibble_count != ch1_header.nibble_count || - ch0_header.sample_rate != ch1_header.sample_rate || - ch0_header.loop_flag != ch1_header.loop_flag || - ch0_header.loop_start_offset != ch1_header.loop_start_offset || - ch0_header.loop_end_offset != ch1_header.loop_end_offset - ) goto fail; - - if (ch0_header.loop_flag) { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/16*8; - if (ch0_header.loop_ps != - (uint8_t)read_8bit(channel_1_start+0x60+loop_off,streamFile)) - goto fail; - if (ch1_header.loop_ps != - (uint8_t)read_8bit(channel_2_start+0x60+loop_off,streamFile)) - goto fail; - } - - /* build the VGMSTREAM */ - - vgmstream = allocate_vgmstream(2,ch0_header.loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; - - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_none; - vgmstream->meta_type = meta_DSP_WII_WSD; - - /* coeffs */ - { - int i; - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; - } - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; - vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; - - /* open the file for reading */ - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) goto fail; - - vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[1].streamfile) goto fail; - - vgmstream->ch[0].channel_start_offset = - vgmstream->ch[0].offset=channel_1_start+0x60; - vgmstream->ch[1].channel_start_offset = - vgmstream->ch[1].offset=channel_2_start+0x60; - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - -/* .ddsp files, two DSP files stuck together, without additional header */ -VGMSTREAM * init_vgmstream_dsp_ddsp(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - off_t channel_1_start, channel_2_start, channel_1_size, channel_2_size; - - struct dsp_header ch0_header,ch1_header; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("ddsp",filename_extension(filename))) goto fail; - - /* read .wsd header */ - channel_1_start = 0; - channel_2_start = (get_streamfile_size(streamFile)/2); - channel_1_size = (get_streamfile_size(streamFile)/2)-0x60; - channel_2_size = (get_streamfile_size(streamFile)/2)-0x60; - - /* check header */ - if (channel_1_size != channel_2_size) goto fail; - if (channel_1_start != 0x0) goto fail; - if (channel_1_size < 0x20 || channel_2_size < 0x20) goto fail; - if (channel_1_start + channel_1_size > channel_2_start) goto fail; - if (channel_2_start + channel_2_size > get_streamfile_size(streamFile)) - goto fail; - - /* get DSP headers */ - if (read_dsp_header(&ch0_header, channel_1_start, streamFile)) goto fail; - if (read_dsp_header(&ch1_header, channel_2_start, streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch0_header.initial_ps != - (uint8_t)read_8bit(channel_1_start + 0x60, streamFile)) - goto fail; - - if (ch1_header.initial_ps != - (uint8_t)read_8bit(channel_2_start + 0x60, streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain || - ch1_header.format || ch1_header.gain) - goto fail; - - /* check for agreement */ - if ( - ch0_header.sample_count != ch1_header.sample_count || - ch0_header.nibble_count != ch1_header.nibble_count || - ch0_header.sample_rate != ch1_header.sample_rate || - ch0_header.loop_flag != ch1_header.loop_flag || - ch0_header.loop_start_offset != ch1_header.loop_start_offset || - ch0_header.loop_end_offset != ch1_header.loop_end_offset - ) goto fail; - - if (ch0_header.loop_flag) { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/16*8; - if (ch0_header.loop_ps != - (uint8_t)read_8bit(channel_1_start+0x60+loop_off,streamFile)) - goto fail; - if (ch1_header.loop_ps != - (uint8_t)read_8bit(channel_2_start+0x60+loop_off,streamFile)) - goto fail; - } - - /* build the VGMSTREAM */ - - vgmstream = allocate_vgmstream(2,ch0_header.loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; - - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_none; - vgmstream->meta_type = meta_DSP_DDSP; - - /* coeffs */ - { - int i; - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; - } - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; - vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; - - /* open the file for reading */ - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) goto fail; - - vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[1].streamfile) goto fail; - - vgmstream->ch[0].channel_start_offset = - vgmstream->ch[0].offset=channel_1_start+0x60; - vgmstream->ch[1].channel_start_offset = - vgmstream->ch[1].offset=channel_2_start+0x60; - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - -/* .was files, DSP file(s), with additional iSWS header */ -VGMSTREAM * init_vgmstream_wii_was(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - struct dsp_header ch0_header,ch1_header; - off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start; + off_t start_offset, header_offset; + size_t header_spacing, interleave; int channel_count; - int i; + struct dsp_header ch_header[WSD_MAX_CHANNELS]; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if ((strcasecmp("dsp",filename_extension(filename))) && - (strcasecmp("isws",filename_extension(filename))) && - (strcasecmp("was",filename_extension(filename)))) - goto fail; - - /* read iSWS header */ - if (read_32bitBE(0x0,streamFile) != 0x69535753) - goto fail; - - channel_count = read_32bitBE(0x08,streamFile); - - if (channel_count == 1) - { - - ch1_header_start = 0x20; - ch1_start = 0x80; - - /* get DSP headers */ - if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain) - goto fail; - - if (ch0_header.loop_flag) - { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/16*8; - if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile)) - goto fail; - } - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(1,ch0_header.loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; - - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_none; - vgmstream->meta_type = meta_WII_WAS; - - /* coeffs */ - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - - /* open the file for reading */ - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) - goto fail; - vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start; - - } - else if (channel_count == 2) - { - - - ch1_header_start = 0x20; - ch2_header_start = 0x80; - ch1_start = 0xE0; - ch2_start = 0xE0 + (read_32bitBE(0x10,streamFile)); - - /* get DSP headers */ - if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail; - if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile)) - goto fail; - if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain) - goto fail; - if (ch1_header.format || ch1_header.gain) - goto fail; - - /* check for agreement */ - if ( - ch0_header.sample_count != ch1_header.sample_count || - ch0_header.nibble_count != ch1_header.nibble_count || - ch0_header.sample_rate != ch1_header.sample_rate || - ch0_header.loop_flag != ch1_header.loop_flag || - ch0_header.loop_start_offset != ch1_header.loop_start_offset || - ch0_header.loop_end_offset != ch1_header.loop_end_offset - ) goto fail; - - if (ch0_header.loop_flag) - { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/16*8; - - if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile)) - goto fail; - if (ch1_header.loop_ps != (uint8_t)read_8bit(ch2_start+loop_off,streamFile)) - goto fail; - } - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(2,ch0_header.loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; - - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitBE(0x10,streamFile); - vgmstream->meta_type = meta_WII_WAS; - - /* coeffs */ - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; - vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; - - /* open the file for reading */ - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) - goto fail; - vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start; - - vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[1].streamfile) - goto fail; - vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start; - - } - else - { - goto fail; - } - - return vgmstream; - - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - -/* .str found in Micro Machines, Superman: Shadow of Apokolips */ -VGMSTREAM * init_vgmstream_dsp_str_ig(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - struct dsp_header ch0_header,ch1_header; - off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start; - int channel_count; - int i; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("str",filename_extension(filename))) - goto fail; + /* check extension */ + if (!check_extensions(streamFile, "wsd")) + goto fail; + if (read_32bitBE(0x08,streamFile) != read_32bitBE(0x0c,streamFile)) /* channel sizes */ + goto fail; channel_count = 2; + if (channel_count > WSD_MAX_CHANNELS) goto fail; - ch1_header_start = 0x00; - ch2_header_start = 0x80; - ch1_start = 0x800; - ch2_start = 0x4800; + header_offset = read_32bitBE(0x00,streamFile); + header_spacing = read_32bitBE(0x04,streamFile) - header_offset; + start_offset = header_offset + 0x60; + interleave = header_spacing; - /* get DSP headers */ - if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail; - if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile)) - goto fail; - if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain) - goto fail; - if (ch1_header.format || ch1_header.gain) - goto fail; - - /* check for agreement */ - if ( - ch0_header.sample_count != ch1_header.sample_count || - ch0_header.nibble_count != ch1_header.nibble_count || - ch0_header.sample_rate != ch1_header.sample_rate || - ch0_header.loop_flag != ch1_header.loop_flag || - ch0_header.loop_start_offset != ch1_header.loop_start_offset || - ch0_header.loop_end_offset != ch1_header.loop_end_offset - ) goto fail; - - if (ch0_header.loop_flag) - { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/16*8; - - if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile)) - goto fail; - if (ch1_header.loop_ps != (uint8_t)read_8bit(ch2_start+loop_off,streamFile)) - goto fail; - } + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count, ch0_header.loop_flag); + vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; + vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; + vgmstream->meta_type = meta_DSP_WII_WSD; vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x4000; - vgmstream->meta_type = meta_DSP_STR_IG; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); - /* coeffs */ - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; - vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; - - /* open the file for reading */ - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) - goto fail; - vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start; - - vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[1].streamfile) - goto fail; - vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start; - + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; return vgmstream; - fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } -/* .dsp found in: Speed Challenge - Jacques Villeneuve's Racing Vision (NGC) - XIII (NGC) - always 2 channels, and an interleave of 0x8 */ +#define DDSP_MAX_CHANNELS 2 +/* .ddsp - full interleaved dsp [The Sims 2 - Pets (Wii)] */ +VGMSTREAM * init_vgmstream_dsp_ddsp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset, header_offset; + size_t header_spacing, interleave; + int channel_count; + struct dsp_header ch_header[DDSP_MAX_CHANNELS]; + + /* check extension */ + if (!check_extensions(streamFile, "ddsp")) + goto fail; + + channel_count = 2; + if (channel_count > DDSP_MAX_CHANNELS) goto fail; + + header_offset = 0x00; + header_spacing = (get_streamfile_size(streamFile) / channel_count); + start_offset = 0x60; + interleave = header_spacing; + + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; + + vgmstream->meta_type = meta_DSP_DDSP; + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + +#define ISWS_MAX_CHANNELS 2 +/* iSWS - Sumo Digital header + interleaved dsp [DiRT 2 (Wii), F1 2009 (Wii)] */ +VGMSTREAM * init_vgmstream_wii_was(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset, header_offset; + size_t header_spacing, interleave; + int channel_count; + struct dsp_header ch_header[ISWS_MAX_CHANNELS]; + + /* check extension */ + if (!check_extensions(streamFile, "was,dsp,isws")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x69535753) /* "iSWS" */ + goto fail; + + channel_count = read_32bitBE(0x08,streamFile); + if (channel_count > ISWS_MAX_CHANNELS) goto fail; + + header_offset = 0x08 + read_32bitBE(0x04,streamFile); + header_spacing = 0x60; + start_offset = header_offset + channel_count*header_spacing; + interleave = read_32bitBE(0x10,streamFile); + + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; + + vgmstream->meta_type = meta_WII_WAS; + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + +#define STR_IG_MAX_CHANNELS 2 +/* .str - Infogrames raw interleaved dsp [Micro Machines (GC), Superman: Shadow of Apokolips (GC)] */ +VGMSTREAM * init_vgmstream_dsp_str_ig(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset, header_offset; + size_t header_spacing, interleave; + int channel_count; + struct dsp_header ch_header[STR_IG_MAX_CHANNELS]; + + /* check extension */ + if (!check_extensions(streamFile, "str")) + goto fail; + + channel_count = 2; + if (channel_count > STR_IG_MAX_CHANNELS) goto fail; + + header_offset = 0x00; + header_spacing = 0x80; + start_offset = 0x800; + interleave = 0x4000; + + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; + + vgmstream->meta_type = meta_DSP_STR_IG; + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + +/* .dsp - Ubisoft raw interleaved dsp [Speed Challenge: Jacques Villeneuve's Racing Vision (GC), XIII (GC)] */ +//todo unusual loop values VGMSTREAM * init_vgmstream_dsp_xiii(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; @@ -1903,10 +1583,9 @@ VGMSTREAM * init_vgmstream_dsp_xiii(STREAMFILE *streamFile) { int channel_count; int i; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("dsp",filename_extension(filename))) - goto fail; + /* check extension */ + if (!check_extensions(streamFile, "dsp")) + goto fail; channel_count = 2; @@ -1987,12 +1666,12 @@ VGMSTREAM * init_vgmstream_dsp_xiii(STREAMFILE *streamFile) { /* open the file for reading */ vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[0].streamfile) - goto fail; + goto fail; vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start; vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[1].streamfile) - goto fail; + goto fail; vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start; return vgmstream; @@ -2005,105 +1684,56 @@ fail: } -/* .ndp found in Vertigo (WII) */ +#define NDP_MAX_CHANNELS 2 +/* NPD - Icon Games header + subinterleaved DSPs [Vertigo (Wii), Build n' Race (Wii)] */ VGMSTREAM * init_vgmstream_wii_ndp(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - struct dsp_header ch0_header,ch1_header; - off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start; - int i; + off_t start_offset, header_offset; + size_t header_spacing, interleave; + int channel_count; + struct dsp_header ch_header[NDP_MAX_CHANNELS]; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("ndp",filename_extension(filename))) - goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x4E445000) /* NDP */ - goto fail; - - /* check size */ - if ((read_32bitLE(0x8,streamFile)+0x18 != get_streamfile_size(streamFile))) /* NDP */ - goto fail; - //channel_count = (read_16bitLE(0x10,streamFile) != 2); + /* check extension */ + if (!check_extensions(streamFile, "ndp")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x4E445000) /* "NDP\0" */ + goto fail; + if (read_32bitLE(0x08,streamFile) + 0x18 != get_streamfile_size(streamFile)) + goto fail; + /* 0x0c: sample rate */ - ch1_header_start = 0x18; - ch2_header_start = 0x78; - ch1_start = 0xD8; - ch2_start = 0xDC; + channel_count = read_32bitLE(0x10,streamFile); + if (channel_count > NDP_MAX_CHANNELS) goto fail; - /* get DSP headers */ - if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail; - if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile)) - goto fail; - if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile)) - goto fail; + header_offset = 0x18; + header_spacing = 0x60; + start_offset = header_offset + channel_count*header_spacing; + interleave = 0x04; - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain) - goto fail; - if (ch1_header.format || ch1_header.gain) - goto fail; - - /* check for agreement */ - if ( - ch0_header.sample_count != ch1_header.sample_count || - ch0_header.nibble_count != ch1_header.nibble_count || - ch0_header.sample_rate != ch1_header.sample_rate || - ch0_header.loop_flag != ch1_header.loop_flag || - ch0_header.loop_start_offset != ch1_header.loop_start_offset || - ch0_header.loop_end_offset != ch1_header.loop_end_offset - ) goto fail; - - if (ch0_header.loop_flag) - { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/16*8; - - if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile)) - goto fail; - if (ch1_header.loop_ps != (uint8_t)read_8bit(ch2_start+loop_off,streamFile)) - goto fail; - } + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(2, ch0_header.loop_flag); + vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; - - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; + vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; + vgmstream->meta_type = meta_WII_NDP; vgmstream->coding_type = coding_NGC_DSP_subint; vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = 0x4; - vgmstream->meta_type = meta_WII_NDP; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); - /* coeffs */ - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; - vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; - - /* open the file for reading */ - if (!vgmstream_open_stream(vgmstream,streamFile,ch1_start)) + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; return vgmstream; @@ -2124,7 +1754,7 @@ VGMSTREAM * init_vgmstream_dsp_cabelas(STREAMFILE *streamFile) { /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("dsp",filename_extension(filename))) - goto fail; + goto fail; channel_count = 2; @@ -2192,12 +1822,12 @@ VGMSTREAM * init_vgmstream_dsp_cabelas(STREAMFILE *streamFile) { /* open the file for reading */ vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[0].streamfile) - goto fail; + goto fail; vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start; vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[1].streamfile) - goto fail; + goto fail; vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start; return vgmstream; @@ -2210,248 +1840,133 @@ fail: } - -/* dual dsp header with additional "AAAp" header, found in Vexx (NGC) and Turok: Evolution (NGC) */ +#define AAAP_MAX_CHANNELS 2 +/* AAAp - Acclaim Austin Audio header + interleaved dsp [Vexx (GC), Turok: Evolution (GC)] */ VGMSTREAM * init_vgmstream_ngc_dsp_aaap(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - struct dsp_header ch0_header,ch1_header; - off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start; + off_t start_offset, header_offset; + size_t header_spacing, interleave; int channel_count; - int i; + struct dsp_header ch_header[AAAP_MAX_CHANNELS]; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("dsp",filename_extension(filename))) - goto fail; + /* check extension */ + if (!check_extensions(streamFile, "dsp")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x41414170) /* "AAAp" */ + goto fail; - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x41414170) /* AAAp */ - goto fail; - - channel_count = (uint16_t)read_16bitBE(0x6,streamFile); + channel_count = read_16bitBE(0x06,streamFile); + if (channel_count > AAAP_MAX_CHANNELS) goto fail; - ch1_header_start = 0x08; - ch2_header_start = 0x68; - ch1_start = 0xC8; - ch2_start = ch1_start + (uint16_t)read_16bitBE(0x4,streamFile); + header_offset = 0x08; + header_spacing = 0x60; + start_offset = header_offset + channel_count*header_spacing; + interleave = (uint16_t)read_16bitBE(0x04,streamFile); - /* get DSP headers */ - if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail; - if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile)) - goto fail; - if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain) - goto fail; - if (ch1_header.format || ch1_header.gain) - goto fail; - - /* check for agreement */ - if ( - ch0_header.sample_count != ch1_header.sample_count || - ch0_header.nibble_count != ch1_header.nibble_count || - ch0_header.sample_rate != ch1_header.sample_rate || - ch0_header.loop_flag != ch1_header.loop_flag || - ch0_header.loop_start_offset != ch1_header.loop_start_offset || - ch0_header.loop_end_offset != ch1_header.loop_end_offset - ) goto fail; - - if (ch0_header.loop_flag) - { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/16*8; - - if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile)) - goto fail; - if (ch1_header.loop_ps != (uint8_t)read_8bit(ch2_start+loop_off,streamFile)) - goto fail; - } + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,ch0_header.loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; - - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = ch2_start-ch1_start; - vgmstream->meta_type = meta_NGC_DSP_AAAP; - - /* coeffs */ - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; - vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; - - /* open the file for reading */ - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) - goto fail; - vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start; - - vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[1].streamfile) - goto fail; - vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start; - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - -/* .dspw files, multiple DSP files stuck together */ -/* found in Sengoku Basara 3 Wii */ -VGMSTREAM * init_vgmstream_dsp_dspw(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - off_t streamSize, mrkrOffset, channelSpacing; - int channel_count, i, j; - int found_mrkr = 0; - VARDECL(struct dsp_header, ch_header); - VARDECL(off_t, channel_start); - - channel_count = (unsigned char)read_8bit(0x1B, streamFile); - - ALLOC(ch_header, channel_count, struct dsp_header); - ALLOC(channel_start, channel_count, off_t); - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("dspw",filename_extension(filename))) goto fail; - - if (read_32bitBE(0x0,streamFile) != 0x44535057) // DSPW - goto fail; - - streamSize = read_32bitBE(0x8, streamFile); - - - if (read_32bitBE(streamSize - 0x10, streamFile) == 0x74494D45) // tIME - streamSize -= 0x10; - - mrkrOffset = streamSize - 4; - while ((mrkrOffset > streamSize - 0x1000) && !(found_mrkr)) { // some files have a mrkr section with multiple loop regions at the end - if (read_32bitBE(mrkrOffset, streamFile) != 0x6D726B72) // mrkr - mrkrOffset -= 4; - else { - streamSize = mrkrOffset; - found_mrkr++; - } - } - streamSize -= 0x20; // minus the main header - channelSpacing = streamSize / channel_count; - - /* read .dspw header */ - for (i = 0; i < channel_count; i++) { - channel_start[i] = 0x20 + i*channelSpacing; - - /* get DSP headers */ - if (read_dsp_header(&ch_header[i], channel_start[i], streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch_header[i].initial_ps != - (uint8_t)read_8bit(channel_start[i] + 0x60, streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch_header[i].format || ch_header[i].gain) - goto fail; - - /* check for agreement */ - if (i > 0) { - if ( - ch_header[i].sample_count != ch_header[i-1].sample_count || - ch_header[i].nibble_count != ch_header[i-1].nibble_count || - ch_header[i].sample_rate != ch_header[i-1].sample_rate || - ch_header[i].loop_flag != ch_header[i-1].loop_flag || - ch_header[i].loop_start_offset != ch_header[i-1].loop_start_offset || - ch_header[i].loop_end_offset != ch_header[i-1].loop_end_offset - ) goto fail; - } - - if (ch_header[0].loop_flag) { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch_header[0].loop_start_offset/16*8; - if (ch_header[i].loop_ps != - (uint8_t)read_8bit(channel_start[i]+0x60+loop_off,streamFile)) - goto fail; - } - } - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - vgmstream->num_samples = ch_header[0].sample_count; vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch_header[0].loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch_header[0].loop_end_offset)+1; - + vgmstream->meta_type = meta_NGC_DSP_AAAP; vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_none; - // vgmstream->layout_type = layout_interleave; - // vgmstream->interleave_block_size = channelSpacing; - vgmstream->meta_type = meta_DSP_DSPW; - - /* coeffs */ - for (i=0;ich[i].adpcm_coef[j] = ch_header[i].coef[j]; - } - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[i].adpcm_history1_16 = ch_header[i].initial_hist1; - vgmstream->ch[i].adpcm_history2_16 = ch_header[i].initial_hist2; - } - - - - /* open the file for reading */ - - for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[i].streamfile) goto fail; - - vgmstream->ch[i].channel_start_offset = - vgmstream->ch[i].offset=channel_start[i]+0x60; - } + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); + 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; +} + + +#define DSPW_MAX_CHANNELS 6 /* 6ch in Monster Hunter 3 Ultimate */ +/* DSPW - Capcom header + full interleaved DSP [Sengoku Basara 3 (Wii), Monster Hunter 3 Ultimate (WiiU)] */ +VGMSTREAM * init_vgmstream_dsp_dspw(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset, header_offset; + size_t header_spacing, interleave, data_size; + int channel_count; + struct dsp_header ch_header[DSPW_MAX_CHANNELS]; + + /* check extension */ + if (!check_extensions(streamFile, "dspw")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x44535057) /* "DSPW" */ + goto fail; + + + /* 0x10: loop start, 0x14: loop end, 0x1c: num_samples */ + channel_count = read_32bitBE(0x18, streamFile); + if (channel_count > DSPW_MAX_CHANNELS) goto fail; + + data_size = read_32bitBE(0x08, streamFile); + if (read_32bitBE(data_size - 0x10, streamFile) == 0x74494D45) /* "tIME" */ + data_size -= 0x10; /* (ignore, 2 ints in YYYYMMDD hhmmss00) */ + + /* some files have a mrkr section with multiple loop regions added at the end (variable size) */ + { + off_t mrkr_offset = data_size - 0x04; + off_t max_offset = data_size - 0x1000; + while (mrkr_offset > max_offset) { + if (read_32bitBE(mrkr_offset, streamFile) != 0x6D726B72) { /* "mrkr" */ + mrkr_offset -= 0x04; + } else { + data_size = mrkr_offset; + break; + } + } + } + data_size -= 0x20; /* header size */ + + header_offset = 0x20; + header_spacing = data_size / channel_count; + start_offset = header_offset + 0x60; + interleave = data_size / channel_count; + + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; + + vgmstream->meta_type = meta_DSP_DSPW; + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); return NULL; } @@ -2468,11 +1983,11 @@ VGMSTREAM * init_vgmstream_ngc_dsp_iadp(STREAMFILE *streamFile) { /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("iadp",filename_extension(filename))) - goto fail; + goto fail; /* check header */ if (read_32bitBE(0x0,streamFile) != 0x69616470) /* iadp */ - goto fail; + goto fail; channel_count = read_32bitBE(0x4,streamFile); @@ -2531,10 +2046,8 @@ VGMSTREAM * init_vgmstream_ngc_dsp_iadp(STREAMFILE *streamFile) { vgmstream->num_samples = ch0_header.sample_count; vgmstream->sample_rate = ch0_header.sample_rate; - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch0_header.loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch0_header.loop_end_offset)+1; vgmstream->coding_type = coding_NGC_DSP; vgmstream->interleave_block_size = read_32bitBE(0x8,streamFile); @@ -2557,12 +2070,12 @@ VGMSTREAM * init_vgmstream_ngc_dsp_iadp(STREAMFILE *streamFile) { /* open the file for reading */ vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[0].streamfile) - goto fail; + goto fail; vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start; vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[1].streamfile) - goto fail; + goto fail; vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start; return vgmstream; @@ -2573,58 +2086,42 @@ fail: return NULL; } -/* the csmp format from Metroid Prime 3 and DKCR */ - -#define CSMP_MAGIC 0x43534D50 -#define CSMP_DATA 0x44415441 - -struct csmp_chunk { - uint32_t id; - uint32_t length; -}; - +//todo might be only part of a full header? +/* CSMP - Retro Studios header + interleaved DSPs [Metroid Prime 3 (Wii), Donkey Kong Country Returns (Wii)] */ VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; + off_t start_offset; char filename[PATH_LIMIT]; long current_offset; int tries; - struct dsp_header header; - const off_t start_offset = 0x60; - int i; - int csmp_magic; - int csmp_version; + int chanel_count, i; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("csmp",filename_extension(filename))) goto fail; - current_offset = 0; + if (read_32bitBE(0x00, streamFile) != 0x43534D50) /* "CSMP" */ + goto fail; + if (read_32bitBE(0x04, streamFile) != 1) /* version? */ + goto fail; - csmp_magic = read_32bitBE(current_offset, streamFile); - if (csmp_magic != CSMP_MAGIC) goto fail; + chanel_count = 1; + start_offset = 0x60; - current_offset += 4; - - csmp_version = read_32bitBE(current_offset, streamFile); - if (csmp_version != 1) goto fail; - - current_offset += 4; - - tries =0; - while (1) - { - struct csmp_chunk chunk; + current_offset = 0x08; + tries = 0; + while (1) { + uint32_t chunk_id, chunk_size; if (tries > 4) goto fail; - - chunk.id = read_32bitBE(current_offset, streamFile); - chunk.length = read_32bitBE(current_offset + 4, streamFile); - current_offset += 8; - if (chunk.id != CSMP_DATA) - { - current_offset += chunk.length; + + chunk_id = read_32bitBE(current_offset + 0x00, streamFile); + chunk_size = read_32bitBE(current_offset + 0x04, streamFile); + current_offset += 0x08; + if (chunk_id != 0x44415441) { /* "DATA" */ + current_offset += chunk_size; tries++; continue; } @@ -2632,10 +2129,12 @@ VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile) { break; } - if (read_dsp_header(&header, current_offset, streamFile)) goto fail; + if (read_dsp_header(&header, current_offset, streamFile)) goto fail; + + /* check initial predictor/scale */ - /* Retro doesn't seem to abide by this */ + /* Retro doesn't seem to abide by this */ //if (header.initial_ps != (uint8_t)read_8bit(current_offset + start_offset,streamFile)) // goto fail; @@ -2647,7 +2146,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile) { // off_t loop_off; /* check loop predictor/scale */ // loop_off = header.loop_start_offset/16*8; - /* Retro doesn't seem to abide by this */ + /* 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; } @@ -2659,19 +2158,15 @@ VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile) { */ /* build the VGMSTREAM */ - - - vgmstream = allocate_vgmstream(1,header.loop_flag); + vgmstream = allocate_vgmstream(chanel_count,header.loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->num_samples = header.sample_count; vgmstream->sample_rate = header.sample_rate; - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - header.loop_end_offset)+1; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(header.loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(header.loop_end_offset)+1; /* don't know why, but it does happen*/ if (vgmstream->loop_end_sample > vgmstream->num_samples) @@ -2684,25 +2179,18 @@ VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile) { /* coeffs */ for (i=0;i<16;i++) vgmstream->ch[0].adpcm_coef[i] = header.coef[i]; - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ vgmstream->ch[0].adpcm_history1_16 = header.initial_hist1; vgmstream->ch[0].adpcm_history2_16 = header.initial_hist2; /* open the file for reading */ vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) goto fail; - vgmstream->ch[0].channel_start_offset= - vgmstream->ch[0].offset=current_offset + start_offset; + vgmstream->ch[0].offset=current_offset + start_offset; return vgmstream; fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } - diff --git a/src/meta/ogg_vorbis.c b/src/meta/ogg_vorbis.c index 79704ec1..0c680e3e 100644 --- a/src/meta/ogg_vorbis.c +++ b/src/meta/ogg_vorbis.c @@ -193,13 +193,13 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) { /* check extension */ - if (check_extensions(streamFile,"ogg,logg")) { /* .ogg: standard/psychic, .logg: renamed for plugins */ + if (check_extensions(streamFile,"ogg,logg,adx")) { /* .ogg: standard/psychic, .logg: renamed for plugins, .adx: KID [Remember11 (PC)] */ is_ogg = 1; } else if (check_extensions(streamFile,"um3")) { is_um3 = 1; } else if (check_extensions(streamFile,"kvs,kovs")) { /* .kvs: Atelier Sophie (PC), kovs: header id only? */ is_kovs = 1; - } else if (check_extensions(streamFile,"sngw")) { /* .sngw: Devil May Cry 4 SE (PC), Biohazard 6 (PC) */ + } else if (check_extensions(streamFile,"sngw")) { /* .sngw: Capcom [Devil May Cry 4 SE (PC), Biohazard 6 (PC)] */ is_sngw = 1; } else if (check_extensions(streamFile,"isd")) { /* .isd: Azure Striker Gunvolt (PC) */ is_isd = 1; @@ -390,7 +390,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch loop_length = atol(strrchr(user_comment,'=')+1); loop_length_found = 1; } - else if (strstr(user_comment,"title=-lps")==user_comment) { /* Memories Off #5 (PC) */ + else if (strstr(user_comment,"title=-lps")==user_comment) { /* KID [Memories Off #5 (PC), Remember11 (PC)] */ loop_start = atol(user_comment+10); loop_flag = (loop_start >= 0); } diff --git a/src/meta/ps2_mihb.c b/src/meta/ps2_mihb.c index 826d1d5c..9f3118db 100644 --- a/src/meta/ps2_mihb.c +++ b/src/meta/ps2_mihb.c @@ -1,72 +1,53 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* MIHB (Merged MIH+MIB) */ +/* MIC/MIHB - Merged MIH+MIB [Rogue Trooper (PS2), The Sims 2 (PS2)] */ VGMSTREAM * init_vgmstream_ps2_mihb(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; off_t start_offset; - int mib_blocks; - int loop_flag = 0; - int channel_count; + size_t data_size, frame_size, frame_last, frame_count; + int channel_count, loop_flag; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("mihb",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x40000000) + /* check extension */ + /* .mic: Rebellion Dev. games, .mihb: assumed? */ + if (!check_extensions(streamFile, "mic,mihb")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x40000000) /* header size */ goto fail; - mib_blocks = read_32bitLE(0x14,streamFile); loop_flag = 0; channel_count = read_32bitLE(0x08,streamFile); - + start_offset = 0x40; + + /* frame_size * frame_count * channels = data_size, but last frame has less usable data */ + { + /* 0x04(1): 0x20? */ + frame_last = (uint16_t)read_16bitLE(0x05,streamFile); + frame_size = read_32bitLE(0x10,streamFile); + frame_count = read_32bitLE(0x14,streamFile); + + data_size = frame_count * frame_size; + data_size -= frame_last ? (frame_size-frame_last) : 0; + data_size *= channel_count; + } + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = 0x40; - vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(0x0C,streamFile); + vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count); + + vgmstream->meta_type = meta_PS2_MIHB; vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = ((read_32bitLE(0x10,streamFile))*mib_blocks)*28/16; - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = ((read_32bitLE(0x10,streamFile))*mib_blocks)*28/16; - } - - - if (vgmstream->channels > 1) { - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0x10,streamFile); - } else { - vgmstream->layout_type = layout_none; - } - - vgmstream->meta_type = meta_PS2_MIHB; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = frame_size; + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } diff --git a/src/meta/riff.c b/src/meta/riff.c index 7b810ae5..969ee083 100644 --- a/src/meta/riff.c +++ b/src/meta/riff.c @@ -232,9 +232,9 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { int fact_sample_skip = 0; int loop_flag = 0; - int loop_start_sample = 0, loop_end_sample = 0; long loop_start_ms = -1, loop_end_ms = -1; - off_t loop_start_offset = -1, loop_end_offset = -1; + int32_t loop_start_wsmp = -1, loop_end_wsmp = -1; + int32_t loop_start_smpl = -1, loop_end_smpl = -1; int FormatChunkFound = 0, DataChunkFound = 0, JunkFound = 0; @@ -248,8 +248,9 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { /* check extension */ /* .lwav: to avoid hijacking .wav, .xwav: fake for Xbox games (unneded anymore) */ - /* .da: The Great Battle VI (PS), .cd: Exector (PS), .med: Psi Ops (PC), .snd: Layton Brothers (iOS/Android) */ - if ( check_extensions(streamFile, "wav,lwav,xwav,da,cd,med,snd") ) { + /* .da: The Great Battle VI (PS), .cd: Exector (PS), .med: Psi Ops (PC), .snd: Layton Brothers (iOS/Android), + * .adx: Remember11 (PC) sfx */ + if ( check_extensions(streamFile, "wav,lwav,xwav,da,cd,med,snd,adx") ) { ; } else if ( check_extensions(streamFile, "mwv") ) { @@ -347,8 +348,8 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { * 0x2c: start, 0x30: end, 0x34: fraction, 0x38: play count */ if (read_32bitLE(current_chunk+0x08+0x28, streamFile)==0) { loop_flag = 1; - loop_start_offset = read_32bitLE(current_chunk+0x08+0x2c, streamFile); - loop_end_offset = read_32bitLE(current_chunk+0x08+0x30, streamFile); + loop_start_smpl = read_32bitLE(current_chunk+0x08+0x2c, streamFile); + loop_end_smpl = read_32bitLE(current_chunk+0x08+0x30, streamFile); } } break; @@ -363,9 +364,9 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { /* 0x14: size, 0x18: loop type (0=forward, 1=release), 0x1c: loop start, 0x20: loop length */ if (read_32bitLE(current_chunk+0x08+0x18, streamFile)==0) { loop_flag = 1; - loop_start_sample = read_32bitLE(current_chunk+0x08+0x1c, streamFile); - loop_end_sample = read_32bitLE(current_chunk+0x08+0x20, streamFile); - loop_end_sample += loop_start_sample; + loop_start_wsmp = read_32bitLE(current_chunk+0x08+0x1c, streamFile); + loop_end_wsmp = read_32bitLE(current_chunk+0x08+0x20, streamFile); + loop_end_wsmp += loop_start_wsmp; } } break; @@ -528,8 +529,8 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { /* RIFF loop/sample values are absolute (with skip samples), adjust */ if (loop_flag) { - loop_start_offset -= ffmpeg_data->skipSamples; - loop_end_offset -= ffmpeg_data->skipSamples; + loop_start_smpl -= (int32_t)ffmpeg_data->skipSamples; + loop_end_smpl -= (int32_t)ffmpeg_data->skipSamples; } } break; @@ -560,8 +561,8 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { vgmstream->num_samples = fact_sample_count; /* RIFF loop/sample values are absolute (with skip samples), adjust */ if (loop_flag) { - loop_start_offset -= fact_sample_skip; - loop_end_offset -= fact_sample_skip; + loop_start_smpl -= fact_sample_skip; + loop_end_smpl -= fact_sample_skip; } break; @@ -603,14 +604,14 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { vgmstream->loop_end_sample = (long long)loop_end_ms*fmt.sample_rate/1000; vgmstream->meta_type = meta_RIFF_WAVE_labl; } - else if (loop_start_offset >= 0) { - vgmstream->loop_start_sample = loop_start_offset; - vgmstream->loop_end_sample = loop_end_offset; + else if (loop_start_smpl >= 0) { + vgmstream->loop_start_sample = loop_start_smpl; + vgmstream->loop_end_sample = loop_end_smpl; vgmstream->meta_type = meta_RIFF_WAVE_smpl; } - else if (loop_start_sample >= 0) { - vgmstream->loop_start_sample = loop_start_sample; - vgmstream->loop_end_sample = loop_end_sample; + else if (loop_start_wsmp >= 0) { + vgmstream->loop_start_sample = loop_start_wsmp; + vgmstream->loop_end_sample = loop_end_wsmp; vgmstream->meta_type = meta_RIFF_WAVE_wsmp; } else if (mwv && mwv_ctrl_offset != -1) { diff --git a/src/meta/sqex_sead.c b/src/meta/sqex_sead.c index cd2cbf5c..14d55138 100644 --- a/src/meta/sqex_sead.c +++ b/src/meta/sqex_sead.c @@ -304,32 +304,33 @@ typedef struct { static size_t sead_decryption_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, sead_decryption_data* data) { /* Found in FFXII_TZA.exe (same key in SCD Ogg V3) */ static const uint8_t encryption_key[0x100] = { - 0x3A, 0x32, 0x32, 0x32, 0x03, 0x7E, 0x12, 0xF7, 0xB2, 0xE2, 0xA2, 0x67, 0x32, 0x32, 0x22, 0x32, // 00-0F - 0x32, 0x52, 0x16, 0x1B, 0x3C, 0xA1, 0x54, 0x7B, 0x1B, 0x97, 0xA6, 0x93, 0x1A, 0x4B, 0xAA, 0xA6, // 10-1F - 0x7A, 0x7B, 0x1B, 0x97, 0xA6, 0xF7, 0x02, 0xBB, 0xAA, 0xA6, 0xBB, 0xF7, 0x2A, 0x51, 0xBE, 0x03, // 20-2F - 0xF4, 0x2A, 0x51, 0xBE, 0x03, 0xF4, 0x2A, 0x51, 0xBE, 0x12, 0x06, 0x56, 0x27, 0x32, 0x32, 0x36, // 30-3F - 0x32, 0xB2, 0x1A, 0x3B, 0xBC, 0x91, 0xD4, 0x7B, 0x58, 0xFC, 0x0B, 0x55, 0x2A, 0x15, 0xBC, 0x40, // 40-4F - 0x92, 0x0B, 0x5B, 0x7C, 0x0A, 0x95, 0x12, 0x35, 0xB8, 0x63, 0xD2, 0x0B, 0x3B, 0xF0, 0xC7, 0x14, // 50-5F - 0x51, 0x5C, 0x94, 0x86, 0x94, 0x59, 0x5C, 0xFC, 0x1B, 0x17, 0x3A, 0x3F, 0x6B, 0x37, 0x32, 0x32, // 60-6F - 0x30, 0x32, 0x72, 0x7A, 0x13, 0xB7, 0x26, 0x60, 0x7A, 0x13, 0xB7, 0x26, 0x50, 0xBA, 0x13, 0xB4, // 70-7F - 0x2A, 0x50, 0xBA, 0x13, 0xB5, 0x2E, 0x40, 0xFA, 0x13, 0x95, 0xAE, 0x40, 0x38, 0x18, 0x9A, 0x92, // 80-8F - 0xB0, 0x38, 0x00, 0xFA, 0x12, 0xB1, 0x7E, 0x00, 0xDB, 0x96, 0xA1, 0x7C, 0x08, 0xDB, 0x9A, 0x91, // 90-9F - 0xBC, 0x08, 0xD8, 0x1A, 0x86, 0xE2, 0x70, 0x39, 0x1F, 0x86, 0xE0, 0x78, 0x7E, 0x03, 0xE7, 0x64, // A0-AF - 0x51, 0x9C, 0x8F, 0x34, 0x6F, 0x4E, 0x41, 0xFC, 0x0B, 0xD5, 0xAE, 0x41, 0xFC, 0x0B, 0xD5, 0xAE, // B0-BF - 0x41, 0xFC, 0x3B, 0x70, 0x71, 0x64, 0x33, 0x32, 0x12, 0x32, 0x32, 0x36, 0x70, 0x34, 0x2B, 0x56, // C0-CF - 0x22, 0x70, 0x3A, 0x13, 0xB7, 0x26, 0x60, 0xBA, 0x1B, 0x94, 0xAA, 0x40, 0x38, 0x00, 0xFA, 0xB2, // D0-DF - 0xE2, 0xA2, 0x67, 0x32, 0x32, 0x12, 0x32, 0xB2, 0x32, 0x32, 0x32, 0x32, 0x75, 0xA3, 0x26, 0x7B, // E0-EF - 0x83, 0x26, 0xF9, 0x83, 0x2E, 0xFF, 0xE3, 0x16, 0x7D, 0xC0, 0x1E, 0x63, 0x21, 0x07, 0xE3, 0x01, // F0-FF + 0x3A,0x32,0x32,0x32,0x03,0x7E,0x12,0xF7,0xB2,0xE2,0xA2,0x67,0x32,0x32,0x22,0x32, // 00-0F + 0x32,0x52,0x16,0x1B,0x3C,0xA1,0x54,0x7B,0x1B,0x97,0xA6,0x93,0x1A,0x4B,0xAA,0xA6, // 10-1F + 0x7A,0x7B,0x1B,0x97,0xA6,0xF7,0x02,0xBB,0xAA,0xA6,0xBB,0xF7,0x2A,0x51,0xBE,0x03, // 20-2F + 0xF4,0x2A,0x51,0xBE,0x03,0xF4,0x2A,0x51,0xBE,0x12,0x06,0x56,0x27,0x32,0x32,0x36, // 30-3F + 0x32,0xB2,0x1A,0x3B,0xBC,0x91,0xD4,0x7B,0x58,0xFC,0x0B,0x55,0x2A,0x15,0xBC,0x40, // 40-4F + 0x92,0x0B,0x5B,0x7C,0x0A,0x95,0x12,0x35,0xB8,0x63,0xD2,0x0B,0x3B,0xF0,0xC7,0x14, // 50-5F + 0x51,0x5C,0x94,0x86,0x94,0x59,0x5C,0xFC,0x1B,0x17,0x3A,0x3F,0x6B,0x37,0x32,0x32, // 60-6F + 0x30,0x32,0x72,0x7A,0x13,0xB7,0x26,0x60,0x7A,0x13,0xB7,0x26,0x50,0xBA,0x13,0xB4, // 70-7F + 0x2A,0x50,0xBA,0x13,0xB5,0x2E,0x40,0xFA,0x13,0x95,0xAE,0x40,0x38,0x18,0x9A,0x92, // 80-8F + 0xB0,0x38,0x00,0xFA,0x12,0xB1,0x7E,0x00,0xDB,0x96,0xA1,0x7C,0x08,0xDB,0x9A,0x91, // 90-9F + 0xBC,0x08,0xD8,0x1A,0x86,0xE2,0x70,0x39,0x1F,0x86,0xE0,0x78,0x7E,0x03,0xE7,0x64, // A0-AF + 0x51,0x9C,0x8F,0x34,0x6F,0x4E,0x41,0xFC,0x0B,0xD5,0xAE,0x41,0xFC,0x0B,0xD5,0xAE, // B0-BF + 0x41,0xFC,0x3B,0x70,0x71,0x64,0x33,0x32,0x12,0x32,0x32,0x36,0x70,0x34,0x2B,0x56, // C0-CF + 0x22,0x70,0x3A,0x13,0xB7,0x26,0x60,0xBA,0x1B,0x94,0xAA,0x40,0x38,0x00,0xFA,0xB2, // D0-DF + 0xE2,0xA2,0x67,0x32,0x32,0x12,0x32,0xB2,0x32,0x32,0x32,0x32,0x75,0xA3,0x26,0x7B, // E0-EF + 0x83,0x26,0xF9,0x83,0x2E,0xFF,0xE3,0x16,0x7D,0xC0,0x1E,0x63,0x21,0x07,0xE3,0x01, // F0-FF }; size_t bytes_read; + off_t encrypted_offset = data->header_size; int i; bytes_read = streamfile->read(streamfile, dest, offset, length); /* decrypt data (xor) */ - if (offset >= data->header_size) { + if (offset >= encrypted_offset) { for (i = 0; i < bytes_read; i++) { - dest[i] ^= encryption_key[(data->key_start + (offset - data->header_size) + i) % 0x100]; + dest[i] ^= encryption_key[(data->key_start + (offset - encrypted_offset) + i) % 0x100]; } } diff --git a/src/meta/txth.c b/src/meta/txth.c index 82d6e560..1edce04e 100644 --- a/src/meta/txth.c +++ b/src/meta/txth.c @@ -206,7 +206,15 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) { vgmstream->layout_type = layout_none; break; case coding_XBOX_IMA: - vgmstream->layout_type = layout_none; + if (txth.codec_mode == 1) { + if (!txth.interleave) goto fail; /* creates garbage */ + coding = coding_XBOX_IMA_int; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = txth.interleave; + } + else { + vgmstream->layout_type = layout_none; + } break; case coding_NGC_DTK: if (vgmstream->channels != 2) goto fail; diff --git a/src/meta/waf.c b/src/meta/waf.c new file mode 100644 index 00000000..c8efd92b --- /dev/null +++ b/src/meta/waf.c @@ -0,0 +1,43 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* WAF - KID's earlier PC games [ever17 (PC)] (for RLE-compressed WAFs see https://github.com/dsp2003/e17p) */ +VGMSTREAM * init_vgmstream_waf(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag, channel_count; + + + /* check extension */ + if (!check_extensions(streamFile, "waf")) + goto fail; + + if (read_32bitBE(0x00,streamFile) != 0x57414600) /* "WAF\0" "*/ + goto fail; + if (read_32bitLE(0x34,streamFile) + 0x38 != get_streamfile_size(streamFile)) + goto fail; + + channel_count = read_16bitLE(0x06,streamFile); + loop_flag = 0; + start_offset = 0x38; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = read_32bitLE(0x08, streamFile); + vgmstream->meta_type = meta_WAF; + vgmstream->coding_type = coding_MSADPCM; + vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = read_16bitLE(0x10, streamFile); + vgmstream->num_samples = msadpcm_bytes_to_samples(read_32bitLE(0x34,streamFile), vgmstream->interleave_block_size, channel_count); + /* 0x04: null?, 0x0c: avg br, 0x12: bps, 0x14: s_p_f, 0x16~34: count + standard MSADPCM coefs (a modified RIFF fmt) */ + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/meta/wwise.c b/src/meta/wwise.c index 61c72e02..19fa3b5e 100644 --- a/src/meta/wwise.c +++ b/src/meta/wwise.c @@ -451,7 +451,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { vgmstream->num_samples = msd.num_samples; if (!vgmstream->num_samples) - vgmstream->num_samples = ffmpeg_data->totalSamples; /* very wrong, from avg-br */ + vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples; /* very wrong, from avg-br */ //num_samples seem to be found in the last "seek" table entry too, as: entry / channels / 2 } @@ -470,7 +470,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; - vgmstream->num_samples = ffmpeg_data->totalSamples; + vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples; break; } diff --git a/src/meta/xwb.c b/src/meta/xwb.c index 383b31cc..9746b4f9 100644 --- a/src/meta/xwb.c +++ b/src/meta/xwb.c @@ -420,7 +420,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) { /* no wma_bytes_to_samples, this should be ok */ if (!vgmstream->num_samples) - vgmstream->num_samples = ffmpeg_data->totalSamples; + vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples; break; } diff --git a/src/streamfile.c b/src/streamfile.c index 9c3c75c0..0e894e9e 100644 --- a/src/streamfile.c +++ b/src/streamfile.c @@ -492,7 +492,7 @@ static void fakename_close(FAKENAME_STREAMFILE *streamfile) { free(streamfile); } -STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, char * fakename, char* fakeext) { +STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, const char * fakename, const char* fakeext) { FAKENAME_STREAMFILE *this_sf; if (!streamfile || (!fakename && !fakeext)) return NULL; diff --git a/src/streamfile.h b/src/streamfile.h index 6841b939..ff160027 100644 --- a/src/streamfile.h +++ b/src/streamfile.h @@ -88,7 +88,7 @@ STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_s * Can be used to trick a meta's extension check (to call from another, with a modified SF). * When fakename isn't supplied it's read from the streamfile, and the extension swapped with fakeext. * If the fakename is an existing file, open won't work on it as it'll reopen the fake-named streamfile. */ -STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, char * fakename, char * fakeext); +STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, const char * fakename, const char * fakeext); /* A streamfile formed from multiple streamfiles, their data joined during reads. * Can be used when data is segmented in multiple separate files. diff --git a/src/vgmstream.c b/src/vgmstream.c index 463f1e09..eb15f229 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -375,10 +375,11 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_kma9, init_vgmstream_fsb_encrypted, init_vgmstream_xwc, - init_vgmstream_atsl3, + init_vgmstream_atsl, init_vgmstream_sps_n1, init_vgmstream_atx, init_vgmstream_sqex_sead, + init_vgmstream_waf, init_vgmstream_txth, /* should go at the end (lower priority) */ #ifdef VGM_USE_FFMPEG @@ -911,9 +912,9 @@ int32_t get_vgmstream_play_samples(double looptimes, double fadeseconds, double + (vgmstream->num_samples - vgmstream->loop_end_sample); } else { - return vgmstream->loop_start_sample + return (int32_t)(vgmstream->loop_start_sample + (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * looptimes - + (fadedelayseconds + fadeseconds) * vgmstream->sample_rate; + + (fadedelayseconds + fadeseconds) * vgmstream->sample_rate); } } else { diff --git a/src/vgmstream.h b/src/vgmstream.h index 5121be79..39c60dde 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -661,6 +661,7 @@ typedef enum { meta_SQEX_SAB, /* Square-Enix newest middleware (sound) */ meta_SQEX_MAB, /* Square-Enix newest middleware (music) */ meta_OGG_L2SD, /* Ogg Vorbis with obfuscation [Lineage II Chronicle 4 (PC)] */ + meta_WAF, /* KID WAF [Ever 17 (PC)] */ #ifdef VGM_USE_MP4V2 meta_MP4, /* AAC (iOS) */ diff --git a/winamp/in_vgmstream.c b/winamp/in_vgmstream.c index 24b68ff3..cab93049 100644 --- a/winamp/in_vgmstream.c +++ b/winamp/in_vgmstream.c @@ -170,11 +170,11 @@ static off_t wasf_get_offset(WINAMP_STREAMFILE *streamfile) { } static void wasf_get_name(WINAMP_STREAMFILE *streamfile, char *buffer, size_t length) { - return streamfile->stdiosf->get_name(streamfile->stdiosf, buffer, length); + streamfile->stdiosf->get_name(streamfile->stdiosf, buffer, length); } static void wasf_get_realname(WINAMP_STREAMFILE *streamfile, char *buffer, size_t length) { - return streamfile->stdiosf->get_realname(streamfile->stdiosf, buffer, length); + streamfile->stdiosf->get_realname(streamfile->stdiosf, buffer, length); } static STREAMFILE *wasf_open(WINAMP_STREAMFILE *streamFile, const char *const filename, size_t buffersize) { diff --git a/winamp/in_vgmstream.vcxproj b/winamp/in_vgmstream.vcxproj index 0fe193c1..8df8276d 100644 --- a/winamp/in_vgmstream.vcxproj +++ b/winamp/in_vgmstream.vcxproj @@ -52,7 +52,9 @@ - + + ../dependencies + <_ProjectFileVersion>10.0.30319.1 AllRules.ruleset @@ -68,7 +70,7 @@ Disabled - ../ext_includes;../dependencies/qaac/mp4v2/include;../dependencies/fdk-aac/libSYS/include;../dependencies/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) + ../ext_includes;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) WIN32;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;_DEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks @@ -96,7 +98,7 @@ - ../ext_includes;../dependencies/qaac/mp4v2/include;../dependencies/fdk-aac/libSYS/include;../dependencies/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) + ../ext_includes;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) WIN32;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;NDEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) MultiThreaded @@ -134,10 +136,10 @@ - + {308e2ad5-be31-4770-9441-a8d50f56895c} - + {86a064e2-c81b-4eee-8be0-a39a2e7c7c76} diff --git a/xmplay/xmp-vgmstream.vcxproj b/xmplay/xmp-vgmstream.vcxproj index 57f445bd..d77f9493 100644 --- a/xmplay/xmp-vgmstream.vcxproj +++ b/xmplay/xmp-vgmstream.vcxproj @@ -43,7 +43,9 @@ - + + ../dependencies + <_ProjectFileVersion>10.0.30319.1 AllRules.ruleset @@ -59,7 +61,7 @@ Disabled - ../ext_includes;../dependencies/qaac/mp4v2/include;../dependencies/fdk-aac/libSYS/include;../dependencies/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) + ../ext_includes;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) WIN32;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;_DEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks @@ -84,7 +86,7 @@ - ../ext_includes;../dependencies/qaac/mp4v2/include;../dependencies/fdk-aac/libSYS/include;../dependencies/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) + ../ext_includes;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories) _WIN32_WINNT=0x501;WIN32;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;NDEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) MultiThreaded Level3 @@ -123,10 +125,10 @@ - + {308e2ad5-be31-4770-9441-a8d50f56895c} - + {86a064e2-c81b-4eee-8be0-a39a2e7c7c76}