From bb07299daed8577836aeb8388e94aa3c0c7bc833 Mon Sep 17 00:00:00 2001 From: bnnm Date: Mon, 20 Aug 2018 19:21:51 +0200 Subject: [PATCH 01/55] Make libvorbis/libmpg123 optional in autotools --- BUILD.md | 2 +- configure.ac | 34 +++++++++++++++++++------------- src/Makefile.autotools.am | 13 +++++++++++- src/layout/Makefile.autotools.am | 9 +++++++++ src/meta/Makefile.autotools.am | 9 +++++++++ 5 files changed, 51 insertions(+), 16 deletions(-) diff --git a/BUILD.md b/BUILD.md index 7f720a4a..4fc53ed6 100644 --- a/BUILD.md +++ b/BUILD.md @@ -85,7 +85,7 @@ Requires the dev version of Audacious (and dependencies), automake/autoconf, and The plugin needs Audacious 3.5 or higher. New Audacious releases can break plugin compatibility so it may not work with the latest version unless adapted first. -FFmpeg and other external libraries aren't enabled, thus some formats are not supported. libvorbis and libmpg123 can be disabled with -DVGM_DISABLE_VORBIS and -DVGM_DISABLE_MPEG. +libvorbis and libmpg123 will be used if found, while FFmpeg and other external libraries aren't enabled, thus some formats won't work. Windows builds aren't supported at the moment (should be possible but there are complex dependency chains). diff --git a/configure.ac b/configure.ac index 94f61852..3e4456d8 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ -dnl audacious-vgmstream m4 script +dnl automake-vgmstream m4 script dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.53) -AC_INIT(audacious-vgmstream,1.3.0) +AC_INIT(automake-vgmstream,1.3.0) AM_INIT_AUTOMAKE([subdir-objects]) AC_CONFIG_HEADERS(audacious/config.h) AM_DISABLE_STATIC @@ -17,22 +17,28 @@ AM_PROG_LIBTOOL AC_PATH_X AC_PATH_XTRA +have_vorbis=no +PKG_CHECK_MODULES(VORBIS, [vorbis], have_vorbis=yes, + [AC_MSG_WARN([Cannot find libvorbis - will not enable Vorbis formats])] +) +AM_CONDITIONAL(HAVE_VORBIS, test "$have_vorbis" = yes) + +have_vorbisfile=no +PKG_CHECK_MODULES(VORBISFILE, [vorbisfile], have_vorbisfile=yes, + [AC_MSG_WARN([Cannot find libvorbisfile - will not enable Vorbis formats])] +) +AM_CONDITIONAL(HAVE_VORBISFILE, test "$have_vorbisfile" = yes) + +have_libmpg123=no +PKG_CHECK_MODULES(MPG123, [libmpg123], have_libmpg123=yes, + [AC_MSG_WARN([Cannot find libmpg123 - will not enable MPEG formats])] +) +AM_CONDITIONAL(HAVE_LIBMPG123, test "$have_libmpg123" = yes) + PKG_CHECK_MODULES(AUDACIOUS, [audacious >= 3.5.0],, [AC_MSG_ERROR([Cannot find audacious >= 3.5.0 correctly installed])] ) -PKG_CHECK_MODULES(VORBIS, [vorbis],, - [AC_MSG_ERROR([Cannot find libvorbis])] -) - -PKG_CHECK_MODULES(VORBISFILE, [vorbisfile],, - [AC_MSG_ERROR([Cannot find libvorbisfile])] -) - -PKG_CHECK_MODULES(MPG123, [libmpg123],, - [AC_MSG_ERROR([Cannot find libmpg123])] -) - PKG_CHECK_MODULES(GTK, [glib-2.0 >= 2.6.0 gtk+-2.0 >= 2.6.0 gthread-2.0 pango], , [AC_MSG_ERROR([Cannot find glib2/gtk2/pango])] ) diff --git a/src/Makefile.autotools.am b/src/Makefile.autotools.am index a15eb51f..68104532 100644 --- a/src/Makefile.autotools.am +++ b/src/Makefile.autotools.am @@ -11,6 +11,17 @@ SUBDIRS = coding layout meta libvgmstream_la_LDFLAGS = coding/libcoding.la layout/liblayout.la meta/libmeta.la libvgmstream_la_SOURCES = (auto-updated) libvgmstream_la_SOURCES += ../ext_libs/clHCA.c -libvgmstream_la_LIBADD = $(AUDACIOUS_LIBS) $(GTK_LIBS) $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(MPG123_LIBS) -lm +libvgmstream_la_LIBADD = $(AUDACIOUS_LIBS) $(GTK_LIBS) -lm EXTRA_DIST = (auto-updated) EXTRA_DIST += ../ext_includes/clHCA.h + +if HAVE_VORBIS +if HAVE_VORBISFILE +AM_CFLAGS += -DVGM_USE_VORBIS +libvgmstream_la_LIBADD += $(VORBISFILE_LIBS) $(VORBIS_LIBS) +endif +endif +if HAVE_LIBMPG123 +AM_CFLAGS += -DVGM_USE_MPEG +libvgmstream_la_LIBADD += $(MPG123_LIBS) +endif diff --git a/src/layout/Makefile.autotools.am b/src/layout/Makefile.autotools.am index 9d0ea898..cd877881 100644 --- a/src/layout/Makefile.autotools.am +++ b/src/layout/Makefile.autotools.am @@ -9,3 +9,12 @@ AM_MAKEFLAGS=-f Makefile.autotools liblayout_la_LDFLAGS = liblayout_la_SOURCES = (auto-updated) EXTRA_DIST = (auto-updated) + +if HAVE_VORBIS +if HAVE_VORBISFILE +AM_CFLAGS += -DVGM_USE_VORBIS +endif +endif +if HAVE_LIBMPG123 +AM_CFLAGS += -DVGM_USE_MPEG +endif diff --git a/src/meta/Makefile.autotools.am b/src/meta/Makefile.autotools.am index 03a89813..c6081a67 100644 --- a/src/meta/Makefile.autotools.am +++ b/src/meta/Makefile.autotools.am @@ -9,3 +9,12 @@ AM_MAKEFLAGS=-f Makefile.autotools libmeta_la_LDFLAGS = libmeta_la_SOURCES = (auto-updated) EXTRA_DIST = (auto-updated) + +if HAVE_VORBIS +if HAVE_VORBISFILE +AM_CFLAGS += -DVGM_USE_VORBIS +endif +endif +if HAVE_LIBMPG123 +AM_CFLAGS += -DVGM_USE_MPEG +endif From 2f0aaaf4fd60f1963304cc7982543fc4fca94d24 Mon Sep 17 00:00:00 2001 From: bnnm Date: Mon, 20 Aug 2018 20:05:44 +0200 Subject: [PATCH 02/55] Fix some compile ifdefs and warnings --- src/meta/atsl.c | 2 ++ src/meta/bnk_sony.c | 2 +- src/meta/mus_acm.c | 2 ++ src/meta/txth.c | 2 +- src/meta/txtp.c | 2 +- src/meta/wave_segmented.c | 2 ++ src/vgmstream.c | 2 +- xmplay/xmp_vgmstream.c | 24 ++++++++++++------------ 8 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/meta/atsl.c b/src/meta/atsl.c index bb19f62f..7ec19024 100644 --- a/src/meta/atsl.c +++ b/src/meta/atsl.c @@ -120,10 +120,12 @@ VGMSTREAM * init_vgmstream_atsl(STREAMFILE *streamFile) { vgmstream = init_vgmstream_riff(temp_streamFile); if (!vgmstream) goto fail; break; +#ifdef VGM_USE_VORBIS case KOVS: vgmstream = init_vgmstream_ogg_vorbis(temp_streamFile); if (!vgmstream) goto fail; break; +#endif case KTSS: vgmstream = init_vgmstream_ktss(temp_streamFile); if (!vgmstream) goto fail; diff --git a/src/meta/bnk_sony.c b/src/meta/bnk_sony.c index 51da0c0f..2e5b1ed0 100644 --- a/src/meta/bnk_sony.c +++ b/src/meta/bnk_sony.c @@ -8,7 +8,7 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { off_t start_offset, stream_offset, name_offset = 0; size_t stream_size; off_t sblk_offset, data_offset; - int channel_count, loop_flag, sample_rate, codec; + int channel_count = 0, loop_flag, sample_rate, codec; int version; uint32_t atrac9_info = 0; int loop_start = 0, loop_length = 0; diff --git a/src/meta/mus_acm.c b/src/meta/mus_acm.c index 84cfc4e2..56b9e69c 100644 --- a/src/meta/mus_acm.c +++ b/src/meta/mus_acm.c @@ -50,9 +50,11 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) { case 0x97280301: /* ACM header id [Planescape: Torment (PC)] */ data->segments[i] = init_vgmstream_acm(temp_streamFile); break; +#ifdef VGM_USE_VORBIS case 0x4F676753: /* "OggS" [Planescape: Torment Enhanced Edition (PC)] */ data->segments[i] = init_vgmstream_ogg_vorbis(temp_streamFile); break; +#endif default: data->segments[i] = NULL; break; diff --git a/src/meta/txth.c b/src/meta/txth.c index f3e2252b..c0bff483 100644 --- a/src/meta/txth.c +++ b/src/meta/txth.c @@ -430,7 +430,7 @@ static int parse_txth(STREAMFILE * streamFile, STREAMFILE * streamText, txth_hea txth->data_size = get_streamfile_size(streamFile); /* for later use */ /* skip BOM if needed */ - if (read_16bitLE(0x00, streamText) == 0xFFFE || read_16bitLE(0x00, streamText) == 0xFEFF) + if ((uint16_t)read_16bitLE(0x00, streamText) == 0xFFFE || (uint16_t)read_16bitLE(0x00, streamText) == 0xFEFF) txt_offset = 0x02; /* read lines */ diff --git a/src/meta/txtp.c b/src/meta/txtp.c index 995bedf6..a735f375 100644 --- a/src/meta/txtp.c +++ b/src/meta/txtp.c @@ -422,7 +422,7 @@ static txtp_header* parse_txtp(STREAMFILE* streamFile) { /* skip BOM if needed */ - if (read_16bitLE(0x00, streamFile) == 0xFFFE || read_16bitLE(0x00, streamFile) == 0xFEFF) + if ((uint16_t)read_16bitLE(0x00, streamFile) == 0xFFFE || (uint16_t)read_16bitLE(0x00, streamFile) == 0xFEFF) txt_offset = 0x02; /* read lines */ diff --git a/src/meta/wave_segmented.c b/src/meta/wave_segmented.c index a4af548c..ddb947bd 100644 --- a/src/meta/wave_segmented.c +++ b/src/meta/wave_segmented.c @@ -134,6 +134,7 @@ VGMSTREAM * init_vgmstream_wave_segmented(STREAMFILE *streamFile) { break; } +#ifdef VGM_USE_VORBIS case 0x04: { /* "vorbis" */ ogg_vorbis_meta_info_t ovmi = {0}; @@ -153,6 +154,7 @@ VGMSTREAM * init_vgmstream_wave_segmented(STREAMFILE *streamFile) { break; } +#endif default: /* others: s16be/s16le/mp3 as referenced in the exe? */ VGM_LOG("WAVE: unknown codec\n"); diff --git a/src/vgmstream.c b/src/vgmstream.c index 139829ae..376a219b 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -2690,7 +2690,7 @@ int get_vgmstream_average_bitrate(VGMSTREAM * vgmstream) { * Should be called in metas before returning the VGMSTREAM. */ int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t start_offset) { - STREAMFILE * file; + STREAMFILE * file = NULL; char filename[PATH_LIMIT]; int ch; int use_streamfile_per_channel = 0; diff --git a/xmplay/xmp_vgmstream.c b/xmplay/xmp_vgmstream.c index eb26f6ce..3d0a48e8 100644 --- a/xmplay/xmp_vgmstream.c +++ b/xmplay/xmp_vgmstream.c @@ -331,20 +331,20 @@ char * WINAPI xmplay_GetTags() { void WINAPI xmplay_GetInfoText(char* format, char* length) { if (!format) return; - if (!vgmstream) - return; + if (!vgmstream) + return; - int rate = vgmstream->sample_rate; - int samples = vgmstream->num_samples; - int bps = get_vgmstream_average_bitrate(vgmstream) / 1000; - char* fmt = get_vgmstream_coding_description(vgmstream->coding_type); - - int t = samples / rate; - int tmin = t / 60; - int tsec = t % 60; + int rate = vgmstream->sample_rate; + int samples = vgmstream->num_samples; + int bps = get_vgmstream_average_bitrate(vgmstream) / 1000; + const char* fmt = get_vgmstream_coding_description(vgmstream->coding_type); - sprintf(format, "%s", fmt); - sprintf(length, "%d:%02d - %dKb/s - %dHz", tmin, tsec, bps, rate); + int t = samples / rate; + int tmin = t / 60; + int tsec = t % 60; + + sprintf(format, "%s", fmt); + sprintf(length, "%d:%02d - %dKb/s - %dHz", tmin, tsec, bps, rate); } /* info for the "General" window/tab (buf is ~40K) */ From cae82e90747cbaf77ba87e5918be0d8f1f332d18 Mon Sep 17 00:00:00 2001 From: bnnm Date: Mon, 20 Aug 2018 20:08:24 +0200 Subject: [PATCH 03/55] Clean builds and enable VGM_USE_VORBIS/MPEG manually for consistency --- Makefile | 6 +++--- cli/Makefile | 16 ++++++---------- cli/test.vcproj | 2 +- cli/test.vcxproj | 4 ++-- ext_libs/Makefile | 4 ++-- fb2k/foo_input_vgmstream.vcproj | 4 ++-- fb2k/foo_input_vgmstream.vcxproj | 4 ++-- src/libvgmstream.vcproj | 4 ++-- src/libvgmstream.vcxproj | 4 ++-- src/vgmstream.h | 17 ++++------------- winamp/Makefile | 15 ++++++--------- winamp/in_vgmstream.vcproj | 2 +- winamp/in_vgmstream.vcxproj | 4 ++-- xmplay/Makefile | 15 ++++++--------- xmplay/xmp-vgmstream.vcxproj | 4 ++-- 15 files changed, 43 insertions(+), 62 deletions(-) diff --git a/Makefile b/Makefile index cd7bff0f..efa21762 100644 --- a/Makefile +++ b/Makefile @@ -4,13 +4,13 @@ ### defs # currently aimed to WIN32 builds but vgmstream_cli should work for others (or use autotools instead) -export TARGET_OS = WIN32 - +export TARGET_OS = $(OS) + ### tools RMF = rm -f -ifeq ($(TARGET_OS),WIN32) +ifeq ($(TARGET_OS),Windows_NT) SHELL = sh CC = gcc AR = ar diff --git a/cli/Makefile b/cli/Makefile index 93d1e39b..245a7521 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -5,7 +5,7 @@ ### main defs -ifeq ($(TARGET_OS),WIN32) +ifeq ($(TARGET_OS),Windows_NT) OUTPUT_CLI = test.exe OUTPUT_123 = vgmstream123.exe else @@ -14,12 +14,12 @@ else endif # -DUSE_ALLOCA -ifeq ($(TARGET_OS),WIN32) +ifeq ($(TARGET_OS),Windows_NT) CFLAGS += -DWIN32 endif CFLAGS += -Wall -O3 -DVAR_ARRAYS -I../ext_includes $(EXTRA_CFLAGS) -LDFLAGS += -L../src -L../ext_libs -lm -lvgmstream $(EXTRA_LDFLAGS) +LDFLAGS += -L../src -L../ext_libs -lvgmstream $(EXTRA_LDFLAGS) -lm TARGET_EXT_LIBS = LIBAO_INC_PATH = ../../libao/include @@ -32,24 +32,20 @@ LIBAO_LIB_PATH = ../../libao/bin ### external libs -ifeq ($(TARGET_OS),WIN32) +ifeq ($(TARGET_OS),Windows_NT) VGM_ENABLE_VORBIS = 1 ifeq ($(VGM_ENABLE_VORBIS),1) - #CFLAGS += -DVGM_USE_VORBIS + CFLAGS += -DVGM_USE_VORBIS LDFLAGS += -lvorbis TARGET_EXT_LIBS += libvorbis.a -else - CFLAGS += -DVGM_DISABLE_VORBIS endif VGM_ENABLE_MPEG = 1 ifeq ($(VGM_ENABLE_MPEG),1) - #CFLAGS += -DVGM_USE_MPEG + CFLAGS += -DVGM_USE_MPEG LDFLAGS += -lmpg123-0 TARGET_EXT_LIBS += libmpg123-0.a -else - CFLAGS += -DVGM_DISABLE_MPEG endif VGM_ENABLE_G7221 = 1 diff --git a/cli/test.vcproj b/cli/test.vcproj index 17264224..2f916d66 100644 --- a/cli/test.vcproj +++ b/cli/test.vcproj @@ -121,7 +121,7 @@ Optimization="2" EnableIntrinsicFunctions="true" AdditionalIncludeDirectories="..\ext_libs\Getopt;..\ext_includes" - PreprocessorDefinitions="WIN32;VGM_USE_G7221;NDEBUG;_CONSOLE" + PreprocessorDefinitions="WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_G7221;NDEBUG;_CONSOLE" RuntimeLibrary="2" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" diff --git a/cli/test.vcxproj b/cli/test.vcxproj index 82258039..588672ee 100644 --- a/cli/test.vcxproj +++ b/cli/test.vcxproj @@ -71,7 +71,7 @@ Disabled ../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;VGM_USE_ATRAC9;VGM_USE_CELT;_DEBUG;_WINDOWS;_CONSOLE;%(PreprocessorDefinitions) + WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;VGM_USE_ATRAC9;VGM_USE_CELT;_DEBUG;_WINDOWS;_CONSOLE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug @@ -97,7 +97,7 @@ ../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;VGM_USE_ATRAC9;VGM_USE_CELT;NDEBUG;_WINDOWS;_CONSOLE;%(PreprocessorDefinitions) + WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;VGM_USE_ATRAC9;VGM_USE_CELT;NDEBUG;_WINDOWS;_CONSOLE;%(PreprocessorDefinitions) MultiThreaded diff --git a/ext_libs/Makefile b/ext_libs/Makefile index af644561..826cf54f 100644 --- a/ext_libs/Makefile +++ b/ext_libs/Makefile @@ -3,8 +3,8 @@ # # needed? -ifneq ($(TARGET_OS),WIN32) -$(error option must be built with TARGET_OS = WIN32) +ifneq ($(TARGET_OS),Windows_NT) +$(error option must be built with TARGET_OS = Windows_NT) endif diff --git a/fb2k/foo_input_vgmstream.vcproj b/fb2k/foo_input_vgmstream.vcproj index e142a1b0..411856dc 100644 --- a/fb2k/foo_input_vgmstream.vcproj +++ b/fb2k/foo_input_vgmstream.vcproj @@ -42,7 +42,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="../ext_includes" - PreprocessorDefinitions="WIN32;VGM_USE_FFMPEG;VGM_USE_G719;VGM_USE_G7221;_DEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;" + PreprocessorDefinitions="WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G719;VGM_USE_G7221;_DEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -120,7 +120,7 @@ Disabled ../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;VGM_USE_ATRAC9;VGM_USE_CELT;_DEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) + WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;VGM_USE_ATRAC9;VGM_USE_CELT;_DEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug @@ -98,7 +98,7 @@ ../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;VGM_USE_ATRAC9;VGM_USE_CELT;NDEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) + WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;VGM_USE_ATRAC9;VGM_USE_CELT;NDEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) MultiThreaded diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 81ae3a83..49a9f8fa 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -41,7 +41,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="../ext_includes" - PreprocessorDefinitions="WIN32;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_G719;USE_ALLOCA;_DEBUG;_LIB;" + PreprocessorDefinitions="WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_G719;USE_ALLOCA;_DEBUG;_LIB;" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -103,7 +103,7 @@ Disabled ../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;VGM_USE_CELT;USE_ALLOCA;_DEBUG;_LIB;%(PreprocessorDefinitions) + WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_G719;VGM_USE_MP4V2;VGM_USE_FDKAAC;VGM_USE_ATRAC9;VGM_USE_CELT;USE_ALLOCA;_DEBUG;_LIB;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug @@ -73,7 +73,7 @@ ../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;VGM_USE_CELT;USE_ALLOCA;NDEBUG;_LIB;%(PreprocessorDefinitions) + _WIN32_WINNT=0x501;WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_G719;VGM_USE_MP4V2;VGM_USE_FDKAAC;VGM_USE_ATRAC9;VGM_USE_CELT;USE_ALLOCA;NDEBUG;_LIB;%(PreprocessorDefinitions) MultiThreaded diff --git a/src/vgmstream.h b/src/vgmstream.h index 0ecf8e6e..c9f42bdd 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -10,19 +10,10 @@ enum { STREAM_NAME_SIZE = 255 }; /* reasonable max */ #include "streamfile.h" -/* Due mostly to licensing issues, Vorbis, MPEG, G.722.1, etc decoding is - * done by external libraries. - * If someone wants to do a standalone build, they can do it by simply - * removing these defines (and the references to the libraries in the Makefile) */ -#ifndef VGM_DISABLE_VORBIS -#define VGM_USE_VORBIS -#endif - -#ifndef VGM_DISABLE_MPEG -#define VGM_USE_MPEG -#endif - -/* disabled by default, defined on compile-time for builds that support it */ +/* Due mostly to licensing issues, Vorbis, MPEG, G.722.1, etc decoding is done by external libraries. + * Libs are disabled by default, defined on compile-time for builds that support it */ +//#define VGM_USE_VORBIS +//#define VGM_USE_MPEG //#define VGM_USE_G7221 //#define VGM_USE_G719 //#define VGM_USE_MP4V2 diff --git a/winamp/Makefile b/winamp/Makefile index d1251d92..5c5886c0 100644 --- a/winamp/Makefile +++ b/winamp/Makefile @@ -2,8 +2,9 @@ # Winamp plugin # -ifneq ($(TARGET_OS),WIN32) -$(error option must be built with TARGET_OS = WIN32) + +ifneq ($(TARGET_OS),Windows_NT) +$(error option must be built with TARGET_OS = Windows_NT) endif @@ -16,24 +17,20 @@ TARGET_EXT_LIBS = ### external libs -ifeq ($(TARGET_OS),WIN32) +ifeq ($(TARGET_OS),Windows_NT) VGM_ENABLE_VORBIS = 1 ifeq ($(VGM_ENABLE_VORBIS),1) - #CFLAGS += -DVGM_USE_VORBIS + CFLAGS += -DVGM_USE_VORBIS LDFLAGS += -lvorbis TARGET_EXT_LIBS += libvorbis.a -else - CFLAGS += -DVGM_DISABLE_VORBIS endif VGM_ENABLE_MPEG = 1 ifeq ($(VGM_ENABLE_MPEG),1) - #CFLAGS += -DVGM_USE_MPEG + CFLAGS += -DVGM_USE_MPEG LDFLAGS += -lmpg123-0 TARGET_EXT_LIBS += libmpg123-0.a -else - CFLAGS += -DVGM_DISABLE_MPEG endif VGM_ENABLE_G7221 = 1 diff --git a/winamp/in_vgmstream.vcproj b/winamp/in_vgmstream.vcproj index 33c37853..b453e102 100644 --- a/winamp/in_vgmstream.vcproj +++ b/winamp/in_vgmstream.vcproj @@ -115,7 +115,7 @@ Disabled ../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;VGM_USE_ATRAC9;VGM_USE_CELT;_DEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) + WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;VGM_USE_ATRAC9;VGM_USE_CELT;_DEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug @@ -99,7 +99,7 @@ ../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) + WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;NDEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) MultiThreaded diff --git a/xmplay/Makefile b/xmplay/Makefile index 4253c275..78ee5254 100644 --- a/xmplay/Makefile +++ b/xmplay/Makefile @@ -2,8 +2,9 @@ # XMPlay plugin # -ifneq ($(TARGET_OS),WIN32) -$(error option must be built with TARGET_OS = WIN32) + +ifneq ($(TARGET_OS),Windows_NT) +$(error option must be built with TARGET_OS = Windows_NT) endif @@ -16,24 +17,20 @@ TARGET_EXT_LIBS = ### external libs -ifeq ($(TARGET_OS),WIN32) +ifeq ($(TARGET_OS),Windows_NT) VGM_ENABLE_VORBIS = 1 ifeq ($(VGM_ENABLE_VORBIS),1) - #CFLAGS += -DVGM_USE_VORBIS + CFLAGS += -DVGM_USE_VORBIS LDFLAGS += -lvorbis TARGET_EXT_LIBS += libvorbis.a -else - CFLAGS += -DVGM_DISABLE_VORBIS endif VGM_ENABLE_MPEG = 1 ifeq ($(VGM_ENABLE_MPEG),1) - #CFLAGS += -DVGM_USE_MPEG + CFLAGS += -DVGM_USE_MPEG LDFLAGS += -lmpg123-0 TARGET_EXT_LIBS += libmpg123-0.a -else - CFLAGS += -DVGM_DISABLE_MPEG endif VGM_ENABLE_G7221 = 1 diff --git a/xmplay/xmp-vgmstream.vcxproj b/xmplay/xmp-vgmstream.vcxproj index 41fd6020..56bc7e63 100644 --- a/xmplay/xmp-vgmstream.vcxproj +++ b/xmplay/xmp-vgmstream.vcxproj @@ -62,7 +62,7 @@ Disabled ../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;VGM_USE_ATRAC9;VGM_USE_CELT;_DEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) + WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;VGM_USE_ATRAC9;VGM_USE_CELT;_DEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug @@ -87,7 +87,7 @@ ../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) + _WIN32_WINNT=0x501;WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;NDEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;%(PreprocessorDefinitions) MultiThreaded Level3 ProgramDatabase From fe3538520b927421cad575b715a202e53776d2fc Mon Sep 17 00:00:00 2001 From: bnnm Date: Tue, 21 Aug 2018 22:14:55 +0200 Subject: [PATCH 04/55] Add ps_find_loop_offsets util to find loop point in PS-ADPCM data --- src/coding/coding.h | 2 + src/coding/psx_decoder.c | 127 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 119 insertions(+), 10 deletions(-) diff --git a/src/coding/coding.h b/src/coding/coding.h index 44ed2787..4ca9b29b 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -79,6 +79,8 @@ size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample); /* psx_decoder */ void decode_psx(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int is_badflags); void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size); +int ps_find_loop_offsets(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end); +int ps_find_loop_offsets_full(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end); size_t ps_bytes_to_samples(size_t bytes, int channels); size_t ps_cfg_bytes_to_samples(size_t bytes, size_t frame_size, int channels); diff --git a/src/coding/psx_decoder.c b/src/coding/psx_decoder.c index 63bae82e..8cdf4f7c 100644 --- a/src/coding/psx_decoder.c +++ b/src/coding/psx_decoder.c @@ -40,16 +40,6 @@ static const int ps_adpcm_coefs_i[5][2] = { * Some official PC tools decode using float coefs (from the spec), as does this code, but * consoles/games/libs would vary (PS1 could do it in hardware using BRR/XA's logic, FMOD/PS3 * may use int math in software, etc). There are inaudible rounding diffs between implementations. - * - * Optional bit flag combinations in the header control the SPU: - * 0x0 (0000): Nothing - * 0x1 (0001): End marker + decode - * 0x2 (0010): Loop region - * 0x3 (0011): Loop end - * 0x4 (0100): Start marker - * 0x6 (0110): Loop start - * 0x7 (0111): End marker + don't decode - * 0x5/8+ (1NNN): Not valid */ /* standard PS-ADPCM (float math version) */ @@ -162,6 +152,122 @@ void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int cha stream->adpcm_history2_32 = hist2; } + +/* Find loop samples in PS-ADPCM data and return if the file loops. + * + * PS-ADPCM/VAG has optional bit flags that control looping in the SPU. + * Possible combinations (as usually defined in Sony's docs): + * - 0x0 (0000): Normal decode + * - 0x1 (0001): End marker (last frame) + * - 0x2 (0010): Loop region (marks files that *may* have loop flags somewhere) + * - 0x3 (0011): Loop end (jump to loop address) + * - 0x4 (0100): Start marker + * - 0x5 (0101): Same as 0x07? Extremely rare [Blood Omen: Legacy of Kain (PS1)] + * - 0x6 (0110): Loop start (save loop address) + * - 0x7 (0111): End marker and don't decode + * - 0x8+(1NNN): Not valid + */ +static int ps_find_loop_offsets_internal(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end, int config) { + int num_samples = 0, loop_start = 0, loop_end = 0; + int loop_start_found = 0, loop_end_found = 0; + off_t offset = start_offset; + off_t max_offset = start_offset + data_size; + size_t interleave_consumed = 0; + int detect_full_loops = config & 1; + + + while (offset < max_offset) { + uint8_t flag = (uint8_t)read_8bit(offset+0x01,streamFile) & 0x0F; /* lower nibble only (for HEVAG) */ + + /* theoretically possible and would use last 0x06 */ + VGM_ASSERT_ONCE(loop_start_found && flag == 0x06, "PS LOOPS: multiple loop start found at %lx\n", offset); + + if (flag == 0x06 && !loop_start_found) { + loop_start = num_samples; /* loop start before this frame */ + loop_start_found = 1; + } + + if (flag == 0x03 && !loop_end) { + loop_end = num_samples + 28; /* loop end after this frame */ + loop_end_found = 1; + + /* ignore strange case in Commandos (PS2), has many loop starts and ends */ + if (channels == 1 + && offset + 0x10 < max_offset + && ((uint8_t)read_8bit(offset+0x11,streamFile) & 0x0F) == 0x06) { + loop_end = 0; + loop_end_found = 0; + } + + if (loop_start_found && loop_end_found) + break; + } + + /* hack for some games that don't have loop points but do full loops, + * if there is a "partial" 0x07 end flag pretend it wants to loop + * (sometimes this will loop non-looping tracks, and won't loop all repeating files) */ + if (flag == 0x01 && detect_full_loops) { + static const uint8_t eof1[0x10] = {0x00,0x07,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77}; /* common */ + static const uint8_t eof2[0x10] = {0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + //static const uint8_t eofx[0x10] = {0x07,0x00,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77}; /* sometimes loops */ + //static const uint8_t eofx[0x10] = {0xNN,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; /* sometimes loops */ + uint8_t buf[0x10]; + + int read = read_streamfile(buf,offset+0x10,0x10,streamFile); + + if (read > 0 + /* also test some extra stuff */ + && buf[0] != 0x00 /* skip padding */ + && buf[0] != 0x0c + && buf[0] != 0x3c /* skip Ecco the Dolphin (PS2), Ratchet & Clank 2 (PS2), lame hack */ + ) { + + /* assume full loop if there isn't an EOF tag after current frame */ + if (memcmp(buf,eof1,0x10) != 0 && memcmp(buf,eof2,0x10) != 0) { + loop_start = 28; /* skip first frame as it's null in PS-ADPCM */ + loop_end = num_samples + 28; /* loop end after this frame */ + loop_start_found = 1; + loop_end_found = 1; + //;VGM_LOG("PS LOOPS: full loop found\n"); + break; + } + } + } + + + num_samples += 28; + offset += 0x10; + + /* skip other channels */ + interleave_consumed += 0x10; + if (interleave_consumed == interleave) { + interleave_consumed = 0; + offset += interleave*(channels - 1); + } + } + + VGM_ASSERT(loop_start_found && !loop_end_found, "PS LOOPS: found loop start but not loop end\n"); + VGM_ASSERT(loop_end_found && !loop_start_found, "PS LOOPS: found loop end but not loop start\n"); + //;VGM_LOG("PS LOOPS: start=%i, end=%i\n", loop_start, loop_end); + + /* From Sony's docs: if only loop_end is set loop back to "phoneme region start", but in practice doesn't */ + if (loop_start_found && loop_end_found) { + *out_loop_start = loop_start; + *out_loop_end = loop_end; + return 1; + } + + return 0; /* no loop */ +} + +int ps_find_loop_offsets(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end) { + return ps_find_loop_offsets_internal(streamFile, start_offset, data_size, channels, interleave, out_loop_start, out_loop_end, 0); +} + +int ps_find_loop_offsets_full(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, size_t interleave, int32_t * out_loop_start, int32_t * out_loop_end) { + return ps_find_loop_offsets_internal(streamFile, start_offset, data_size, channels, interleave, out_loop_start, out_loop_end, 1); +} + size_t ps_bytes_to_samples(size_t bytes, int channels) { return bytes / channels / 0x10 * 28; } @@ -169,3 +275,4 @@ size_t ps_bytes_to_samples(size_t bytes, int channels) { size_t ps_cfg_bytes_to_samples(size_t bytes, size_t frame_size, int channels) { return bytes / channels / frame_size * 28; } + From 58b8b0c8df9f993f19a786d2298b5fa05a743e49 Mon Sep 17 00:00:00 2001 From: bnnm Date: Tue, 21 Aug 2018 22:16:56 +0200 Subject: [PATCH 05/55] Fix various .vag issues [Shikigami no Shiro (PS2), Red Star (PS2)] Also cleanup and loop end was also off by 28 samples in several cases --- src/meta/meta.h | 2 +- src/meta/sps_n1.c | 2 +- src/meta/vag.c | 437 ++++++++++++++++++---------------------------- src/vgmstream.c | 6 +- 4 files changed, 175 insertions(+), 272 deletions(-) diff --git a/src/meta/meta.h b/src/meta/meta.h index 38e6fe3c..9ef1d6bf 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -65,7 +65,7 @@ VGMSTREAM * init_vgmstream_ps2_mic(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_raw(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_ps2_vag(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_psx_gms(STREAMFILE *streamFile); diff --git a/src/meta/sps_n1.c b/src/meta/sps_n1.c index 6eca1300..ba0280fc 100644 --- a/src/meta/sps_n1.c +++ b/src/meta/sps_n1.c @@ -29,7 +29,7 @@ VGMSTREAM * init_vgmstream_sps_n1(STREAMFILE *streamFile) { temp_streamFile = setup_sps_streamfile(streamFile, subfile_offset, subfile_size, "vag"); if (!temp_streamFile) goto fail; - vgmstream = init_vgmstream_ps2_vag(temp_streamFile); + vgmstream = init_vgmstream_vag(temp_streamFile); if (!vgmstream) goto fail; break; diff --git a/src/meta/vag.c b/src/meta/vag.c index 9d5303c8..2e58441c 100644 --- a/src/meta/vag.c +++ b/src/meta/vag.c @@ -1,24 +1,25 @@ #include "meta.h" +#include "../coding/coding.h" -static int vag_find_loop_offsets(STREAMFILE *streamFile, off_t start_offset, off_t * loop_start, off_t * loop_end); - -/* VAGp - SDK format, created by various Sony's tools (like AIFF2VAG) */ -VGMSTREAM * init_vgmstream_ps2_vag(STREAMFILE *streamFile) { +/* VAGp - Sony SDK format, created by various tools */ +VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - off_t start_offset, loopStart = 0, loopEnd = 0; + off_t start_offset; + size_t file_size, channel_size, interleave; + meta_t meta_type; + int channel_count = 0, loop_flag, sample_rate; + uint32_t vag_id, version; + int32_t loop_start_sample = 0, loop_end_sample = 0; + //int allow_dual_stereo = 0; - uint8_t vagID; - uint32_t version = 0; - - size_t filesize = 0, datasize = 0, interleave; - - int loop_flag = 0, loop_samples_found = 0; - int channel_count = 0; - int is_swag = 0; /* checks */ - /* .swag: Frantix (PSP), .str: Ben10 Galactic Racing, .vig: MX vs. ATV Untamed (PS2) .l/r: Crash Nitro Kart (PS2) */ + /* .vag: standard + * .swag: Frantix (PSP) + * .str: Ben10 Galactic Racing + * .vig: MX vs. ATV Untamed (PS2) + * .l/r: Crash Nitro Kart (PS2), Gradius V (PS2) */ if ( !check_extensions(streamFile,"vag,swag,str,vig,l,r") ) goto fail; @@ -27,302 +28,204 @@ VGMSTREAM * init_vgmstream_ps2_vag(STREAMFILE *streamFile) { ((read_32bitLE(0x00,streamFile) & 0xFFFFFF00) != 0x56414700)) goto fail; - /* Frantix VAGp .swag: some (not all) fields in LE + 2 VAGp in the same file (full interleave) */ - is_swag = check_extensions(streamFile,"swag"); + file_size = get_streamfile_size(streamFile); - filesize = get_streamfile_size(streamFile); - - /* version used to create the file - * ex: 00000000 = v1.8 PC, 00000002 = v1.3 Mac, 00000003 = v1.6+ Mac, 00000020 = v2.0+ PC */ - version = read_32bitBE(0x04,streamFile); + /* version used to create the file: + * - 00000000 = v1.8 PC, + * - 00000002 = v1.3 Mac (used?) + * - 00000003 = v1.6+ Mac + * - 00000020 = v2.0 PC (most common) + * - 00000004 = ? (later games) + * - 00000006 = ? (vagconv) + * - 00020001 = v2.1 (vagconv2) + * - 00030000 = v3.0 (vagconv2) */ + version = (uint32_t)read_32bitBE(0x04,streamFile); /* 0x08-0c: reserved */ - if (is_swag) - datasize = read_32bitLE(0x0c,streamFile); - else - datasize = read_32bitBE(0x0c,streamFile); + channel_size = read_32bitBE(0x0c,streamFile); + sample_rate = read_32bitBE(0x10,streamFile); /* 0x14-20 reserved */ /* 0x20-30: name (optional) */ /* 0x30: data start (first 0x10 usually 0s to init SPU) */ - /* Check for correct channel count and loop flag */ - vagID=read_8bit(0x03,streamFile); - switch(vagID) { - case '1': /* "VAG1" (1 channel) [Metal Gear Solid 3] */ - channel_count=1; - break; - case '2': /* "VAG2" (2 channels) [Metal Gear Solid 3] */ - channel_count=2; - break; - case 'i': /* "VAGi" (interleaved) */ - channel_count=2; - break; - case 'V': /* pGAV (little endian / stereo) [Jak 3, Jak X] */ - if (read_32bitBE(0x20,streamFile)==0x53746572) /* "Ster" */ - channel_count=2; - else - channel_count=1; - break; - case 'p': /* "VAGp" (extended) [most common, ex Ratchet & Clank] */ - if (check_extensions(streamFile,"vig")) { /* MX vs. ATV Untamed PS2 */ - channel_count = 2; /* normal interleave */ + /* check variation */ + vag_id = read_32bitBE(0x00,streamFile); + switch(vag_id) { + + case 0x56414731: /* "VAG1" (1 channel) [Metal Gear Solid 3 (PS2)] */ + meta_type = meta_PS2_VAG1; + start_offset = 0x40; /* 0x30 is extra data in VAG1 */ + channel_count = 1; + interleave = 0; + loop_flag = 0; + break; + + case 0x56414732: /* "VAG2" (2 channels) [Metal Gear Solid 3 (PS2)] */ + meta_type = meta_PS2_VAG2; + start_offset = 0x40; /* 0x30 is extra data in VAG2 */ + channel_count = 2; + interleave = 0x800; + loop_flag = 0; + break; + + case 0x56414769: /* "VAGi" (interleaved) */ + meta_type = meta_PS2_VAGi; + start_offset = 0x800; + channel_count = 2; + interleave = read_32bitLE(0x08,streamFile); + loop_flag = 0; + break; + + case 0x70474156: /* pGAV (little endian / stereo) [Jak 3 (PS2), Jak X (PS2)] */ + meta_type = meta_PS2_pGAV; + start_offset = 0x00; //todo 0x30, requires interleave_first + + if (read_32bitBE(0x20,streamFile) == 0x53746572) { /* "Ster" */ + channel_count = 2; + + if (read_32bitLE(0x2000,streamFile) == 0x56414770) /* "pGAV" */ + interleave = 0x2000; /* Jak 3 interleave, includes header */ + else if (read_32bitLE(0x1000,streamFile) == 0x56414770) /* "pGAV" */ + interleave = 0x1000; /* Jak X interleave, includes header */ + else + goto fail; + //todo interleave_first = interleave - start_offset; /* interleave includes header */ + } + else { + channel_count = 1; + interleave = 0; + } + + channel_size = read_32bitLE(0x0C,streamFile) / channel_count; + sample_rate = read_32bitLE(0x10,streamFile); + //todo adjust channel_size, includes part of header? + loop_flag = 0; + break; + + case 0x56414770: /* "VAGp" (standard and variations) */ + meta_type = meta_PS2_VAGp; + + if (check_extensions(streamFile,"vig")) { + /* MX vs. ATV Untamed (PS2) */ + start_offset = 0x800 - 0x20; + channel_count = 2; + interleave = 0x10; loop_flag = 0; } + else if (check_extensions(streamFile,"swag")) { /* algo "VAGp" at (file_size / channels) */ + /* Frantix (PSP) */ + start_offset = 0x40; /* channel_size ignores empty frame */ + channel_count = 2; + interleave = file_size / channel_count; + + channel_size = read_32bitLE(0x0c,streamFile); + sample_rate = read_32bitLE(0x10,streamFile); + + loop_flag = ps_find_loop_offsets(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start_sample, &loop_end_sample); + } else if (read_32bitBE(0x6000,streamFile) == 0x56414770) { /* "VAGp" */ - channel_count = 2; /* The Simpsons Wrestling PSX interleave */ + /* The Simpsons Wrestling (PS1) */ + start_offset = 0x00; //todo 0x30, requires interleave_first + channel_count = 2; + interleave = 0x6000; + //todo interleave_first = interleave - start_offset; /* includes header */ + channel_size += 0x30; + loop_flag = 0; } - else if ((version <= 0x00000004) && (datasize < filesize / 2)) { /* two VAGp in the same file */ - if (is_swag) - loop_flag = vag_find_loop_offsets(streamFile, 0x30, &loopStart, &loopEnd); - else - loop_flag = read_32bitBE(0x14,streamFile) != 0; - channel_count=2; - } - else if (version == 0x00020001) { /* HEVAG */ - loop_flag = vag_find_loop_offsets(streamFile, 0x30, &loopStart, &loopEnd); + else if (read_32bitBE(0x1000,streamFile) == 0x56414770) { /* "VAGp" */ + /* Shikigami no Shiro (PS2) */ + start_offset = 0x00; //todo 0x30, requires interleave_first + channel_count = 2; + interleave = 0x1000; + //todo interleave_first = interleave - start_offset; /* includes header */ + channel_size += 0x30; - /* channels are usually at 0x1e, but not in Ukiyo no Roushi which has some kind - * of loop-like values instead (who designs this crap?) */ + loop_flag = ps_find_loop_offsets(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start_sample, &loop_end_sample); + } + else if (read_32bitBE(0x30,streamFile) == 0x56414770) { /* "VAGp" */ + /* The Red Star (PS2) */ + start_offset = 0x60; /* two VAGp headers */ + channel_count = 2; + + if ((file_size - start_offset) % 0x4000 == 0) + interleave = 0x4000; + else if ((file_size - start_offset) % 0x4180 == 0) + interleave = 0x4180; + else + goto fail; + + loop_flag = 0; /* loop segments */ + } + else if (version == 0x40000000) { + /* Killzone (PS2) */ + start_offset = 0x30; + channel_count = 1; + interleave = 0; + + channel_size = read_32bitLE(0x0C,streamFile) / channel_count; + sample_rate = read_32bitLE(0x10,streamFile); + loop_flag = 0; + } + else if (version == 0x00020001 || version == 0x00030000) { + /* standard Vita/PS4 .vag [Chronovolt (Vita), Grand Kingdom (PS4)] */ + start_offset = 0x30; + interleave = 0x10; + + /* channels are at 0x1e, except Ukiyo no Roushi (Vita), which has + * loop start/end frame (but also uses PS-ADPCM flags) */ if (read_32bitBE(0x18,streamFile) == 0 && (read_32bitBE(0x1c,streamFile) & 0xFFFF00FF) == 0 && read_8bit(0x1e,streamFile) < 16) { channel_count = read_8bit(0x1e,streamFile); if (channel_count == 0) - channel_count = 1; /* ex. early Vita vag (Lumines) */ + channel_count = 1; /* ex. early games [Lumines (Vita)] */ } else { channel_count = 1; } + + channel_size = channel_size / channel_count; + loop_flag = ps_find_loop_offsets(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start_sample, &loop_end_sample); } else { - loop_flag = vag_find_loop_offsets(streamFile, 0x30, &loopStart, &loopEnd); + /* standard PS1/PS2/PS3 .vag [Ecco the Dolphin (PS2), Legasista (PS3)] */ + start_offset = 0x30; + interleave = 0; + channel_count = 1; + loop_flag = ps_find_loop_offsets_full(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start_sample, &loop_end_sample); + //allow_dual_stereo = 1; /* often found with external L/R files */ } break; + default: goto fail; } + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ + vgmstream->meta_type = meta_type; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = ps_bytes_to_samples(channel_size,1); + vgmstream->loop_start_sample = loop_start_sample; + vgmstream->loop_end_sample = loop_end_sample; vgmstream->coding_type = coding_PSX; - if (is_swag) - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - else - vgmstream->sample_rate = read_32bitBE(0x10,streamFile); + if (version == 0x00020001 || version == 0x00030000) + vgmstream->coding_type = coding_HEVAG; + vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave; + vgmstream->interleave_block_size = interleave; - switch(vagID) { - case '1': // VAG1 - vgmstream->layout_type=layout_none; - vgmstream->num_samples = datasize / 16 * 28; - interleave = read_32bitLE(0x08,streamFile); - if (interleave != 0) goto fail; - vgmstream->meta_type=meta_PS2_VAG1; - start_offset=0x40; /* 0x30 is extra data in VAG1 */ - break; - case '2': // VAG2 - vgmstream->layout_type=layout_interleave; - vgmstream->num_samples = datasize / 16 * 28; /* datasize is for 1 channel only in VAG2 */ - interleave = 0x800; - vgmstream->meta_type=meta_PS2_VAG2; - start_offset=0x40; /* 0x30 is extra data in VAG2 */ - break; - case 'i': // VAGi - vgmstream->layout_type=layout_interleave; - vgmstream->num_samples = datasize / 16 * 28; - interleave = read_32bitLE(0x08,streamFile); - vgmstream->meta_type=meta_PS2_VAGi; - start_offset=0x800; - break; - case 'p': // VAGp - interleave=0x10; + read_string(vgmstream->stream_name,0x10+1, 0x20,streamFile); /* always, can be null */ - if (check_extensions(streamFile,"vig")) { /* MX vs. ATV Untamed PS2 */ - vgmstream->layout_type=layout_interleave; - vgmstream->meta_type=meta_PS2_VAGp; - - vgmstream->num_samples = (datasize - 0x10*channel_count) / 16 * 28; - start_offset = 0x800; - } - else if (read_32bitBE(0x6000,streamFile) == 0x56414770) { /* interleaved "VAGp" */ - interleave = 0x6000; /* The Simpsons Wrestling PSX interleave, includes header */ - vgmstream->layout_type = layout_interleave; - vgmstream->meta_type = meta_PS2_VAGs; - - vgmstream->num_samples = datasize / 16 * 28; - start_offset = 0x30; - } - else if ((version == 0x00000004) && (datasize < filesize / 2)) { - vgmstream->channels=2; - vgmstream->layout_type=layout_interleave; - vgmstream->meta_type=meta_PS2_VAGs; - - if (is_swag) { - start_offset = 0x30; - interleave = datasize; - vgmstream->num_samples = datasize / 16 * 28; - vgmstream->loop_start_sample = (loopStart-start_offset) / 16 * 28; - vgmstream->loop_end_sample = (loopEnd-start_offset) / 16 * 28; - loop_samples_found = 1; - - } else { - start_offset=0x80; - vgmstream->num_samples = datasize; /* todo test if datasize/16*28? */ - if(loop_flag) { - vgmstream->loop_start_sample=read_32bitBE(0x14,streamFile); - vgmstream->loop_end_sample =read_32bitBE(0x18,streamFile); - loop_samples_found = 1; - // Double VAG Header @ 0x0000 & 0x1000 - if(read_32bitBE(0,streamFile)==read_32bitBE(0x1000,streamFile)) { - vgmstream->num_samples = datasize / 16 * 28; - interleave=0x1000; - start_offset=0; - } - } - } - } - else if (version == 0x40000000) { /* Guerilla VAG (little endian) */ - datasize = read_32bitLE(0x0c,streamFile); - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->layout_type=layout_none; - vgmstream->meta_type=meta_PS2_VAGp; - - vgmstream->num_samples = datasize / channel_count / 16 * 28; - start_offset = 0x30; - } - else if (version == 0x00020001) { /* HEVAG */ - vgmstream->coding_type = coding_HEVAG; - vgmstream->layout_type = layout_interleave; - vgmstream->meta_type = meta_PS2_VAGs; - - vgmstream->num_samples = datasize / channel_count / 16 * 28; - start_offset = 0x30; - } - else { /* VAGp, usually separate L/R files */ - vgmstream->layout_type=layout_none; - vgmstream->meta_type=meta_PS2_VAGp; - - vgmstream->num_samples = datasize / channel_count / 16 * 28; - start_offset=0x30; - } - break; - case 'V': // pGAV - vgmstream->layout_type=layout_interleave; - interleave=0x2000; /* Jak 3 interleave, includes header */ - - if(read_32bitLE(0x1000,streamFile)==0x56414770) /* "pGAV" */ - interleave=0x1000; /* Jak X interleave, includes header */ - - vgmstream->sample_rate = read_32bitLE(0x10,streamFile); - vgmstream->num_samples = read_32bitLE(0x0C,streamFile)/16*14; - vgmstream->meta_type=meta_PS2_pGAV; - start_offset=0; - break; - default: - goto fail; - } - - vgmstream->interleave_block_size=interleave; - - /* Don't add the header size to loop calc points */ - if(loop_flag && !loop_samples_found) { - loopStart-=start_offset; - loopEnd-=start_offset; - - vgmstream->loop_start_sample = (int32_t)((loopStart/(interleave*channel_count))*interleave)/16*28; - vgmstream->loop_start_sample += (int32_t)(loopStart%(interleave*channel_count))/16*28; - vgmstream->loop_end_sample = (int32_t)((loopEnd/(interleave*channel_count))*interleave)/16*28; - vgmstream->loop_end_sample += (int32_t)(loopEnd%(interleave*channel_count))/16*28; - } - - /* always, but can be null or used as special string */ - read_string(vgmstream->stream_name,0x10+1, 0x20,streamFile); - - - /* open the file for reading */ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; - return vgmstream; fail: close_vgmstream(vgmstream); return NULL; } - - -/** - * Finds loop points in VAG data using flag markers and updates loop_start and loop_end with the global offsets. - * - * returns 0 if not found - */ -static int vag_find_loop_offsets(STREAMFILE *streamFile, off_t start_offset, off_t * loop_start, off_t * loop_end) { - off_t loopStart = 0; - off_t loopEnd = 0; - - /* used for loop points (todo: variations: 0x0c0700..00, 0x070077..77 ) */ - /* 'used to prevent unnecessary SPU interrupts' (optional if no IRQ or no looping) */ - uint8_t eofVAG[16]={0x00,0x07,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77}; - uint8_t eofVAG2[16]={0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - uint8_t readbuf[16]; - uint8_t flag; - - /* Search for loop in VAG */ - size_t fileLength = get_streamfile_size(streamFile); - - - off_t readOffset = start_offset - 0x10; - do { - readOffset+=0x10; - - flag = read_8bit(readOffset+0x01,streamFile) & 0x0F; /* lower nibble (for HEVAG) */ - - // Loop Start ... - if (flag == 0x06 && !loopStart) { - loopStart = readOffset; - } - - // Loop End ... - if (flag == 0x03 && !loopEnd) { - loopEnd = readOffset; - - if (loopStart && loopEnd) - break; - } - - /* hack for some games that don't have loop points but play the same track on repeat - * (sometimes this will loop non-looping tracks incorrectly) - * if there is a "partial" 0x07 end flag pretend it wants to loop */ - if (flag == 0x01) { - // Check if we have a full eof tag after the loop point ... - // if so we don't loop, if not present, we loop from end to start ... - int read = read_streamfile(readbuf,readOffset+0x10,0x10,streamFile); - /* is there valid data after flag 0x1? */ - if (read > 0 - && readbuf[0] != 0x00 - && readbuf[0] != 0x0c - && readbuf[0] != 0x3c /* Ecco the Dolphin, Ratchet & Clank 2 */ - ) { - if (memcmp(readbuf,eofVAG,0x10) && (memcmp(readbuf,eofVAG2,0x10))) { /* full end flags */ - loopStart = start_offset + 0x10; /* todo proper start */ - loopEnd = readOffset; - break; - } - } - } - - } while (streamFile->get_offset(streamFile)<(off_t)fileLength); - - - if (loopStart && loopEnd) { - *loop_start = loopStart; - *loop_end = loopEnd; - return 1; - } - - return 0; -} diff --git a/src/vgmstream.c b/src/vgmstream.c index 376a219b..299d0682 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -50,7 +50,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ps2_mic, init_vgmstream_ngc_dsp_std_int, init_vgmstream_raw, - init_vgmstream_ps2_vag, + init_vgmstream_vag, init_vgmstream_psx_gms, init_vgmstream_ps2_ild, init_vgmstream_ps2_pnb, @@ -2388,8 +2388,8 @@ static void try_dual_file_stereo(VGMSTREAM * opened_vgmstream, STREAMFILE *strea {"left","right"}, {"Left","Right"}, {".V0",".V1"}, /* Homura (PS2) */ - {".L",".R"}, /* Crash Nitro Racing (PS2) */ - {"_0","_1"}, //unneeded? + {".L",".R"}, /* Crash Nitro Racing (PS2), Gradius V (PS2) */ + {"_0","_1"}, //fake for Homura/unneeded? }; char new_filename[PATH_LIMIT]; char * ext; From 27038c9ec84fc97c2357ee50e595427d4fad815e Mon Sep 17 00:00:00 2001 From: bnnm Date: Tue, 21 Aug 2018 22:39:47 +0200 Subject: [PATCH 06/55] Add .wavebatch PCM8 [Cars 2 (3DS)] --- src/meta/wavebatch.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/meta/wavebatch.c b/src/meta/wavebatch.c index bb72db1b..03cb3a50 100644 --- a/src/meta/wavebatch.c +++ b/src/meta/wavebatch.c @@ -98,6 +98,12 @@ VGMSTREAM * init_vgmstream_wavebatch(STREAMFILE *streamFile) { vgmstream->interleave_block_size = 0x02; break; + case 0x01: /* PCM8 [Cars 2 (3DS)] */ + vgmstream->coding_type = coding_PCM8; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x01; + break; + case 0x02: { /* DSP [WRC FIA World Rally Championship (3DS)] */ size_t config_size = (0x20+0x14)*channel_count + (0x0c)*channel_count; /* coefs+hist + padding */ @@ -113,7 +119,7 @@ VGMSTREAM * init_vgmstream_wavebatch(STREAMFILE *streamFile) { } default: - VGM_LOG("WAVEBATCH: unknown codec\n"); + VGM_LOG("WAVEBATCH: unknown codec %x\n", codec); goto fail; } From 75fb12eed4ec8e7b1d2da44c82ff655cc7648d60 Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 22 Aug 2018 19:19:31 +0200 Subject: [PATCH 07/55] Fix PS2 VGS/ASS/VPK/etc samples, glitches and cleanup --- src/formats.c | 14 ++--- src/meta/ps2_ass.c | 103 +++++++++++----------------------- src/meta/ps2_joe.c | 71 ++++++------------------ src/meta/ps2_vbk.c | 135 +++++++++++++++------------------------------ src/meta/ps2_vgs.c | 129 ++++++++++--------------------------------- src/vgmstream.h | 2 - 6 files changed, 127 insertions(+), 327 deletions(-) diff --git a/src/formats.c b/src/formats.c index 872cdb3b..42b18c93 100644 --- a/src/formats.c +++ b/src/formats.c @@ -707,11 +707,9 @@ static const meta_info meta_info_list[] = { {meta_IDSP_TT, "Traveller's Tales IDSP header"}, {meta_RSTM_SPM, "Nintendo RSTM header (brstmspm)"}, {meta_RAW, "assumed RAW PCM file by .raw extension"}, - {meta_PS2_VAGi, "Sony VAG Interleaved header (VAGi)"}, - {meta_PS2_VAGp, "Sony VAG Mono header (VAGp)"}, - {meta_PS2_VAGs, "Sony VAG Stereo header (VAGp)"}, - {meta_PS2_VAGm, "Sony VAG Mono header (VAGm)"}, - {meta_PS2_pGAV, "Sony VAG Stereo Little Endian header (pGAV)"}, + {meta_PS2_VAGi, "Sony VAGi header"}, + {meta_PS2_VAGp, "Sony VAGp header"}, + {meta_PS2_pGAV, "Sony pGAV header"}, {meta_PSX_GMS, "assumed Grandia GMS file by .gms extension"}, {meta_STR_WAV, "Blitz Games STR+WAV header"}, {meta_PS2_ILD, "ILD header"}, @@ -823,7 +821,7 @@ static const meta_info meta_info_list[] = { {meta_NAOMI_SPSD, "Naomi SPSD header"}, {meta_FFXI_BGW, "BGW BGMStream header"}, {meta_FFXI_SPW, "SPW SeWave header"}, - {meta_PS2_ASS, "ASS Header"}, + {meta_PS2_ASS, "SystemSoft .ASS header"}, {meta_NUB_IDSP, "Namco NUB IDSP header"}, {meta_IDSP_NL, "Next Level IDSP header"}, {meta_IDSP_IE, "Inevitable Entertainment IDSP Header"}, @@ -955,8 +953,8 @@ static const meta_info meta_info_list[] = { {meta_EB_SF0, "assumed Excitebots .sf0 by extension"}, {meta_PS3_KLBS, "klBS Header"}, {meta_PS2_MTAF, "Konami MTAF header"}, - {meta_PS2_VAG1, "Konami VAG Mono header (VAG1)"}, - {meta_PS2_VAG2, "Konami VAG Stereo header (VAG2)"}, + {meta_PS2_VAG1, "Konami VAG1 header"}, + {meta_PS2_VAG2, "Konami VAG2 header"}, {meta_TUN, "Lego Racers ALP header"}, {meta_WPD, "WPD 'DPW' header"}, {meta_MN_STR, "Mini Ninjas 'STR' header"}, diff --git a/src/meta/ps2_ass.c b/src/meta/ps2_ass.c index 1253bc43..6fe656bb 100644 --- a/src/meta/ps2_ass.c +++ b/src/meta/ps2_ass.c @@ -1,92 +1,51 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* SVS (from Dai Senryaku VII - Exceed) */ +/* .ASS - from Dai Senryaku VII: Exceed (PS2) */ VGMSTREAM * init_vgmstream_ps2_ass(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - uint8_t testBuffer[0x10]; - off_t loopStart = 0; - off_t loopEnd = 0; - off_t readOffset = 0; - size_t fileLength; - int loop_flag; - int channel_count; + off_t start_offset; + size_t channel_size, interleave; + int loop_flag, channel_count, sample_rate; + int32_t num_samples, loop_start = 0, loop_end = 0; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("ass",filename_extension(filename))) goto fail; - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x02000000) /* "0x02000000" */ + /* checks */ + if (!check_extensions(streamFile, "ass")) goto fail; - loop_flag = 1; - channel_count = 2; - - /* build the VGMSTREAM */ + start_offset = 0x800; + channel_count = read_32bitLE(0x00,streamFile); /* assumed */ + if (channel_count != 2) goto fail; + sample_rate = read_32bitLE(0x04,streamFile); + channel_size = read_32bitLE(0x08,streamFile); + interleave = read_32bitLE(0x0c,streamFile); + num_samples = ps_bytes_to_samples(channel_size,1); + + loop_flag = ps_find_loop_offsets(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start, &loop_end); + loop_flag = loop_flag && (num_samples > 10*sample_rate); /* disable looping for smaller files (in seconds) */ + + + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = 0x800; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x04,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = (read_32bitLE(0x08,streamFile)*2)*28/16/channel_count; - - fileLength = get_streamfile_size(streamFile); - - do { - - readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); - /* Loop Start */ - if(testBuffer[0x01]==0x06) { - if(loopStart == 0) loopStart = readOffset-0x10; - /* break; */ - } - /* Loop End */ - if(testBuffer[0x01]==0x03) { - if(loopEnd == 0) loopEnd = readOffset-0x10; - /* break; */ - } - } while (streamFile->get_offset(streamFile)<(int32_t)fileLength); - - if(loopStart == 0) { - loop_flag = 0; - vgmstream->num_samples = read_32bitLE(0x4,streamFile)*28/16/channel_count; - } else { - loop_flag = 1; - vgmstream->loop_start_sample = (loopStart-start_offset)*28/16/channel_count; - vgmstream->loop_end_sample = (loopEnd-start_offset)*28/16/channel_count; - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0x0C,streamFile); vgmstream->meta_type = meta_PS2_ASS; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = num_samples; + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; - /* 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->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } diff --git a/src/meta/ps2_joe.c b/src/meta/ps2_joe.c index 02c51c95..4d7872d3 100644 --- a/src/meta/ps2_joe.c +++ b/src/meta/ps2_joe.c @@ -5,7 +5,8 @@ VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; - int channel_count, loop_flag, sample_rate, num_samples; + int channel_count, loop_flag, sample_rate; + int32_t num_samples, loop_start = 0, loop_end = 0; size_t file_size, data_size, unknown1, unknown2, interleave; @@ -20,37 +21,41 @@ VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE *streamFile) { /* detect version */ if (data_size/2 == file_size - 0x10 - && unknown1 == 0x0045039A && unknown2 == 0x00108920) { /* Super Farm */ + && unknown1 == 0x0045039A && unknown2 == 0x00108920) { /* Super Farm (PS2) */ data_size = data_size / 2; interleave = 0x4000; + start_offset = 0x10; } else if (data_size/2 == file_size - 0x10 - && unknown1 == 0xCCCCCCCC && unknown2 == 0xCCCCCCCC) { /* Sitting Ducks */ + && unknown1 == 0xCCCCCCCC && unknown2 == 0xCCCCCCCC) { /* Sitting Ducks (PS2) */ data_size = data_size / 2; interleave = 0x8000; + start_offset = 0x10; } else if (data_size == file_size - 0x10 - && unknown1 == 0xCCCCCCCC && unknown2 == 0xCCCCCCCC) { /* The Mummy: The Animated Series */ + && unknown1 == 0xCCCCCCCC && unknown2 == 0xCCCCCCCC) { /* The Mummy: The Animated Series (PS2) */ interleave = 0x8000; + start_offset = 0x10; } - else if (data_size == file_size - 0x4020) { /* CT Special Forces (and all games beyond) */ + else if (data_size == file_size - 0x4020) { /* CT Special Forces (PS2), and all games beyond */ interleave = unknown1; /* always 0? */ if (!interleave) interleave = 0x10; - /* header padding contains garbage */ + start_offset = 0x4020; /* header padding contains garbage */ } else { goto fail; } - start_offset = file_size - data_size; - + //start_offset = file_size - data_size; /* also ok */ channel_count = 2; sample_rate = read_32bitLE(0x00,streamFile); num_samples = ps_bytes_to_samples(data_size, channel_count); + + loop_flag = ps_find_loop_offsets(streamFile, start_offset, data_size, channel_count, interleave,&loop_start, &loop_end); /* most songs simply repeat except a few jingles (PS-ADPCM flags are always set) */ - loop_flag = (num_samples > 20*sample_rate); /* in seconds */ + loop_flag = loop_flag && (num_samples > 20*sample_rate); /* in seconds */ /* build the VGMSTREAM */ @@ -59,52 +64,8 @@ VGMSTREAM * init_vgmstream_ps2_joe(STREAMFILE *streamFile) { vgmstream->sample_rate = sample_rate; vgmstream->num_samples = num_samples; - - //todo improve, not working 100% with early .joe - { - uint8_t testBuffer[0x10]; - off_t blockOffset = 0; - off_t sampleOffset = 0; - off_t readOffset = 0; - off_t loopStart = 0, loopEnd = 0; - - readOffset = start_offset; - do { - off_t blockRead = (off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); - - readOffset += blockRead; - blockOffset += blockRead; - - if (blockOffset >= interleave) { - readOffset += interleave; - blockOffset -= interleave; - } - - /* Loop Start */ - if(testBuffer[0x01]==0x06) { - if(loopStart == 0) - loopStart = sampleOffset; - /* break; */ - } - - sampleOffset += 28; - - /* Loop End */ - if(testBuffer[0x01]==0x03) { - if(loopEnd == 0) - loopEnd = sampleOffset; - /* break; */ - } - - } while (streamFile->get_offset(streamFile)<(int32_t)file_size); - - if (loopStart == 0 && loopEnd == 0) { - vgmstream->loop_flag = 0; - } else { - vgmstream->loop_start_sample = loopStart; - vgmstream->loop_end_sample = loopEnd; - } - } + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_interleave; diff --git a/src/meta/ps2_vbk.c b/src/meta/ps2_vbk.c index 3bc44fe1..ea303ac8 100644 --- a/src/meta/ps2_vbk.c +++ b/src/meta/ps2_vbk.c @@ -1,111 +1,66 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -//#include -//#include -/* VBK (from Disney's Stitch - Experiment 626) */ - -VGMSTREAM * init_vgmstream_ps2_vbk(STREAMFILE *streamFile) -{ +/* VBK - from Disney's Stitch - Experiment 626 (PS2) */ +VGMSTREAM * init_vgmstream_ps2_vbk(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - uint8_t testBuffer[0x10]; - off_t loopStart = 0; - off_t loopEnd = 0; - off_t readOffset = 0; - size_t fileLength; - int loop_flag; - int channel_count; + off_t start_offset, header_offset, stream_offset; + size_t stream_size, interleave; + int loop_flag, channel_count, sample_rate; + int32_t num_samples, loop_start = 0, loop_end = 0; + int total_subsongs, target_subsong = streamFile->stream_index; - //_TCHAR szBuffer[100]; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("vbk",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x2E56424B) /* .VBK */ + /* checks */ + if (!check_extensions(streamFile, "vbk")) goto fail; + if (read_32bitBE(0x00,streamFile) != 0x2E56424B) /* ".VBK" */ + goto fail; + /* 0x04: version? always 0x02? */ + start_offset = read_32bitLE(0x0C, streamFile); + /* 0x10: file size */ - loop_flag = 1; - channel_count = read_32bitLE(0x28,streamFile) + 1; + total_subsongs = read_32bitLE(0x08,streamFile); + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; - //_stprintf(szBuffer, _T("%x"), channel_count); - //MessageBox(NULL, szBuffer, _T("Foo"), MB_OK); + header_offset = 0x14 + (target_subsong-1)*0x18; - /* build the VGMSTREAM */ + stream_size = read_32bitLE(header_offset+0x00,streamFile); + /* 0x04: id? */ + stream_offset = read_32bitLE(header_offset+0x08,streamFile); + sample_rate = read_32bitLE(header_offset+0x0c,streamFile); + interleave = read_32bitLE(header_offset+0x10,streamFile); + channel_count = read_32bitLE(header_offset+0x14,streamFile) + 1; /* 4ch is common, 1ch sfx too */ + start_offset += stream_offset; + + num_samples = ps_bytes_to_samples(stream_size,channel_count); + loop_flag = ps_find_loop_offsets(streamFile, start_offset, stream_size, channel_count, interleave, &loop_start, &loop_end); + loop_flag = loop_flag && (num_samples > 10*sample_rate); /* disable looping for smaller files (in seconds) */ + + + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - fileLength = get_streamfile_size(streamFile); - start_offset = read_32bitLE(0x0C, streamFile); - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitLE(0x20,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = (fileLength - start_offset)*28/16/channel_count; - - // get loop start - do { - - readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); - - if(testBuffer[0x01]==0x06) - { - loopStart = readOffset-0x10; - break; - } - - } while (streamFile->get_offset(streamFile)<(int32_t)fileLength); - - - // get loop end - readOffset = fileLength - 0x10; - - do { - readOffset-=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); - - /* Loop End */ - if(testBuffer[0x01]==0x03) - { - loopEnd = readOffset-0x10; - break; - } - } while (readOffset > 0); - - loop_flag = 1; - vgmstream->loop_start_sample = (loopStart-start_offset)*28/16/channel_count; - vgmstream->loop_end_sample = (loopEnd-start_offset)*28/16/channel_count; - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile); vgmstream->meta_type = meta_PS2_VBK; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = num_samples; + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; + vgmstream->num_streams = total_subsongs; + vgmstream->stream_size = stream_size; - /* 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->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } - diff --git a/src/meta/ps2_vgs.c b/src/meta/ps2_vgs.c index ea19558e..9af59737 100644 --- a/src/meta/ps2_vgs.c +++ b/src/meta/ps2_vgs.c @@ -1,122 +1,51 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* VGS (Phantom of Inferno) - - This format is used in _many_ Princess Soft games. -*/ +/* VGS - from Princess Soft games [Gin no Eclipse (PS2), Metal Wolf REV (PS2)] */ VGMSTREAM * init_vgmstream_ps2_vgs(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - size_t fileLength; - off_t readOffset = 0; off_t start_offset; - off_t loop_start_offset = 0; - off_t loop_end_offset = 0; + size_t data_size, channel_size, interleave; + int loop_flag, channel_count; + int32_t loop_start = 0, loop_end = 0; - uint8_t testBuffer[0x10]; - int loop_flag = 0; - int channel_count; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("vgs",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x56475300) + /* check */ + if ( !check_extensions(streamFile,"vgs") ) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x56475300) /* "VGS\0" ('VAG stereo', presumably) */ goto fail; - // get file length - fileLength = get_streamfile_size(streamFile); - - // Find loop start - do { - readOffset += (off_t)read_streamfile(testBuffer, readOffset, 0x10, streamFile); - - // Loop Start ... - if(testBuffer[0x01] == 0x06) - { - loop_start_offset = readOffset - 0x10; - break; - } - - } while (streamFile->get_offset(streamFile)<((int32_t)fileLength)); - - // start at last line of file and move up - readOffset = (int32_t)fileLength - 0x10; - - // Find loop end - do { - readOffset -= (off_t)read_streamfile(testBuffer, readOffset, 0x10, streamFile); - - // Loop End ... - if((testBuffer[0x01]==0x03) && (testBuffer[0x03]!=0x77)) - { - loop_end_offset = readOffset + 0x20; - break; - } - } while (readOffset > 0); - - // setup loops - if (loop_start_offset > 0) - { - loop_flag = 1; - - // if we have a start loop, use EOF if end loop is not found - if (loop_end_offset == 0) - { - loop_end_offset = (int32_t)fileLength - 0x10; - } - } - else - { - loop_flag = 0; - } - + start_offset = 0x30; + data_size = get_streamfile_size(streamFile) - start_offset; + interleave = 0x20000; channel_count = 2; - + channel_size = read_32bitBE(0x0c,streamFile); + loop_flag = 0; /* all files have loop flags but simply fade out normally and repeat */ + + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = 0x30; - vgmstream->channels = channel_count; - vgmstream->sample_rate = read_32bitBE(0x10,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = ((get_streamfile_size(streamFile)-0x30)/16/channel_count*28); - - if (loop_flag) - { - vgmstream->loop_start_sample = loop_start_offset/16/channel_count*28; - vgmstream->loop_end_sample = loop_end_offset/16/channel_count*28; - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitBE(0x04,streamFile)*0x1000; vgmstream->meta_type = meta_PS2_VGS; + vgmstream->sample_rate = read_32bitBE(0x10,streamFile); + vgmstream->num_samples = ps_bytes_to_samples(channel_size,1); + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; - /* 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->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + if (vgmstream->interleave_block_size) + vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels; + read_string(vgmstream->stream_name,0x10+1, 0x20,streamFile); /* always, can be null */ + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } diff --git a/src/vgmstream.h b/src/vgmstream.h index c9f42bdd..dcb70451 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -336,13 +336,11 @@ typedef enum { meta_PS2_MIC, /* KOEI MIC File */ meta_PS2_VAGi, /* VAGi Interleaved File */ meta_PS2_VAGp, /* VAGp Mono File */ - meta_PS2_VAGm, /* VAGp Mono File */ meta_PS2_pGAV, /* VAGp with Little Endian Header */ meta_PSX_GMS, /* GMS File (used in PS1 & PS2) [no header_id] */ meta_STR_WAV, /* Blitz Games STR+WAV files */ meta_PS2_ILD, /* ILD File */ meta_PS2_PNB, /* PsychoNauts Bgm File */ - meta_PS2_VAGs, /* VAG Stereo from Kingdom Hearts */ meta_VPK, /* VPK Audio File */ meta_PS2_BMDX, /* Beatmania thing */ meta_PS2_IVB, /* Langrisser 3 IVB */ From 925916690af0f8061dd924841c62a4ba9e326e30 Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 22 Aug 2018 19:26:19 +0200 Subject: [PATCH 08/55] Parse PS3 .bnk properly and remove ps3_klbs.c [L@ve Once (PS3)] --- src/formats.c | 1 - src/libvgmstream.vcproj | 4 - src/libvgmstream.vcxproj | 1 - src/libvgmstream.vcxproj.filters | 3 - src/meta/bnk_sony.c | 271 +++++++++++++++++++------------ src/meta/meta.h | 2 - src/meta/ps3_klbs.c | 122 -------------- src/vgmstream.c | 1 - src/vgmstream.h | 1 - 9 files changed, 168 insertions(+), 238 deletions(-) delete mode 100644 src/meta/ps3_klbs.c diff --git a/src/formats.c b/src/formats.c index 42b18c93..bcc256ae 100644 --- a/src/formats.c +++ b/src/formats.c @@ -951,7 +951,6 @@ static const meta_info meta_info_list[] = { {meta_OTNS_ADP, "Omikron: The Nomad Soul ADP header"}, {meta_EB_SFX, "Excitebots .sfx header"}, {meta_EB_SF0, "assumed Excitebots .sf0 by extension"}, - {meta_PS3_KLBS, "klBS Header"}, {meta_PS2_MTAF, "Konami MTAF header"}, {meta_PS2_VAG1, "Konami VAG1 header"}, {meta_PS2_VAG2, "Konami VAG2 header"}, diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 49a9f8fa..baab4017 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -1138,10 +1138,6 @@ RelativePath=".\meta\ps3_ivag.c" > - - diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index a30b7697..8e1446ab 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -167,7 +167,6 @@ - diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 1c1bc65a..4321f757 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -1252,9 +1252,6 @@ meta\Source Files - - meta\Source Files - coding\Source Files diff --git a/src/meta/bnk_sony.c b/src/meta/bnk_sony.c index 2e5b1ed0..387a9bd5 100644 --- a/src/meta/bnk_sony.c +++ b/src/meta/bnk_sony.c @@ -1,40 +1,55 @@ #include "meta.h" #include "../coding/coding.h" +typedef enum { PSX, PCM16, ATRAC9 } bnk_codec; + /* BNK - Sony's Scream Tool bank format [Puyo Puyo Tetris (PS4), NekoBuro: Cats Block (Vita)] */ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { #if 1 VGMSTREAM * vgmstream = NULL; off_t start_offset, stream_offset, name_offset = 0; - size_t stream_size; + size_t stream_size, interleave = 0; off_t sblk_offset, data_offset; - int channel_count = 0, loop_flag, sample_rate, codec; - int version; + size_t data_size; + int channel_count = 0, loop_flag, sample_rate, version; + int loop_start = 0, loop_end = 0; uint32_t atrac9_info = 0; - int loop_start = 0, loop_length = 0; + int total_subsongs, target_subsong = streamFile->stream_index; + int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; + int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL; + bnk_codec codec; /* checks */ if (!check_extensions(streamFile, "bnk")) goto fail; - if (read_32bitBE(0x00,streamFile) != 0x03000000) + + if (read_32bitBE(0x00,streamFile) == 0x00000003 && read_32bitBE(0x04,streamFile) == 0x00000002) { /* PS3 */ + read_32bit = read_32bitBE; + read_16bit = read_16bitBE; + } + else if (read_32bitBE(0x00,streamFile) == 0x03000000 && read_32bitBE(0x04,streamFile) == 0x02000000) { /* Vita/PS4 */ + read_32bit = read_32bitLE; + read_16bit = read_16bitLE; + } + else { goto fail; - if (read_32bitBE(0x04,streamFile) != 0x02000000) - goto fail; - sblk_offset = read_32bitLE(0x08,streamFile); - /* 0x0c: sblk size */ - data_offset = read_32bitLE(0x10,streamFile); - /* 0x14: data size */ + } + + sblk_offset = read_32bit(0x08,streamFile); + /* 0x0c: sklb size */ + data_offset = read_32bit(0x10,streamFile); + data_size = read_32bit(0x14,streamFile); /* SE banks, also used for music. Most table fields seems reserved/defaults and * don't change much between subsongs or files, so they aren't described in detail */ /* SBlk part: parse header */ - if (read_32bitBE(sblk_offset+0x00,streamFile) != 0x53426C6B) /* "SBlk" */ + if (read_32bit(sblk_offset+0x00,streamFile) != 0x6B6C4253) /* "SBlk" (sample block?) */ goto fail; - version = read_32bitLE(sblk_offset+0x04,streamFile); + version = read_32bit(sblk_offset+0x04,streamFile); /* 0x08: possibly when version=0x0d, 0x03=Vita, 0x06=PS4 */ //;VGM_LOG("BNK: sblk_offset=%lx, data_offset=%lx, version %x\n", sblk_offset, data_offset, version); @@ -50,18 +65,15 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { switch(version) { + case 0x03: /* L@ove Once - Mermaid's Tears (PS3) */ case 0x09: /* Puyo Puyo Tetris (PS4) */ - section_entries = (uint16_t)read_16bitLE(sblk_offset+0x16,streamFile); /* entry size: ~0x0c */ - material_entries = (uint16_t)read_16bitLE(sblk_offset+0x18,streamFile); /* entry size: ~0x08 */ - stream_entries = (uint16_t)read_16bitLE(sblk_offset+0x1a,streamFile); /* entry size: ~0x60 */ - table1_offset = sblk_offset + read_32bitLE(sblk_offset+0x1c,streamFile); - table2_offset = sblk_offset + read_32bitLE(sblk_offset+0x20,streamFile); - /* 0x24: null? */ - /* 0x28: offset to end? */ - /* 0x2c: offset to table3? */ - /* 0x30: null? */ - table3_offset = sblk_offset + read_32bitLE(sblk_offset+0x34,streamFile); - table4_offset = sblk_offset + read_32bitLE(sblk_offset+0x38,streamFile); + section_entries = (uint16_t)read_16bit(sblk_offset+0x16,streamFile); /* entry size: ~0x0c */ + material_entries = (uint16_t)read_16bit(sblk_offset+0x18,streamFile); /* entry size: ~0x08 */ + stream_entries = (uint16_t)read_16bit(sblk_offset+0x1a,streamFile); /* entry size: ~0x60 */ + table1_offset = sblk_offset + read_32bit(sblk_offset+0x1c,streamFile); + table2_offset = sblk_offset + read_32bit(sblk_offset+0x20,streamFile); + table3_offset = sblk_offset + read_32bit(sblk_offset+0x34,streamFile); + table4_offset = sblk_offset + read_32bit(sblk_offset+0x38,streamFile); table1_entry_size = 0x0c; table1_suboffset = 0x08; @@ -70,17 +82,13 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { break; case 0x0d: /* Polara (Vita), Crypt of the Necrodancer (Vita) */ - table1_offset = sblk_offset + read_32bitLE(sblk_offset+0x18,streamFile); - table2_offset = sblk_offset + read_32bitLE(sblk_offset+0x1c,streamFile); - /* 0x20: null? */ - /* 0x24: offset to end? */ - /* 0x28: offset to table4? */ - table3_offset = sblk_offset + read_32bitLE(sblk_offset+0x2c,streamFile); - table4_offset = sblk_offset + read_32bitLE(sblk_offset+0x30,streamFile); - /* 0x34: null? */ - section_entries = (uint16_t)read_16bitLE(sblk_offset+0x38,streamFile); /* entry size: ~0x24 */ - material_entries = (uint16_t)read_16bitLE(sblk_offset+0x3a,streamFile); /* entry size: ~0x08 */ - stream_entries = (uint16_t)read_16bitLE(sblk_offset+0x3c,streamFile); /* entry size: ~0x90 + variable (sometimes) */ + table1_offset = sblk_offset + read_32bit(sblk_offset+0x18,streamFile); + table2_offset = sblk_offset + read_32bit(sblk_offset+0x1c,streamFile); + table3_offset = sblk_offset + read_32bit(sblk_offset+0x2c,streamFile); + table4_offset = sblk_offset + read_32bit(sblk_offset+0x30,streamFile); + section_entries = (uint16_t)read_16bit(sblk_offset+0x38,streamFile); /* entry size: ~0x24 */ + material_entries = (uint16_t)read_16bit(sblk_offset+0x3a,streamFile); /* entry size: ~0x08 */ + stream_entries = (uint16_t)read_16bit(sblk_offset+0x3c,streamFile); /* entry size: ~0x90 + variable (sometimes) */ table1_entry_size = 0x24; table1_suboffset = 0x0c; @@ -93,7 +101,7 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { goto fail; } - //;VGM_LOG("BNK: table offsets=t1=%lx, %lx, %lx, %lx\n", table1_offset,table2_offset,table3_offset,table4_offset); + //;VGM_LOG("BNK: table offsets=%lx, %lx, %lx, %lx\n", table1_offset,table2_offset,table3_offset,table4_offset); //;VGM_LOG("BNK: table entries=%i, %i, %i\n", section_entries,material_entries,stream_entries); @@ -108,19 +116,24 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { * - get stream offsets * - find if one section points to the selected material, and get section name = stream name */ + /* parse materials */ total_subsongs = 0; if (target_subsong == 0) target_subsong = 1; for (i = 0; i < material_entries; i++) { - uint16_t table2_subtype = (uint16_t)read_16bitLE(table2_offset+(i*0x08)+table2_suboffset+0x02,streamFile); + uint32_t table2_value, table2_subinfo, table2_subtype; + + table2_value = (uint32_t)read_32bit(table2_offset+(i*0x08)+table2_suboffset+0x00,streamFile); + table2_subinfo = (table2_value >> 0) & 0xFFFF; + table2_subtype = (table2_value >> 16) & 0xFFFF; if (table2_subtype != 0x100) continue; /* not sounds */ total_subsongs++; if (total_subsongs == target_subsong) { table2_entry_offset = (i*0x08); - table3_entry_offset = (uint16_t)read_16bitLE(table2_offset+(i*0x08)+table2_suboffset+0x00,streamFile); + table3_entry_offset = table2_subinfo; /* continue to count all subsongs*/ } } @@ -136,106 +149,152 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { /* parse sounds */ - stream_offset = read_32bitLE(table3_offset+table3_entry_offset+table3_suboffset+0x00,streamFile); - stream_size = read_32bitLE(table3_offset+table3_entry_offset+table3_suboffset+0x04,streamFile); + stream_offset = read_32bit(table3_offset+table3_entry_offset+table3_suboffset+0x00,streamFile); + stream_size = read_32bit(table3_offset+table3_entry_offset+table3_suboffset+0x04,streamFile); + /* parse names */ + switch(version) { + //case 0x03: /* different format? */ + case 0x09: + case 0x0d: + /* find if this sound has an assigned name in table1 */ + for (i = 0; i < section_entries; i++) { + off_t entry_offset = (uint16_t)read_16bit(table1_offset+(i*table1_entry_size)+table1_suboffset+0x00,streamFile); - /* find if this sound has an assigned name in table1 */ - for (i = 0; i < section_entries; i++) { - off_t entry_offset = (uint16_t)read_16bitLE(table1_offset+(i*table1_entry_size)+table1_suboffset+0x00,streamFile); + /* rarely (ex. Polara sfx) one name applies to multiple materials, + * from current entry_offset to next entry_offset (section offsets should be in order) */ + if (entry_offset <= table2_entry_offset ) { + table4_entry_id = i; + //break; + } + } - /* rarely (ex. Polara sfx) one name applies to multiple materials, - * from current entry_offset to next entry_offset (section offsets should be in order) */ - if (entry_offset <= table2_entry_offset ) { - table4_entry_id = i; - //break; - } - } + /* table4: */ + /* 0x00: bank name (optional) */ + /* 0x08: header size */ + /* 0x0c: table4 size */ + /* variable: entries */ + /* variable: names (null terminated) */ + table4_entries_offset = table4_offset + read_32bit(table4_offset+0x08, streamFile); + table4_names_offset = table4_entries_offset + (0x10*section_entries); + //;VGM_LOG("BNK: t4_entries=%lx, t4_names=%lx\n", table4_entries_offset, table4_names_offset); - /* table4: */ - /* 0x00: bank name (optional) */ - /* 0x08: header size */ - /* 0x0c: table4 size */ - /* variable: entries */ - /* variable: names (null terminated) */ - table4_entries_offset = table4_offset + read_32bitLE(table4_offset+0x08, streamFile); - table4_names_offset = table4_entries_offset + (0x10*section_entries); - //;VGM_LOG("BNK: t4_entries=%lx, t4_names=%lx\n", table4_entries_offset, table4_names_offset); + /* get assigned name from table4 names */ + for (i = 0; i < section_entries; i++) { + int entry_id = read_32bit(table4_entries_offset+(i*0x10)+0x0c, streamFile); + if (entry_id == table4_entry_id) { + name_offset = table4_names_offset + read_32bit(table4_entries_offset+(i*0x10)+0x00, streamFile); + break; + } + } - /* get assigned name from table4 names */ - for (i = 0; i < section_entries; i++) { - int entry_id = read_32bitLE(table4_entries_offset+(i*0x10)+0x0c, streamFile); - if (entry_id == table4_entry_id) { - name_offset = table4_names_offset + read_32bitLE(table4_entries_offset+(i*0x10)+0x00, streamFile); break; - } + default: + break; } //;VGM_LOG("BNK: stream_offset=%lx, stream_size=%x, name_offset=%lx\n", stream_offset, stream_size, name_offset); } - /* data part: parse extradata before the codec, very annoying */ + /* data part: parse extradata before the codec, if needed */ { - size_t extradata_size = 0; + int type, loop_length; + size_t extradata_size = 0, postdata_size = 0; start_offset = data_offset + stream_offset; switch(version) { - case 0x09: - codec = read_16bitLE(start_offset+0x00,streamFile); - extradata_size = 0x08 + read_32bitLE(start_offset+0x04,streamFile); /* 0x14 for AT9 */ + case 0x03: + sample_rate = 48000; /* seems ok */ + channel_count = 1; - switch(codec) { + /* hack for PS3 files that use dual subsongs as stereo */ + if (total_subsongs == 2 && stream_size * 2 == data_size) { + channel_count = 2; + stream_size = stream_size*channel_count; + total_subsongs = 1; + } + + interleave = stream_size / channel_count; + //postdata_size = 0x10; /* last frame may be garbage */ + + loop_flag = ps_find_loop_offsets(streamFile, start_offset, stream_size, channel_count, interleave, &loop_start, &loop_end); + loop_flag = (loop_start > 28); /* ignore full loops since they just fadeout + repeat */ + + codec = PSX; + break; + + case 0x09: + type = read_16bit(start_offset+0x00,streamFile); + extradata_size = 0x08 + read_32bit(start_offset+0x04,streamFile); /* 0x14 for AT9 */ + + switch(type) { #ifdef VGM_USE_ATRAC9 - case 0x02: - case 0x05: - if (read_32bitLE(start_offset+0x08,streamFile) + 0x08 != extradata_size) /* repeat? */ + case 0x02: /* ATRAC9 mono? */ + case 0x05: /* ATRAC9 stereo? */ + if (read_32bit(start_offset+0x08,streamFile) + 0x08 != extradata_size) /* repeat? */ goto fail; atrac9_info = (uint32_t)read_32bitBE(start_offset+0x0c,streamFile); /* 0x10: null? */ - loop_length = read_32bitLE(start_offset+0x14,streamFile); - loop_start = read_32bitLE(start_offset+0x18,streamFile); + loop_length = read_32bit(start_offset+0x14,streamFile); + loop_start = read_32bit(start_offset+0x18,streamFile); + loop_end = loop_start + loop_length; /* loop_start is -1 if not set */ /* get from AT9 config just in case, but probably: sr=48000 / codec 0x02=1ch, 0x05=2ch */ atrac9_parse_config(atrac9_info, &sample_rate, &channel_count, NULL); + codec = ATRAC9; break; #endif + default: + VGM_LOG("BNK: unknown type %x\n", type); + goto fail; } break; case 0x0d: - codec = read_16bitLE(start_offset+0x00,streamFile); - if (read_32bitLE(start_offset+0x04,streamFile) != 0x01) /* type? */ + type = read_16bit(start_offset+0x00,streamFile); + if (read_32bit(start_offset+0x04,streamFile) != 0x01) /* type? */ goto fail; - extradata_size = 0x10 + read_32bitLE(start_offset+0x08,streamFile); /* 0x80 for AT9, 0x10 for PCM */ + extradata_size = 0x10 + read_32bit(start_offset+0x08,streamFile); /* 0x80 for AT9, 0x10 for PCM */ /* 0x0c: null? */ - - switch(codec) { + switch(type) { #ifdef VGM_USE_ATRAC9 - case 0x02: - case 0x05: - if (read_32bitLE(start_offset+0x10,streamFile) + 0x10 != extradata_size) /* repeat? */ + case 0x02: /* ATRAC9 mono? */ + case 0x05: /* ATRAC9 stereo? */ + if (read_32bit(start_offset+0x10,streamFile) + 0x10 != extradata_size) /* repeat? */ goto fail; atrac9_info = (uint32_t)read_32bitBE(start_offset+0x14,streamFile); /* 0x18: null? */ /* 0x1c: channels? */ /* 0x20: null? */ - loop_length = read_32bitLE(start_offset+0x24,streamFile); - loop_start = read_32bitLE(start_offset+0x28,streamFile); + interleave = 0x02; + + loop_length = read_32bit(start_offset+0x24,streamFile); + loop_start = read_32bit(start_offset+0x28,streamFile); + loop_end = loop_start + loop_length; /* loop_start is -1 if not set */ /* get from AT9 config just in case, but probably: sr=48000 / codec 0x02=1ch, 0x05=2ch */ atrac9_parse_config(atrac9_info, &sample_rate, &channel_count, NULL); + codec = ATRAC9; break; #endif - case 0x01: - case 0x04: + case 0x01: /* PCM16LE mono? (NekoBuro/Polara sfx) */ + case 0x04: /* PCM16LE stereo? (NekoBuro/Polara sfx) */ sample_rate = 48000; /* seems ok */ /* 0x10: null? */ - channel_count = read_32bitLE(start_offset+0x14,streamFile); - loop_start = read_32bitLE(start_offset+0x18,streamFile); - loop_length = read_32bitLE(start_offset+0x1c,streamFile); + channel_count = read_32bit(start_offset+0x14,streamFile); + interleave = 0x02; + loop_start = read_32bit(start_offset+0x18,streamFile); + loop_length = read_32bit(start_offset+0x1c,streamFile); + loop_end = loop_start + loop_length; /* loop_start is -1 if not set */ + + codec = PCM16; break; + + default: + VGM_LOG("BNK: unknown type %x\n", type); + goto fail; } break; @@ -245,9 +304,11 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { start_offset += extradata_size; stream_size -= extradata_size; + stream_size -= postdata_size; + //;VGM_LOG("BNK: offset=%lx, size=%x\n", start_offset, stream_size); } - loop_flag = (loop_start >= 0) && (loop_length > 0); /* loop_start is -1 if not set */ + loop_flag = (loop_start >= 0) && (loop_end > 0); /* build the VGMSTREAM */ @@ -262,8 +323,7 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { switch(codec) { #ifdef VGM_USE_ATRAC9 - case 0x02: /* ATRAC9 mono? */ - case 0x05: { /* ATRAC9 stereo? */ + case ATRAC9: { atrac9_config cfg = {0}; cfg.channels = vgmstream->channels; @@ -277,25 +337,30 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { vgmstream->num_samples = atrac9_bytes_to_samples(stream_size, vgmstream->codec_data); vgmstream->loop_start_sample = loop_start; - vgmstream->loop_end_sample = loop_start + loop_length; + vgmstream->loop_end_sample = loop_end; break; } #endif - case 0x01: /* PCM16LE mono? (NekoBuro/Polara sfx) */ - case 0x04: /* PCM16LE stereo? (NekoBuro/Polara sfx) */ + case PCM16: vgmstream->coding_type = coding_PCM16LE; vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x02; + vgmstream->interleave_block_size = interleave; vgmstream->num_samples = pcm_bytes_to_samples(stream_size, vgmstream->channels, 16); vgmstream->loop_start_sample = loop_start; - vgmstream->loop_end_sample = loop_start + loop_length; - + vgmstream->loop_end_sample = loop_end; break; - default: - VGM_LOG("BNK: unknown codec %x\n", codec); - goto fail; + case PSX: + vgmstream->sample_rate = 48000; + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + + vgmstream->num_samples = ps_bytes_to_samples(stream_size,channel_count); + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; + break; } if (name_offset) diff --git a/src/meta/meta.h b/src/meta/meta.h index 9ef1d6bf..190a2361 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -563,8 +563,6 @@ VGMSTREAM * init_vgmstream_pc_adp_otns(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_eb_sfx(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_eb_sf0(STREAMFILE* streamFile); -VGMSTREAM * init_vgmstream_ps3_klbs(STREAMFILE* streamFile); - VGMSTREAM * init_vgmstream_ps2_mtaf(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_tun(STREAMFILE* streamFile); diff --git a/src/meta/ps3_klbs.c b/src/meta/ps3_klbs.c deleted file mode 100644 index 272c5c53..00000000 --- a/src/meta/ps3_klbs.c +++ /dev/null @@ -1,122 +0,0 @@ -#include "meta.h" -#include "../util.h" - -/* .KLBS (L@VE ONCE PS3 */ -VGMSTREAM * init_vgmstream_ps3_klbs(STREAMFILE *streamFile) -{ - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - size_t fileLength; - off_t readOffset = 0; - off_t start_offset; - off_t loop_start_offset = 0; - off_t loop_end_offset = 0; - - uint8_t testBuffer[0x10]; - int loop_flag = 0; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("bnk",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x20,streamFile) != 0x6B6C4253) - goto fail; - - // get file length - fileLength = get_streamfile_size(streamFile); - - // Find loop start - start_offset = read_32bitBE(0x10,streamFile); - readOffset = start_offset; - - do { - readOffset += (off_t)read_streamfile(testBuffer, readOffset, 0x10, streamFile); - - // Loop Start ... - if(testBuffer[0x01] == 0x06) - { - loop_start_offset = readOffset - 0x10; - break; - } - - } while (streamFile->get_offset(streamFile)<((int32_t)fileLength)); - - // start at last line of file and move up - readOffset = (int32_t)fileLength - 0x10; - - // Find loop end - do { - readOffset -= (off_t)read_streamfile(testBuffer, readOffset, 0x10, streamFile); - - // Loop End ... - if((testBuffer[0x01]==0x03) && (testBuffer[0x03]!=0x77)) - { - loop_end_offset = readOffset + 0x20; - break; - } - } while (readOffset > 0); - - // setup loops - if (loop_start_offset > 0) - { - loop_flag = 1; - - // if we have a start loop, use EOF if end loop is not found - if (loop_end_offset == 0) - { - loop_end_offset = (int32_t)fileLength - 0x10; - } - } - else - { - loop_flag = 0; - } - - channel_count = 2; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitBE(0x90, streamFile); - vgmstream->meta_type = meta_PS3_KLBS; - - vgmstream->channels = channel_count; - vgmstream->sample_rate = 48000; - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = ((vgmstream->interleave_block_size * channel_count)/16/channel_count*28); - - if (loop_flag) - { - vgmstream->loop_start_sample = loop_start_offset/16/channel_count*28; - vgmstream->loop_end_sample = loop_end_offset/16/channel_count*28; - } - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/src/vgmstream.c b/src/vgmstream.c index 299d0682..3ac59091 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -302,7 +302,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_pc_adp_otns, init_vgmstream_eb_sfx, init_vgmstream_eb_sf0, - init_vgmstream_ps3_klbs, init_vgmstream_ps2_mtaf, init_vgmstream_tun, init_vgmstream_wpd, diff --git a/src/vgmstream.h b/src/vgmstream.h index dcb70451..433da779 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -581,7 +581,6 @@ typedef enum { meta_OTNS_ADP, /* Omikron: The Nomad Soul .adp (PC/DC) */ meta_EB_SFX, /* Excitebots .sfx */ meta_EB_SF0, /* Excitebots .sf0 */ - meta_PS3_KLBS, /* L@VE ONCE (PS3) */ meta_PS2_MTAF, /* Metal Gear Solid 3 MTAF */ meta_PS2_VAG1, /* Metal Gear Solid 3 VAG1 */ meta_PS2_VAG2, /* Metal Gear Solid 3 VAG2 */ From 69c791656e7426c6b7dcba5b5c5b814ac7733ea1 Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 22 Aug 2018 20:10:31 +0200 Subject: [PATCH 09/55] Move MIB+MIH to its own meta and fix rare files [Gladius (PS2)] --- src/libvgmstream.vcproj | 4 +++ src/libvgmstream.vcxproj | 1 + src/libvgmstream.vcxproj.filters | 3 ++ src/meta/meta.h | 2 ++ src/meta/mib_mih.c | 60 ++++++++++++++++++++++++++++++++ src/meta/ps2_mib.c | 58 +++++++++--------------------- src/vgmstream.c | 1 + 7 files changed, 87 insertions(+), 42 deletions(-) create mode 100644 src/meta/mib_mih.c diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index baab4017..9f56c397 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -576,6 +576,10 @@ RelativePath=".\meta\mca.c" > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 8e1446ab..5fc99fce 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -147,6 +147,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 4321f757..40c18166 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -1270,6 +1270,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files diff --git a/src/meta/meta.h b/src/meta/meta.h index 190a2361..f5637f04 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -61,6 +61,8 @@ VGMSTREAM * init_vgmstream_ps2_svag(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ps2_mib(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_mib_mih(STREAMFILE *streamFile); + VGMSTREAM * init_vgmstream_ps2_mic(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_raw(STREAMFILE *streamFile); diff --git a/src/meta/mib_mih.c b/src/meta/mib_mih.c new file mode 100644 index 00000000..b3f3f638 --- /dev/null +++ b/src/meta/mib_mih.c @@ -0,0 +1,60 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* MIB+MIH - SCEE MultiStream interleaved bank (header+data) [namCollection: Ace Combat 2 (PS2), Rampage: Total Destruction (PS2)] */ +VGMSTREAM * init_vgmstream_mib_mih(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + STREAMFILE * streamHeader = NULL; + off_t start_offset; + size_t data_size, frame_size, frame_last, frame_count; + int channel_count, loop_flag; + + /* check extension */ + if (!check_extensions(streamFile, "mib")) + goto fail; + + streamHeader = open_streamfile_by_ext(streamFile,"mih"); + if (!streamHeader) goto fail; + + if (read_32bitBE(0x00,streamHeader) != 0x40000000) /* header size */ + goto fail; + + loop_flag = 0; /* MIB+MIH don't PS-ADPCM loop flags */ + channel_count = read_32bitLE(0x08,streamHeader); + start_offset = 0x00; + + /* 0x04: padding (0x20, MIH header must be multiple of 0x40) */ + frame_last = (uint16_t)read_16bitLE(0x05,streamHeader); + frame_size = read_32bitLE(0x10,streamHeader); + frame_count = read_32bitLE(0x14,streamHeader); + if (frame_count == 0) { /* rarely [Gladius (PS2)] */ + frame_count = get_streamfile_size(streamFile) / (frame_size * channel_count); + } + + data_size = frame_count * frame_size; + data_size -= frame_last ? (frame_size-frame_last) : 0; /* last frame has less usable data */ + data_size *= channel_count; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = read_32bitLE(0x0C,streamHeader); + vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count); + + vgmstream->meta_type = meta_PS2_MIB_MIH; + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = frame_size; + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + close_streamfile(streamHeader); + return vgmstream; + +fail: +close_streamfile(streamHeader); + close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/meta/ps2_mib.c b/src/meta/ps2_mib.c index b3de5989..974b87a1 100644 --- a/src/meta/ps2_mib.c +++ b/src/meta/ps2_mib.c @@ -4,13 +4,11 @@ static int check_psadpcm(STREAMFILE *streamFile); -/* MIB+MIH - SCEE MultiStream interleaved bank (header+data) [namCollection: Ace Combat 2 (PS2), Rampage: Total Destruction (PS2)] */ /* headerless PS-ADPCM - from Katamary Damacy (PS2), Air (PS2), Aladdin: Nasira's Revenge (PS1) * (guesses interleave and channels by testing data and using the file extension, and finds * loops in PS-ADPCM flags; this is a crutch for convenience, consider using GENH/TXTH instead). */ VGMSTREAM * init_vgmstream_ps2_mib(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - STREAMFILE * streamFileMIH = NULL; off_t start_offset = 0x00; char filename[PATH_LIMIT]; @@ -32,8 +30,6 @@ VGMSTREAM * init_vgmstream_ps2_mib(STREAMFILE *streamFile) { int forceNoLoop=0; int gotEmptyLine=0; - uint8_t gotMIH=0; - int i, channel_count=0; @@ -59,14 +55,6 @@ VGMSTREAM * init_vgmstream_ps2_mib(STREAMFILE *streamFile) { goto fail; - /* .MIB may come with a .MIH header file */ - if (strcasecmp("mib",filename_extension(filename))==0) { - streamFileMIH = open_streamfile_by_ext(streamFile,"mih"); - if (streamFileMIH) - gotMIH = 1; - } - - fileLength = get_streamfile_size(streamFile); /* Search for interleave value (checking channel starts) and loop points (using PS-ADPCM flags). @@ -137,7 +125,7 @@ VGMSTREAM * init_vgmstream_ps2_mib(STREAMFILE *streamFile) { } } - } while (streamFile->get_offset(streamFile)<((int32_t)fileLength)); + } while (readOffset<((int32_t)fileLength)); } if(testBuffer[0]==0x0c && testBuffer[1]==0) @@ -146,9 +134,6 @@ VGMSTREAM * init_vgmstream_ps2_mib(STREAMFILE *streamFile) { if(channel_count==0) channel_count=1; - if(gotMIH) - channel_count=read_32bitLE(0x08,streamFileMIH); - // force no loop if(!strcasecmp("vb",filename_extension(filename))) loopStart=0; @@ -229,34 +214,25 @@ VGMSTREAM * init_vgmstream_ps2_mib(STREAMFILE *streamFile) { vgmstream->coding_type = coding_PSX; vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave; - if(gotMIH) { - // Read stuff from the MIH file - vgmstream->sample_rate = read_32bitLE(0x0C,streamFileMIH); - vgmstream->interleave_block_size = read_32bitLE(0x10,streamFileMIH); - vgmstream->num_samples=((read_32bitLE(0x10,streamFileMIH)* - (read_32bitLE(0x14,streamFileMIH)-1)*2)+ - ((read_32bitLE(0x04,streamFileMIH)>>8)*2))/16*28/2; - } else { - vgmstream->interleave_block_size = interleave; + vgmstream->interleave_block_size = interleave; - if(!strcasecmp("mib",filename_extension(filename))) - vgmstream->sample_rate = 44100; + if(!strcasecmp("mib",filename_extension(filename))) + vgmstream->sample_rate = 44100; - if(!strcasecmp("mi4",filename_extension(filename))) - vgmstream->sample_rate = 48000; + if(!strcasecmp("mi4",filename_extension(filename))) + vgmstream->sample_rate = 48000; - if(!strcasecmp("snds", filename_extension(filename))) - vgmstream->sample_rate = 48000; + if(!strcasecmp("snds", filename_extension(filename))) + vgmstream->sample_rate = 48000; - if(!strcasecmp("xag",filename_extension(filename))) - vgmstream->sample_rate = 44100; + if(!strcasecmp("xag",filename_extension(filename))) + vgmstream->sample_rate = 44100; - if (!strcasecmp("cvs", filename_extension(filename)) || - !strcasecmp("vb",filename_extension(filename))) - vgmstream->sample_rate = 22050; + if (!strcasecmp("cvs", filename_extension(filename)) || + !strcasecmp("vb",filename_extension(filename))) + vgmstream->sample_rate = 22050; - vgmstream->num_samples = (int32_t)(fileLength/16/channel_count*28); - } + vgmstream->num_samples = (int32_t)(fileLength/16/channel_count*28); if(loopEnd!=0) { if(vgmstream->channels==1) { @@ -299,17 +275,15 @@ VGMSTREAM * init_vgmstream_ps2_mib(STREAMFILE *streamFile) { vgmstream->loop_end_sample-=(emptySamples*channel_count); } - vgmstream->meta_type = gotMIH ? meta_PS2_MIB_MIH : meta_PS2_MIB; - + vgmstream->meta_type = meta_PS2_MIB; + //if (vgmstream->loop_end_sample) goto fail; if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; - close_streamfile(streamFileMIH); return vgmstream; fail: - close_streamfile(streamFileMIH); close_vgmstream(vgmstream); return NULL; } diff --git a/src/vgmstream.c b/src/vgmstream.c index 3ac59091..fde44b0c 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -45,6 +45,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ngc_dsp_stm, init_vgmstream_ps2_exst, init_vgmstream_ps2_svag, + init_vgmstream_mib_mih, init_vgmstream_ps2_mib, init_vgmstream_ngc_mpdsp, init_vgmstream_ps2_mic, From 785741e7e10c21b8e7352caa7f392e99b53f4759 Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 22 Aug 2018 20:29:29 +0200 Subject: [PATCH 10/55] Rename ps2_mib.c to ps_headerless,c --- src/libvgmstream.vcproj | 2 +- src/libvgmstream.vcxproj | 2 +- src/libvgmstream.vcxproj.filters | 2 +- src/meta/{ps2_mib.c => ps_headerless.c} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename src/meta/{ps2_mib.c => ps_headerless.c} (100%) diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 9f56c397..700a6161 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -967,7 +967,7 @@ > - + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 40c18166..c9750741 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -589,7 +589,7 @@ meta\Source Files - + meta\Source Files diff --git a/src/meta/ps2_mib.c b/src/meta/ps_headerless.c similarity index 100% rename from src/meta/ps2_mib.c rename to src/meta/ps_headerless.c From dcbc7e5b9b9682b976a405c66ed5ed987b134b38 Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 22 Aug 2018 20:39:31 +0200 Subject: [PATCH 11/55] Lower parse priority of raw metas so TXTH has a chance to go first --- src/formats.c | 2 +- src/meta/meta.h | 2 +- src/meta/ps_headerless.c | 8 +++----- src/vgmstream.c | 13 +++++++------ src/vgmstream.h | 2 +- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/formats.c b/src/formats.c index bcc256ae..f5eccb4b 100644 --- a/src/formats.c +++ b/src/formats.c @@ -697,7 +697,7 @@ static const meta_info meta_info_list[] = { {meta_DSP_STM, "Nintendo STM header"}, {meta_PS2_EXST, "Sony EXST header"}, {meta_PS2_SVAG, "Konami SVAG header"}, - {meta_PS2_MIB, "Headerless/MIB PS-ADPCM raw header"}, + {meta_PS_HEADERLESS, "Headerless PS-ADPCM raw header"}, {meta_PS2_MIB_MIH, "Sony MultiStream MIH+MIB header"}, {meta_DSP_MPDSP, "Single DSP header stereo by .mpdsp extension"}, {meta_PS2_MIC, "assume KOEI MIC file by .mic extension"}, diff --git a/src/meta/meta.h b/src/meta/meta.h index f5637f04..94938e20 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -59,7 +59,7 @@ VGMSTREAM * init_vgmstream_ps2_exst(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ps2_svag(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_ps2_mib(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_mib_mih(STREAMFILE *streamFile); diff --git a/src/meta/ps_headerless.c b/src/meta/ps_headerless.c index 974b87a1..e722e4d0 100644 --- a/src/meta/ps_headerless.c +++ b/src/meta/ps_headerless.c @@ -7,7 +7,7 @@ static int check_psadpcm(STREAMFILE *streamFile); /* headerless PS-ADPCM - from Katamary Damacy (PS2), Air (PS2), Aladdin: Nasira's Revenge (PS1) * (guesses interleave and channels by testing data and using the file extension, and finds * loops in PS-ADPCM flags; this is a crutch for convenience, consider using GENH/TXTH instead). */ -VGMSTREAM * init_vgmstream_ps2_mib(STREAMFILE *streamFile) { +VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset = 0x00; char filename[PATH_LIMIT]; @@ -275,12 +275,10 @@ VGMSTREAM * init_vgmstream_ps2_mib(STREAMFILE *streamFile) { vgmstream->loop_end_sample-=(emptySamples*channel_count); } - vgmstream->meta_type = meta_PS2_MIB; - //if (vgmstream->loop_end_sample) goto fail; + vgmstream->meta_type = meta_PS_HEADERLESS; + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; - - return vgmstream; fail: diff --git a/src/vgmstream.c b/src/vgmstream.c index fde44b0c..42a362f5 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -41,16 +41,13 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_cdxa, init_vgmstream_ps2_rxws, init_vgmstream_ps2_rxw, - init_vgmstream_ps2_int, init_vgmstream_ngc_dsp_stm, init_vgmstream_ps2_exst, init_vgmstream_ps2_svag, init_vgmstream_mib_mih, - init_vgmstream_ps2_mib, init_vgmstream_ngc_mpdsp, init_vgmstream_ps2_mic, init_vgmstream_ngc_dsp_std_int, - init_vgmstream_raw, init_vgmstream_vag, init_vgmstream_psx_gms, init_vgmstream_ps2_ild, @@ -426,9 +423,13 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_nus3bank, init_vgmstream_scd_sscf, - init_vgmstream_txth, /* should go at the end (lower priority) */ + /* lowest priority metas (TXTH should go before raw formats) */ + init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */ + init_vgmstream_ps2_int, /* .int raw PS-ADPCM */ + init_vgmstream_ps_headerless, /* tries to detect a bunch of PS-ADPCM formats */ + init_vgmstream_raw, /* .raw PCM */ #ifdef VGM_USE_FFMPEG - init_vgmstream_ffmpeg, /* should go at the end (lowest priority) */ + init_vgmstream_ffmpeg, /* may play anything incorrectly, since FFmpeg doesn't check extensions */ #endif }; @@ -479,7 +480,7 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile) { (vgmstream->meta_type == meta_GENH) || (vgmstream->meta_type == meta_TXTH) || (vgmstream->meta_type == meta_KRAW) || - (vgmstream->meta_type == meta_PS2_MIB) || + (vgmstream->meta_type == meta_PS_HEADERLESS) || (vgmstream->meta_type == meta_NGC_LPS) || (vgmstream->meta_type == meta_DSP_YGO) || (vgmstream->meta_type == meta_DSP_AGSC) || diff --git a/src/vgmstream.h b/src/vgmstream.h index 433da779..b6f63345 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -331,7 +331,7 @@ typedef enum { meta_PS2_RAW, /* RAW Interleaved Format */ meta_PS2_EXST, /* Shadow of Colossus EXST */ meta_PS2_SVAG, /* Konami SVAG */ - meta_PS2_MIB, /* MIB File */ + meta_PS_HEADERLESS, /* headerless PS-ADPCM */ meta_PS2_MIB_MIH, /* MIB File + MIH Header*/ meta_PS2_MIC, /* KOEI MIC File */ meta_PS2_VAGi, /* VAGi Interleaved File */ From 06c8ab1b3f6509f69b29a1a0b96081ae9d950375 Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 22 Aug 2018 20:43:19 +0200 Subject: [PATCH 12/55] Remove bik2a/bk2a fake extensions since they aren't used --- src/formats.c | 2 -- src/meta/bik.c | 7 +++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/formats.c b/src/formats.c index f5eccb4b..cb7de7e7 100644 --- a/src/formats.c +++ b/src/formats.c @@ -79,9 +79,7 @@ static const char* extension_list[] = { "bik", "bika", "bik2", - "bik2a", "bk2", - "bk2a", "bmdx", "bms", "bnk", diff --git a/src/meta/bik.c b/src/meta/bik.c index 18a3996d..eecff1f0 100644 --- a/src/meta/bik.c +++ b/src/meta/bik.c @@ -12,8 +12,11 @@ VGMSTREAM * init_vgmstream_bik(STREAMFILE *streamFile) { size_t stream_size; - /* check extension, case insensitive (bika = manually demuxed audio) */ - if (!check_extensions(streamFile,"bik,bika,bik2,bik2a,bk2,bk2a")) goto fail; + /* checks */ + /* .bik/bik2/bk2: standard + * .bika = fake extension for demuxed audio */ + if (!check_extensions(streamFile,"bik,bika,bik2,bk2")) + goto fail; /* check header "BIK" (bink 1) or "KB2" (bink 2), followed by version-char (audio is the same for both) */ if ((read_32bitBE(0x00,streamFile) & 0xffffff00) != 0x42494B00 && From 6b4f54df92f6544c189aff38597d37ca511f2dd8 Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 22 Aug 2018 21:04:16 +0200 Subject: [PATCH 13/55] Add TXTH "loop_flag = auto" to autodetect PS-ADPCM loop points --- src/meta/txth.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/meta/txth.c b/src/meta/txth.c index c0bff483..b8b02d72 100644 --- a/src/meta/txth.c +++ b/src/meta/txth.c @@ -57,6 +57,7 @@ typedef struct { uint32_t loop_flag; int loop_flag_set; + int loop_flag_auto; uint32_t coef_offset; uint32_t coef_spacing; @@ -132,6 +133,13 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) { goto fail; } + /* try to autodetect PS-ADPCM loop data */ + if (txth.loop_flag_auto && coding == coding_PSX) { + size_t data_size = get_streamfile_size(streamFile) - txth.start_offset; + txth.loop_flag = ps_find_loop_offsets(streamFile, txth.start_offset, data_size, txth.channels, txth.interleave, + (int32_t*)&txth.loop_start_sample, (int32_t*)&txth.loop_end_sample); + } + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(txth.channels,txth.loop_flag); @@ -583,8 +591,13 @@ static int parse_keyval(STREAMFILE * streamFile, STREAMFILE * streamText, txth_h txth->loop_adjust = get_bytes_to_samples(txth, txth->loop_adjust * (txth->interleave*txth->channels)); } else if (0==strcmp(key,"loop_flag")) { - if (!parse_num(streamFile,val, &txth->loop_flag)) goto fail; - txth->loop_flag_set = 1; + if (0==strcmp(val,"auto")) { + txth->loop_flag_auto = 1; + } + else { + if (!parse_num(streamFile,val, &txth->loop_flag)) goto fail; + txth->loop_flag_set = 1; + } } else if (0==strcmp(key,"coef_offset")) { if (!parse_num(streamFile,val, &txth->coef_offset)) goto fail; @@ -602,6 +615,9 @@ static int parse_keyval(STREAMFILE * streamFile, STREAMFILE * streamText, txth_h else if (0==strcmp(key,"coef_mode")) { if (!parse_num(streamFile,val, &txth->coef_mode)) goto fail; } + else if (0==strcmp(key,"psx_loops")) { + if (!parse_num(streamFile,val, &txth->coef_mode)) goto fail; + } else { VGM_LOG("TXTH: unknown key=%s, val=%s\n", key,val); goto fail; From 41281aa4e9a15230bed0c9eceddd4d7c887fcb16 Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 22 Aug 2018 21:16:25 +0200 Subject: [PATCH 14/55] Tweak .snds priority again --- src/vgmstream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vgmstream.c b/src/vgmstream.c index 42a362f5..f0f4e738 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -292,7 +292,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ps2_strlr, init_vgmstream_lsf_n1nj4n, init_vgmstream_vawx, - init_vgmstream_pc_snds, init_vgmstream_ps2_wmus, init_vgmstream_hyperscan_kvag, init_vgmstream_ios_psnd, @@ -427,6 +426,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */ init_vgmstream_ps2_int, /* .int raw PS-ADPCM */ init_vgmstream_ps_headerless, /* tries to detect a bunch of PS-ADPCM formats */ + init_vgmstream_pc_snds, /* .snds PC, after ps_headerless */ init_vgmstream_raw, /* .raw PCM */ #ifdef VGM_USE_FFMPEG init_vgmstream_ffmpeg, /* may play anything incorrectly, since FFmpeg doesn't check extensions */ From d7c224935801995c34c0234ad6d775771fad2987 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 23 Aug 2018 17:00:52 +0200 Subject: [PATCH 15/55] Simplify XVAG looping code --- src/meta/xvag.c | 93 +++++-------------------------------------------- 1 file changed, 9 insertions(+), 84 deletions(-) diff --git a/src/meta/xvag.c b/src/meta/xvag.c index 06868745..520b6a22 100644 --- a/src/meta/xvag.c +++ b/src/meta/xvag.c @@ -3,8 +3,6 @@ #include "../layout/layout.h" -static int ps_adpcm_find_loop_offsets(STREAMFILE *streamFile, int channel_count, off_t start_offset, off_t * loop_start, off_t * loop_end); - /* XVAG - Sony's Scream Tool/Stream Creator format (God of War III, Ratchet & Clank Future, The Last of Us, Uncharted) */ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; @@ -16,7 +14,7 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { off_t start_offset, loop_start = 0, loop_end = 0, chunk_offset; off_t first_offset = 0x20; - size_t chunk_size, stream_size; + size_t chunk_size, data_size; /* checks */ @@ -55,7 +53,7 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { interleave_factor = read_32bit(chunk_offset+0x10,streamFile); sample_rate = read_32bit(chunk_offset+0x14,streamFile); - stream_size = read_32bit(chunk_offset+0x18,streamFile); + data_size = read_32bit(chunk_offset+0x18,streamFile); /* not always accurate */ /* extra data, seen in versions 0x61+ */ if (chunk_size > 0x1c) { @@ -77,10 +75,13 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { /* "cues": cue/labels (rare) */ /* "0000": end chunk before start_offset */ - /* some XVAG seem to do full loops, this should detect them as looping (basically tests is last frame is empty) */ - //todo remove, looping seems external and specified in Scream Tool's bank formats + /* XVAG has no looping, but some PS3 PS-ADPCM seems to do full loops (without data flags) */ if (codec == 0x06 && total_subsongs == 1) { - loop_flag = ps_adpcm_find_loop_offsets(streamFile, channel_count, start_offset, &loop_start, &loop_end); + size_t file_size = get_streamfile_size(streamFile); + /* simply test if last frame is not empty = may loop */ + loop_flag = (read_8bit(file_size - 0x01, streamFile) != 0); + loop_start = 0; + loop_end = file_size - start_offset; } @@ -91,7 +92,7 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { vgmstream->sample_rate = sample_rate; vgmstream->num_samples = num_samples; vgmstream->num_streams = total_subsongs; - vgmstream->stream_size = (stream_size / total_subsongs); + vgmstream->stream_size = (data_size / total_subsongs); vgmstream->meta_type = meta_XVAG; switch (codec) { @@ -209,79 +210,3 @@ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; } - - -static int ps_adpcm_find_loop_offsets(STREAMFILE *streamFile, int channel_count, off_t start_offset, off_t * loop_start, off_t * loop_end) { - uint8_t testBuffer[0x10]; - int loopStartPointsCount=0; - int loopEndPointsCount=0; - off_t readOffset = 0; - off_t loopStartPoints[0x10]; - off_t loopEndPoints[0x10]; - - off_t loopStart = 0; - off_t loopEnd = 0; - off_t fileLength; - int loop_flag = 0; - - readOffset=start_offset; - fileLength = get_streamfile_size(streamFile); - - // get the loops the same way we get on .MIB - do { - readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); - - // Loop Start ... - if(testBuffer[0x01]==0x06) { - if(loopStartPointsCount<0x10) { - loopStartPoints[loopStartPointsCount] = readOffset-0x10; - loopStartPointsCount++; - } - } - - // Loop End ... - if(((testBuffer[0x01]==0x03) && (testBuffer[0x03]!=0x77)) || (testBuffer[0x01]==0x01)) { - if(loopEndPointsCount<0x10) { - loopEndPoints[loopEndPointsCount] = readOffset; //-0x10; - loopEndPointsCount++; - } - } - - } while (readOffset<((int32_t)fileLength)); - - // Calc Loop Points & Interleave ... - if(loopStartPointsCount>=channel_count) { - // can't get more then 0x10 loop point ! - if((loopStartPointsCount<=0x0F) && (loopStartPointsCount>=2)) { - // Always took the first 2 loop points - loopStart=loopStartPoints[1]-start_offset; - loop_flag=1; - } else { - loopStart=0; - } - } - - if(loopEndPointsCount>=channel_count) { - // can't get more then 0x10 loop point ! - if((loopEndPointsCount<=0x0F) && (loopEndPointsCount>=2)) { - loop_flag=1; - loopEnd=loopEndPoints[loopEndPointsCount-1]-start_offset; - } else { - loopEnd=0; - } - } - - // as i can get on the header if a song is looped or not - // if try to take the loop marker on the file - // if the last byte of the file is = 00 is assume that the song is not looped - // i know that i can cover 95% of the file, but can't work on some of them - if(read_8bit((fileLength-1),streamFile)==0) - loop_flag=0; - - if (loop_flag) { - *loop_start = loopStart; - *loop_end = loopEnd; - } - - return loop_flag; -} From 9ad2f578e6437a78463b00ff5507ee9ef7294b2c Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 23 Aug 2018 17:13:46 +0200 Subject: [PATCH 16/55] Fix PSH/VSV loops and glitches [Romancing SaGa (PS2)] --- src/libvgmstream.vcproj | 4 ++ src/libvgmstream.vcxproj | 1 + src/libvgmstream.vcxproj.filters | 3 + src/meta/ps2_psh.c | 101 +++++++++++++++---------------- src/meta/ps2_psh_streamfile.h | 48 +++++++++++++++ 5 files changed, 105 insertions(+), 52 deletions(-) create mode 100644 src/meta/ps2_psh_streamfile.h diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 700a6161..33f88d27 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -248,6 +248,10 @@ RelativePath=".\meta\ppst_streamfile.h" > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index a7d150c4..44a0590c 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -103,6 +103,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index c9750741..512f9539 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -92,6 +92,9 @@ meta\Header Files + + meta\Header Files + meta\Header Files diff --git a/src/meta/ps2_psh.c b/src/meta/ps2_psh.c index cb9d3a1b..e0b11df2 100644 --- a/src/meta/ps2_psh.c +++ b/src/meta/ps2_psh.c @@ -1,75 +1,72 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" +#include "ps2_psh_streamfile.h" -/* PSH (from Dawn of Mana - Seiken Densetsu 4, Kingdom Hearts Re:Chain of Memories) */ -/* probably Square Vag Stream */ + +/* PSH/VSV - from Square Enix games [Dawn of Mana: Seiken Densetsu 4 (PS2), Kingdom Hearts Re:Chain of Memories (PS2)] */ VGMSTREAM * init_vgmstream_ps2_psh(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; + STREAMFILE *temp_streamFile = NULL; off_t start_offset; - uint8_t testBuffer[0x10]; - off_t loopEnd = 0; - off_t readOffset = 0; - size_t fileLength; + int loop_flag, channel_count; + size_t loop_start, adjust, data_size, interleave; - int loop_flag; - int channel_count; - /* check extension, case insensitive */ - if (!check_extensions(streamFile, "psh,vsv")) // vsv seems to be official extension + /* checks */ + /* .psh: assumed? [Romancing SaGa: Minstrel's Song (PS2)] + * .vsv: official? [Kingdom Hearts HD I.5 + II.5 ReMIX (PS4)] */ + if (!check_extensions(streamFile, "psh,vsv")) + goto fail; + /* 0x00(2): 0x0000 (RS:MS) / 0x6440 (KH:RCoM) / varies (DoM) */ + if ((uint16_t)read_16bitBE(0x02,streamFile) != 0x6400) goto fail; - /* check header */ - if (read_16bitBE(0x02,streamFile) != 0x6400) - goto fail; - - loop_flag = (read_16bitLE(0x06,streamFile)!=0); channel_count = 2; - + start_offset = 0x00; /* correct, but needs some tricks to fix sound (see below) */ + interleave = 0x800; + + adjust = (uint16_t)read_16bitLE(0x04,streamFile) & 0x7FF; /* upper bits = ??? */ + data_size = (uint16_t)read_16bitLE(0x0c,streamFile) * interleave; + /* 0x0e: ? (may be 0x0001, or a low-ish value, not related to looping?) */ + loop_start = ((uint16_t)read_16bitLE(0x06,streamFile) & 0x7FFF) * interleave; /* uper bit == loop flag? */ + loop_flag = (loop_start != 0); /* (no known files loop from beginning to end) */ + + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = 0; - vgmstream->channels = channel_count; - vgmstream->sample_rate = (uint16_t)read_16bitLE(0x08,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->num_samples = (uint16_t)read_16bitLE(0x0C,streamFile)*0x800*28/16/channel_count; - - // loop end is set by the loop marker which we need to find ... - // there's some extra data on unloop files, so we calculate - // the sample count with loop marker on this files - fileLength = get_streamfile_size(streamFile); - do { - readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); - - // Loop End ... - if(testBuffer[0x01]==0x03) { - if(loopEnd==0) loopEnd = readOffset-0x10; - break; - } - } while (streamFile->get_offset(streamFile)<(int32_t)fileLength); - - if(loopEnd!=0) - vgmstream->num_samples = loopEnd*28/16/channel_count; - - if(loop_flag) { - vgmstream->loop_start_sample = - ((uint16_t)read_16bitLE(0x06,streamFile)-0x8000)*0x400*28/16; - vgmstream->loop_end_sample=vgmstream->num_samples; - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x800; vgmstream->meta_type = meta_PS2_PSH; + vgmstream->sample_rate = (uint16_t)read_16bitLE(0x08,streamFile); + vgmstream->num_samples = ps_bytes_to_samples(data_size,channel_count); - /* open the file for reading */ - if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) + vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start,channel_count); + vgmstream->loop_end_sample = vgmstream->num_samples; + + /* loops are odd, but comparing the audio wave with the OSTs these values seem correct */ + if (adjust == 0) { /* Romancing SaGa (PS2) */ + vgmstream->loop_start_sample -= ps_bytes_to_samples(channel_count*interleave,channel_count); /* maybe *before* loop block? */ + vgmstream->loop_start_sample -= ps_bytes_to_samples(0x200*channel_count,channel_count); /* maybe default adjust? */ + } + else { /* all others */ + vgmstream->loop_end_sample -= ps_bytes_to_samples((0x800 - adjust)*channel_count,channel_count); /* at last block + adjust is a 0x03 flag */ + } + + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + + temp_streamFile = setup_ps2_psh_streamfile(streamFile, start_offset, data_size); + if (!temp_streamFile) goto fail; + + if (!vgmstream_open_stream(vgmstream, temp_streamFile, start_offset)) goto fail; + + close_streamfile(temp_streamFile); return vgmstream; - /* clean up anything we may have opened */ fail: + close_streamfile(temp_streamFile); close_vgmstream(vgmstream); return NULL; } diff --git a/src/meta/ps2_psh_streamfile.h b/src/meta/ps2_psh_streamfile.h new file mode 100644 index 00000000..105ce566 --- /dev/null +++ b/src/meta/ps2_psh_streamfile.h @@ -0,0 +1,48 @@ +#ifndef _PS2_PSH_STREAMFILE_H_ +#define _PS2_PSH_STREAMFILE_H_ +#include "../streamfile.h" + +typedef struct { + off_t null_offset; +} ps2_psh_io_data; + +static size_t ps2_psh_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, ps2_psh_io_data* data) { + size_t bytes_read; + int i; + + bytes_read = streamfile->read(streamfile, dest, offset, length); + + /* PSHs do start at 0x00, but first line is also the header; must null it to avoid clicks */ + if (offset < data->null_offset) { + for (i = 0; i < data->null_offset - offset; i++) { + dest[i] = 0; + } + } + + return bytes_read; +} + +static STREAMFILE* setup_ps2_psh_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t data_size) { + STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL; + ps2_psh_io_data io_data = {0}; + size_t io_data_size = sizeof(ps2_psh_io_data); + + io_data.null_offset = 0x10; + + /* setup custom streamfile */ + new_streamFile = open_wrap_streamfile(streamFile); + if (!new_streamFile) goto fail; + temp_streamFile = new_streamFile; + + new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, ps2_psh_io_read,NULL); + if (!new_streamFile) goto fail; + temp_streamFile = new_streamFile; + + return temp_streamFile; + +fail: + close_streamfile(temp_streamFile); + return NULL; +} + +#endif /* _PS2_PSH_STREAMFILE_H_ */ From ad4478ac2ceb0197d3ba5a462a0a85e48dcf5f66 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 23 Aug 2018 18:00:34 +0200 Subject: [PATCH 17/55] Set dual stereo as a meta flag rather than a static list Mainly for cleanup/style --- src/meta/agsc.c | 1 + src/meta/excitebots.c | 1 + src/meta/genh.c | 1 + src/meta/kraw.c | 1 + src/meta/ngc_dsp_std.c | 1 + src/meta/ngc_dsp_ygo.c | 1 + src/meta/ngc_lps.c | 1 + src/meta/ngca.c | 1 + src/meta/nub_vag.c | 1 + src/meta/ps2_smpl.c | 9 ++++----- src/meta/ps_headerless.c | 1 + src/meta/rwsd.c | 7 +++++-- src/meta/spt_spd.c | 3 ++- src/meta/txth.c | 1 + src/meta/vag.c | 6 ++++-- src/vgmstream.c | 18 +----------------- src/vgmstream.h | 9 ++++----- 17 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/meta/agsc.c b/src/meta/agsc.c index d2f55b42..72629315 100644 --- a/src/meta/agsc.c +++ b/src/meta/agsc.c @@ -43,6 +43,7 @@ VGMSTREAM * init_vgmstream_agsc(STREAMFILE *streamFile) { vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_DSP_AGSC; + vgmstream->allow_dual_stereo = 1; for (i=0;i<16;i++) { vgmstream->ch[0].adpcm_coef[i]=read_16bitBE(header_offset+0xf6+i*2,streamFile); diff --git a/src/meta/excitebots.c b/src/meta/excitebots.c index 5ba06f00..2f5de05b 100644 --- a/src/meta/excitebots.c +++ b/src/meta/excitebots.c @@ -82,6 +82,7 @@ VGMSTREAM * init_vgmstream_eb_sfx(STREAMFILE *streamFile) { vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_EB_SFX; + vgmstream->allow_dual_stereo = 1; /* open the file for reading */ { diff --git a/src/meta/genh.c b/src/meta/genh.c index 70cac106..22a39025 100644 --- a/src/meta/genh.c +++ b/src/meta/genh.c @@ -325,6 +325,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { vgmstream->coding_type = coding; vgmstream->meta_type = meta_GENH; + vgmstream->allow_dual_stereo = 1; if ( !vgmstream_open_stream(vgmstream,streamFile,genh.start_offset) ) diff --git a/src/meta/kraw.c b/src/meta/kraw.c index 2fd4123e..a14a2146 100644 --- a/src/meta/kraw.c +++ b/src/meta/kraw.c @@ -37,6 +37,7 @@ VGMSTREAM * init_vgmstream_kraw(STREAMFILE *streamFile) { vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_KRAW; + vgmstream->allow_dual_stereo = 1; /* open the file for reading */ { diff --git a/src/meta/ngc_dsp_std.c b/src/meta/ngc_dsp_std.c index 7908131a..b3ee0110 100644 --- a/src/meta/ngc_dsp_std.c +++ b/src/meta/ngc_dsp_std.c @@ -348,6 +348,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) { vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->meta_type = meta_DSP_STD; + vgmstream->allow_dual_stereo = 1; /* very common in .dsp */ vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_none; diff --git a/src/meta/ngc_dsp_ygo.c b/src/meta/ngc_dsp_ygo.c index 77608018..e53905ef 100644 --- a/src/meta/ngc_dsp_ygo.c +++ b/src/meta/ngc_dsp_ygo.c @@ -39,6 +39,7 @@ VGMSTREAM * init_vgmstream_dsp_ygo(STREAMFILE *streamFile) { vgmstream->num_samples = read_32bitBE(0x20,streamFile); vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_DSP_YGO; + vgmstream->allow_dual_stereo = 1; if (loop_flag) { vgmstream->loop_start_sample = (read_32bitBE(0x30,streamFile)*14/16); vgmstream->loop_end_sample = (read_32bitBE(0x34,streamFile)*14/16); diff --git a/src/meta/ngc_lps.c b/src/meta/ngc_lps.c index 6957a782..bafa5f90 100644 --- a/src/meta/ngc_lps.c +++ b/src/meta/ngc_lps.c @@ -37,6 +37,7 @@ VGMSTREAM * init_vgmstream_ngc_lps(STREAMFILE *streamFile) { vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_NGC_LPS; + vgmstream->allow_dual_stereo = 1; if (vgmstream->coding_type == coding_NGC_DSP) { int i; diff --git a/src/meta/ngca.c b/src/meta/ngca.c index 271be64e..fb135204 100644 --- a/src/meta/ngca.c +++ b/src/meta/ngca.c @@ -34,6 +34,7 @@ VGMSTREAM * init_vgmstream_ngca(STREAMFILE *streamFile) { vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_NGCA; + vgmstream->allow_dual_stereo = 1; if (vgmstream->coding_type == coding_NGC_DSP) { int i; diff --git a/src/meta/nub_vag.c b/src/meta/nub_vag.c index c74393e9..6d68746c 100644 --- a/src/meta/nub_vag.c +++ b/src/meta/nub_vag.c @@ -32,6 +32,7 @@ VGMSTREAM * init_vgmstream_nub_vag(STREAMFILE *streamFile) { vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_NUB_VAG; + vgmstream->allow_dual_stereo = 1; start_offset = 0xC0; diff --git a/src/meta/ps2_smpl.c b/src/meta/ps2_smpl.c index e44bd7ed..b4a03712 100644 --- a/src/meta/ps2_smpl.c +++ b/src/meta/ps2_smpl.c @@ -8,11 +8,11 @@ VGMSTREAM * init_vgmstream_ps2_smpl(STREAMFILE *streamFile) { int loop_flag, channel_count; size_t channel_size; - /* check extension (.v0: left channel, .v1: right channel, .smpl: header id) */ + /* checks*/ + /* .v0: left channel, .v1: right channel + * .smpl: header id */ if ( !check_extensions(streamFile,"v0,v1,smpl") ) goto fail; - - /* check header */ if (read_32bitBE(0x00,streamFile) != 0x534D504C) /* "SMPL" */ goto fail; @@ -31,13 +31,12 @@ VGMSTREAM * init_vgmstream_ps2_smpl(STREAMFILE *streamFile) { vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->meta_type = meta_PS2_SMPL; + vgmstream->allow_dual_stereo = 1; vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_none; - /* always, but can be null or used as special string */ read_string(vgmstream->stream_name,0x10+1, 0x20,streamFile); - /* open the file for reading */ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; return vgmstream; diff --git a/src/meta/ps_headerless.c b/src/meta/ps_headerless.c index e722e4d0..8a4a7d97 100644 --- a/src/meta/ps_headerless.c +++ b/src/meta/ps_headerless.c @@ -276,6 +276,7 @@ VGMSTREAM * init_vgmstream_ps_headerless(STREAMFILE *streamFile) { } vgmstream->meta_type = meta_PS_HEADERLESS; + vgmstream->allow_dual_stereo = 1; if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; diff --git a/src/meta/rwsd.c b/src/meta/rwsd.c index 769f2bbf..7dd87f08 100644 --- a/src/meta/rwsd.c +++ b/src/meta/rwsd.c @@ -280,10 +280,13 @@ VGMSTREAM * init_vgmstream_rwsd(STREAMFILE *streamFile) { vgmstream->meta_type = meta_RWAR; else if (rwav) { - if (big_endian) + if (big_endian) { vgmstream->meta_type = meta_RWAV; - else + } + else { vgmstream->meta_type = meta_CWAV; + vgmstream->allow_dual_stereo = 1; /* LEGO 3DS games */ + } } else vgmstream->meta_type = meta_RWSD; diff --git a/src/meta/spt_spd.c b/src/meta/spt_spd.c index 749ef0f8..5535a74b 100644 --- a/src/meta/spt_spd.c +++ b/src/meta/spt_spd.c @@ -71,7 +71,8 @@ VGMSTREAM * init_vgmstream_spt_spd(STREAMFILE *streamFile) { } vgmstream->meta_type = meta_SPT_SPD; - + vgmstream->allow_dual_stereo = 1; + /* open the file for reading */ { for (i=0;icoding_type = coding; vgmstream->meta_type = meta_TXTH; + vgmstream->allow_dual_stereo = 1; if ( !vgmstream_open_stream(vgmstream,streamFile,txth.start_offset) ) diff --git a/src/meta/vag.c b/src/meta/vag.c index 2e58441c..e88a78a5 100644 --- a/src/meta/vag.c +++ b/src/meta/vag.c @@ -11,7 +11,7 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { int channel_count = 0, loop_flag, sample_rate; uint32_t vag_id, version; int32_t loop_start_sample = 0, loop_end_sample = 0; - //int allow_dual_stereo = 0; + int allow_dual_stereo = 0; /* checks */ @@ -195,7 +195,7 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { channel_count = 1; loop_flag = ps_find_loop_offsets_full(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start_sample, &loop_end_sample); - //allow_dual_stereo = 1; /* often found with external L/R files */ + allow_dual_stereo = 1; /* often found with external L/R files */ } break; @@ -209,6 +209,8 @@ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { if (!vgmstream) goto fail; vgmstream->meta_type = meta_type; + vgmstream->allow_dual_stereo = allow_dual_stereo; + vgmstream->sample_rate = sample_rate; vgmstream->num_samples = ps_bytes_to_samples(channel_size,1); vgmstream->loop_start_sample = loop_start_sample; diff --git a/src/vgmstream.c b/src/vgmstream.c index f0f4e738..a691fc69 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -474,23 +474,7 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile) { } /* test if candidate for dual stereo */ - if (vgmstream->channels == 1 && ( - (vgmstream->meta_type == meta_DSP_STD) || - (vgmstream->meta_type == meta_PS2_VAGp) || - (vgmstream->meta_type == meta_GENH) || - (vgmstream->meta_type == meta_TXTH) || - (vgmstream->meta_type == meta_KRAW) || - (vgmstream->meta_type == meta_PS_HEADERLESS) || - (vgmstream->meta_type == meta_NGC_LPS) || - (vgmstream->meta_type == meta_DSP_YGO) || - (vgmstream->meta_type == meta_DSP_AGSC) || - (vgmstream->meta_type == meta_PS2_SMPL) || - (vgmstream->meta_type == meta_NGCA) || - (vgmstream->meta_type == meta_NUB_VAG) || - (vgmstream->meta_type == meta_SPT_SPD) || - (vgmstream->meta_type == meta_EB_SFX) || - (vgmstream->meta_type == meta_CWAV) - )) { + if (vgmstream->channels == 1 && vgmstream->allow_dual_stereo == 1) { try_dual_file_stereo(vgmstream, streamFile, init_vgmstream_functions[i]); } diff --git a/src/vgmstream.h b/src/vgmstream.h index b6f63345..1366371b 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -757,10 +757,11 @@ typedef struct { int num_streams; /* for multi-stream formats (0=not set/one stream, 1=one stream) */ int stream_index; /* selected stream (also 1-based) */ char stream_name[STREAM_NAME_SIZE]; /* name of the current stream (info), if the file stores it and it's filled */ - size_t stream_size; /* info to properly calculate bitrate */ + size_t stream_size; /* info to properly calculate bitrate in case of subsongs */ uint32_t channel_mask; /* to silence crossfading subsongs/layers */ int channel_mappings_on; /* channel mappings are active */ int channel_mappings[32]; /* swap channel "i" with "[i]" */ + int allow_dual_stereo; /* search for dual stereo (file_L.ext + file_R.ext = single stereo file) */ /* looping */ int loop_flag; /* is this stream looped? */ @@ -804,7 +805,7 @@ typedef struct { int32_t ws_output_size; /* WS ADPCM: output bytes for this block */ - void * start_vgmstream; /* a copy of the VGMSTREAM as it was at the beginning of the stream (for AAX/AIX/SCD) */ + void * start_vgmstream; /* a copy of the VGMSTREAM as it was at the beginning of the stream (for custom layouts) */ /* Data the codec needs for the whole stream. This is for codecs too * different from vgmstream's structure to be reasonably shoehorned into @@ -812,9 +813,7 @@ typedef struct { * Note also that support must be added for resetting, looping and * closing for every codec that uses this, as it will not be handled. */ void * codec_data; - /* Same, for special layouts. - * Reusing the above pointer causes bugs when it's using special layout + codec - * (vgmstream may try to free/loop/etc codec_data). */ + /* Same, for special layouts. layout_data + codec_data may exist at the same time. */ void * layout_data; } VGMSTREAM; From 6c553882f3acd9c00be8d0f94fdd0e87ef73e775 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 23 Aug 2018 18:07:45 +0200 Subject: [PATCH 18/55] Rename codec_version to codec_config to clarify --- src/layout/blocked_ea_1snh.c | 2 +- src/layout/blocked_ea_schl.c | 4 ++-- src/layout/blocked_h4m.c | 4 ++-- src/meta/ea_1snh.c | 10 +++++----- src/meta/ea_schl.c | 12 ++++++------ src/meta/h4m.c | 2 +- src/vgmstream.c | 2 +- src/vgmstream.h | 2 +- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/layout/blocked_ea_1snh.c b/src/layout/blocked_ea_1snh.c index f57a5bcc..7df1c3a6 100644 --- a/src/layout/blocked_ea_1snh.c +++ b/src/layout/blocked_ea_1snh.c @@ -88,7 +88,7 @@ void block_update_ea_1snh(off_t block_offset, VGMSTREAM * vgmstream) { break; case coding_DVI_IMA: - if (vgmstream->codec_version == 1) { /* ADPCM hist */ + if (vgmstream->codec_config == 1) { /* ADPCM hist */ vgmstream->current_block_samples = read_32bit(block_offset + block_header, streamFile); vgmstream->current_block_size = 0; // - (0x04 + 0x08*vgmstream->channels); /* should be equivalent */ diff --git a/src/layout/blocked_ea_schl.c b/src/layout/blocked_ea_schl.c index 6293feb9..bfa07412 100644 --- a/src/layout/blocked_ea_schl.c +++ b/src/layout/blocked_ea_schl.c @@ -23,7 +23,7 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) { { uint32_t block_id = read_32bitBE(block_offset+0x00,streamFile); - if (vgmstream->codec_version & 0x02) /* size is always LE, except in early SS/MAC */ + if (vgmstream->codec_config & 0x02) /* size is always LE, except in early SS/MAC */ block_size = read_32bitBE(block_offset + 0x04,streamFile); else block_size = read_32bitLE(block_offset + 0x04,streamFile); @@ -180,7 +180,7 @@ void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) { } /* read ADPCM history before each channel if needed (not actually read in sx.exe) */ - if (vgmstream->codec_version & 0x01) { + if (vgmstream->codec_config & 0x01) { for (i = 0; i < vgmstream->channels; i++) { //vgmstream->ch[i].adpcm_history1_32 = read_16bit(vgmstream->ch[i].offset+0x00,streamFile); //vgmstream->ch[i].adpcm_history3_32 = read_16bit(vgmstream->ch[i].offset+0x02,streamFile); diff --git a/src/layout/blocked_h4m.c b/src/layout/blocked_h4m.c index a328292e..f488d624 100644 --- a/src/layout/blocked_h4m.c +++ b/src/layout/blocked_h4m.c @@ -34,7 +34,7 @@ void block_update_h4m(off_t block_offset, VGMSTREAM * vgmstream) { uint32_t frame_samples = read_32bitBE(block_offset+0x08, streamFile); size_t block_skip; - if (vgmstream->codec_version & 0x80) { + if (vgmstream->codec_config & 0x80) { frame_samples /= 2; /* ??? */ } @@ -51,7 +51,7 @@ void block_update_h4m(off_t block_offset, VGMSTREAM * vgmstream) { VGM_ASSERT(frame_format == 1, "H4M: unknown frame_format %x at %lx\n", frame_format, block_offset); /* pass current mode to the decoder */ - vgmstream->codec_version = (frame_format << 8) | (vgmstream->codec_version & 0xFF); + vgmstream->codec_config = (frame_format << 8) | (vgmstream->codec_config & 0xFF); for (i = 0; i < vgmstream->channels; i++) { vgmstream->ch[i].offset = block_offset + block_skip; diff --git a/src/meta/ea_1snh.c b/src/meta/ea_1snh.c index c4259f22..ff204b9d 100644 --- a/src/meta/ea_1snh.c +++ b/src/meta/ea_1snh.c @@ -21,7 +21,7 @@ typedef struct { int big_endian; int loop_flag; int is_sead; - int codec_version; + int codec_config; } ea_header; static int parse_header(STREAMFILE* streamFile, ea_header* ea, off_t begin_offset); @@ -85,7 +85,7 @@ VGMSTREAM * init_vgmstream_ea_1snh(STREAMFILE *streamFile) { case EA_CODEC_IMA: /* Need for Speed II (PC) */ if (ea.bits && ea.bits!=2) goto fail; /* only in EACS */ vgmstream->coding_type = coding_DVI_IMA; /* stereo/mono, high nibble first */ - vgmstream->codec_version = ea.codec_version; + vgmstream->codec_config = ea.codec_config; break; case EA_CODEC_PSX: /* Need for Speed (PS) */ @@ -127,7 +127,7 @@ static int parse_header(STREAMFILE* streamFile, ea_header* ea, off_t offset) { VGM_ASSERT(ea->type != 0, "EA EACS: unknown type\n"); /* block type? */ if (ea->codec == EA_CODEC_IMA) - ea->codec_version = get_ea_1snh_ima_version(streamFile, 0x00, ea); + ea->codec_config = get_ea_1snh_ima_version(streamFile, 0x00, ea); } else if (ea->is_sead) { /* alt subheader (found in some PC videos) */ @@ -136,7 +136,7 @@ static int parse_header(STREAMFILE* streamFile, ea_header* ea, off_t offset) { ea->codec = read_32bit(offset+0x08, streamFile); if (ea->codec == EA_CODEC_IMA) - ea->codec_version = get_ea_1snh_ima_version(streamFile, 0x00, ea); + ea->codec_config = get_ea_1snh_ima_version(streamFile, 0x00, ea); set_ea_1snh_num_samples(streamFile, 0x00, ea); if (ea->loop_start_offset) /* offset found, now find actual start sample */ @@ -198,7 +198,7 @@ static void set_ea_1snh_num_samples(STREAMFILE* streamFile, off_t start_offset, block_samples = ps_bytes_to_samples(block_size - block_header, ea->channels); break; case EA_CODEC_IMA: - if (ea->codec_version == 1) + if (ea->codec_config == 1) block_samples = read_32bit(block_offset + block_header, streamFile); else block_samples = ima_bytes_to_samples(block_size - block_header, ea->channels); diff --git a/src/meta/ea_schl.c b/src/meta/ea_schl.c index f63e8ac7..2968f4c8 100644 --- a/src/meta/ea_schl.c +++ b/src/meta/ea_schl.c @@ -93,7 +93,7 @@ typedef struct { int big_endian; int loop_flag; - int codec_version; + int codec_config; } ea_header; static VGMSTREAM * parse_schl_block(STREAMFILE *streamFile, off_t offset, int total_streams); @@ -447,7 +447,7 @@ static VGMSTREAM * parse_schl_block(STREAMFILE *streamFile, off_t offset, int to if (guess_endianness32bit(offset + 0x04, streamFile)) { /* size is always LE, except in early SS/MAC */ header_size = read_32bitBE(offset + 0x04, streamFile); - ea.codec_version |= 0x02; + ea.codec_config |= 0x02; } else { header_size = read_32bitLE(offset + 0x04, streamFile); @@ -573,7 +573,7 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_ vgmstream->loop_end_sample = ea->loop_end; vgmstream->codec_endian = ea->big_endian; - vgmstream->codec_version = ea->codec_version; + vgmstream->codec_config = ea->codec_config; vgmstream->meta_type = is_bnk ? meta_EA_BNK : meta_EA_SCHL; @@ -1120,7 +1120,7 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be if (!is_bnk) { if (ea->codec2 == EA_CODEC2_GCADPCM) { if (ea->platform == EA_PLATFORM_3DS) - ea->codec_version |= 0x01; + ea->codec_config |= 0x01; } else if (ea->codec2 == EA_CODEC2_EAXA) { /* EA-XA has ADPCM hist in earlier versions */ @@ -1128,11 +1128,11 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be /* V2: consoles only */ /* V3: never */ if (ea->version <= EA_VERSION_V1) { - ea->codec_version |= 0x01; + ea->codec_config |= 0x01; } else if (ea->version == EA_VERSION_V2) { if (ea->platform == EA_PLATFORM_PS2 || ea->platform == EA_PLATFORM_GC_WII || ea->platform == EA_PLATFORM_XBOX) - ea->codec_version |= 0x01; + ea->codec_config |= 0x01; } } } diff --git a/src/meta/h4m.c b/src/meta/h4m.c index e077f34a..d01f21ba 100644 --- a/src/meta/h4m.c +++ b/src/meta/h4m.c @@ -67,7 +67,7 @@ VGMSTREAM * init_vgmstream_h4m(STREAMFILE *streamFile) { vgmstream->sample_rate = sample_rate; vgmstream->num_streams = total_subsongs; vgmstream->stream_size = get_streamfile_size(streamFile) / total_subsongs; /* approx... */ - vgmstream->codec_version = format; /* for blocks */ + vgmstream->codec_config = format; /* for blocks */ vgmstream->meta_type = meta_H4M; vgmstream->layout_type = layout_blocked_h4m; diff --git a/src/vgmstream.c b/src/vgmstream.c index a691fc69..79ff9e9a 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1827,7 +1827,7 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to break; case coding_H4M_IMA: for (chan=0;chanchannels;chan++) { - uint16_t frame_format = (uint16_t)((vgmstream->codec_version >> 8) & 0xFFFF); + uint16_t frame_format = (uint16_t)((vgmstream->codec_config >> 8) & 0xFFFF); decode_h4m_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, vgmstream->channels,vgmstream->samples_into_block, diff --git a/src/vgmstream.h b/src/vgmstream.h index 1366371b..78d14980 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -801,7 +801,7 @@ typedef struct { /* decoder specific */ int codec_endian; /* little/big endian marker; name is left vague but usually means big endian */ - int codec_version; /* flag for codecs with minor variations */ + int codec_config; /* flags for codecs or layouts with minor variations; meaning is up to the user */ int32_t ws_output_size; /* WS ADPCM: output bytes for this block */ From b4884522d8c1f8d2d6e41a41bf43c42813168034 Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 24 Aug 2018 18:48:42 +0200 Subject: [PATCH 19/55] Optimize STDIO/FOO streamfiles slightly Tries to simplify code, and buffer is not emptied unless we really read more data (useful for edge reads). get_offset is now reliable (though never used). --- fb2k/foo_streamfile.cpp | 232 +++++++++++++++------------------------- src/streamfile.c | 106 ++++++++---------- 2 files changed, 134 insertions(+), 204 deletions(-) diff --git a/fb2k/foo_streamfile.cpp b/fb2k/foo_streamfile.cpp index 2608bb7e..3235cdb0 100644 --- a/fb2k/foo_streamfile.cpp +++ b/fb2k/foo_streamfile.cpp @@ -15,80 +15,73 @@ extern "C" { } #include "foo_vgmstream.h" -/* On EOF reads we can return length 0, or ignore and return the requested length + 0-set the buffer. - * Some decoders don't check for EOF and may decode garbage if returned 0, as read_Nbit() funcs return -1. - * Only matters for metas that get num_samples wrong (bigger than total data). */ -#define STREAMFILE_IGNORE_EOF 0 - /* a STREAMFILE that operates via foobar's file service using a buffer */ -typedef struct _FOO_STREAMFILE { - struct _STREAMFILE sf; - abort_callback * p_abort; - service_ptr_t m_file; - char * name; - off_t offset; - size_t validsize; - uint8_t * buffer; - size_t buffersize; - size_t filesize; -} FOO_STREAMFILE; +typedef struct { + STREAMFILE sf; /* callbacks */ + + service_ptr_t m_file; /* foobar IO service */ + abort_callback * p_abort; /* foobar error stuff */ + char * name; /* IO filename */ + off_t offset; /* last read offset (info) */ + off_t buffer_offset; /* current buffer data start */ + uint8_t * buffer; /* data buffer */ + size_t buffersize; /* max buffer size */ + size_t validsize; /* current buffer size */ + size_t filesize; /* buffered file size */ +} FOO_STREAMFILE; -static STREAMFILE * open_foo_streamfile_buffer_by_file(service_ptr_t m_file,const char * const filename, size_t buffersize, abort_callback * p_abort); static STREAMFILE * open_foo_streamfile_buffer(const char * const filename, size_t buffersize, abort_callback * p_abort, t_filestats * stats); +static STREAMFILE * open_foo_streamfile_buffer_by_file(service_ptr_t m_file,const char * const filename, size_t buffersize, abort_callback * p_abort); -static size_t read_the_rest_foo(uint8_t * dest, off_t offset, size_t length, FOO_STREAMFILE * streamfile) { - size_t length_read_total=0; +static size_t read_foo(FOO_STREAMFILE *streamfile, uint8_t * dest, off_t offset, size_t length) { + size_t length_read_total = 0; + + if (!streamfile || !dest || length <= 0 || offset < 0) + return 0; /* is the part of the requested length in the buffer? */ - if (offset >= streamfile->offset && offset < streamfile->offset + streamfile->validsize) { - size_t length_read; - off_t offset_into_buffer = offset - streamfile->offset; - length_read = streamfile->validsize - offset_into_buffer; + if (offset >= streamfile->buffer_offset && offset < streamfile->buffer_offset + streamfile->validsize) { + size_t length_to_read; + off_t offset_into_buffer = offset - streamfile->buffer_offset; - memcpy(dest,streamfile->buffer + offset_into_buffer,length_read); - length_read_total += length_read; - length -= length_read; - offset += length_read; - dest += length_read; + length_to_read = streamfile->validsize - offset_into_buffer; + if (length_to_read > length) + length_to_read = length; + + memcpy(dest,streamfile->buffer + offset_into_buffer,length_to_read); + length_read_total += length_to_read; + length -= length_to_read; + offset += length_to_read; + dest += length_to_read; } - /* What would make more sense here is to read the whole request - * at once into the dest buffer, as it must be large enough, and then - * copy some part of that into our own buffer. - * The destination buffer is supposed to be much smaller than the - * STREAMFILE buffer, though. Maybe we should only ever return up - * to the buffer size to avoid having to deal with things like this - * which are outside of my intended use. - */ + /* read the rest of the requested length */ while (length > 0) { size_t length_to_read; - size_t length_read; - streamfile->validsize = 0; /* buffer is empty now */ - /* request outside file: ignore to avoid seek/read */ - if (offset > streamfile->filesize) { - streamfile->offset = streamfile->filesize; - -#if STREAMFILE_IGNORE_EOF - memset(dest,0,length); /* dest is already shifted */ - return length_read_total + length; /* partially-read + 0-set buffer */ -#else - return length_read_total; /* partially-read buffer */ -#endif + /* ignore requests at EOF */ + if (offset >= streamfile->filesize) { + //offset = streamfile->filesize; /* seems fseek doesn't clamp offset */ + //VGM_ASSERT_ONCE(offset > streamfile->filesize, "STDIO: reading over filesize 0x%x @ 0x%lx + 0x%x\n", streamfile->filesize, offset, length); + break; } /* position to new offset */ try { streamfile->m_file->seek(offset,*streamfile->p_abort); - //if (streamfile->m_file->is_eof(*streamfile->p_abort)) /* allow edge case of offset=filesize */ - // return length_read; } catch (...) { - streamfile->offset = streamfile->filesize; - return 0; /* fail miserably (fseek shouldn't fail and reach this) */ + break; /* this shouldn't happen in our code */ + } + + /* fill the buffer (offset now is beyond buffer_offset) */ + try { + streamfile->buffer_offset = offset; + streamfile->validsize = streamfile->m_file->read(streamfile->buffer,streamfile->buffersize,*streamfile->p_abort); + } catch(...) { + break; /* improbable? */ } - streamfile->offset = offset; /* decide how much must be read this time */ if (length > streamfile->buffersize) @@ -96,70 +89,45 @@ static size_t read_the_rest_foo(uint8_t * dest, off_t offset, size_t length, FOO else length_to_read = length; - /* fill the buffer */ - try { - length_read = streamfile->m_file->read(streamfile->buffer,streamfile->buffersize,*streamfile->p_abort); - } catch(...) { - return 0; /* fail miserably */ - } - streamfile->validsize = length_read; - - - /* if we can't get enough to satisfy the request (EOF) we give up */ - if (length_read < length_to_read) { - memcpy(dest,streamfile->buffer,length_read); - -#if STREAMFILE_IGNORE_EOF - memset(dest+length_read,0,length-length_read); - return length_read_total + length; /* partially-read + 0-set buffer */ -#else - return length_read_total + length_read; /* partially-read buffer */ -#endif + /* give up on partial reads (EOF) */ + if (streamfile->validsize < length_to_read) { + memcpy(dest,streamfile->buffer,streamfile->validsize); + offset += streamfile->validsize; + length_read_total += streamfile->validsize; + break; } /* use the new buffer */ memcpy(dest,streamfile->buffer,length_to_read); + offset += length_to_read; length_read_total += length_to_read; length -= length_to_read; dest += length_to_read; - offset += length_to_read; } + streamfile->offset = offset; /* last fread offset */ return length_read_total; } - -static size_t read_foo(FOO_STREAMFILE *streamfile, uint8_t * dest, off_t offset, size_t length) { - - if (!streamfile || !dest || length<=0) - return 0; - - /* request outside file: ignore to avoid seek/read in read_the_rest_foo() */ - if (offset > streamfile->filesize) { - streamfile->offset = streamfile->filesize; - -#if STREAMFILE_IGNORE_EOF - memset(dest,0,length); - return length; /* 0-set buffer */ -#else - return 0; /* nothing to read */ -#endif - } - - /* just copy if entire request is within the buffer */ - if (offset >= streamfile->offset && offset + length <= streamfile->offset + streamfile->validsize) { - off_t offset_into_buffer = offset - streamfile->offset; - memcpy(dest,streamfile->buffer + offset_into_buffer,length); - return length; - } - - /* request outside buffer: new fread */ - { - return read_the_rest_foo(dest,offset,length,streamfile); - } +static size_t get_size_foo(FOO_STREAMFILE * streamfile) { + return streamfile->filesize; } - -STREAMFILE * open_foo_streamfile(const char * const filename, abort_callback * p_abort, t_filestats * stats) { - return open_foo_streamfile_buffer(filename,STREAMFILE_DEFAULT_BUFFER_SIZE, p_abort, stats); +static off_t get_offset_foo(FOO_STREAMFILE *streamfile) { + return streamfile->offset; +} +static void get_name_foo(FOO_STREAMFILE *streamfile,char *buffer,size_t length) { + /* Most crap only cares about the filename itself */ + size_t ourlen = strlen(streamfile->name); + if (ourlen > length) { + if (length) strcpy(buffer, streamfile->name + ourlen - length + 1); + } else { + strcpy(buffer, streamfile->name); + } +} +static void close_foo(FOO_STREAMFILE * streamfile) { + streamfile->m_file.release(); + free(streamfile->name); + free(streamfile->buffer); + free(streamfile); } static STREAMFILE *open_foo(FOO_STREAMFILE *streamFile,const char * const filename,size_t buffersize) { @@ -173,7 +141,7 @@ static STREAMFILE *open_foo(FOO_STREAMFILE *streamFile,const char * const filena // if same name, duplicate the file pointer we already have open if (!strcmp(streamFile->name,filename)) { m_file = streamFile->m_file; - if (1) { + { newstreamFile = open_foo_streamfile_buffer_by_file(m_file,filename,buffersize,streamFile->p_abort); if (newstreamFile) { return newstreamFile; @@ -186,45 +154,15 @@ static STREAMFILE *open_foo(FOO_STREAMFILE *streamFile,const char * const filena return open_foo_streamfile_buffer(filename,buffersize,streamFile->p_abort,NULL); } -static size_t get_size_foo(FOO_STREAMFILE * streamfile) { - return streamfile->filesize; -} - -static off_t get_offset_foo(FOO_STREAMFILE *streamFile) { - return streamFile->offset; -} - -static void close_foo(FOO_STREAMFILE * streamfile) { - streamfile->m_file.release(); - free(streamfile->name); - free(streamfile->buffer); - free(streamfile); -} - -static void get_name_foo(FOO_STREAMFILE *streamfile,char *buffer,size_t length) { - /* Most crap only cares about the filename itself */ - size_t ourlen = strlen(streamfile->name); - if (ourlen > length) { - if (length) strcpy(buffer, streamfile->name + ourlen - length + 1); - } else { - strcpy(buffer, streamfile->name); - } -} - static STREAMFILE * open_foo_streamfile_buffer_by_file(service_ptr_t m_file,const char * const filename, size_t buffersize, abort_callback * p_abort) { uint8_t * buffer; FOO_STREAMFILE * streamfile; buffer = (uint8_t *) calloc(buffersize,1); - if (!buffer) { - return NULL; - } + if (!buffer) goto fail; streamfile = (FOO_STREAMFILE *) calloc(1,sizeof(FOO_STREAMFILE)); - if (!streamfile) { - free(buffer); - return NULL; - } + if (!streamfile) goto fail; streamfile->sf.read = (size_t (__cdecl *)(_STREAMFILE *,uint8_t *,off_t,size_t)) read_foo; streamfile->sf.get_size = (size_t (__cdecl *)(_STREAMFILE *)) get_size_foo; @@ -234,22 +172,22 @@ static STREAMFILE * open_foo_streamfile_buffer_by_file(service_ptr_t m_fil streamfile->sf.close = (void (__cdecl *)(_STREAMFILE *)) close_foo; streamfile->m_file = m_file; - + streamfile->p_abort = p_abort; streamfile->buffersize = buffersize; streamfile->buffer = buffer; - streamfile->p_abort = p_abort; streamfile->name = strdup(filename); - if (!streamfile->name) { - free(streamfile); - free(buffer); - return NULL; - } + if (!streamfile->name) goto fail; /* cache filesize */ streamfile->filesize = streamfile->m_file->get_size(*streamfile->p_abort); return &streamfile->sf; + +fail: + free(buffer); + free(streamfile); + return NULL; } static STREAMFILE * open_foo_streamfile_buffer(const char * const filename, size_t buffersize, abort_callback * p_abort, t_filestats * stats) { @@ -269,3 +207,7 @@ static STREAMFILE * open_foo_streamfile_buffer(const char * const filename, size return streamFile; } + +STREAMFILE * open_foo_streamfile(const char * const filename, abort_callback * p_abort, t_filestats * stats) { + return open_foo_streamfile_buffer(filename,STREAMFILE_DEFAULT_BUFFER_SIZE, p_abort, stats); +} diff --git a/src/streamfile.c b/src/streamfile.c index e81bc3aa..ae9e615e 100644 --- a/src/streamfile.c +++ b/src/streamfile.c @@ -9,13 +9,15 @@ /* a STREAMFILE that operates via standard IO using a buffer */ typedef struct { STREAMFILE sf; /* callbacks */ + FILE * infile; /* actual FILE */ - char name[PATH_LIMIT]; - off_t offset; /* current offset */ - size_t validsize; /* current buffer size */ + char name[PATH_LIMIT]; /* FILE filename */ + off_t offset; /* last read offset (info) */ + off_t buffer_offset; /* current buffer data start */ uint8_t * buffer; /* data buffer */ size_t buffersize; /* max buffer size */ - size_t filesize; /* cached file size (max offset) */ + size_t validsize; /* current buffer size */ + size_t filesize; /* buffered file size */ } STDIOSTREAMFILE; static STREAMFILE * open_stdio_streamfile_buffer(const char * const filename, size_t buffersize); @@ -28,9 +30,9 @@ static size_t read_stdio(STDIOSTREAMFILE *streamfile,uint8_t * dest, off_t offse return 0; /* is the part of the requested length in the buffer? */ - if (offset >= streamfile->offset && offset < streamfile->offset + streamfile->validsize) { + if (offset >= streamfile->buffer_offset && offset < streamfile->buffer_offset + streamfile->validsize) { size_t length_to_read; - off_t offset_into_buffer = offset - streamfile->offset; + off_t offset_into_buffer = offset - streamfile->buffer_offset; length_to_read = streamfile->validsize - offset_into_buffer; if (length_to_read > length) @@ -43,32 +45,34 @@ static size_t read_stdio(STDIOSTREAMFILE *streamfile,uint8_t * dest, off_t offse dest += length_to_read; } - /* What would make more sense here is to read the whole request - * at once into the dest buffer, as it must be large enough, and then - * copy some part of that into our own buffer. - * The destination buffer is supposed to be much smaller than the - * STREAMFILE buffer, though. Maybe we should only ever return up - * to the buffer size to avoid having to deal with things like this - * which are outside of my intended use. */ /* read the rest of the requested length */ while (length > 0) { - size_t length_to_read, length_read; - streamfile->validsize = 0; /* buffer is empty now */ + size_t length_to_read; - /* request outside file: ignore to avoid seek/read */ - if (offset > streamfile->filesize) { - streamfile->offset = streamfile->filesize; - VGM_LOG_ONCE("ERROR: reading over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length); - return length_read_total; /* partially-read buffer */ + /* ignore requests at EOF */ + if (offset >= streamfile->filesize) { + //offset = streamfile->filesize; /* seems fseek doesn't clamp offset */ + VGM_ASSERT_ONCE(offset > streamfile->filesize, "STDIO: reading over filesize 0x%x @ 0x%lx + 0x%x\n", streamfile->filesize, offset, length); + break; } /* position to new offset */ if (fseeko(streamfile->infile,offset,SEEK_SET)) { - streamfile->offset = streamfile->filesize; - return 0; /* fail miserably (fseek shouldn't fail and reach this) */ + break; /* this shouldn't happen in our code */ } - streamfile->offset = offset; + +#ifdef _MSC_VER + /* Workaround a bug that appears when compiling with MSVC (later versions). + * This bug is deterministic and seemingly appears randomly after seeking. + * It results in fread returning data from the wrong area of the file. + * HPS is one format that is almost always affected by this. */ + fseek(streamfile->infile, ftell(streamfile->infile), SEEK_SET); +#endif + + /* fill the buffer (offset now is beyond buffer_offset) */ + streamfile->buffer_offset = offset; + streamfile->validsize = fread(streamfile->buffer,sizeof(uint8_t),streamfile->buffersize,streamfile->infile); /* decide how much must be read this time */ if (length > streamfile->buffersize) @@ -76,57 +80,41 @@ static size_t read_stdio(STDIOSTREAMFILE *streamfile,uint8_t * dest, off_t offse else length_to_read = length; -#ifdef _MSC_VER - /* Workaround a bug that appears when compiling witn MSVC. - * This bug is dertiministic and seemingly appears randomly - * after seeking. - * It results in fread returning data from the wrong - * area of the file. - * HPS is one format that is almost always affected - * by this. */ - fseek(streamfile->infile, ftell(streamfile->infile), SEEK_SET); -#endif - - /* fill the buffer */ - length_read = fread(streamfile->buffer,sizeof(uint8_t),streamfile->buffersize,streamfile->infile); - streamfile->validsize = length_read; - - /* if we can't get enough to satisfy the request (EOF) we give up */ - if (length_read < length_to_read) { - memcpy(dest,streamfile->buffer,length_read); - return length_read_total + length_read; /* partially-read buffer */ + /* give up on partial reads (EOF) */ + if (streamfile->validsize < length_to_read) { + memcpy(dest,streamfile->buffer,streamfile->validsize); + offset += streamfile->validsize; + length_read_total += streamfile->validsize; + break; } /* use the new buffer */ memcpy(dest,streamfile->buffer,length_to_read); + offset += length_to_read; length_read_total += length_to_read; length -= length_to_read; dest += length_to_read; - offset += length_to_read; } + streamfile->offset = offset; /* last fread offset */ return length_read_total; } - +static size_t get_size_stdio(STDIOSTREAMFILE * streamfile) { + return streamfile->filesize; +} +static off_t get_offset_stdio(STDIOSTREAMFILE *streamfile) { + return streamfile->offset; +} +static void get_name_stdio(STDIOSTREAMFILE *streamfile,char *buffer,size_t length) { + strncpy(buffer,streamfile->name,length); + buffer[length-1]='\0'; +} static void close_stdio(STDIOSTREAMFILE * streamfile) { fclose(streamfile->infile); free(streamfile->buffer); free(streamfile); } -static size_t get_size_stdio(STDIOSTREAMFILE * streamfile) { - return streamfile->filesize; -} - -static off_t get_offset_stdio(STDIOSTREAMFILE *streamfile) { - return streamfile->offset; -} - -static void get_name_stdio(STDIOSTREAMFILE *streamfile,char *buffer,size_t length) { - strncpy(buffer,streamfile->name,length); - buffer[length-1]='\0'; -} - static STREAMFILE *open_stdio(STDIOSTREAMFILE *streamFile,const char * const filename,size_t buffersize) { int newfd; FILE *newfile; @@ -264,12 +252,12 @@ static size_t buffer_read(BUFFER_STREAMFILE *streamfile, uint8_t * dest, off_t o /* ignore requests at EOF */ if (offset >= streamfile->filesize) { - //offset = streamfile->filesize; /* seems fseek doesn't clamp offset */ //todo once + //offset = streamfile->filesize; /* seems fseek doesn't clamp offset */ VGM_ASSERT_ONCE(offset > streamfile->filesize, "BUFFER: reading over filesize 0x%x @ 0x%lx + 0x%x\n", streamfile->filesize, offset, length); break; } - /* fill the buffer (being here means offset is outside buffer thus empty) */ + /* fill the buffer (offset now is beyond buffer_offset) */ streamfile->buffer_offset = offset; streamfile->validsize = streamfile->inner_sf->read(streamfile->inner_sf, streamfile->buffer, streamfile->buffer_offset, streamfile->buffersize); From f576d9568c20824c7941f6aa2a4833c798755f31 Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 24 Aug 2018 19:29:39 +0200 Subject: [PATCH 20/55] Rename nolayout.c to flat.c for consistency/clarity --- src/layout/{nolayout.c => flat.c} | 0 src/libvgmstream.vcproj | 2 +- src/libvgmstream.vcxproj | 2 +- src/libvgmstream.vcxproj.filters | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename src/layout/{nolayout.c => flat.c} (100%) diff --git a/src/layout/nolayout.c b/src/layout/flat.c similarity index 100% rename from src/layout/nolayout.c rename to src/layout/flat.c diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 33f88d27..97610ae0 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -1899,7 +1899,7 @@ > - + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 512f9539..bdb79f24 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -1129,7 +1129,7 @@ layout\Source Files - + layout\Source Files From b17719f69ccbafd500e36396729c6f56f31d9d6f Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 24 Aug 2018 19:37:02 +0200 Subject: [PATCH 21/55] Rename render_vgmstream_nolayout to _flat for clarity/consistency But not layout_none to layout_flat, since it's used everywhere --- src/formats.c | 2 +- src/layout/flat.c | 2 +- src/layout/layout.h | 2 +- src/vgmstream.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/formats.c b/src/formats.c index cb7de7e7..6fca461c 100644 --- a/src/formats.c +++ b/src/formats.c @@ -614,7 +614,7 @@ static const coding_info coding_info_list[] = { }; static const layout_info layout_info_list[] = { - {layout_none, "flat (no layout)"}, + {layout_none, "flat"}, {layout_interleave, "interleave"}, {layout_segmented, "segmented"}, diff --git a/src/layout/flat.c b/src/layout/flat.c index f481a034..f38198aa 100644 --- a/src/layout/flat.c +++ b/src/layout/flat.c @@ -1,7 +1,7 @@ #include "layout.h" #include "../vgmstream.h" -void render_vgmstream_nolayout(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { +void render_vgmstream_flat(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { int samples_written=0; const int samples_this_block = vgmstream->num_samples; diff --git a/src/layout/layout.h b/src/layout/layout.h index bd17b738..b3597320 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -49,7 +49,7 @@ void block_update_xa_aiff(off_t block_offset, VGMSTREAM * vgmstream); /* other layouts */ void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); -void render_vgmstream_nolayout(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); +void render_vgmstream_flat(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); void render_vgmstream_aix(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); diff --git a/src/vgmstream.c b/src/vgmstream.c index 79ff9e9a..bf1488b2 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -940,7 +940,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre render_vgmstream_interleave(buffer,sample_count,vgmstream); break; case layout_none: - render_vgmstream_nolayout(buffer,sample_count,vgmstream); + render_vgmstream_flat(buffer,sample_count,vgmstream); break; case layout_blocked_mxch: case layout_blocked_ast: From 92a6d572277d85971b5f83eb80e5156be007615b Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 24 Aug 2018 19:37:31 +0200 Subject: [PATCH 22/55] Fix typos and doc stuff --- BUILD.md | 6 +++--- README.md | 4 ++-- cli/vgmstream_cli.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/BUILD.md b/BUILD.md index 4fc53ed6..72879644 100644 --- a/BUILD.md +++ b/BUILD.md @@ -200,7 +200,7 @@ To add a new one: - *src/libvgmstream.vcproj/vcxproj/filters*: add to compile new (format-name).c parser in VS - if the format needs an external library don't forget to mark optional parts with: *#ifdef VGM_USE_X ... #endif* -Ultimately the meta must alloc the VGMSTREAM, set config and initial state. vgmstream needs the total number samples to work, so at times must convert from data sizes to samples (doing calculations or using helpers). +Ultimately the meta must alloc the VGMSTREAM, set config and initial state. vgmstream needs the total of number samples to work, so at times must convert from data sizes to samples (doing calculations or using helpers). It also needs to open and assign to the VGMSTREAM one or several STREAMFILEs (usually reopening the base one, but could be any other file) to do I/O during decode, as well as setting the starting offsets of each channel and other values; this gives metas full flexibility at the cost of some repetition. The STREAMFILE passed to the meta will be discarded and its pointer must not be reused. @@ -208,7 +208,7 @@ The .c file is usually named after the format's main extension or header id, opt Different formats may use the same extension but this isn't a problem as long as the header id or some other validation tells them apart, and should be implemented in separate .c files. If the format is headerless and the extension isn't unique enough it probably needs a generic GENH/TXTH header instead of direct support. -If the format supports subsongs it should read the stream index (subsong number) in the passed STREAMFILE, and use it to parse a section of the file. Then it must report the number of subsongs in the VGMSTREAM, to signal this feature is enabled. The index is 1-based (first subsong is 1, 0 is default/first). +If the format supports subsongs it should read the stream index (subsong number) in the passed STREAMFILE, and use it to parse a section of the file. Then it must report the number of subsongs in the VGMSTREAM, to signal this feature is enabled. The index is 1-based (first subsong is 1, 0 is default/first). This makes possible to directly use bank-like formats like .FSB, and while vgmstream could technically support any container (like generic bigfiles or even .zip) it should be restricted to files that actually are audio banks. #### layouts Layouts control most of the main logic: @@ -225,7 +225,7 @@ Available layouts, depending on how codec data is laid out: - blocked: data is divided into blocks, often with a header. Layout detects when a block is done and asks a helper function to fix offsets (skipping the header and pointing to data per channel), depending on the block format. - others: uncommon cases may need its own custom layout (ex.- multistream/subfiles) -The layout is used mainly depends on the decoder. MP3 data (that may have 1 or 2 channels per frame) uses the flat layout, while DSP ADPCM (that only decodes one channel at a time) is interleaved. In case of mono files either could be used as there won't be any actual difference. +The layout used mainly depends on the decoder. MP3 data (that may have 1 or 2 channels per frame) uses flat layout, while DSP ADPCM (that only decodes one channel at a time) is interleaved. In case of mono files either could be used as there won't be any actual difference. Layouts expect the VGMSTREAM to be properly initialized during the meta processing (channel offsets must point to each channel start offset). diff --git a/README.md b/README.md index d77d2f04..ffc322c2 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ Options: -c: loop forever (continuously) -m: print metadata only, don't decode -x: decode and print adxencd command line to encode as ADX -2 -g: decode and print oggenc command line to encode as OGG + -g: decode and print oggenc command line to encode as OGG -b: decode and print batch variable commands -L: append a smpl chunk and create a looping wav -e: force end-to-end looping @@ -64,7 +64,7 @@ Options: -r outfile2.wav: output a second time after resetting -2 N: only output the Nth (first is 0) set of stereo channels -F: don't fade after N loops and play the rest of the stream - -s N: select subtream N, if the format supports multiple streams + -s N: select subsong N, if the format supports multiple subsongs ``` Typical usage would be: ```test -o happy.wav happy.adx``` to decode ```happy.adx``` to ```happy.wav```. diff --git a/cli/vgmstream_cli.c b/cli/vgmstream_cli.c index 1fe89833..a26cd987 100644 --- a/cli/vgmstream_cli.c +++ b/cli/vgmstream_cli.c @@ -50,7 +50,7 @@ static void usage(const char * name) { " -r outfile2.wav: output a second time after resetting\n" " -2 N: only output the Nth (first is 0) set of stereo channels\n" " -F: don't fade after N loops and play the rest of the stream\n" - " -s N: select subtream N, if the format supports multiple streams\n" + " -s N: select subsong N, if the format supports multiple subsongs\n" ,name); } From 19e6e635e1c059153cf0b646e88d257788a107ea Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 24 Aug 2018 20:08:44 +0200 Subject: [PATCH 23/55] Minor VRTS speedup --- cli/vrts.bat | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/vrts.bat b/cli/vrts.bat index dd4debd5..e53bd5d6 100644 --- a/cli/vrts.bat +++ b/cli/vrts.bat @@ -138,9 +138,9 @@ REM # ######################################################################## ) ) - REM # compare files (doesn't use /b for speedup, somehow) - set CMP_WAV=fc /a /lb1 "%WAV_OLD%" "%WAV_NEW%" - set CMP_TXT=fc /a /lb1 "%TXT_OLD%" "%TXT_NEW%" + REM # compare files (without /b may to be faster for small files?) + set CMP_WAV=fc /a /b "%WAV_OLD%" "%WAV_NEW%" + set CMP_TXT=fc /a /b "%TXT_OLD%" "%TXT_NEW%" %CMP_WAV% 1> nul 2>&1 set CMP_WAV_ERROR=0 From 131e4ea12373b0c4ef14933fc6d09cc8c8c18fcc Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 09:55:42 +0200 Subject: [PATCH 24/55] Add VRTS configurable file comparer, since Windows's FC is so slow --- cli/vrts.bat | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cli/vrts.bat b/cli/vrts.bat index e53bd5d6..fee41a4d 100644 --- a/cli/vrts.bat +++ b/cli/vrts.bat @@ -30,6 +30,8 @@ REM # -nc: don't report correct files set OP_NOCORRECT= REM # -p: performance test (decode with new exe and no comparison done) set OP_PERFORMANCE= +REM # -fc : file comparer (Windows's FC is slow) +set OP_CMD_FC=fc /a /b REM # parse options @@ -42,6 +44,7 @@ if "%~1"=="-r" set OP_RECURSIVE=/s if "%~1"=="-nd" set OP_NODELETE=true if "%~1"=="-nc" set OP_NOCORRECT=true if "%~1"=="-p" set OP_PERFORMANCE=true +if "%~1"=="-fc" set OP_CMD_FC=%2 shift goto set_options :end_options @@ -139,8 +142,8 @@ REM # ######################################################################## ) REM # compare files (without /b may to be faster for small files?) - set CMP_WAV=fc /a /b "%WAV_OLD%" "%WAV_NEW%" - set CMP_TXT=fc /a /b "%TXT_OLD%" "%TXT_NEW%" + set CMP_WAV=%OP_CMD_FC% "%WAV_OLD%" "%WAV_NEW%" + set CMP_TXT=%OP_CMD_FC% "%TXT_OLD%" "%TXT_NEW%" %CMP_WAV% 1> nul 2>&1 set CMP_WAV_ERROR=0 From 6654e44517b22c7d43550f182a08faa88a9b8c70 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 09:57:20 +0200 Subject: [PATCH 25/55] Improve/fix AWC XMA streamfile for certain cases It was assuming reads were sequential, though they can skip to offset (in practice rarely affected), and adjusted packet skip to improve a few songs. --- src/meta/awc_xma_streamfile.h | 208 ++++++++++++++++------------------ 1 file changed, 98 insertions(+), 110 deletions(-) diff --git a/src/meta/awc_xma_streamfile.h b/src/meta/awc_xma_streamfile.h index f4c231c7..54106624 100644 --- a/src/meta/awc_xma_streamfile.h +++ b/src/meta/awc_xma_streamfile.h @@ -5,26 +5,25 @@ typedef struct { /* config */ + int channel; + int channel_count; + size_t block_size; off_t stream_offset; size_t stream_size; - int channel_count; - int channel; - size_t chunk_size; /* state */ - off_t logical_offset; /* offset that corresponds to physical_offset */ - off_t physical_offset; /* actual file offset */ - off_t next_block_offset; /* physical offset of the next block start */ - off_t last_offset; /* physical offset of where the last block ended */ - size_t current_data_size; - size_t current_consumed_size; + off_t logical_offset; /* offset that corresponds to physical_offset */ + off_t physical_offset; /* actual file offset */ - size_t total_size; /* size of the resulting XMA data */ + size_t skip_size; /* size to skip from a block start to reach data start */ + size_t data_size; /* logical size of the block */ + + size_t logical_size; } awc_xma_io_data; static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, awc_xma_io_data *data); -static size_t get_repeated_data_size(STREAMFILE *streamFile, off_t new_offset, off_t last_offset); +static size_t get_repeated_data_size(STREAMFILE *streamFile, off_t next_offset, size_t repeat_samples); static size_t get_block_skip_count(STREAMFILE *streamFile, off_t offset, int channel); /* Reads plain XMA data of a single stream. Each block has a header and channels have different num_samples/frames. @@ -35,7 +34,7 @@ static size_t awc_xma_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offse size_t frame_size = 0x800; /* ignore bad reads */ - if (offset < 0 || offset > data->total_size) { + if (offset < 0 || offset > data->logical_size) { return 0; } @@ -44,97 +43,84 @@ static size_t awc_xma_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offse if (offset < data->logical_offset) { data->logical_offset = 0x00; data->physical_offset = data->stream_offset; - data->next_block_offset = 0; - data->last_offset = 0; - data->current_data_size = 0; - data->current_consumed_size = 0; + data->data_size = 0; } - /* read from block, moving to next when all data is consumed */ + /* read blocks, one at a time */ while (length > 0) { - size_t to_read, bytes_read; - /* new block */ - if (data->current_data_size == 0) { + /* ignore EOF */ + if (data->logical_offset >= data->logical_size) { + break; + } + + /* process new block */ + if (data->data_size == 0) { size_t header_size = get_block_header_size(streamfile, data->physical_offset, data); /* header table entries = frames... I hope */ - size_t skip_size = get_block_skip_count(streamfile, data->physical_offset, data->channel) * frame_size; + size_t others_size = get_block_skip_count(streamfile, data->physical_offset, data->channel) * frame_size; //size_t skip_size = read_32bitBE(data->physical_offset + 0x10*data->channel + 0x00, streamfile) * frame_size; size_t data_size = read_32bitBE(data->physical_offset + 0x10*data->channel + 0x04, streamfile) * frame_size; size_t repeat_samples = read_32bitBE(data->physical_offset + 0x10*data->channel + 0x08, streamfile); size_t repeat_size = 0; + /* if there are repeat samples current block repeats some frames from last block, find out size */ - if (repeat_samples && data->last_offset) { - off_t data_offset = data->physical_offset + header_size + skip_size; - repeat_size = get_repeated_data_size(streamfile, data_offset, data->last_offset); + if (repeat_samples) { + off_t data_offset = data->physical_offset + header_size + others_size; + repeat_size = get_repeated_data_size(streamfile, data_offset, repeat_samples); } - data->next_block_offset = data->physical_offset + data->chunk_size; - data->physical_offset += header_size + skip_size + repeat_size; /* data start */ - data->current_data_size = data_size - repeat_size; /* readable max in this block */ - data->current_consumed_size = 0; + data->skip_size = header_size + others_size + repeat_size; + data->data_size = data_size - repeat_size; + } + + /* move to next block */ + if (offset >= data->logical_offset + data->data_size) { + data->physical_offset += data->block_size; + data->logical_offset += data->data_size; + data->data_size = 0; continue; } - /* block end, go next */ - if (data->current_consumed_size == data->current_data_size) { - data->last_offset = data->physical_offset; /* where last block ended */ - data->physical_offset = data->next_block_offset; - data->current_data_size = 0; - continue; + /* read data */ + { + size_t bytes_consumed, bytes_done, to_read; + + bytes_consumed = offset - data->logical_offset; + + to_read = data->data_size - bytes_consumed; + if (to_read > length) + to_read = length; + bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile); + + offset += bytes_done; + total_read += bytes_done; + length -= bytes_done; + dest += bytes_done; + + if (bytes_done != to_read || bytes_done == 0) { + break; /* error/EOF */ + } } - /* requested offset is further along, pretend we consumed data and try again */ - if (offset > data->logical_offset) { - size_t to_consume = offset - data->logical_offset; - if (to_consume > data->current_data_size - data->current_consumed_size) - to_consume = data->current_data_size - data->current_consumed_size; - - data->physical_offset += to_consume; - data->logical_offset += to_consume; - data->current_consumed_size += to_consume; - continue; - } - - /* clamp reads up to this block's end */ - to_read = (data->current_data_size - data->current_consumed_size); - if (to_read > length) - to_read = length; - if (to_read == 0) - return total_read; /* should never happen... */ - - /* finally read and move buffer/offsets */ - bytes_read = read_streamfile(dest, data->physical_offset, to_read, streamfile); - total_read += bytes_read; - if (bytes_read != to_read) - return total_read; /* couldn't read fully */ - - dest += bytes_read; - offset += bytes_read; - length -= bytes_read; - - data->physical_offset += bytes_read; - data->logical_offset += bytes_read; - data->current_consumed_size += bytes_read; } return total_read; } static size_t awc_xma_io_size(STREAMFILE *streamfile, awc_xma_io_data* data) { - off_t physical_offset, max_physical_offset, last_offset; + off_t physical_offset, max_physical_offset; size_t frame_size = 0x800; - size_t total_size = 0; + size_t logical_size = 0; - if (data->total_size) - return data->total_size; + if (data->logical_size) + return data->logical_size; physical_offset = data->stream_offset; max_physical_offset = data->stream_offset + data->stream_size; - last_offset = 0; - /* read blocks and sum final size */ + /* get size of the logical stream */ while (physical_offset < max_physical_offset) { size_t header_size = get_block_header_size(streamfile, physical_offset, data); /* header table entries = frames... I hope */ @@ -145,33 +131,38 @@ static size_t awc_xma_io_size(STREAMFILE *streamfile, awc_xma_io_data* data) { size_t repeat_size = 0; /* if there are repeat samples current block repeats some frames from last block, find out size */ - if (repeat_samples && last_offset) { + if (repeat_samples) { off_t data_offset = physical_offset + header_size + skip_size; - repeat_size = get_repeated_data_size(streamfile, data_offset, last_offset); + repeat_size = get_repeated_data_size(streamfile, data_offset, repeat_samples); } - last_offset = physical_offset + header_size + skip_size + data_size; - total_size += data_size - repeat_size; - physical_offset += data->chunk_size; + logical_size += data_size - repeat_size; + physical_offset += data->block_size; } - data->total_size = total_size; - return data->total_size; + data->logical_size = logical_size; + return data->logical_size; } /* Prepares custom IO for AWC XMA, which is interleaved XMA in AWC blocks */ -static STREAMFILE* setup_awc_xma_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t stream_size, size_t chunk_size, int channel_count, int channel) { +static STREAMFILE* setup_awc_xma_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t stream_size, size_t block_size, int channel_count, int channel) { STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL; awc_xma_io_data io_data = {0}; size_t io_data_size = sizeof(awc_xma_io_data); + io_data.channel = channel; + io_data.channel_count = channel_count; io_data.stream_offset = stream_offset; io_data.stream_size = stream_size; - io_data.chunk_size = chunk_size; - io_data.channel_count = channel_count; - io_data.channel = channel; + io_data.block_size = block_size; io_data.physical_offset = stream_offset; + io_data.logical_size = awc_xma_io_size(streamFile, &io_data); /* force init */ + + if (io_data.logical_size > io_data.stream_size) { + VGM_LOG("AWC XMA: wrong logical size\n"); + goto fail; + } /* setup subfile */ new_streamFile = open_wrap_streamfile(streamFile); @@ -182,7 +173,10 @@ static STREAMFILE* setup_awc_xma_streamfile(STREAMFILE *streamFile, off_t stream if (!new_streamFile) goto fail; temp_streamFile = new_streamFile; - //todo maybe should force to read filesize once + new_streamFile = open_buffer_streamfile(new_streamFile,0); + if (!new_streamFile) goto fail; + temp_streamFile = new_streamFile; + return temp_streamFile; fail: @@ -209,35 +203,29 @@ static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, awc_xm /* find data that repeats in the beginning of a new block at the end of last block */ -static size_t get_repeated_data_size(STREAMFILE *streamFile, off_t new_offset, off_t last_offset) { - uint8_t new_frame[0x800];/* buffer to avoid fseek back and forth */ - size_t frame_size = 0x800; - off_t offset; - int i; +static size_t get_repeated_data_size(STREAMFILE *streamFile, off_t next_offset, size_t repeat_samples) { + const size_t frame_size = 0x800; + const size_t samples_per_subframe = 512; + size_t samples_this_frame; + uint8_t subframes; - /* read block first frame */ - if (read_streamfile(new_frame,new_offset, frame_size,streamFile) != frame_size) - goto fail; + //todo: fix this + /* Repeat samples are the number of decoded samples to discard, but in this streamfile we can't do that. + * Also XMA is VBR, and may encode silent frames with up to 63 subframes yet we may have few repeat samples. + * We could find out how many subframes of 512 samples to skip, then adjust the XMA frame header, though + * output will be slightly off since subframes are related. + * + * For now just skip a full frame depending on the number of subframes vs repeat samples. + * Most files work ok-ish but channels may desync slightly. */ - /* find the frame in last bytes of prev block */ - offset = last_offset - 0x4000; /* typical max is 1 frame of ~0x800, no way to know exact size */ - while (offset < last_offset) { - /* compare frame vs prev block data */ - for (i = 0; i < frame_size; i++) { - if ((uint8_t)read_8bit(offset+i,streamFile) != new_frame[i]) - break; - } - - /* frame fully compared? */ - if (i == frame_size) - return last_offset - offset; - else - offset += i+1; + subframes = ((uint8_t)read_8bit(next_offset,streamFile) >> 2) & 0x3F; /* peek into frame header */ + samples_this_frame = subframes*samples_per_subframe; + if (repeat_samples >= (int)(samples_this_frame*0.13)) { /* skip mosts */ + return frame_size; + } + else { + return 0; } - -fail: - VGM_LOG("AWC: can't find repeat size, new=0x%08lx, last=0x%08lx\n", new_offset, last_offset); - return 0; /* keep on truckin' */ } /* header has a skip value, but somehow it's sometimes bigger than expected (WHY!?!?) so just sum all */ From 07ad3250f69ea61e02204af317eb193dd0d6e87d Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 09:57:46 +0200 Subject: [PATCH 26/55] Clean EAAC streamfile and prepare for EA-XMA --- src/meta/ea_eaac.c | 11 +- src/meta/ea_eaac_streamfile.h | 257 +++++++++++++++++++++------------- 2 files changed, 167 insertions(+), 101 deletions(-) diff --git a/src/meta/ea_eaac.c b/src/meta/ea_eaac.c index 1d65786d..9568a29f 100644 --- a/src/meta/ea_eaac.c +++ b/src/meta/ea_eaac.c @@ -638,7 +638,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST vgmstream->layout_type = layout_segmented; } else { - temp_streamFile = setup_eaac_streamfile(streamData, eaac.version, eaac.codec, eaac.streamed, eaac.stream_offset,0); + temp_streamFile = setup_eaac_streamfile(streamData, eaac.version, eaac.codec, eaac.streamed,0,0, eaac.stream_offset); if (!temp_streamFile) goto fail; vgmstream->codec_data = init_mpeg_custom(temp_streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, type, &cfg); @@ -659,7 +659,6 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST #ifdef VGM_USE_ATRAC9 case EAAC_CODEC_EATRAX: { /* EATrax (unknown FourCC) [Need for Speed: Most Wanted (Vita)] */ atrac9_config cfg = {0}; - size_t total_size; /* EATrax is "buffered" ATRAC9, uses custom IO since it's kind of complex to add to the decoder */ @@ -668,14 +667,15 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST cfg.channels = eaac.channels; cfg.config_data = read_32bitBE(header_offset + 0x08,streamHead); /* 0x10: frame size? (same as config data?) */ - total_size = read_32bitLE(header_offset + 0x0c,streamHead); /* actual data size without blocks, LE b/c why make sense */ + /* actual data size without blocks, LE b/c why make sense (but don't use it in case of truncated files) */ + //total_size = read_32bitLE(header_offset + 0x0c,streamHead); vgmstream->codec_data = init_atrac9(&cfg); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_ATRAC9; vgmstream->layout_type = layout_none; - temp_streamFile = setup_eaac_streamfile(streamData, eaac.version, eaac.codec, eaac.streamed, eaac.stream_offset, total_size); + temp_streamFile = setup_eaac_streamfile(streamData, eaac.version, eaac.codec, eaac.streamed,0,0, eaac.stream_offset); if (!temp_streamFile) goto fail; break; @@ -729,7 +729,6 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *st segmented_layout_data *data = NULL; STREAMFILE* temp_streamFile[2] = {0}; off_t offsets[2] = { eaac->stream_offset, eaac->loop_offset }; - off_t sizes[2] = { eaac->stream_offset + eaac->loop_offset, 0}; /* 0 = let streamfile guess */ int num_samples[2] = { eaac->loop_start, eaac->num_samples - eaac->loop_start}; int segment_count = 2; /* intro/loop */ int i; @@ -740,7 +739,7 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *st if (!data) goto fail; for (i = 0; i < segment_count; i++) { - temp_streamFile[i] = setup_eaac_streamfile(streamData, eaac->version,eaac->codec,eaac->streamed, offsets[i], sizes[i]); + temp_streamFile[i] = setup_eaac_streamfile(streamData, eaac->version,eaac->codec,eaac->streamed,0,0, offsets[i]); if (!temp_streamFile[i]) goto fail; data->segments[i] = allocate_vgmstream(eaac->channels, 0); diff --git a/src/meta/ea_eaac_streamfile.h b/src/meta/ea_eaac_streamfile.h index cb2434ae..ddffe1c2 100644 --- a/src/meta/ea_eaac_streamfile.h +++ b/src/meta/ea_eaac_streamfile.h @@ -2,141 +2,186 @@ #define _EA_EAAC_STREAMFILE_H_ #include "../streamfile.h" +#define XMA_FRAME_SIZE 0x800 typedef struct { - /* state */ - off_t logical_offset; /* offset that corresponds to physical_offset */ - off_t physical_offset; /* actual file offset */ - /* config */ int version; int codec; int streamed; - off_t start_offset; - size_t total_size; /* size of the resulting substream */ + int stream_number; + int stream_count; + off_t stream_offset; + + /* state */ + off_t logical_offset; /* offset that corresponds to physical_offset */ + off_t physical_offset; /* actual file offset */ + + uint32_t block_flag; /* current block flags */ + size_t block_size; /* current block size */ + size_t skip_size; /* size to skip from a block start to reach data start */ + size_t data_size; /* logical size of the block */ + size_t extra_size; /* extra padding/etc size of the block */ + + size_t logical_size; } eaac_io_data; /* Reads skipping EA's block headers, so the resulting data is smaller or larger than physical data. - * physical/logical_offset should always be at the start of a block and only advance when a block is fully done */ + * physical/logical_offset will be at the start of a block and only advance when a block is done */ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, eaac_io_data* data) { size_t total_read = 0; /* ignore bad reads */ - if (offset < 0 || offset > data->total_size) { + if (offset < 0 || offset > data->logical_size) { return total_read; } /* previous offset: re-start as we can't map logical<>physical offsets * (kinda slow as it trashes buffers, but shouldn't happen often) */ if (offset < data->logical_offset) { - data->physical_offset = data->start_offset; + data->physical_offset = data->stream_offset; data->logical_offset = 0x00; + data->data_size = 0; + data->extra_size = 0; } - /* read doing one EA block at a time */ + /* read blocks, one at a time */ while (length > 0) { - size_t to_read, bytes_read; - off_t intrablock_offset, intradata_offset; - uint32_t block_flag, block_size, data_size, skip_size; - block_flag = (uint8_t)read_8bit(data->physical_offset+0x00,streamfile); - block_size = read_32bitBE(data->physical_offset+0x00,streamfile) & 0x00FFFFFF; - - if (data->version == 1 && block_flag == 0x48) { - data->physical_offset += block_size; - continue; /* skip header block */ + /* ignore EOF (implicitly handles block end flags) */ + if (data->logical_offset >= data->logical_size) { + break; } - if (data->version == 1 && block_flag == 0x45) - break; /* stop on last block (always empty) */ - switch(data->codec) { + /* process new block */ + if (data->data_size == 0) { + data->block_flag = (uint8_t)read_8bit(data->physical_offset+0x00,streamfile); + data->block_size = read_32bitBE(data->physical_offset+0x00,streamfile) & 0x00FFFFFF; + + /* ignore header block */ + if (data->version == 1 && data->block_flag == 0x48) { + data->physical_offset += data->block_size; + continue; + } + + switch(data->codec) { #if 0 - case 0x03: - data_size = block_size - ???; - extra_size = (data_size % 0x800); /* deflated padding */ + case 0x03: { /* EA-XMA */ + /* block format: 0x04=num-samples, (size*4 + N XMA packets) per stream (with 1/2ch XMA headers) */ + int i; - - skip_size = 0x08 + 0x04*data->stream_count; - break; + data->skip_size = 0x04 + 0x04; + for (i = 0; i < data->stream_number - 1; i++) { + data->skip_size += read_32bitBE(data->physical_offset+data->skip_size, streamfile) / 4; + } + data->data_size = read_32bitBE(data->physical_offset+data->skip_size, streamfile) / 4; /* why size*4...? */ + data->skip_size += 0x04; /* skip mini header */ + data->data_size -= 0x04; /* remove mini header */ + if (data->data_size % XMA_FRAME_SIZE) + data->extra_size = XMA_FRAME_SIZE - (data->data_size % XMA_FRAME_SIZE); + break; + } #endif + case 0x05: /* EALayer3 v1 */ + case 0x06: /* EALayer3 v2 "PCM" */ + case 0x07: /* EALayer3 v2 "Spike" */ + data->skip_size = 0x08; + data->data_size = data->block_size - data->skip_size; + break; - case 0x05: /* EALayer3 v1 */ - case 0x06: /* EALayer3 v2 "PCM" */ - case 0x07: /* EALayer3 v2 "Spike" */ - data_size = block_size - 0x08; - skip_size = 0x08; - break; - - case 0x0a: /* EATrax */ - data_size = read_32bitBE(data->physical_offset+0x04,streamfile); /* should be block_size - 0x08 */ - skip_size = 0x08; - break; - - default: - return total_read; + case 0x0a: /* EATrax */ + data->skip_size = 0x08; + data->data_size = read_32bitBE(data->physical_offset+0x04,streamfile); /* also block_size - 0x08 */ + break; +#if 0 + case 0x0c: /* EA Opus */ + data->skip_size = 0x08; + data->data_size = data->block_size - data->skip_size; + break; +#endif + default: + return total_read; + } } - /* requested offset is outside current block, try next */ - if (offset >= data->logical_offset + data_size) { - data->physical_offset += block_size; - data->logical_offset += data_size; + /* move to next block */ + if (offset >= data->logical_offset + data->data_size + data->extra_size) { + data->physical_offset += data->block_size; + data->logical_offset += data->data_size + data->extra_size; + data->data_size = 0; + data->extra_size = 0; continue; } - /* reads could fall in the middle of the block */ - intradata_offset = offset - data->logical_offset; - intrablock_offset = skip_size + intradata_offset; + /* read data */ + { + size_t bytes_consumed, bytes_done, to_read; - /* clamp reads up to this block's end */ - to_read = (data_size - intradata_offset); - if (to_read > length) - to_read = length; - if (to_read == 0) - break; /* should never happen... */ + bytes_consumed = offset - data->logical_offset; - /* finally read and move buffer/offsets */ - bytes_read = read_streamfile(dest, data->physical_offset + intrablock_offset, to_read, streamfile); - total_read += bytes_read; - if (bytes_read != to_read) - break; /* couldn't read fully */ + switch(data->codec) { +#if 0 + case 0x03: { /* EA-XMA */ + if (bytes_consumed < data->data_size) { /* offset falls within actual data */ + to_read = data->data_size - bytes_consumed; + if (to_read > length) + to_read = length; + bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile); + } + else { /* offset falls within logical padded data */ + to_read = data->data_size + data->extra_size - bytes_consumed; + if (to_read > length) + to_read = length; + memset(dest, 0xFF, to_read); /* no real need though, padding is ignored */ + bytes_done = to_read; + } + break; + } +#endif + default: + to_read = data->data_size - bytes_consumed; + if (to_read > length) + to_read = length; + bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile); + break; + } - dest += bytes_read; - offset += bytes_read; - length -= bytes_read; + total_read += bytes_done; + dest += bytes_done; + offset += bytes_done; + length -= bytes_done; - /* block fully read, go next */ - if (intradata_offset + bytes_read == data_size) { - data->physical_offset += block_size; - data->logical_offset += data_size; + if (bytes_done != to_read || bytes_done == 0) { + break; /* error/EOF */ + } } - - if (data->version == 0 && (!data->streamed || block_flag == 0x80)) - break; /* stop on last block */ } return total_read; } + static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) { off_t physical_offset, max_physical_offset; - size_t total_size = 0; + size_t logical_size = 0; - if (data->total_size) - return data->total_size; + if (data->logical_size) + return data->logical_size; - physical_offset = data->start_offset; + physical_offset = data->stream_offset; max_physical_offset = get_streamfile_size(streamfile); - /* get size of the underlying, non-blocked data */ + /* get size of the logical stream */ while (physical_offset < max_physical_offset) { - uint32_t block_flag, block_size, data_size; + uint32_t block_flag, block_size, data_size, skip_size; + //int i; block_flag = (uint8_t)read_8bit(physical_offset+0x00,streamfile); block_size = read_32bitBE(physical_offset+0x00,streamfile) & 0x00FFFFFF; if (data->version == 0 && block_flag != 0x00 && block_flag != 0x80) - break; /* data/end block expected */ + break; /* unknown block */ if (data->version == 1 && block_flag == 0x48) { physical_offset += block_size; @@ -145,13 +190,20 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) { if (data->version == 1 && block_flag == 0x45) break; /* stop on last block (always empty) */ if (data->version == 1 && block_flag != 0x44) - break; /* data block expected */ + break; /* unknown block */ switch(data->codec) { #if 0 - case 0x03: - data_size = block_size - ???; - data_size += (data_size % 0x800); /* deflated padding */ + case 0x03: /* EA-XMA */ + skip_size = 0x04 + 0x04; + for (i = 0; i < data->stream_number - 1; i++) { + skip_size += read_32bitBE(physical_offset + skip_size, streamfile) / 4; /* why size*4...? */ + } + data_size = read_32bitBE(physical_offset + skip_size, streamfile) / 4; + skip_size += 0x04; /* skip mini header */ + data_size -= 0x04; /* remove mini header */ + if (data_size % XMA_FRAME_SIZE) + data_size += XMA_FRAME_SIZE - (data_size % XMA_FRAME_SIZE); /* extra padding */ break; #endif case 0x05: /* EALayer3 v1 */ @@ -161,46 +213,61 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) { break; case 0x0a: /* EATrax */ - data_size = read_32bitBE(physical_offset+0x04,streamfile); /* should be block_size - 0x08 */ + data_size = read_32bitBE(physical_offset+0x04,streamfile); /* also block_size - 0x08 */ break; +#if 0 + case 0x0c: { /* EAOpus */ + size_t done; + data_size = 0; + while (done < block_size - 0x08) { + size_t packet_size = read_16bitBE(physical_offset+0x08+done,streamfile); + done += 0x02 + packet_size; + data_size = 0x1a + packet_size; /* OggS page per Opus packet */ + } + break; + } +#endif default: return 0; } physical_offset += block_size; - total_size += data_size; + logical_size += data_size; if (data->version == 0 && (!data->streamed || block_flag == 0x80)) break; /* stop on last block */ } - if (total_size > get_streamfile_size(streamfile)) { - VGM_LOG("EA SCHL: wrong streamfile total_size\n"); - total_size = 0; - } - - data->total_size = total_size; - return data->total_size; + data->logical_size = logical_size; + return data->logical_size; } /* Prepares custom IO for some blocked EAAudioCore formats, that need clean reads without block headers: - * - EA-XMA: deflated XMA in multistreams (separate 2ch frames) + * - EA-XMA: deflated XMA in multistreams (separate 1/2ch packets) * - EALayer3: MPEG granule 1 can go in the next block (in V2"P" mainly, others could use layout blocked_sns) * - EATrax: ATRAC9 frames can be split between blooks + * - EAOpus: */ -static STREAMFILE* setup_eaac_streamfile(STREAMFILE *streamFile, int version, int codec, int streamed, off_t start_offset, size_t total_size) { +static STREAMFILE* setup_eaac_streamfile(STREAMFILE *streamFile, int version, int codec, int streamed, int stream_number, int stream_count, off_t stream_offset) { STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL; eaac_io_data io_data = {0}; size_t io_data_size = sizeof(eaac_io_data); io_data.version = version; io_data.codec = codec; - io_data.start_offset = start_offset; io_data.streamed = streamed; - io_data.total_size = total_size; /* optional */ - io_data.physical_offset = start_offset; + io_data.stream_number = stream_number; + io_data.stream_count = stream_count; + io_data.stream_offset = stream_offset; + io_data.physical_offset = stream_offset; + io_data.logical_size = eaac_io_size(streamFile, &io_data); /* force init */ + + if (io_data.logical_size > get_streamfile_size(streamFile)) { + VGM_LOG("EA EAAC: wrong logical size\n"); + goto fail; + } /* setup subfile */ new_streamFile = open_wrap_streamfile(streamFile); From db899deb993774083957f2772f5c246fab6ea3ee Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 12:19:51 +0200 Subject: [PATCH 27/55] Add some Makefile extra cflags --- cli/Makefile | 4 ++-- winamp/Makefile | 2 +- xmplay/Makefile | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/Makefile b/cli/Makefile index 245a7521..23a93c1f 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -18,7 +18,7 @@ ifeq ($(TARGET_OS),Windows_NT) CFLAGS += -DWIN32 endif -CFLAGS += -Wall -O3 -DVAR_ARRAYS -I../ext_includes $(EXTRA_CFLAGS) +CFLAGS += -Wall -Werror=format-security -Wdeclaration-after-statement -Wvla -O3 -DVAR_ARRAYS -I../ext_includes $(EXTRA_CFLAGS) LDFLAGS += -L../src -L../ext_libs -lvgmstream $(EXTRA_LDFLAGS) -lm TARGET_EXT_LIBS = @@ -26,7 +26,7 @@ LIBAO_INC_PATH = ../../libao/include LIBAO_LIB_PATH = ../../libao/bin #ifdef VGM_DEBUG -# CFLAGS += -DVGM_DEBUG_OUTPUT -O0 -Werror=format-security -Wdeclaration-after-statement -Wvla +# CFLAGS += -DVGM_DEBUG_OUTPUT -O0 # CFLAGS += -Wold-style-definition -Woverflow -Wpointer-arith -Wstrict-prototypes -pedantic -std=gnu90 -fstack-protector -Wformat #endif diff --git a/winamp/Makefile b/winamp/Makefile index 5c5886c0..ba727e96 100644 --- a/winamp/Makefile +++ b/winamp/Makefile @@ -11,7 +11,7 @@ endif ### main defs OUTPUT_WINAMP = in_vgmstream.dll -CFLAGS += -Wall -O3 -DUSE_ALLOCA -DWIN32 -I../ext_includes $(EXTRA_CFLAGS) +CFLAGS += -Wall -Werror=format-security -Wdeclaration-after-statement -Wvla -O3 -DUSE_ALLOCA -DWIN32 -I../ext_includes $(EXTRA_CFLAGS) LDFLAGS += -L../src -L../ext_libs -lm -lvgmstream $(EXTRA_LDFLAGS) TARGET_EXT_LIBS = diff --git a/xmplay/Makefile b/xmplay/Makefile index 78ee5254..c7115de5 100644 --- a/xmplay/Makefile +++ b/xmplay/Makefile @@ -11,7 +11,7 @@ endif ### main defs OUTPUT_XMPLAY = xmp-vgmstream.dll -CFLAGS += -Wall -O3 -DUSE_ALLOCA -DWIN32 -I../ext_includes $(EXTRA_CFLAGS) +CFLAGS += -Wall -Werror=format-security -Wdeclaration-after-statement -Wvla -O3 -DUSE_ALLOCA -DWIN32 -I../ext_includes $(EXTRA_CFLAGS) LDFLAGS += -L../src -L../ext_libs -lm -lvgmstream $(EXTRA_LDFLAGS) TARGET_EXT_LIBS = From 8a57cf47290505f6a6fc3b1bdb15645fcf9af1cf Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 12:20:55 +0200 Subject: [PATCH 28/55] Add .dax RIFF [Love Game's - Wai Wai Tennis (PS1)] --- src/formats.c | 1 + src/meta/riff.c | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/formats.c b/src/formats.c index 6fca461c..edffa2dc 100644 --- a/src/formats.c +++ b/src/formats.c @@ -106,6 +106,7 @@ static const char* extension_list[] = { "cxs", "da", + "dax", "dbm", "dcs", "ddsp", diff --git a/src/meta/riff.c b/src/meta/riff.c index 56d00de6..a3b0c69a 100644 --- a/src/meta/riff.c +++ b/src/meta/riff.c @@ -254,19 +254,26 @@ 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), + /* .lwav: to avoid hijacking .wav + * .xwav: fake for Xbox games (not needed anymore) + * .da: The Great Battle VI (PS1) + * .dax: Love Game's - Wai Wai Tennis (PS1) + * .cd: Exector (PS) + * .med: Psi Ops (PC) + * .snd: Layton Brothers (iOS/Android) * .adx: Remember11 (PC) sfx * .adp: Headhunter (DC) * .xss: Spider-Man The Movie (Xbox) * .xsew: Mega Man X Legacy Collections (PC) */ - if ( check_extensions(streamFile, "wav,lwav,xwav,da,cd,med,snd,adx,adp,xss,xsew") ) { + if ( check_extensions(streamFile, "wav,lwav,xwav,da,dax,cd,med,snd,adx,adp,xss,xsew") ) { ; } else if ( check_extensions(streamFile, "mwv") ) { mwv = 1; } - /* .rws: Climax games (Silent Hill Origins PSP, Oblivion PSP), .aud: EA Replay */ + /* .at3: standard + * .rws: Climax games (Silent Hill Origins PSP, Oblivion PSP) + * .aud: EA Replay */ else if ( check_extensions(streamFile, "at3,rws,aud") ) { at3 = 1; } From 8cf27cc15ea66da5a7fa2f1542a9c713e293ba2e Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 12:21:21 +0200 Subject: [PATCH 29/55] Add .xna XWB [Touhou Makukasai ~ Fantastic Danmaku Festival (PC)] --- src/meta/xwb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/meta/xwb.c b/src/meta/xwb.c index 8f7ad6ab..bad57882 100644 --- a/src/meta/xwb.c +++ b/src/meta/xwb.c @@ -83,13 +83,15 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) { /* checks */ - if (!check_extensions(streamFile,"xwb")) + /* .xwb: standard + * .xna: Touhou Makukasai ~ Fantasy Danmaku Festival (PC) */ + if (!check_extensions(streamFile,"xwb,xna")) goto fail; if ((read_32bitBE(0x00,streamFile) != 0x57424E44) && /* "WBND" (LE) */ (read_32bitBE(0x00,streamFile) != 0x444E4257)) /* "DNBW" (BE) */ goto fail; - xwb.little_endian = read_32bitBE(0x00,streamFile) == 0x57424E44;/* WBND */ + xwb.little_endian = read_32bitBE(0x00,streamFile) == 0x57424E44; /* WBND */ if (xwb.little_endian) { read_32bit = read_32bitLE; } else { From d8758f0cb533d10995f61d77f9c5ecb18cc15370 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 12:22:40 +0200 Subject: [PATCH 30/55] Fix describe_vgmstream with layered_layout + FFmpeg --- src/vgmstream.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/vgmstream.c b/src/vgmstream.c index bf1488b2..523e1baf 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -2248,8 +2248,14 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { switch (vgmstream->coding_type) { #ifdef VGM_USE_FFMPEG case coding_FFmpeg: { - ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data; - if (vgmstream->codec_data) { + ffmpeg_codec_data *data = (ffmpeg_codec_data *)vgmstream->codec_data; + if (!data && vgmstream->layout_data) { + layered_layout_data* layout_data = vgmstream->layout_data; + if (layout_data->layers[0]->coding_type == coding_FFmpeg) + data = layout_data->layers[0]->codec_data; + } + + if (data) { if (data->codec && data->codec->long_name) { snprintf(temp,TEMPSIZE,"%s",data->codec->long_name); } else if (data->codec && data->codec->name) { @@ -2289,7 +2295,7 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { "\n"); concatn(length,desc,temp); - if (vgmstream->layout_type == layout_interleave) { + if (vgmstream->layout_type == layout_interleave && vgmstream->channels > 1) { snprintf(temp,TEMPSIZE, "interleave: %#x bytes\n", (int32_t)vgmstream->interleave_block_size); @@ -2303,7 +2309,7 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { } } - /* codecs with blocks + headers (there are more, this is a start) */ + /* codecs with configurable frame size */ if (vgmstream->layout_type == layout_none && vgmstream->interleave_block_size > 0) { switch (vgmstream->coding_type) { case coding_MSADPCM: @@ -2312,8 +2318,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { case coding_MC3: case coding_WWISE_IMA: case coding_REF_IMA: + case coding_PSX_cfg: snprintf(temp,TEMPSIZE, - "block size: %#x bytes\n", + "frame size: %#x bytes\n", (int32_t)vgmstream->interleave_block_size); concatn(length,desc,temp); break; From e3255344cfef3652c473647a455ece79cf69187d Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 12:48:55 +0200 Subject: [PATCH 31/55] Redo EA-XMA with custom IO for fixes [Skate (X360), NFS: MW (X360)] --- src/meta/ea_eaac.c | 92 ++++++++++++++++++++++++++--------- src/meta/ea_eaac_streamfile.h | 26 +++++----- 2 files changed, 82 insertions(+), 36 deletions(-) diff --git a/src/meta/ea_eaac.c b/src/meta/ea_eaac.c index 9568a29f..7875c302 100644 --- a/src/meta/ea_eaac.c +++ b/src/meta/ea_eaac.c @@ -483,6 +483,7 @@ typedef struct { } eaac_header; static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *streamData, eaac_header *eaac); +static layered_layout_data* build_layered_eaaudiocore_eaxma(STREAMFILE *streamFile, eaac_header *eaac); /* EA newest header from RwAudioCore (RenderWare?) / EAAudioCore library (still generated by sx.exe). @@ -508,7 +509,6 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST /* rest is optional, depends on used flags and codec (handled below) */ eaac.stream_offset = start_offset; - /* V0: SNR+SNS, V1: SPR+SPS (no apparent differences, other than block flags) */ if (eaac.version != EAAC_VERSION_V0 && eaac.version != EAAC_VERSION_V1) { VGM_LOG("EA EAAC: unknown version\n"); @@ -586,28 +586,10 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST #ifdef VGM_USE_FFMPEG case EAAC_CODEC_EAXMA: { /* "EXm0": EA-XMA [Dante's Inferno (X360)] */ - uint8_t buf[0x100]; - int bytes, block_size, block_count; - size_t stream_size, virtual_size; - ffmpeg_custom_config cfg = {0}; - - stream_size = get_streamfile_size(streamData) - eaac.stream_offset; //todo not correct for banks - virtual_size = ffmpeg_get_eaxma_virtual_size(vgmstream->channels, eaac.streamed, eaac.stream_offset,stream_size, streamData); - block_size = 0x10000; /* todo unused and not correctly done by the parser */ - block_count = stream_size / block_size + (stream_size % block_size ? 1 : 0); - - bytes = ffmpeg_make_riff_xma2(buf, 0x100, vgmstream->num_samples, virtual_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size); - if (bytes <= 0) goto fail; - - cfg.type = FFMPEG_EA_XMA; - cfg.virtual_size = virtual_size; - cfg.channels = vgmstream->channels; - - vgmstream->codec_data = init_ffmpeg_config(streamData, buf,bytes, eaac.stream_offset,stream_size, &cfg); - if (!vgmstream->codec_data) goto fail; - + vgmstream->layout_data = build_layered_eaaudiocore_eaxma(streamData, &eaac); + if (!vgmstream->layout_data) goto fail; vgmstream->coding_type = coding_FFmpeg; - vgmstream->layout_type = layout_none; + vgmstream->layout_type = layout_layered; break; } #endif @@ -783,3 +765,69 @@ fail: free_layout_segmented(data); return NULL; } + +static layered_layout_data* build_layered_eaaudiocore_eaxma(STREAMFILE *streamData, eaac_header *eaac) { + layered_layout_data* data = NULL; + STREAMFILE* temp_streamFile = NULL; + int i, layers = (eaac->channels+1) / 2; + + + /* init layout */ + data = init_layout_layered(layers); + if (!data) goto fail; + + /* open each layer subfile (1/2ch streams: 2ch+2ch..+1ch or 2ch+2ch..+2ch). + * EA-XMA uses completely separate 1/2ch streams, unlike standard XMA that interleaves 1/2ch streams + * with a skip counter to reinterleave (so EA-XMA streams don't have skips set) */ + for (i = 0; i < layers; i++) { + int layer_channels = (i+1 == layers && eaac->channels % 2 == 1) ? 1 : 2; /* last layer can be 1/2ch */ + + /* build the layer VGMSTREAM */ + data->layers[i] = allocate_vgmstream(layer_channels, eaac->loop_flag); + if (!data->layers[i]) goto fail; + + data->layers[i]->sample_rate = eaac->sample_rate; + data->layers[i]->num_samples = eaac->num_samples; + data->layers[i]->loop_start_sample = eaac->loop_start; + data->layers[i]->loop_end_sample = eaac->loop_end; + +#ifdef VGM_USE_FFMPEG + { + uint8_t buf[0x100]; + int bytes, block_size, block_count; + size_t stream_size; + + temp_streamFile = setup_eaac_streamfile(streamData, eaac->version, eaac->codec, eaac->streamed,i,layers, eaac->stream_offset); + if (!temp_streamFile) goto fail; + + stream_size = get_streamfile_size(temp_streamFile); + block_size = 0x10000; /* unused */ + block_count = stream_size / block_size + (stream_size % block_size ? 1 : 0); + + bytes = ffmpeg_make_riff_xma2(buf, 0x100, data->layers[i]->num_samples, stream_size, data->layers[i]->channels, data->layers[i]->sample_rate, block_count, block_size); + data->layers[i]->codec_data = init_ffmpeg_header_offset(temp_streamFile, buf,bytes, 0x00, stream_size); + if (!data->layers[i]->codec_data) goto fail; + + data->layers[i]->coding_type = coding_FFmpeg; + data->layers[i]->layout_type = layout_none; + } +#else + goto fail; +#endif + + if ( !vgmstream_open_stream(data->layers[i], temp_streamFile, 0x00) ) { + goto fail; + } + } + + /* setup layered VGMSTREAMs */ + if (!setup_layout_layered(data)) + goto fail; + close_streamfile(temp_streamFile); + return data; + +fail: + close_streamfile(temp_streamFile); + free_layout_layered(data); + return NULL; +} diff --git a/src/meta/ea_eaac_streamfile.h b/src/meta/ea_eaac_streamfile.h index ddffe1c2..c662697e 100644 --- a/src/meta/ea_eaac_streamfile.h +++ b/src/meta/ea_eaac_streamfile.h @@ -66,13 +66,12 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, } switch(data->codec) { -#if 0 case 0x03: { /* EA-XMA */ /* block format: 0x04=num-samples, (size*4 + N XMA packets) per stream (with 1/2ch XMA headers) */ int i; data->skip_size = 0x04 + 0x04; - for (i = 0; i < data->stream_number - 1; i++) { + for (i = 0; i < data->stream_number; i++) { data->skip_size += read_32bitBE(data->physical_offset+data->skip_size, streamfile) / 4; } data->data_size = read_32bitBE(data->physical_offset+data->skip_size, streamfile) / 4; /* why size*4...? */ @@ -82,7 +81,7 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, data->extra_size = XMA_FRAME_SIZE - (data->data_size % XMA_FRAME_SIZE); break; } -#endif + case 0x05: /* EALayer3 v1 */ case 0x06: /* EALayer3 v2 "PCM" */ case 0x07: /* EALayer3 v2 "Spike" */ @@ -121,7 +120,6 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, bytes_consumed = offset - data->logical_offset; switch(data->codec) { -#if 0 case 0x03: { /* EA-XMA */ if (bytes_consumed < data->data_size) { /* offset falls within actual data */ to_read = data->data_size - bytes_consumed; @@ -138,7 +136,7 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, } break; } -#endif + default: to_read = data->data_size - bytes_consumed; if (to_read > length) @@ -175,7 +173,7 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) { /* get size of the logical stream */ while (physical_offset < max_physical_offset) { uint32_t block_flag, block_size, data_size, skip_size; - //int i; + int i; block_flag = (uint8_t)read_8bit(physical_offset+0x00,streamfile); block_size = read_32bitBE(physical_offset+0x00,streamfile) & 0x00FFFFFF; @@ -193,10 +191,9 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) { break; /* unknown block */ switch(data->codec) { -#if 0 case 0x03: /* EA-XMA */ skip_size = 0x04 + 0x04; - for (i = 0; i < data->stream_number - 1; i++) { + for (i = 0; i < data->stream_number; i++) { skip_size += read_32bitBE(physical_offset + skip_size, streamfile) / 4; /* why size*4...? */ } data_size = read_32bitBE(physical_offset + skip_size, streamfile) / 4; @@ -205,7 +202,7 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) { if (data_size % XMA_FRAME_SIZE) data_size += XMA_FRAME_SIZE - (data_size % XMA_FRAME_SIZE); /* extra padding */ break; -#endif + case 0x05: /* EALayer3 v1 */ case 0x06: /* EALayer3 v2 "PCM" */ case 0x07: /* EALayer3 v2 "Spike" */ @@ -239,6 +236,12 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) { break; /* stop on last block */ } + /* logical size can be bigger in EA-XMA though */ + if (physical_offset > get_streamfile_size(streamfile)) { + VGM_LOG("EA EAAC: wrong size %lx\n", physical_offset); + return 0; + } + data->logical_size = logical_size; return data->logical_size; } @@ -264,11 +267,6 @@ static STREAMFILE* setup_eaac_streamfile(STREAMFILE *streamFile, int version, in io_data.physical_offset = stream_offset; io_data.logical_size = eaac_io_size(streamFile, &io_data); /* force init */ - if (io_data.logical_size > get_streamfile_size(streamFile)) { - VGM_LOG("EA EAAC: wrong logical size\n"); - goto fail; - } - /* setup subfile */ new_streamFile = open_wrap_streamfile(streamFile); if (!new_streamFile) goto fail; From 9e54efe6d81aeace3f856c4297423ccd86e41a5a Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 13:22:57 +0200 Subject: [PATCH 32/55] Remove FFMPEG_EA_XMA as it's now done with custom IO + layers --- src/coding/coding.h | 1 - src/coding/ffmpeg_decoder.c | 9 - src/coding/ffmpeg_decoder_utils.h | 12 - src/coding/ffmpeg_decoder_utils_ea_xma.c | 267 ----------------------- src/libvgmstream.vcproj | 4 - src/libvgmstream.vcxproj | 1 - src/libvgmstream.vcxproj.filters | 3 - src/vgmstream.h | 1 - 8 files changed, 298 deletions(-) delete mode 100644 src/coding/ffmpeg_decoder_utils_ea_xma.c diff --git a/src/coding/coding.h b/src/coding/coding.h index 4ca9b29b..11e62042 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -271,7 +271,6 @@ void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples); size_t ffmpeg_make_opus_header(uint8_t * buf, int buf_size, int channels, int skip, int sample_rate); -size_t ffmpeg_get_eaxma_virtual_size(int channels, int streamed, off_t real_offset, size_t real_size, STREAMFILE *streamFile); size_t switch_opus_get_samples(off_t offset, size_t data_size, int sample_rate, STREAMFILE *streamFile); diff --git a/src/coding/ffmpeg_decoder.c b/src/coding/ffmpeg_decoder.c index 07733f8c..05098880 100644 --- a/src/coding/ffmpeg_decoder.c +++ b/src/coding/ffmpeg_decoder.c @@ -220,10 +220,7 @@ static int ffmpeg_read(void *opaque, uint8_t *buf, int buf_size) { /* main read */ switch(data->config.type) { - case FFMPEG_EA_XMA: ret = ffmpeg_custom_read_eaxma(data, buf, buf_size); break; case FFMPEG_SWITCH_OPUS: ret = ffmpeg_custom_read_switch_opus(data, buf, buf_size); break; - //case FFMPEG_EA_SCHL: ret = ffmpeg_custom_read_ea_schl(data, buf, buf_size); break; - //case FFMPEG_SFH: ret = ffmpeg_custom_read_sfh(data, buf, buf_size); break; default: ret = ffmpeg_custom_read_standard(data, buf, buf_size); break; } data->virtual_offset += ret; @@ -288,10 +285,7 @@ static int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) { /* main seek */ switch(data->config.type) { - case FFMPEG_EA_XMA: offset = ffmpeg_custom_seek_eaxma(data, offset); break; case FFMPEG_SWITCH_OPUS: offset = ffmpeg_custom_seek_switch_opus(data, offset); break; - //case FFMPEG_EA_SCHL: offset = ffmpeg_custom_seek_ea_schl(data, offset); break; - //case FFMPEG_SFH: offset = ffmpeg_custom_seek_sfh(data, offset); break; default: offset = ffmpeg_custom_seek_standard(data, offset); break; } data->virtual_offset = offset; @@ -305,10 +299,7 @@ static int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) { static int64_t ffmpeg_size(ffmpeg_codec_data * data) { int64_t bytes; switch(data->config.type) { - case FFMPEG_EA_XMA: bytes = ffmpeg_custom_size_eaxma(data); break; case FFMPEG_SWITCH_OPUS: bytes = ffmpeg_custom_size_switch_opus(data); break; - //case FFMPEG_EA_SCHL: bytes = ffmpeg_custom_size_ea_schl(data); break; - //case FFMPEG_SFH: bytes = ffmpeg_custom_size_sfh(data); break; default: bytes = ffmpeg_custom_size_standard(data); break; } diff --git a/src/coding/ffmpeg_decoder_utils.h b/src/coding/ffmpeg_decoder_utils.h index 64461fe9..beaf1493 100644 --- a/src/coding/ffmpeg_decoder_utils.h +++ b/src/coding/ffmpeg_decoder_utils.h @@ -23,22 +23,10 @@ int ffmpeg_custom_read_standard(ffmpeg_codec_data *data, uint8_t *buf, int buf_s int64_t ffmpeg_custom_seek_standard(ffmpeg_codec_data *data, int64_t virtual_offset); int64_t ffmpeg_custom_size_standard(ffmpeg_codec_data *data); -int ffmpeg_custom_read_eaxma(ffmpeg_codec_data *data, uint8_t *buf, int buf_size); -int64_t ffmpeg_custom_seek_eaxma(ffmpeg_codec_data *data, int64_t virtual_offset); -int64_t ffmpeg_custom_size_eaxma(ffmpeg_codec_data *data); - int ffmpeg_custom_read_switch_opus(ffmpeg_codec_data *data, uint8_t *buf, int buf_size); int64_t ffmpeg_custom_seek_switch_opus(ffmpeg_codec_data *data, int64_t virtual_offset); int64_t ffmpeg_custom_size_switch_opus(ffmpeg_codec_data *data); -//int ffmpeg_custom_read_ea_schl(ffmpeg_codec_data *data, uint8_t *buf, int buf_size); -//int64_t ffmpeg_custom_seek_ea_schl(ffmpeg_codec_data *data, int64_t virtual_offset); -//int64_t ffmpeg_custom_size_ea_schl(ffmpeg_codec_data *data); - -//int ffmpeg_custom_read_sfh(ffmpeg_codec_data *data, uint8_t *buf, int buf_size); -//int64_t ffmpeg_custom_seek_sfh(ffmpeg_codec_data *data, int64_t virtual_offset); -//int64_t ffmpeg_custom_size_sfh(ffmpeg_codec_data *data); - #endif #endif/*_FFMPEG_DECODER_UTILS_*/ diff --git a/src/coding/ffmpeg_decoder_utils_ea_xma.c b/src/coding/ffmpeg_decoder_utils_ea_xma.c deleted file mode 100644 index a9729d36..00000000 --- a/src/coding/ffmpeg_decoder_utils_ea_xma.c +++ /dev/null @@ -1,267 +0,0 @@ -#include "coding.h" -#include "ffmpeg_decoder_utils.h" - -#ifdef VGM_USE_FFMPEG - -#define EAXMA_XMA_MAX_PACKETS_PER_SNS_BLOCK 4 /* normally max 3 (Dante's Inferno), ~14 (1 stream) in Burnout Paradise */ -#define EAXMA_XMA_MAX_STREAMS_PER_SNS_BLOCK 4 /* XMA2 max is 8ch = 4 * 2ch */ -#define EAXMA_XMA_PACKET_SIZE 0x800 -#define EAXMA_XMA_BUFFER_SIZE (EAXMA_XMA_MAX_PACKETS_PER_SNS_BLOCK * EAXMA_XMA_MAX_STREAMS_PER_SNS_BLOCK * EAXMA_XMA_PACKET_SIZE) - -/** - * EA-XMA is XMA2 with padding removed (so a real 0x450 block would be padded to a virtual 0x800 block). - * Each EA-XMA SNS block contains 1~3 packets per stream, and multistream uses fully separate streams - * (no packet_skip set). We'll pad and reinterleave packets so it resembles standard XMA2. - * - * XMA2 data layout (XMA1 is the same but doesn't use blocks, they are only for seeking): - * - frames (containing 1..4 subframes): decode into 128*4 samples - * - packets: size 0x800, containing N frames (last frame can spill into next packet), must be padded - * - blocks: fixed size, containing N packets (last packet's frames won't spill into next block) - * - stream: N interleaved packets (1/2ch) for multichannel (Nch) audio. Interleave is not fixed: - * at file start/new block has one packet per stream, then must follow the "packet_skip" value - * in the XMA packet header to find its next packet (skiping packets from other streams). - * ex.: s1_p1 skip1, s2_p1 skip2, s1_p2 skip0 s1_p3 skip1, s2_p2 skip1, s1_p4... - */ - -static int get_block_max_packets(int num_streams, off_t packets_offset, STREAMFILE * streamfile); - - -int ffmpeg_custom_read_eaxma(ffmpeg_codec_data *data, uint8_t *buf, int buf_size) { - uint8_t v_buf[EAXMA_XMA_BUFFER_SIZE]; /* intermediate buffer, could be simplified */ - int buf_done = 0; - uint64_t real_offset = data->real_offset; - uint64_t virtual_offset = data->virtual_offset - data->header_size; - uint64_t virtual_base = data->virtual_base; - /* EA-XMA always uses late XMA2 streams (2ch + ... + 1/2ch) */ - int num_streams = (data->config.channels / 2) + (data->config.channels % 2 ? 1 : 0); - - - /* read and transform SNS/EA-XMA blocks into XMA packets */ - while (buf_done < buf_size) { - int s, p, bytes_to_copy, max_packets; - size_t block_size, data_size = 0, gap_size = 0; - uint32_t block_flag; - off_t packets_offset; - - block_flag = (uint8_t)read_8bit(real_offset+0x00,data->streamfile); - block_size = read_32bitBE(real_offset+0x00,data->streamfile) & 0x00FFFFFF; - packets_offset = real_offset + 0x08; /* 0x04(4): decoded samples */ - - if (block_flag == 0x45) /* exit on last block just in case, though should reach real_size */ - break; - - max_packets = get_block_max_packets(num_streams, packets_offset, data->streamfile); - if (max_packets == 0) goto fail; - - if (max_packets * num_streams * EAXMA_XMA_PACKET_SIZE > EAXMA_XMA_BUFFER_SIZE) { - VGM_LOG("EA XMA: block too big (%i * %i * 0x%x = 0x%x vs max 0x%x) at %lx\n", - max_packets,num_streams,EAXMA_XMA_PACKET_SIZE, max_packets*num_streams*EAXMA_XMA_PACKET_SIZE, EAXMA_XMA_BUFFER_SIZE,(off_t)real_offset); - goto fail; - } - - /* data is divided into a sub-block per stream (N packets), can be smaller than block_size (= has padding) - * copy XMA data re-interleaving for multichannel. To simplify some calcs fills the same number of packets - * per stream and adjusts packet headers (see above for XMA2 multichannel layout). */ - //to-do this doesn't make correct blocks sizes (but blocks are not needed to decode) - for (s = 0; s < num_streams; s++) { - size_t packets_size; - size_t packets_size4 = read_32bitBE(packets_offset, data->streamfile); /* size * 4, no idea */ - - packets_size = (packets_size4 / 4) - 0x04; - - /* Re-interleave all packets in order, one per stream. If one stream has more packets than - * others we add empty packets to keep the same number for all, avoiding packet_skip calcs */ - for (p = 0; p < max_packets; p++) { - off_t packet_offset = packets_offset + 0x04 + p * EAXMA_XMA_PACKET_SIZE; /* can be off but will copy 0 */ - off_t v_buf_offset = p * EAXMA_XMA_PACKET_SIZE * num_streams + s * EAXMA_XMA_PACKET_SIZE; - size_t packet_to_do = packets_size - p * EAXMA_XMA_PACKET_SIZE; - size_t extra_size = 0; - uint32_t header; - - if (packets_size < p * EAXMA_XMA_PACKET_SIZE) - packet_to_do = 0; /* empty packet */ - else if (packet_to_do > EAXMA_XMA_PACKET_SIZE) - packet_to_do = EAXMA_XMA_PACKET_SIZE; - - /* padding will be full size if packet_to_do is 0 */ - if (packet_to_do < EAXMA_XMA_PACKET_SIZE) - extra_size = EAXMA_XMA_PACKET_SIZE - (packet_to_do % EAXMA_XMA_PACKET_SIZE); - - /* copy data (or fully pad if empty packet) */ - read_streamfile(v_buf + v_buf_offset, packet_offset, packet_to_do, data->streamfile); - memset(v_buf + v_buf_offset + packet_to_do, 0xFF, extra_size); /* add padding, typically 0xFF */ - - /* rewrite packet header to add packet skips for multichannel (EA XMA streams are fully separate and have none) - * header bits: 6=num_frames, 15=first_frame_bits_offset, 3=metadata, 8=packet_skip */ - if (packet_to_do == 0) - header = 0x3FFF800; /* new empty packet header (0 num_frames, first_frame_bits_offset set to max) */ - else - header = (uint32_t)read_32bitBE(packet_offset, data->streamfile); - - /* get base header + change packet_skip since we know interleave is always 1 packet per stream */ - header = (header & 0xFFFFFF00) | ((header & 0x000000FF) + num_streams - 1); - put_32bitBE(v_buf + v_buf_offset, header); - } - - packets_offset += (packets_size4 / 4); - } - - if (buf_done == 0) /* first read */ - gap_size = virtual_offset - virtual_base; /* might start a few bytes into the XMA */ - - data_size = max_packets * num_streams * EAXMA_XMA_PACKET_SIZE; - - bytes_to_copy = data_size - gap_size; - if (bytes_to_copy > buf_size - buf_done) - bytes_to_copy = buf_size - buf_done; - - /* pad + copy */ - memcpy(buf + buf_done, v_buf + gap_size, bytes_to_copy); - buf_done += bytes_to_copy; - - /* move when block is fully done */ - if (data_size == bytes_to_copy + gap_size) { - real_offset += block_size; - virtual_base += data_size; - } - - if (block_flag == 0x80) /* exit on last block just in case, though should reach real_size */ - break; - } - - - data->real_offset = real_offset; - data->virtual_base = virtual_base; - return buf_size; - -fail: - return 0; -} - -int64_t ffmpeg_custom_seek_eaxma(ffmpeg_codec_data *data, int64_t virtual_offset) { - int64_t real_offset, virtual_base; - int64_t current_virtual_offset = data->virtual_offset - data->header_size; - int64_t seek_virtual_offset = virtual_offset - data->header_size; - - /* Find SNS block start closest to offset. ie. virtual_offset 0x1A10 could mean SNS blocks - * of 0x456+0x820 padded to 0x800+0x1000 (base) + 0x210 (extra for reads), thus real_offset = 0xC76 */ - - if (seek_virtual_offset > current_virtual_offset) { /* seek after current: start from current block */ - real_offset = data->real_offset; - virtual_base = data->virtual_base; - } - else { /* seek before current: start from the beginning */ - real_offset = data->real_start; - virtual_base = 0; - } - - - /* find target block */ - while (virtual_base < seek_virtual_offset) { - size_t block_size, data_size, extra_size = 0; - uint32_t block_flag; - - block_flag = (uint8_t)read_8bit(real_offset+0x00,data->streamfile); - block_size = read_32bitBE(real_offset+0x00,data->streamfile) & 0x00FFFFFF; - - if (block_flag == 0x45) /* exit on last block just in case (v1/SPS, empty) */ - break; - - data_size = block_size - 0x0c; - if (data_size % EAXMA_XMA_PACKET_SIZE) - extra_size = EAXMA_XMA_PACKET_SIZE - (data_size % EAXMA_XMA_PACKET_SIZE); - - /* stop if virtual_offset lands inside current block */ - if (data_size + extra_size > seek_virtual_offset) - break; - - real_offset += block_size; - virtual_base += data_size + extra_size; - - if (block_flag == 0x80) /* exit on last block just in case (v0/SNS, full) */ - break; - } - - /* closest we can use for reads */ - data->real_offset = real_offset; - data->virtual_base = virtual_base; - - return virtual_offset; -} - -int64_t ffmpeg_custom_size_eaxma(ffmpeg_codec_data *data) { - - uint64_t virtual_size = data->config.virtual_size; - if (!virtual_size) - return 0; - - return virtual_size + data->header_size; -} - -/* needed to know in meta for fake RIFF */ -size_t ffmpeg_get_eaxma_virtual_size(int channels, int streamed, off_t real_offset, size_t real_size, STREAMFILE *streamFile) { - size_t virtual_size = 0; - size_t real_end_offset = real_offset + real_size; - /* EA-XMA always uses late XMA2 streams (2ch + ... + 1/2ch) */ - int num_streams = (channels / 2) + (channels % 2 ? 1 : 0); - - - /* count all SNS/EAXMA blocks size + padding size */ - while (real_offset < real_end_offset) { - int max_packets; - uint32_t block_flag, block_size; - off_t packets_offset; - - block_flag = (uint8_t)read_8bit(real_offset+0x00,streamFile); - block_size = read_32bitBE(real_offset+0x00,streamFile) & 0x00FFFFFF; - packets_offset = real_offset + 0x08; /* 0x04(4): decoded samples */ - - if (block_flag == 0x45) /* exit on last block just in case (v1/SPS, empty) */ - break; - - max_packets = get_block_max_packets(num_streams, packets_offset, streamFile); - if (max_packets == 0) goto fail; - - /* fixed data_size per block for multichannel, see reads */ - virtual_size += max_packets * num_streams * EAXMA_XMA_PACKET_SIZE; - - real_offset += block_size; - - if (!streamed || block_flag == 0x80) /* exit on last block just in case (v0/SNS, full) */ - break; - } - - return virtual_size; - -fail: - return 0; -} - -/* a block can have N streams each with a varying number of packets, get max */ -static int get_block_max_packets(int num_streams, off_t packets_offset, STREAMFILE * streamfile) { - int s; - int max_packets = 0; - - for (s = 0; s < num_streams; s++) { - size_t packets_size; - size_t packets_size4 = read_32bitBE(packets_offset, streamfile); /* size * 4, no idea */ - int num_packets; - - if (packets_size4 == 0) { - VGM_LOG("EA XMA: null packets in stream %i at %lx\n", s, (off_t)packets_offset); - goto fail; - } - packets_size = (packets_size4 / 4) - 0x04; - - num_packets = (int)(packets_size / EAXMA_XMA_PACKET_SIZE) + 1; - if (num_packets > max_packets) - max_packets = num_packets; - } - - return max_packets; - -fail: - return 0; -} - -#endif diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 97610ae0..1d40adf9 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -1622,10 +1622,6 @@ RelativePath=".\coding\ffmpeg_decoder_utils_ea_schl.c" > - - diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 5a7715ef..e3c21e36 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -124,7 +124,6 @@ - diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index bdb79f24..8bab5696 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -1339,9 +1339,6 @@ coding\Source Files - - coding\Source Files - coding\Source Files diff --git a/src/vgmstream.h b/src/vgmstream.h index 78d14980..a71464e3 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -1115,7 +1115,6 @@ typedef struct { typedef enum { FFMPEG_STANDARD, /* default FFmpeg */ FFMPEG_SWITCH_OPUS, /* Opus without Ogg layer */ - FFMPEG_EA_XMA, /* XMA with padding removed and custom streams in SNS blocks */ } ffmpeg_custom_t; /* config for the above modes */ From 1ba26372560d2c0eba2ea4e314062b7f1556e900 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 16:23:15 +0200 Subject: [PATCH 33/55] Clean XVAG meta for future changes --- src/meta/xvag.c | 157 ++++++++++++++++++++++++++---------------------- 1 file changed, 84 insertions(+), 73 deletions(-) diff --git a/src/meta/xvag.c b/src/meta/xvag.c index 520b6a22..08fd9713 100644 --- a/src/meta/xvag.c +++ b/src/meta/xvag.c @@ -3,33 +3,47 @@ #include "../layout/layout.h" +typedef struct { + int big_endian; + int channels; + int sample_rate; + int codec; + + int factor; + + int loop_flag; + int num_samples; + int loop_start; + int loop_end; + + int subsongs; + int layers; + + size_t data_size; + off_t stream_offset; +} xvag_header; + /* XVAG - Sony's Scream Tool/Stream Creator format (God of War III, Ratchet & Clank Future, The Last of Us, Uncharted) */ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; + xvag_header xvag = {0}; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; - int loop_flag = 0, channel_count, codec; - int big_endian; - int sample_rate, num_samples, interleave_factor, multistreams = 0; + off_t start_offset, chunk_offset, first_offset = 0x20; + size_t chunk_size; int total_subsongs = 0, target_subsong = streamFile->stream_index; - off_t start_offset, loop_start = 0, loop_end = 0, chunk_offset; - off_t first_offset = 0x20; - size_t chunk_size, data_size; - /* checks */ /* .xvag: standard * (extensionless): The Last Of Us (PS3) speech files */ if (!check_extensions(streamFile,"xvag,")) goto fail; - - /* check header */ if (read_32bitBE(0x00,streamFile) != 0x58564147) /* "XVAG" */ goto fail; /* endian flag (XVAGs of the same game can use BE or LE, usually when reusing from other platforms) */ - big_endian = read_8bit(0x08,streamFile) & 0x01; - if (big_endian) { + xvag.big_endian = read_8bit(0x08,streamFile) & 0x01; + if (xvag.big_endian) { read_32bit = read_32bitBE; } else { read_32bit = read_32bitLE; @@ -43,29 +57,31 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { /* "fmat": base format (always first) */ - if (!find_chunk(streamFile, 0x666D6174,first_offset,0, &chunk_offset,&chunk_size, big_endian, 1)) /*"fmat"*/ + if (!find_chunk(streamFile, 0x666D6174,first_offset,0, &chunk_offset,&chunk_size, xvag.big_endian, 1)) /*"fmat"*/ goto fail; - channel_count = read_32bit(chunk_offset+0x00,streamFile); - codec = read_32bit(chunk_offset+0x04,streamFile); - num_samples = read_32bit(chunk_offset+0x08,streamFile); - /* 0x0c: samples again? playable section? */ - VGM_ASSERT(num_samples != read_32bit(chunk_offset+0x0c,streamFile), "XVAG: num_samples values don't match\n"); + xvag.channels = read_32bit(chunk_offset+0x00,streamFile); + xvag.codec = read_32bit(chunk_offset+0x04,streamFile); + xvag.num_samples = read_32bit(chunk_offset+0x08,streamFile); + /* 0x0c: samples again? */ + VGM_ASSERT(xvag.num_samples != read_32bit(chunk_offset+0x0c,streamFile), "XVAG: num_samples values don't match\n"); - interleave_factor = read_32bit(chunk_offset+0x10,streamFile); - sample_rate = read_32bit(chunk_offset+0x14,streamFile); - data_size = read_32bit(chunk_offset+0x18,streamFile); /* not always accurate */ + xvag.factor = read_32bit(chunk_offset+0x10,streamFile); /* for interleave */ + xvag.sample_rate = read_32bit(chunk_offset+0x14,streamFile); + xvag.data_size = read_32bit(chunk_offset+0x18,streamFile); /* not always accurate */ /* extra data, seen in versions 0x61+ */ if (chunk_size > 0x1c) { - /* number of interleaved subsong layers */ - total_subsongs = read_32bit(chunk_offset+0x1c,streamFile); - /* number of interleaved streams per layer (multistreams * channels_per_stream = channels) */ - multistreams = read_32bit(chunk_offset+0x20,streamFile); + /* number of interleaved subsongs */ + xvag.subsongs = read_32bit(chunk_offset+0x1c,streamFile); + /* number of interleaved layers (layers * channels_per_layer = channels) */ + xvag.layers = read_32bit(chunk_offset+0x20,streamFile); } else { - total_subsongs = 1; - multistreams = 1; + xvag.subsongs = 1; + xvag.layers = 1; } + + total_subsongs = xvag.subsongs; if (target_subsong == 0) target_subsong = 1; if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; @@ -73,72 +89,72 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { /* other chunks: */ /* "cpan": pan/volume per channel */ /* "cues": cue/labels (rare) */ + /* "md5 ": hash (rare) */ /* "0000": end chunk before start_offset */ /* XVAG has no looping, but some PS3 PS-ADPCM seems to do full loops (without data flags) */ - if (codec == 0x06 && total_subsongs == 1) { + if (xvag.codec == 0x06 && xvag.subsongs == 1) { size_t file_size = get_streamfile_size(streamFile); /* simply test if last frame is not empty = may loop */ - loop_flag = (read_8bit(file_size - 0x01, streamFile) != 0); - loop_start = 0; - loop_end = file_size - start_offset; + xvag.loop_flag = (read_8bit(file_size - 0x01, streamFile) != 0); + xvag.loop_start = 0; + xvag.loop_end = ps_bytes_to_samples(file_size - start_offset, xvag.channels); } /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); + vgmstream = allocate_vgmstream(xvag.channels,xvag.loop_flag); if (!vgmstream) goto fail; - vgmstream->sample_rate = sample_rate; - vgmstream->num_samples = num_samples; - vgmstream->num_streams = total_subsongs; - vgmstream->stream_size = (data_size / total_subsongs); vgmstream->meta_type = meta_XVAG; + vgmstream->sample_rate = xvag.sample_rate; + vgmstream->num_samples = xvag.num_samples; + if (xvag.loop_flag) { + vgmstream->loop_start_sample = xvag.loop_start; + vgmstream->loop_end_sample = xvag.loop_end; + } + vgmstream->num_streams = total_subsongs; + vgmstream->stream_size = (xvag.data_size / total_subsongs); - switch (codec) { - case 0x06: /* VAG (PS-ADPCM): God of War III (PS3), Uncharted 1/2 (PS3), Ratchet and Clank Future (PS3) */ - case 0x07: /* SVAG? (PS-ADPCM with extended table?): inFamous 1 (PS3) */ - if (multistreams > 1 && multistreams != vgmstream->channels) goto fail; - if (total_subsongs > 1 && multistreams > 1) goto fail; - if (total_subsongs > 1 && vgmstream->channels > 1) goto fail; /* unknown layout */ + switch (xvag.codec) { + case 0x06: /* VAG (PS-ADPCM): God of War III (PS3), Uncharted 1/2 (PS3), Ratchet and Clank Future (PS3) */ + case 0x07: /* SVAG? (PS-ADPCM with extended table?): inFamous 1 (PS3) */ + if (xvag.subsongs > 1 && xvag.layers > 1) goto fail; + if (xvag.layers > 1 && xvag.layers != xvag.channels) goto fail; + if (xvag.subsongs > 1 && xvag.channels > 1) goto fail; /* unknown layout */ vgmstream->coding_type = coding_PSX; - if (total_subsongs > 1) { /* God of War 3 (PS4) */ + if (xvag.subsongs > 1) { /* God of War 3 (PS4) */ vgmstream->layout_type = layout_blocked_xvag_subsong; vgmstream->interleave_block_size = 0x10; - vgmstream->full_block_size = 0x10 * interleave_factor * total_subsongs; - vgmstream->current_block_size = 0x10 * interleave_factor; - start_offset += 0x10 * interleave_factor * (target_subsong-1); + vgmstream->full_block_size = 0x10 * xvag.factor * xvag.subsongs; + vgmstream->current_block_size = 0x10 * xvag.factor; + start_offset += vgmstream->current_block_size * (target_subsong-1); } else { vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x10 * interleave_factor; /* usually 1, bigger in GoW3 PS4 */ + vgmstream->interleave_block_size = 0x10 * xvag.factor; /* usually 1, bigger in GoW3 PS4 */ } - - if (loop_flag) { - vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, vgmstream->channels); - vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, vgmstream->channels); - } - break; #ifdef VGM_USE_MPEG - case 0x08: { /* MPEG: The Last of Us (PS3), Uncharted 3 (PS3), Medieval Moves (PS3) */ + case 0x08: { /* MPEG: The Last of Us (PS3), Uncharted 3 (PS3), Medieval Moves (PS3) */ mpeg_custom_config cfg = {0}; + if (xvag.subsongs > 1) goto fail; + if (xvag.subsongs > 1 && xvag.layers > 1) goto fail; /* often 2ch per MPEG and rarely 1ch (GoW3 PS4) */ - if (multistreams > 1 && !(multistreams*1 == vgmstream->channels || multistreams*2 == vgmstream->channels)) goto fail; - if (total_subsongs > 1) goto fail; - //todo rare test file in The Last of Us PS4 uses 6ch with 1 2ch stream, surround MPEG/mp3pro? + if (xvag.layers > 1 && !(xvag.layers*1 == vgmstream->channels || xvag.layers*2 == vgmstream->channels)) goto fail; + //todo rare test file in The Last of Us PS4 uses 6ch with one 2ch stream, surround MPEG/mp3pro? (decoded samples map to 6ch) /* "mpin": mpeg info */ /* 0x00/04: mpeg version/layer? other: unknown or repeats of "fmat" */ - if (!find_chunk(streamFile, 0x6D70696E,first_offset,0, &chunk_offset,NULL, big_endian, 1)) /*"mpin"*/ + if (!find_chunk(streamFile, 0x6D70696E,first_offset,0, &chunk_offset,NULL, xvag.big_endian, 1)) /*"mpin"*/ goto fail; cfg.chunk_size = read_32bit(chunk_offset+0x1c,streamFile); /* fixed frame size */ - cfg.interleave = cfg.chunk_size * interleave_factor; + cfg.interleave = cfg.chunk_size * xvag.factor; vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_XVAG, &cfg); if (!vgmstream->codec_data) goto fail; @@ -152,9 +168,11 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { atrac9_config cfg = {0}; size_t frame_size; + if (xvag.subsongs > 1 && xvag.layers > 1) goto fail; + /* "a9in": ATRAC9 info */ /* 0x00: frame size, 0x04: samples per frame, 0x0c: fact num_samples (no change), 0x10: encoder delay1 */ - if (!find_chunk(streamFile, 0x6139696E,first_offset,0, &chunk_offset,NULL, big_endian, 1)) /*"a9in"*/ + if (!find_chunk(streamFile, 0x6139696E,first_offset,0, &chunk_offset,NULL, xvag.big_endian, 1)) /*"a9in"*/ goto fail; frame_size = read_32bit(chunk_offset+0x00,streamFile); @@ -164,24 +182,18 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { cfg.config_data = read_32bitBE(chunk_offset+0x08,streamFile); cfg.encoder_delay = read_32bit(chunk_offset+0x14,streamFile); - if (total_subsongs > 1 && multistreams > 1) { - VGM_LOG("XVAG: unknown %i subsongs and %i multistreams\n", total_subsongs, multistreams); - goto fail; /* not known */ - } - else if (total_subsongs > 1) { + if (xvag.subsongs > 1) { /* interleaves 'multiplier' superframes per subsong (all share config_data) */ - cfg.interleave_skip = frame_size * interleave_factor; - cfg.subsong_skip = total_subsongs; + cfg.interleave_skip = frame_size * xvag.factor; + cfg.subsong_skip = xvag.subsongs; /* start in subsong's first superframe */ start_offset += (target_subsong-1) * cfg.interleave_skip * (cfg.subsong_skip-1); } - else if (multistreams > 1) { - /* Vita multichannel (flower) interleaves streams like MPEG - * PS4 (The Last of Us) uses ATRAC9's multichannel directly instead (multistreams==1) */ - VGM_LOG("XVAG: unknown %i multistreams of size %x\n", multistreams, frame_size * interleave_factor); + else if (xvag.layers > 1) { + /* Vita multichannel, or multilanguage [flower (Vita), Uncharted Collection (PS4)] */ + VGM_LOG("XVAG: unknown %i multistreams of size %x\n", xvag.layers, frame_size * xvag.factor); goto fail;//todo add } - //if (multistreams == vgmstream->channels) goto fail; vgmstream->codec_data = init_atrac9(&cfg); if (!vgmstream->codec_data) goto fail; @@ -191,7 +203,6 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { } #endif - //case 0x??: /* PCM? */ default: goto fail; } @@ -207,6 +218,6 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { return vgmstream; fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } From 9c8dae38dcd0b46a15600a1cbd1e16d8d67dd4e6 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 17:25:02 +0200 Subject: [PATCH 34/55] Fix multilayer XVAG ATRAC9 [flower (Vita), Farpoint (PS4)] --- src/libvgmstream.vcproj | 4 + src/libvgmstream.vcxproj | 2 +- src/libvgmstream.vcxproj.filters | 3 + src/meta/xvag.c | 124 ++++++++++++++++++----- src/meta/xvag_streamfile.h | 163 +++++++++++++++++++++++++++++++ 5 files changed, 271 insertions(+), 25 deletions(-) create mode 100644 src/meta/xvag_streamfile.h diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 1d40adf9..85e60b71 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -259,6 +259,10 @@ + + - + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 8bab5696..52082c1e 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -101,6 +101,9 @@ meta\Header Files + + meta\Header Files + meta\Header Files diff --git a/src/meta/xvag.c b/src/meta/xvag.c index 08fd9713..8847d046 100644 --- a/src/meta/xvag.c +++ b/src/meta/xvag.c @@ -1,6 +1,7 @@ #include "meta.h" #include "../coding/coding.h" #include "../layout/layout.h" +#include "xvag_streamfile.h" typedef struct { @@ -23,9 +24,13 @@ typedef struct { off_t stream_offset; } xvag_header; +static int init_xvag_atrac9(STREAMFILE *streamFile, VGMSTREAM* vgmstream, xvag_header * xvag, off_t chunk_offset); +static layered_layout_data* build_layered_xvag(STREAMFILE *streamFile, xvag_header * xvag, off_t chunk_offset, off_t start_offset); + /* XVAG - Sony's Scream Tool/Stream Creator format (God of War III, Ratchet & Clank Future, The Last of Us, Uncharted) */ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; + STREAMFILE* temp_streamFile = NULL; xvag_header xvag = {0}; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; off_t start_offset, chunk_offset, first_offset = 0x20; @@ -165,9 +170,6 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { #ifdef VGM_USE_ATRAC9 case 0x09: { /* ATRAC9: Sly Cooper and the Thievius Raccoonus (Vita), The Last of Us Remastered (PS4) */ - atrac9_config cfg = {0}; - size_t frame_size; - if (xvag.subsongs > 1 && xvag.layers > 1) goto fail; /* "a9in": ATRAC9 info */ @@ -175,30 +177,27 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { if (!find_chunk(streamFile, 0x6139696E,first_offset,0, &chunk_offset,NULL, xvag.big_endian, 1)) /*"a9in"*/ goto fail; - frame_size = read_32bit(chunk_offset+0x00,streamFile); + if (xvag.layers > 1) { + /* some Vita/PS4 multichannel [flower (Vita), Uncharted Collection (PS4)]. PS4 ATRAC9 also + * does single-stream >2ch, but this can do configs ATRAC9 can't, like 5ch/14ch/etc */ + vgmstream->layout_data = build_layered_xvag(streamFile, &xvag, chunk_offset, start_offset); + if (!vgmstream->layout_data) goto fail; + vgmstream->coding_type = coding_ATRAC9; + vgmstream->layout_type = layout_layered; - cfg.type = ATRAC9_XVAG; - cfg.channels = vgmstream->channels; - cfg.config_data = read_32bitBE(chunk_offset+0x08,streamFile); - cfg.encoder_delay = read_32bit(chunk_offset+0x14,streamFile); - - if (xvag.subsongs > 1) { - /* interleaves 'multiplier' superframes per subsong (all share config_data) */ - cfg.interleave_skip = frame_size * xvag.factor; - cfg.subsong_skip = xvag.subsongs; - /* start in subsong's first superframe */ - start_offset += (target_subsong-1) * cfg.interleave_skip * (cfg.subsong_skip-1); + break; } - else if (xvag.layers > 1) { - /* Vita multichannel, or multilanguage [flower (Vita), Uncharted Collection (PS4)] */ - VGM_LOG("XVAG: unknown %i multistreams of size %x\n", xvag.layers, frame_size * xvag.factor); - goto fail;//todo add + else { + /* interleaved subsongs (section layers) */ + size_t frame_size = read_32bit(chunk_offset+0x00,streamFile); + + if (!init_xvag_atrac9(streamFile, vgmstream, &xvag, chunk_offset)) + goto fail; + temp_streamFile = setup_xvag_streamfile(streamFile, start_offset, frame_size*xvag.factor,frame_size, (target_subsong-1), total_subsongs); + if (!temp_streamFile) goto fail; + start_offset = 0; } - vgmstream->codec_data = init_atrac9(&cfg); - if (!vgmstream->codec_data) goto fail; - vgmstream->coding_type = coding_ATRAC9; - vgmstream->layout_type = layout_none; break; } #endif @@ -209,15 +208,92 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { /* open the file for reading */ - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + if (!vgmstream_open_stream(vgmstream,temp_streamFile ? temp_streamFile : streamFile,start_offset)) goto fail; if (vgmstream->layout_type == layout_blocked_xvag_subsong) block_update_xvag_subsong(start_offset, vgmstream); + close_streamfile(temp_streamFile); return vgmstream; fail: + close_streamfile(temp_streamFile); close_vgmstream(vgmstream); return NULL; } + +#ifdef VGM_USE_ATRAC9 +static int init_xvag_atrac9(STREAMFILE *streamFile, VGMSTREAM* vgmstream, xvag_header * xvag, off_t chunk_offset) { + int32_t (*read_32bit)(off_t,STREAMFILE*) = xvag->big_endian ? read_32bitBE : read_32bitLE; + atrac9_config cfg = {0}; + + cfg.channels = vgmstream->channels; + cfg.config_data = read_32bitBE(chunk_offset+0x08,streamFile); + cfg.encoder_delay = read_32bit(chunk_offset+0x14,streamFile); + + vgmstream->codec_data = init_atrac9(&cfg); + if (!vgmstream->codec_data) goto fail; + vgmstream->coding_type = coding_ATRAC9; + vgmstream->layout_type = layout_none; + + return 1; +fail: + return 0; +} +#endif + +static layered_layout_data* build_layered_xvag(STREAMFILE *streamFile, xvag_header * xvag, off_t chunk_offset, off_t start_offset) { + layered_layout_data* data = NULL; + STREAMFILE* temp_streamFile = NULL; + int32_t (*read_32bit)(off_t,STREAMFILE*) = xvag->big_endian ? read_32bitBE : read_32bitLE; + int i, layers = xvag->layers; + + + /* init layout */ + data = init_layout_layered(layers); + if (!data) goto fail; + + /* interleaves frames per substreams */ + for (i = 0; i < layers; i++) { + int layer_channels = xvag->channels / layers; /* all streams must be equal (XVAG limitation) */ + + /* build the layer VGMSTREAM */ + data->layers[i] = allocate_vgmstream(layer_channels, xvag->loop_flag); + if (!data->layers[i]) goto fail; + + data->layers[i]->sample_rate = xvag->sample_rate; + data->layers[i]->num_samples = xvag->num_samples; + + switch(xvag->codec) { +#ifdef VGM_USE_ATRAC9 + case 0x09: { + size_t frame_size = read_32bit(chunk_offset+0x00,streamFile); + + if (!init_xvag_atrac9(streamFile, data->layers[i], xvag, chunk_offset)) + goto fail; + temp_streamFile = setup_xvag_streamfile(streamFile, start_offset, frame_size*xvag->factor,frame_size, i, layers); + if (!temp_streamFile) goto fail; + break; + } +#endif + default: + goto fail; + } + + if ( !vgmstream_open_stream(data->layers[i], temp_streamFile, 0x00) ) { + goto fail; + } + } + + /* setup layered VGMSTREAMs */ + if (!setup_layout_layered(data)) + goto fail; + close_streamfile(temp_streamFile); + return data; + +fail: + close_streamfile(temp_streamFile); + free_layout_layered(data); + return NULL; +} diff --git a/src/meta/xvag_streamfile.h b/src/meta/xvag_streamfile.h new file mode 100644 index 00000000..bb9820ac --- /dev/null +++ b/src/meta/xvag_streamfile.h @@ -0,0 +1,163 @@ +#ifndef _XVAG_STREAMFILE_H_ +#define _XVAG_STREAMFILE_H_ +#include "../streamfile.h" + + +typedef struct { + /* config */ + int stream_number; + int stream_count; + size_t interleave_size; + size_t frame_size; + off_t stream_offset; + //size_t stream_size; + + /* state */ + off_t logical_offset; /* offset that corresponds to physical_offset */ + off_t physical_offset; /* actual file offset */ + + size_t skip_size; /* size to skip from a block start to reach data start */ + size_t data_size; /* logical size of the block */ + + size_t logical_size; +} xvag_io_data; + + +static size_t xvag_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, xvag_io_data* data) { + size_t total_read = 0; + + /* ignore bad reads */ + if (offset < 0 || offset > data->logical_size) { + return 0; + } + + /* previous offset: re-start as we can't map logical<>physical offsets + * (kinda slow as it trashes buffers, but shouldn't happen often) */ + if (offset < data->logical_offset) { + data->logical_offset = 0x00; + data->physical_offset = data->stream_offset; + data->data_size = 0; + } + + /* read blocks, one at a time */ + while (length > 0) { + + /* ignore EOF */ + if (data->logical_offset >= data->logical_size) { + break; + } + + /* process new block */ + if (data->data_size == 0) { + data->skip_size = data->interleave_size * data->stream_number; + data->data_size = data->interleave_size; + + /* some ATRAC9 XVAG have padding+RIFF at start [The Last of Us (PS4), Farpoint (PS4)] */ + if (data->logical_offset == 0 && read_32bitBE(data->physical_offset+data->skip_size,streamfile) == 0) { + data->skip_size += data->frame_size; + data->data_size -= data->frame_size; + } + } + + /* move to next block */ + if (offset >= data->logical_offset + data->data_size) { + data->physical_offset += data->interleave_size*data->stream_count; + data->logical_offset += data->data_size; + data->data_size = 0; + continue; + } + + /* read data */ + { + size_t bytes_consumed, bytes_done, to_read; + + bytes_consumed = offset - data->logical_offset; + + to_read = data->data_size - bytes_consumed; + if (to_read > length) + to_read = length; + bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile); + + offset += bytes_done; + total_read += bytes_done; + length -= bytes_done; + dest += bytes_done; + + if (bytes_done != to_read || bytes_done == 0) { + break; /* error/EOF */ + } + } + + } + + return total_read; +} + +static size_t xvag_io_size(STREAMFILE *streamfile, xvag_io_data* data) { + off_t physical_offset = data->stream_offset; + off_t max_physical_offset = get_streamfile_size(streamfile); + size_t logical_size = 0; + + if (data->logical_size) + return data->logical_size; + + /* get size of the logical stream */ + while (physical_offset < max_physical_offset) { + size_t skip_size = data->interleave_size * data->stream_number; + size_t data_size = data->interleave_size; + + /* some ATRAC9 XVAG have padding+RIFF at start [The Last of Us (PS4), Farpoint (PS4)] */ + if (logical_size == 0 && read_32bitBE(physical_offset+skip_size,streamfile) == 0) { + skip_size += data->frame_size; + data_size -= data->frame_size; + } + + logical_size += data_size; + physical_offset += data->interleave_size*data->stream_count; + } + + if (logical_size > max_physical_offset) + return 0; + data->logical_size = logical_size; + return data->logical_size; +} + +/* Prepares custom IO for XVAG, which interleaves many superframes per subsong/layer. + * May have start padding, even with only one subsong. All layers share config_data too. */ +static STREAMFILE* setup_xvag_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t interleave_size, size_t frame_size, int stream_number, int stream_count) { + STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL; + xvag_io_data io_data = {0}; + size_t io_data_size = sizeof(xvag_io_data); + + io_data.stream_number = stream_number; + io_data.stream_count = stream_count; + io_data.stream_offset = stream_offset; + //io_data.stream_size = stream_size; + io_data.interleave_size = interleave_size; + io_data.frame_size = frame_size; + io_data.physical_offset = stream_offset; + io_data.logical_size = xvag_io_size(streamFile, &io_data); /* force init */ + + if (io_data.logical_size == 0) { + VGM_LOG("XVAG: wrong logical size\n"); + goto fail; + } + + /* setup subfile */ + new_streamFile = open_wrap_streamfile(streamFile); + if (!new_streamFile) goto fail; + temp_streamFile = new_streamFile; + + new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, xvag_io_read,xvag_io_size); + if (!new_streamFile) goto fail; + temp_streamFile = new_streamFile; + + return temp_streamFile; + +fail: + close_streamfile(temp_streamFile); + return NULL; +} + + +#endif /* _XVAG_STREAMFILE_H_ */ From f86c90c5f92cc5281f3445d86b1b1714c44c11ec Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 17:26:49 +0200 Subject: [PATCH 35/55] Use KMA9 custom IO instead of custom ATRAC9 --- src/libvgmstream.vcproj | 4 + src/libvgmstream.vcxproj | 1 + src/libvgmstream.vcxproj.filters | 3 + src/meta/kma9.c | 29 +++--- src/meta/kma9_streamfile.h | 148 +++++++++++++++++++++++++++++++ 5 files changed, 173 insertions(+), 12 deletions(-) create mode 100644 src/meta/kma9_streamfile.h diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 85e60b71..a5a403ff 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -240,6 +240,10 @@ RelativePath=".\meta\fsb5_interleave_streamfile.h" > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 1166e4a4..c9c90487 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -102,6 +102,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 52082c1e..f8443edf 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -86,6 +86,9 @@ meta\Header Files + + meta\Header Files + meta\Header Files diff --git a/src/meta/kma9.c b/src/meta/kma9.c index 16f2e783..4c0e3c12 100644 --- a/src/meta/kma9.c +++ b/src/meta/kma9.c @@ -1,20 +1,21 @@ #include "meta.h" #include "../coding/coding.h" +#include "kma9_streamfile.h" -/* KMA9 - Koei Tecmo's custom ATRAC9 [Nobunaga no Yabou - Souzou (Vita)] */ + +/* KMA9 - Koei Tecmo's interleaved ATRAC9 [Nobunaga no Yabou - Souzou (Vita)] */ VGMSTREAM * init_vgmstream_kma9(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; + STREAMFILE* temp_streamFile = NULL; off_t start_offset; - size_t stream_size; + size_t stream_size, interleave; int loop_flag, channel_count; int total_subsongs = 0, target_subsong = streamFile->stream_index; - /* check extension */ + /* checks */ if ( !check_extensions(streamFile,"km9") ) goto fail; - - /* check header */ if (read_32bitBE(0x00,streamFile) != 0x4B4D4139) /* "KMA9" */ goto fail; @@ -26,6 +27,7 @@ VGMSTREAM * init_vgmstream_kma9(STREAMFILE *streamFile) { if (target_subsong == 0) target_subsong = 1; if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; /* 0x0c: unknown */ + interleave = read_32bitLE(0x10,streamFile); /* 1 superframe */ stream_size = read_32bitLE(0x14,streamFile); /* per subsong */ @@ -45,14 +47,10 @@ VGMSTREAM * init_vgmstream_kma9(STREAMFILE *streamFile) { { atrac9_config cfg = {0}; - cfg.type = ATRAC9_KMA9; + cfg.type = ATRAC9_DEFAULT; cfg.channels = vgmstream->channels; - cfg.config_data = read_32bitBE(0x5c,streamFile); cfg.encoder_delay = read_32bitLE(0x20,streamFile); - - cfg.interleave_skip = read_32bitLE(0x10,streamFile); /* 1 superframe */ - cfg.subsong_skip = total_subsongs; - start_offset += (target_subsong-1) * cfg.interleave_skip * (cfg.subsong_skip-1); + cfg.config_data = read_32bitBE(0x5c,streamFile); vgmstream->codec_data = init_atrac9(&cfg); if (!vgmstream->codec_data) goto fail; @@ -63,17 +61,24 @@ VGMSTREAM * init_vgmstream_kma9(STREAMFILE *streamFile) { vgmstream->loop_start_sample -= cfg.encoder_delay; //vgmstream->loop_end_sample -= cfg.encoder_delay; } + + /* KMA9 interleaves one ATRAC9 frame per subsong */ + temp_streamFile = setup_kma9_streamfile(streamFile, start_offset, stream_size, interleave, (target_subsong-1), total_subsongs); + if (!temp_streamFile) goto fail; + start_offset = 0; } #else goto fail; #endif /* open the file for reading */ - if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + if ( !vgmstream_open_stream(vgmstream, temp_streamFile, start_offset) ) goto fail; + close_streamfile(temp_streamFile); return vgmstream; fail: + close_streamfile(temp_streamFile); close_vgmstream(vgmstream); return NULL; } diff --git a/src/meta/kma9_streamfile.h b/src/meta/kma9_streamfile.h new file mode 100644 index 00000000..34f21dde --- /dev/null +++ b/src/meta/kma9_streamfile.h @@ -0,0 +1,148 @@ +#ifndef _KM9_STREAMFILE_H_ +#define _KM9_STREAMFILE_H_ +#include "../streamfile.h" + + +typedef struct { + /* config */ + int stream_number; + int stream_count; + size_t interleave_size; + off_t stream_offset; + size_t stream_size; + + /* state */ + off_t logical_offset; /* offset that corresponds to physical_offset */ + off_t physical_offset; /* actual file offset */ + + size_t skip_size; /* size to skip from a block start to reach data start */ + size_t data_size; /* logical size of the block */ + + size_t logical_size; +} kma9_io_data; + + +static size_t kma9_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, kma9_io_data* data) { + size_t total_read = 0; + + /* ignore bad reads */ + if (offset < 0 || offset > data->logical_size) { + return 0; + } + + /* previous offset: re-start as we can't map logical<>physical offsets + * (kinda slow as it trashes buffers, but shouldn't happen often) */ + if (offset < data->logical_offset) { + data->logical_offset = 0x00; + data->physical_offset = data->stream_offset; + data->data_size = 0; + } + + /* read blocks, one at a time */ + while (length > 0) { + + /* ignore EOF */ + if (data->logical_offset >= data->logical_size) { + break; + } + + /* process new block */ + if (data->data_size == 0) { + data->skip_size = data->interleave_size * data->stream_number; + data->data_size = data->interleave_size; + } + + /* move to next block */ + if (offset >= data->logical_offset + data->data_size) { + data->physical_offset += data->interleave_size*data->stream_count; + data->logical_offset += data->data_size; + data->data_size = 0; + continue; + } + + /* read data */ + { + size_t bytes_consumed, bytes_done, to_read; + + bytes_consumed = offset - data->logical_offset; + + to_read = data->data_size - bytes_consumed; + if (to_read > length) + to_read = length; + bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile); + + offset += bytes_done; + total_read += bytes_done; + length -= bytes_done; + dest += bytes_done; + + if (bytes_done != to_read || bytes_done == 0) { + break; /* error/EOF */ + } + } + + } + + return total_read; +} + +static size_t kma9_io_size(STREAMFILE *streamfile, kma9_io_data* data) { + off_t physical_offset = data->stream_offset; + off_t max_physical_offset = get_streamfile_size(streamfile); + size_t logical_size = 0; + + if (data->logical_size) + return data->logical_size; + + /* get size of the logical stream */ + while (physical_offset < max_physical_offset) { + logical_size += data->interleave_size; + physical_offset += data->interleave_size*data->stream_count; + } + + if (logical_size > max_physical_offset) + return 0; + if (logical_size != data->stream_size) + return 0; + data->logical_size = logical_size; + return data->logical_size; +} + + +/* Prepares custom IO for KMA9, which interleaves ATRAC9 frames */ +static STREAMFILE* setup_kma9_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t stream_size, size_t interleave_size, int stream_number, int stream_count) { + STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL; + kma9_io_data io_data = {0}; + size_t io_data_size = sizeof(kma9_io_data); + + io_data.stream_number = stream_number; + io_data.stream_count = stream_count; + io_data.stream_offset = stream_offset; + io_data.stream_size = stream_size; + io_data.interleave_size = interleave_size; + io_data.physical_offset = stream_offset; + io_data.logical_size = kma9_io_size(streamFile, &io_data); /* force init */ + + if (io_data.logical_size == 0) { + VGM_LOG("KMA9: wrong logical size\n"); + goto fail; + } + + /* setup subfile */ + new_streamFile = open_wrap_streamfile(streamFile); + if (!new_streamFile) goto fail; + temp_streamFile = new_streamFile; + + new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, kma9_io_read,kma9_io_size); + if (!new_streamFile) goto fail; + temp_streamFile = new_streamFile; + + return temp_streamFile; + +fail: + close_streamfile(temp_streamFile); + return NULL; +} + + +#endif /* _KM9_STREAMFILE_H_ */ From a734e9c5cbd7b8de3e73c380409181f15ca27e5d Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 17:48:01 +0200 Subject: [PATCH 36/55] Remove custom ATRAC9 in favor of custom IO Formats using custom layouts tend to be weird enough that it's a pain to add support directly in the decoder. Instead should use custom layouts and I/O streamfiles that, though a bit wordy and unwieldy at the moment, are a lot more flexible. --- src/coding/atrac9_decoder.c | 47 +++++++++++++------------------------ src/meta/kma9.c | 1 - src/vgmstream.h | 36 ++++------------------------ 3 files changed, 21 insertions(+), 63 deletions(-) diff --git a/src/coding/atrac9_decoder.c b/src/coding/atrac9_decoder.c index bff83eb3..a5ef1846 100644 --- a/src/coding/atrac9_decoder.c +++ b/src/coding/atrac9_decoder.c @@ -4,6 +4,22 @@ #include "libatrac9.h" +/* opaque struct */ +struct atrac9_codec_data { + uint8_t *data_buffer; + size_t data_buffer_size; + + sample *sample_buffer; + size_t samples_filled; /* number of samples in the buffer */ + size_t samples_used; /* number of samples extracted from the buffer */ + + int samples_to_discard; + + atrac9_config config; + void *handle; /* decoder handle */ +}; + + atrac9_codec_data *init_atrac9(atrac9_config *cfg) { int status; uint8_t config_data[4]; @@ -93,23 +109,6 @@ void decode_atrac9(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, status = Atrac9GetCodecInfo(data->handle, &info); if (status < 0) goto decode_fail; - - /* preadjust */ //todo improve - switch(data->config.type) { - case ATRAC9_XVAG: - /* PS4 (ex. The Last of Us) has a RIFF AT9 (can be ignored) instead of the first superframe. - * As subsongs do too, needs to be skipped here instead of adjusting start_offset */ - if (stream->offset == stream->channel_start_offset) { - if (read_32bitBE(stream->offset, stream->streamfile) == 0x00000000 /* padding before RIFF */ - && read_32bitBE(stream->offset + info.superframeSize - 0x08,stream->streamfile) == 0x64617461) { /* RIFF's "data" */ - stream->offset += info.superframeSize; - } - } - break; - default: - break; - } - /* read one raw block (superframe) and advance offsets */ bytes = read_streamfile(data->data_buffer,stream->offset, info.superframeSize,stream->streamfile); if (bytes != data->data_buffer_size) { @@ -119,20 +118,6 @@ void decode_atrac9(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, stream->offset += bytes; - /* postadjust */ //todo improve - switch(data->config.type) { - case ATRAC9_XVAG: - case ATRAC9_KMA9: - /* skip other subsong blocks */ - if (data->config.interleave_skip && ((stream->offset - stream->channel_start_offset) % data->config.interleave_skip == 0)) { - stream->offset += data->config.interleave_skip * (data->config.subsong_skip - 1); - } - break; - default: - break; - } - - /* decode all frames in the superframe block */ for (iframe = 0; iframe < info.framesInSuperframe; iframe++) { status = Atrac9Decode(data->handle, buffer, data->sample_buffer + data->samples_filled*channels, &bytes_used); diff --git a/src/meta/kma9.c b/src/meta/kma9.c index 4c0e3c12..e1049cd7 100644 --- a/src/meta/kma9.c +++ b/src/meta/kma9.c @@ -47,7 +47,6 @@ VGMSTREAM * init_vgmstream_kma9(STREAMFILE *streamFile) { { atrac9_config cfg = {0}; - cfg.type = ATRAC9_DEFAULT; cfg.channels = vgmstream->channels; cfg.encoder_delay = read_32bitLE(0x20,streamFile); cfg.config_data = read_32bitBE(0x5c,streamFile); diff --git a/src/vgmstream.h b/src/vgmstream.h index a71464e3..9a7fba31 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -1019,39 +1019,13 @@ typedef struct { #endif #ifdef VGM_USE_ATRAC9 - -/* custom ATRAC9 modes */ -typedef enum { - ATRAC9_DEFAULT = 0, /* ATRAC9 standard */ - ATRAC9_XVAG, /* Sony XVAG: interleaved subsongs, Vita multichannel interleaves 2ch xN superframes */ - ATRAC9_KMA9, /* Koei Tecmo KMA9: interleaved subsongs */ -} atrac9_custom_t; - +/* ATRAC9 config */ typedef struct { - atrac9_custom_t type; - - int channels; /* to detect weird multichannel */ - uint32_t config_data; /* ATRAC9 config header */ - int encoder_delay; /* initial samples to discard */ - - size_t interleave_skip; /* XVAG */ - size_t subsong_skip; /* XVAG */ + int channels; /* to detect weird multichannel */ + uint32_t config_data; /* ATRAC9 config header */ + int encoder_delay; /* initial samples to discard */ } atrac9_config; - -typedef struct { - uint8_t *data_buffer; - size_t data_buffer_size; - - sample *sample_buffer; - size_t samples_filled; /* number of samples in the buffer */ - size_t samples_used; /* number of samples extracted from the buffer */ - - int samples_to_discard; - - atrac9_config config; - - void *handle; /* decoder handle */ -} atrac9_codec_data; +typedef struct atrac9_codec_data atrac9_codec_data; #endif #ifdef VGM_USE_CELT From 3765831dbe62372e3acb9d81e05e4823c82705d9 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 18:03:58 +0200 Subject: [PATCH 37/55] Remove usage of atrac9_parse_config --- src/coding/atrac9_decoder.c | 3 ++- src/coding/coding.h | 2 +- src/meta/bnk_sony.c | 26 +++++++++++++------------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/coding/atrac9_decoder.c b/src/coding/atrac9_decoder.c index a5ef1846..16f11e46 100644 --- a/src/coding/atrac9_decoder.c +++ b/src/coding/atrac9_decoder.c @@ -207,6 +207,7 @@ fail: return 0; } +#if 0 //not needed (for now) int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_channels, size_t *out_frame_size) { static const int sample_rate_table[16] = { 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, @@ -237,5 +238,5 @@ int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_c fail: return 0; } - +#endif #endif diff --git a/src/coding/coding.h b/src/coding/coding.h index 11e62042..9614acb4 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -244,7 +244,7 @@ void reset_atrac9(VGMSTREAM *vgmstream); void seek_atrac9(VGMSTREAM *vgmstream, int32_t num_sample); void free_atrac9(atrac9_codec_data *data); size_t atrac9_bytes_to_samples(size_t bytes, atrac9_codec_data *data); -int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_channels, size_t *out_frame_size); +//int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_channels, size_t *out_frame_size); #endif #ifdef VGM_USE_CELT diff --git a/src/meta/bnk_sony.c b/src/meta/bnk_sony.c index 387a9bd5..f6c7a595 100644 --- a/src/meta/bnk_sony.c +++ b/src/meta/bnk_sony.c @@ -229,22 +229,22 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { extradata_size = 0x08 + read_32bit(start_offset+0x04,streamFile); /* 0x14 for AT9 */ switch(type) { -#ifdef VGM_USE_ATRAC9 - case 0x02: /* ATRAC9 mono? */ - case 0x05: /* ATRAC9 stereo? */ + case 0x02: /* ATRAC9 mono */ + case 0x05: /* ATRAC9 stereo */ if (read_32bit(start_offset+0x08,streamFile) + 0x08 != extradata_size) /* repeat? */ goto fail; + sample_rate = 48000; /* seems ok */ + channel_count = (type == 0x02) ? 1 : 2; + atrac9_info = (uint32_t)read_32bitBE(start_offset+0x0c,streamFile); /* 0x10: null? */ loop_length = read_32bit(start_offset+0x14,streamFile); loop_start = read_32bit(start_offset+0x18,streamFile); loop_end = loop_start + loop_length; /* loop_start is -1 if not set */ - /* get from AT9 config just in case, but probably: sr=48000 / codec 0x02=1ch, 0x05=2ch */ - atrac9_parse_config(atrac9_info, &sample_rate, &channel_count, NULL); codec = ATRAC9; break; -#endif + default: VGM_LOG("BNK: unknown type %x\n", type); goto fail; @@ -259,32 +259,32 @@ VGMSTREAM * init_vgmstream_bnk_sony(STREAMFILE *streamFile) { /* 0x0c: null? */ switch(type) { -#ifdef VGM_USE_ATRAC9 - case 0x02: /* ATRAC9 mono? */ - case 0x05: /* ATRAC9 stereo? */ + case 0x02: /* ATRAC9 mono */ + case 0x05: /* ATRAC9 stereo */ if (read_32bit(start_offset+0x10,streamFile) + 0x10 != extradata_size) /* repeat? */ goto fail; + sample_rate = 48000; /* seems ok */ + channel_count = (type == 0x02) ? 1 : 2; + atrac9_info = (uint32_t)read_32bitBE(start_offset+0x14,streamFile); /* 0x18: null? */ /* 0x1c: channels? */ /* 0x20: null? */ - interleave = 0x02; loop_length = read_32bit(start_offset+0x24,streamFile); loop_start = read_32bit(start_offset+0x28,streamFile); loop_end = loop_start + loop_length; /* loop_start is -1 if not set */ - /* get from AT9 config just in case, but probably: sr=48000 / codec 0x02=1ch, 0x05=2ch */ - atrac9_parse_config(atrac9_info, &sample_rate, &channel_count, NULL); codec = ATRAC9; break; -#endif + case 0x01: /* PCM16LE mono? (NekoBuro/Polara sfx) */ case 0x04: /* PCM16LE stereo? (NekoBuro/Polara sfx) */ sample_rate = 48000; /* seems ok */ /* 0x10: null? */ channel_count = read_32bit(start_offset+0x14,streamFile); interleave = 0x02; + loop_start = read_32bit(start_offset+0x18,streamFile); loop_length = read_32bit(start_offset+0x1c,streamFile); loop_end = loop_start + loop_length; /* loop_start is -1 if not set */ From 3130eebf0c52c4b75a46fa9e225fbaaa462619ed Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 20:46:54 +0200 Subject: [PATCH 38/55] Minor layout cleanup + doc --- src/layout/blocked.c | 41 +++++++++++++------------ src/layout/flat.c | 28 ++++++++++------- src/layout/interleave.c | 68 +++++++++++++++++++++++++---------------- src/layout/layered.c | 39 ++++++++++++----------- src/layout/segmented.c | 25 ++++++++------- src/vgmstream.h | 4 +-- 6 files changed, 119 insertions(+), 86 deletions(-) diff --git a/src/layout/blocked.c b/src/layout/blocked.c index 728969e0..3c436420 100644 --- a/src/layout/blocked.c +++ b/src/layout/blocked.c @@ -1,16 +1,20 @@ #include "layout.h" #include "../vgmstream.h" + static void block_update(VGMSTREAM * vgmstream); +/* Decodes samples for blocked streams. + * Data is divided into headered blocks with a bunch of data. The layout calls external helper functions + * when a block is decoded, and those must parse the new block and move offsets accordingly. */ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { - int samples_written=0; + int samples_written = 0; + int frame_size, samples_per_frame, samples_this_block; - int frame_size = get_vgmstream_frame_size(vgmstream); - int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); - int samples_this_block; + frame_size = get_vgmstream_frame_size(vgmstream); + samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); + samples_this_block = 0; - /* get samples in the current block */ if (vgmstream->current_block_samples) { samples_this_block = vgmstream->current_block_samples; } else if (frame_size == 0) { /* assume 4 bit */ //TODO: get_vgmstream_frame_size() really should return bits... */ @@ -19,12 +23,13 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame; } - /* decode all samples */ + while (samples_written < sample_count) { int samples_to_do; + if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { - /* on loop those values are changed */ + /* handle looping, readjust back to loop start values */ if (vgmstream->current_block_samples) { samples_this_block = vgmstream->current_block_samples; } else if (frame_size == 0) { /* assume 4 bit */ //TODO: get_vgmstream_frame_size() really should return bits... */ @@ -35,26 +40,26 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * continue; } - /* probably block bug or EOF, next calcs would give wrong values and buffer segfaults */ if (samples_this_block < 0) { + /* probably block bug or EOF, next calcs would give wrong values/segfaults/infinite loop */ VGM_LOG("layout_blocked: wrong block samples at 0x%lx\n", vgmstream->current_block_offset); memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample)); - break; /* probable infinite loop otherwise */ + break; } - /* probably block bug or EOF, block functions won't be able to read anything useful */ if (vgmstream->current_block_offset < 0 || vgmstream->current_block_offset == 0xFFFFFFFF) { + /* probably block bug or EOF, block functions won't be able to read anything useful/infinite loop */ VGM_LOG("layout_blocked: wrong block offset found\n"); memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample)); - break; /* probable infinite loop otherwise */ + break; } samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream); - if (samples_written + samples_to_do > sample_count) + if (samples_to_do > sample_count - samples_written) samples_to_do = sample_count - samples_written; - /* samples_this_block = 0 is allowed (empty block, do nothing then move to next block) */ if (samples_to_do > 0) { + /* samples_this_block = 0 is allowed (empty block, do nothing then move to next block) */ decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer); } @@ -64,15 +69,13 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * /* move to next block when all samples are consumed */ - if (vgmstream->samples_into_block==samples_this_block - /*&& vgmstream->current_sample < vgmstream->num_samples*/) { /* don't go past last block */ + if (vgmstream->samples_into_block == samples_this_block + /*&& vgmstream->current_sample < vgmstream->num_samples*/) { /* don't go past last block */ //todo block_update(vgmstream); - /* for VBR these may change */ + /* update since these may change each block */ frame_size = get_vgmstream_frame_size(vgmstream); samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); - - /* get samples in the current block */ if (vgmstream->current_block_samples) { samples_this_block = vgmstream->current_block_samples; } else if (frame_size == 0) { /* assume 4 bit */ //TODO: get_vgmstream_frame_size() really should return bits... */ @@ -87,7 +90,7 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * } } - +/* helper functions to parse new block */ static void block_update(VGMSTREAM * vgmstream) { switch (vgmstream->layout_type) { case layout_blocked_ast: diff --git a/src/layout/flat.c b/src/layout/flat.c index f38198aa..59f3ce03 100644 --- a/src/layout/flat.c +++ b/src/layout/flat.c @@ -1,33 +1,39 @@ #include "layout.h" #include "../vgmstream.h" + +/* Decodes samples for flat streams. + * Data forms a single stream, and the decoder may internally skip chunks and move offsets as needed. */ void render_vgmstream_flat(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { - int samples_written=0; + int samples_written = 0; + int samples_per_frame, samples_this_block; - const int samples_this_block = vgmstream->num_samples; - int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); + samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); + samples_this_block = vgmstream->num_samples; /* do all samples if possible */ - while (samples_writtenloop_flag && vgmstream_do_loop(vgmstream)) { + /* handle looping */ continue; } samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream); - - if (samples_written+samples_to_do > sample_count) - samples_to_do=sample_count-samples_written; + if (samples_to_do > sample_count - samples_written) + samples_to_do = sample_count - samples_written; - if (!samples_to_do) { - memset(buffer + samples_written * vgmstream->channels, 0, sizeof(sample) * vgmstream->channels * (sample_count - samples_written)); - return; + if (samples_to_do == 0) { + VGM_LOG("layout_flat: wrong samples_to_do found\n"); + memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample)); + break; } decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer); samples_written += samples_to_do; vgmstream->current_sample += samples_to_do; - vgmstream->samples_into_block+=samples_to_do; + vgmstream->samples_into_block += samples_to_do; } } diff --git a/src/layout/interleave.c b/src/layout/interleave.c index 6090d197..6eda0a92 100644 --- a/src/layout/interleave.c +++ b/src/layout/interleave.c @@ -1,29 +1,35 @@ #include "layout.h" #include "../vgmstream.h" + +/* Decodes samples for interleaved streams. + * Data has interleaved chunks per channel, and once one is decoded the layout moves offsets, + * skipping other chunks (essentially a simplified variety of blocked layout). + * Incompatible with decoders that move offsets. */ void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { - int samples_written=0; - - int frame_size = get_vgmstream_frame_size(vgmstream); - int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); - int samples_this_block; + int samples_written = 0; + int frame_size, samples_per_frame, samples_this_block; + int has_interleave_last = vgmstream->interleave_last_block_size && vgmstream->channels > 1; + frame_size = get_vgmstream_frame_size(vgmstream); + samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame; - if (vgmstream->interleave_last_block_size && vgmstream->channels > 1 && - vgmstream->current_sample - vgmstream->samples_into_block + samples_this_block> vgmstream->num_samples) { + if (has_interleave_last && + vgmstream->current_sample - vgmstream->samples_into_block + samples_this_block > vgmstream->num_samples) { + /* adjust values again if inside last interleave */ frame_size = get_vgmstream_shortframe_size(vgmstream); samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream); - samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame; } - while (samples_writtenloop_flag && vgmstream_do_loop(vgmstream)) { - /* we assume that the loop is not back into a short block */ - if (vgmstream->interleave_last_block_size && vgmstream->channels > 1) { + /* handle looping, restore standard interleave sizes */ + if (has_interleave_last) { /* assumes that won't loop back into a interleave_last */ frame_size = get_vgmstream_frame_size(vgmstream); samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame; @@ -32,33 +38,43 @@ void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREA } samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream); - /*printf("vgmstream_samples_to_do(samples_this_block=%d,samples_per_frame=%d,vgmstream) returns %d\n",samples_this_block,samples_per_frame,samples_to_do);*/ + if (samples_to_do > sample_count - samples_written) + samples_to_do = sample_count - samples_written; - if (samples_written+samples_to_do > sample_count) - samples_to_do=sample_count-samples_written; + //todo test if (samples to do == 0) decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer); samples_written += samples_to_do; vgmstream->current_sample += samples_to_do; - vgmstream->samples_into_block+=samples_to_do; + vgmstream->samples_into_block += samples_to_do; - if (vgmstream->samples_into_block==samples_this_block) { - int chan; - if (vgmstream->interleave_last_block_size && vgmstream->channels > 1 && - vgmstream->current_sample + samples_this_block > vgmstream->num_samples) { + + /* move to next interleaved block when all samples are consumed */ + if (vgmstream->samples_into_block == samples_this_block) { + int ch; + + if (has_interleave_last && + vgmstream->current_sample + samples_this_block > vgmstream->num_samples) { + /* adjust values again if inside last interleave */ frame_size = get_vgmstream_shortframe_size(vgmstream); samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream); - samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame; - for (chan=0;chanchannels;chan++) - vgmstream->ch[chan].offset+=vgmstream->interleave_block_size*(vgmstream->channels-chan)+vgmstream->interleave_last_block_size*chan; - } else { - for (chan=0;chanchannels;chan++) - vgmstream->ch[chan].offset+=vgmstream->interleave_block_size*vgmstream->channels; + for (ch = 0; ch < vgmstream->channels; ch++) { + off_t skip = vgmstream->interleave_block_size*(vgmstream->channels-ch) + + vgmstream->interleave_last_block_size*ch;; + vgmstream->ch[ch].offset += skip; + } } - vgmstream->samples_into_block=0; + else { + for (ch = 0; ch < vgmstream->channels; ch++) { + off_t skip = vgmstream->interleave_block_size*vgmstream->channels; + vgmstream->ch[ch].offset += skip; + } + } + + vgmstream->samples_into_block = 0; } } diff --git a/src/layout/layered.c b/src/layout/layered.c index 624aa670..2dcae87b 100644 --- a/src/layout/layered.c +++ b/src/layout/layered.c @@ -1,37 +1,41 @@ #include "layout.h" #include "../vgmstream.h" -/* TODO: there must be a reasonable way to respect the loop settings, as - the substreams are in their own little world. - Currently the VGMSTREAMs layers loop internally and the external/base VGMSTREAM - doesn't actually loop, and would ignore any altered values/loop_flag. */ +/* NOTE: if loop settings change the layered vgmstreams must be notified (preferably using vgmstream_force_loop) */ #define LAYER_BUF_SIZE 512 #define LAYER_MAX_CHANNELS 6 /* at least 2, but let's be generous */ - +/* Decodes samples for layered streams. + * Similar to interleave layout, but decodec samples are mixed from complete vgmstreams, each + * with custom codecs and different number of channels, creating a single super-vgmstream. + * Usually combined with custom streamfiles to handle data interleaved in weird ways. */ void render_vgmstream_layered(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { - sample interleave_buf[LAYER_BUF_SIZE*LAYER_MAX_CHANNELS]; - int32_t samples_done = 0; + int samples_written = 0; layered_layout_data *data = vgmstream->layout_data; + sample interleave_buf[LAYER_BUF_SIZE*LAYER_MAX_CHANNELS]; - while (samples_done < sample_count) { - int32_t samples_to_do = LAYER_BUF_SIZE; + + while (samples_written < sample_count) { + int samples_to_do = LAYER_BUF_SIZE; int layer, ch = 0; - if (samples_to_do > sample_count - samples_done) - samples_to_do = sample_count - samples_done; + if (samples_to_do > sample_count - samples_written) + samples_to_do = sample_count - samples_written; for (layer = 0; layer < data->layer_count; layer++) { - int s,l_ch; + int s, layer_ch; int layer_channels = data->layers[layer]->channels; + /* each layer will handle its own looping internally */ + render_vgmstream(interleave_buf, samples_to_do, data->layers[layer]); - for (l_ch = 0; l_ch < layer_channels; l_ch++) { + /* mix layer samples to main samples */ + for (layer_ch = 0; layer_ch < layer_channels; layer_ch++) { for (s = 0; s < samples_to_do; s++) { - size_t layer_sample = s*layer_channels + l_ch; - size_t buffer_sample = (samples_done+s)*vgmstream->channels + ch; + size_t layer_sample = s*layer_channels + layer_ch; + size_t buffer_sample = (samples_written+s)*vgmstream->channels + ch; buffer[buffer_sample] = interleave_buf[layer_sample]; } @@ -39,8 +43,9 @@ void render_vgmstream_layered(sample * buffer, int32_t sample_count, VGMSTREAM * } } - - samples_done += samples_to_do; + samples_written += samples_to_do; + vgmstream->current_sample = data->layers[0]->current_sample; /* just in case it's used for info */ + //vgmstream->samples_into_block = 0; /* handled in each layer */ } } diff --git a/src/layout/segmented.c b/src/layout/segmented.c index 4f2b7073..d6303325 100644 --- a/src/layout/segmented.c +++ b/src/layout/segmented.c @@ -2,35 +2,38 @@ #include "../vgmstream.h" +/* Decodes samples for segmented streams. + * Chains together sequential vgmstreams, for data divided into separate sections or files + * (like one part for intro and other for loop segments, which may even use different codecs). */ void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { - int samples_written=0; + int samples_written = 0; segmented_layout_data *data = vgmstream->layout_data; - //int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); - while (samples_writtensegments[data->current_segment]->num_samples; + if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { + /* handle looping, moving to loop segment */ //todo can only loop in a segment start // (for arbitrary values find loop segment from loop_start_sample, and skip N samples until loop start) data->current_segment = data->loop_segment; - reset_vgmstream(data->segments[data->current_segment]); - vgmstream->samples_into_block = 0; continue; } - samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream); - - if (samples_written+samples_to_do > sample_count) - samples_to_do=sample_count-samples_written; + /* decode samples */ + samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream); //todo should use a buffer + if (samples_to_do > sample_count - samples_written) + samples_to_do = sample_count - samples_written; + /* detect segment change and restart */ if (samples_to_do == 0) { data->current_segment++; reset_vgmstream(data->segments[data->current_segment]); - vgmstream->samples_into_block = 0; continue; } @@ -40,7 +43,7 @@ void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM samples_written += samples_to_do; vgmstream->current_sample += samples_to_do; - vgmstream->samples_into_block+=samples_to_do; + vgmstream->samples_into_block += samples_to_do; } } diff --git a/src/vgmstream.h b/src/vgmstream.h index 9a7fba31..2e5a0624 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -779,8 +779,8 @@ typedef struct { /* layout/block state */ size_t full_block_size; /* actual data size of an entire block (ie. may be fixed, include padding/headers, etc) */ - int32_t current_sample; /* number of samples we've passed */ - int32_t samples_into_block; /* number of samples into the current block */ + int32_t current_sample; /* number of samples we've passed (for loop detection) */ + int32_t samples_into_block; /* number of samples into the current block/interleave/segment/etc */ off_t current_block_offset; /* start of this block (offset of block header) */ size_t current_block_size; /* size in usable bytes of the block we're in now (used to calculate num_samples per block) */ size_t current_block_samples; /* size in samples of the block we're in now (used over current_block_size if possible) */ From c9dc0917ffeea678b6193949516fc1f88efd41e2 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Aug 2018 21:15:10 +0200 Subject: [PATCH 39/55] Fix interleave layout hanging when no interleave size set --- src/layout/interleave.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/layout/interleave.c b/src/layout/interleave.c index 6eda0a92..9e64fdfd 100644 --- a/src/layout/interleave.c +++ b/src/layout/interleave.c @@ -23,6 +23,10 @@ void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREA samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame; } + /* mono interleaved stream with no layout set, just behave like flat layout */ + if (samples_this_block == 0 && vgmstream->channels == 1) + samples_this_block = vgmstream->num_samples; + while (samples_written < sample_count) { int samples_to_do; @@ -33,6 +37,8 @@ void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREA frame_size = get_vgmstream_frame_size(vgmstream); samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame; + if (samples_this_block == 0 && vgmstream->channels == 1) + samples_this_block = vgmstream->num_samples; } continue; } @@ -41,7 +47,11 @@ void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREA if (samples_to_do > sample_count - samples_written) samples_to_do = sample_count - samples_written; - //todo test if (samples to do == 0) + if (samples_to_do == 0) { /* happens when interleave is not set */ + VGM_LOG("layout_interleave: wrong samples_to_do found\n"); + memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample)); + break; + } decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer); @@ -60,6 +70,8 @@ void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREA frame_size = get_vgmstream_shortframe_size(vgmstream); samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream); samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame; + if (samples_this_block == 0 && vgmstream->channels == 1) + samples_this_block = vgmstream->num_samples; for (ch = 0; ch < vgmstream->channels; ch++) { off_t skip = vgmstream->interleave_block_size*(vgmstream->channels-ch) + From ee03726bbce1e1d07337a1c40856534d6325b859 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 00:59:31 +0200 Subject: [PATCH 40/55] Find loop_segment automatically in segmented_layout + remove from metas --- src/layout/segmented.c | 25 +++++++++++++++++++++---- src/meta/aax.c | 4 +--- src/meta/ea_eaac.c | 2 -- src/meta/mus_acm.c | 2 -- src/meta/opus_ppp.c | 2 -- src/meta/txtp.c | 3 --- src/meta/wave_segmented.c | 3 --- src/vgmstream.h | 1 - 8 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/layout/segmented.c b/src/layout/segmented.c index d6303325..2176923b 100644 --- a/src/layout/segmented.c +++ b/src/layout/segmented.c @@ -16,10 +16,27 @@ void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { - /* handle looping, moving to loop segment */ - //todo can only loop in a segment start - // (for arbitrary values find loop segment from loop_start_sample, and skip N samples until loop start) - data->current_segment = data->loop_segment; + /* handle looping, finding loop segment */ + int loop_segment = 0, samples = 0, loop_samples_skip = 0; + while (samples < vgmstream->num_samples) { + int32_t segment_samples = data->segments[loop_segment]->num_samples; + if (vgmstream->loop_start_sample >= samples && vgmstream->loop_start_sample < samples + segment_samples) { + loop_samples_skip = vgmstream->loop_start_sample - samples; + break; /* loop_start falls within loop_segment's samples */ + } + samples += segment_samples; + loop_segment++; + } + if (loop_segment == data->segment_count) { + VGM_LOG("segmented_layout: can't find loop segment\n"); + loop_segment = 0; + } + if (loop_samples_skip > 0) { + VGM_LOG("segmented_layout: loop starts after %i samples\n", loop_samples_skip); + //todo skip/fix, but probably won't happen + } + + data->current_segment = loop_segment; reset_vgmstream(data->segments[data->current_segment]); vgmstream->samples_into_block = 0; continue; diff --git a/src/meta/aax.c b/src/meta/aax.c index 15df8ede..1ad4dbaa 100644 --- a/src/meta/aax.c +++ b/src/meta/aax.c @@ -15,7 +15,7 @@ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) { int loop_flag = 0, channel_count = 0; int32_t sample_count, loop_start_sample = 0, loop_end_sample = 0; - int segment_count, loop_segment = 0; + int segment_count; segmented_layout_data *data = NULL; int table_error = 0; @@ -102,7 +102,6 @@ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) { if (!loop_flag && segment_loop_flag) { loop_start_sample = sample_count; - loop_segment = i; } sample_count += data->segments[i]->num_samples; @@ -130,7 +129,6 @@ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) { vgmstream->layout_type = layout_segmented; vgmstream->layout_data = data; - data->loop_segment = loop_segment; return vgmstream; diff --git a/src/meta/ea_eaac.c b/src/meta/ea_eaac.c index 7875c302..34f2a998 100644 --- a/src/meta/ea_eaac.c +++ b/src/meta/ea_eaac.c @@ -755,8 +755,6 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *st /* setup segmented VGMSTREAMs */ if (!setup_layout_segmented(data)) goto fail; - data->loop_segment = 1; - return data; fail: diff --git a/src/meta/mus_acm.c b/src/meta/mus_acm.c index 56b9e69c..fb87869d 100644 --- a/src/meta/mus_acm.c +++ b/src/meta/mus_acm.c @@ -95,9 +95,7 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) { vgmstream->meta_type = meta_MUS_ACM; vgmstream->coding_type = data->segments[0]->coding_type; vgmstream->layout_type = layout_segmented; - vgmstream->layout_data = data; - data->loop_segment = loop_start_index; clean_mus(mus_filenames, segment_count); return vgmstream; diff --git a/src/meta/opus_ppp.c b/src/meta/opus_ppp.c index 6c69b05b..87906b9f 100644 --- a/src/meta/opus_ppp.c +++ b/src/meta/opus_ppp.c @@ -84,9 +84,7 @@ VGMSTREAM * init_vgmstream_opus_ppp(STREAMFILE *streamFile) { vgmstream->meta_type = meta_OPUS_PPP; vgmstream->coding_type = data->segments[0]->coding_type; vgmstream->layout_type = layout_segmented; - vgmstream->layout_data = data; - data->loop_segment = loop_start_segment; return vgmstream; diff --git a/src/meta/txtp.c b/src/meta/txtp.c index a735f375..2c5474bd 100644 --- a/src/meta/txtp.c +++ b/src/meta/txtp.c @@ -180,10 +180,7 @@ VGMSTREAM * init_vgmstream_txtp(STREAMFILE *streamFile) { vgmstream->meta_type = meta_TXTP; vgmstream->coding_type = data_s->segments[0]->coding_type; vgmstream->layout_type = layout_segmented; - vgmstream->layout_data = data_s; - if (loop_flag) - data_s->loop_segment = txtp->loop_start_segment-1; } diff --git a/src/meta/wave_segmented.c b/src/meta/wave_segmented.c index ddb947bd..263b069b 100644 --- a/src/meta/wave_segmented.c +++ b/src/meta/wave_segmented.c @@ -207,10 +207,7 @@ VGMSTREAM * init_vgmstream_wave_segmented(STREAMFILE *streamFile) { /* .wave can mix codecs, usually first segment is a small ADPCM section) */ vgmstream->coding_type = (segment_count == 1 ? data->segments[0]->coding_type : data->segments[1]->coding_type); vgmstream->layout_type = layout_segmented; - vgmstream->layout_data = data; - if (loop_flag) - data->loop_segment = (loop_start_segment); return vgmstream; diff --git a/src/vgmstream.h b/src/vgmstream.h index 2e5a0624..83661b73 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -1057,7 +1057,6 @@ typedef struct { int segment_count; VGMSTREAM **segments; int current_segment; - int loop_segment; } segmented_layout_data; /* for files made of "horizontal" layers, one per group of channels (using a complete sub-VGMSTREAM) */ From 88f50985de21514fb896862357e50fab0d03abc7 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 01:05:07 +0200 Subject: [PATCH 41/55] Optimize segmented layout decode samples --- src/layout/segmented.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/layout/segmented.c b/src/layout/segmented.c index 2176923b..ff87c68e 100644 --- a/src/layout/segmented.c +++ b/src/layout/segmented.c @@ -42,8 +42,7 @@ void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM continue; } - /* decode samples */ - samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream); //todo should use a buffer + samples_to_do = vgmstream_samples_to_do(samples_this_block, sample_count, vgmstream); if (samples_to_do > sample_count - samples_written) samples_to_do = sample_count - samples_written; From b02eeeff049d991764b0c32b28b123f6fe1b6df4 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 02:26:38 +0200 Subject: [PATCH 42/55] Fix some .SFL looping and SLI cleanup [Hanachirasu (PC)] --- src/meta/meta.h | 6 +- src/meta/sfl.c | 302 +++++++++++++++++++++++++----------------------- src/meta/sli.c | 184 +++++++++++++---------------- src/vgmstream.c | 4 +- 4 files changed, 243 insertions(+), 253 deletions(-) diff --git a/src/meta/meta.h b/src/meta/meta.h index 94938e20..19c2376c 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -109,8 +109,6 @@ typedef struct { } ogg_vorbis_meta_info_t; VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callbacks *callbacks, off_t other_header_bytes, const ogg_vorbis_meta_info_t *ovmi); - -VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE * streamFile); #endif VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile); @@ -129,7 +127,9 @@ VGMSTREAM * init_vgmstream_mp4_aac_offset(STREAMFILE *streamFile, uint64_t start VGMSTREAM * init_vgmstream_akb_mp4(STREAMFILE *streamFile); #endif -VGMSTREAM * init_vgmstream_sfl(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE * streamFile); + +VGMSTREAM * init_vgmstream_sfl_ogg(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_sadb(STREAMFILE *streamFile); diff --git a/src/meta/sfl.c b/src/meta/sfl.c index c656142b..51c64092 100644 --- a/src/meta/sfl.c +++ b/src/meta/sfl.c @@ -1,12 +1,118 @@ -#include "../vgmstream.h" +#include "meta.h" + +static void parse_adtl(off_t adtl_offset, off_t adtl_length, STREAMFILE *streamFile, long *loop_start, long *loop_end, int *loop_flag); + + +/* .sfl - odd RIFF-formatted files that go along with .ogg [Hanachirasu (PC), Touhou 10.5 (PC)] */ +VGMSTREAM * init_vgmstream_sfl_ogg(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + STREAMFILE * streamData = NULL; + int loop_flag = 0; + long loop_start_ms = -1; + long loop_end_ms = -1; + + + /* checks */ + if (!check_extensions(streamFile, "sfl")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x52494646) /* "RIFF" */ + goto fail; + if (read_32bitBE(0x08,streamFile) != 0x5346504C) /* "SFPL" */ + goto fail; + + { + /* try with file.ogg.sfl=header and file.ogg=data [Hanachirasu (PC)] */ + char basename[PATH_LIMIT]; + get_streamfile_basename(streamFile,basename,PATH_LIMIT); + streamData = open_streamfile_by_filename(streamFile, basename); + if (!streamData) { + /* try again with file.sfl=header + file.ogg=daba */ + streamData = open_streamfile_by_ext(streamFile,"ogg"); + if (!streamData) goto fail; + } + else { + if (!check_extensions(streamData, "ogg")) + goto fail; + } + } #ifdef VGM_USE_VORBIS + /* let the real initer do the parsing */ + vgmstream = init_vgmstream_ogg_vorbis(streamData); + if (!vgmstream) goto fail; + vgmstream->meta_type = meta_OGG_SFL; +#else + goto fail; +#endif -#include "meta.h" -#include "../layout/layout.h" -#include "../util.h" + /* read through chunks to verify format and find metadata */ + { + size_t riff_size, file_size; + off_t current_chunk = 0x0c; /* start with first chunk */ -/* .sfl, odd RIFF-formatted files that go along with oggs */ + riff_size = read_32bitLE(0x04,streamFile); + file_size = get_streamfile_size(streamFile); + if (file_size < riff_size+0x08) + goto fail; + + while (current_chunk < file_size) { + uint32_t chunk_type = read_32bitBE(current_chunk+0x00,streamFile); + off_t chunk_size = read_32bitLE(current_chunk+0x04,streamFile); + + /* There seem to be a few bytes left over, included in the + * RIFF but not enough to make a new chunk. */ + if (current_chunk+0x08 > file_size) break; + + if (current_chunk+0x08+chunk_size > file_size) + goto fail; + + switch(chunk_type) { + case 0x4C495354: /* "LIST" */ + switch (read_32bitBE(current_chunk+0x08, streamFile)) { + case 0x6164746C: /* "adtl" */ + /* yay, atdl is its own little world */ + parse_adtl(current_chunk + 0x08, chunk_size, streamFile, + &loop_start_ms,&loop_end_ms,&loop_flag); + break; + default: + break; + } + break; + default: + break; + } + current_chunk += 0x08+chunk_size; + } + } + + /* install loops */ + if (loop_flag) { + int loop_start = (long long)loop_start_ms * vgmstream->sample_rate / 1000; + int loop_end = (long long)loop_end_ms * vgmstream->sample_rate / 1000; + vgmstream_force_loop(vgmstream,loop_flag,loop_start, loop_end); + } + /* sfl .ogg often has song endings (use the base .ogg for those) */ + + close_streamfile(streamData); + return vgmstream; + +fail: + close_streamfile(streamData); + close_vgmstream(vgmstream); + return NULL; +} + +/* return milliseconds */ +static long parse_adtl_marker(unsigned char * marker) { + long hh,mm,ss,ms; + + if (memcmp("Marker ",marker,7)) return -1; + + if (4 != sscanf((char*)marker+7,"%ld:%ld:%ld.%ld",&hh,&mm,&ss,&ms)) + return -1; + + return ((hh*60+mm)*60+ss)*1000+ms; +} /* return milliseconds */ static int parse_region(unsigned char * region, long *start, long *end) { @@ -22,161 +128,67 @@ static int parse_region(unsigned char * region, long *start, long *end) { *start = ((start_hh*60+start_mm)*60+start_ss)*1000+start_ms; *end = ((end_hh*60+end_mm)*60+end_ss)*1000+end_ms; - return 0; } /* loop points have been found hiding here */ -static void parse_adtl(off_t adtl_offset, off_t adtl_length, STREAMFILE *streamFile, - long *loop_start, long *loop_end, int *loop_flag) { - int loop_found = 0; +static void parse_adtl(off_t adtl_offset, off_t adtl_length, STREAMFILE *streamFile, long *loop_start, long *loop_end, int *loop_flag) { + int loop_start_found = 0; + int loop_end_found = 0; + off_t current_chunk = adtl_offset+0x04; - off_t current_chunk = adtl_offset+4; + while (current_chunk < adtl_offset + adtl_length) { + uint32_t chunk_type = read_32bitBE(current_chunk+0x00,streamFile); + off_t chunk_size = read_32bitLE(current_chunk+0x04,streamFile); - while (current_chunk < adtl_offset+adtl_length) { - uint32_t chunk_type = read_32bitBE(current_chunk,streamFile); - off_t chunk_size = read_32bitLE(current_chunk+4,streamFile); - - if (current_chunk+8+chunk_size > adtl_offset+adtl_length) return; + if (current_chunk+0x08+chunk_size > adtl_offset+adtl_length) + return; switch(chunk_type) { - case 0x6c61626c: /* labl */ - { - unsigned char *labelcontent; - labelcontent = malloc(chunk_size-4); - if (!labelcontent) return; - if (read_streamfile(labelcontent,current_chunk+0xc, - chunk_size-4,streamFile)!=chunk_size-4) { - free(labelcontent); - return; - } - - if (!loop_found && - parse_region(labelcontent,loop_start,loop_end)>=0) - { - loop_found = 1; - } - + case 0x6c61626c: { /* "labl" */ + unsigned char *labelcontent = malloc(chunk_size-0x04); + if (!labelcontent) return; + if (read_streamfile(labelcontent,current_chunk+0x0c, chunk_size-0x04,streamFile) != chunk_size-0x04) { free(labelcontent); + return; } + + switch (read_32bitLE(current_chunk+8,streamFile)) { + case 1: + if (!loop_start_found && (*loop_start = parse_adtl_marker(labelcontent)) >= 0) + loop_start_found = 1; + + if (!loop_start_found && !loop_end_found && parse_region(labelcontent,loop_start,loop_end) >= 0) { + loop_start_found = 1; + loop_end_found = 1; + } + + break; + case 2: + if (!loop_end_found && (*loop_end = parse_adtl_marker(labelcontent)) >= 0) + loop_end_found = 1; + break; + default: + break; + } + + free(labelcontent); break; + } default: break; } - current_chunk += 8 + chunk_size; + current_chunk += 0x08 + chunk_size; } - if (loop_found) *loop_flag = 1; + if (loop_start_found && loop_end_found) + *loop_flag = 1; + + /* labels don't seem to be consistently ordered */ + if (*loop_start > *loop_end) { + long temp = *loop_start; + *loop_start = *loop_end; + *loop_end = temp; + } } - -VGMSTREAM * init_vgmstream_sfl(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - STREAMFILE * streamFileOGG = NULL; - char filenameOGG[PATH_LIMIT]; - char filename[PATH_LIMIT]; - - off_t file_size = -1; - - int loop_flag = 0; - long loop_start_ms = -1; - long loop_end_ms = -1; - uint32_t riff_size; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("sfl",filename_extension(filename))) goto fail; - - /* check header */ - if ((uint32_t)read_32bitBE(0,streamFile)!=0x52494646) /* "RIFF" */ - goto fail; - /* check for SFPL form */ - if ((uint32_t)read_32bitBE(8,streamFile)!=0x5346504C) /* "SFPL" */ - goto fail; - - /* check for .OGG file */ - strcpy(filenameOGG,filename); - strcpy(filenameOGG+strlen(filenameOGG)-3,"ogg"); - - streamFileOGG = streamFile->open(streamFile,filenameOGG,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!streamFileOGG) { - goto fail; - } - - /* let the real initer do the parsing */ - vgmstream = init_vgmstream_ogg_vorbis(streamFileOGG); - if (!vgmstream) goto fail; - - close_streamfile(streamFileOGG); - streamFileOGG = NULL; - - /* now that we have an ogg, proceed with parsing the .sfl */ - riff_size = read_32bitLE(4,streamFile); - file_size = get_streamfile_size(streamFile); - - /* check for tructated RIFF */ - if (file_size < riff_size+8) goto fail; - - /* read through chunks to verify format and find metadata */ - { - off_t current_chunk = 0xc; /* start with first chunk */ - - while (current_chunk < file_size) { - uint32_t chunk_type = read_32bitBE(current_chunk,streamFile); - off_t chunk_size = read_32bitLE(current_chunk+4,streamFile); - - /* There seem to be a few bytes left over, included in the - * RIFF but not enough to make a new chunk. - */ - if (current_chunk+8 > file_size) break; - - if (current_chunk+8+chunk_size > file_size) goto fail; - - switch(chunk_type) { - case 0x4C495354: /* LIST */ - /* what lurks within?? */ - switch (read_32bitBE(current_chunk + 8, streamFile)) { - case 0x6164746C: /* adtl */ - /* yay, atdl is its own little world */ - parse_adtl(current_chunk + 8, chunk_size, - streamFile, - &loop_start_ms,&loop_end_ms,&loop_flag); - break; - default: - break; - } - break; - default: - /* ignorance is bliss */ - break; - } - - current_chunk += 8+chunk_size; - } - } - - if (loop_flag) { - /* install loops */ - if (!vgmstream->loop_flag) { - vgmstream->loop_flag = 1; - vgmstream->loop_ch = calloc(vgmstream->channels, - sizeof(VGMSTREAMCHANNEL)); - if (!vgmstream->loop_ch) goto fail; - } - - vgmstream->loop_start_sample = (long long)loop_start_ms*vgmstream->sample_rate/1000; - vgmstream->loop_end_sample = (long long)loop_end_ms*vgmstream->sample_rate/1000; - } - - vgmstream->meta_type = meta_OGG_SFL; - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (streamFileOGG) close_streamfile(streamFileOGG); - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - -#endif diff --git a/src/meta/sli.c b/src/meta/sli.c index a2852667..f4ed5024 100644 --- a/src/meta/sli.c +++ b/src/meta/sli.c @@ -1,121 +1,99 @@ -#include "../vgmstream.h" +#include "meta.h" +#include + + +/* .sli - loop points associated with a similarly named .ogg [Fate/Stay Night (PC), World End Economica (PC)]*/ +VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + STREAMFILE * streamData = NULL; + int32_t loop_start = -1, loop_length = -1; + int32_t loop_from = -1, loop_to = -1; + + /* checks */ + if (!check_extensions(streamFile, "sli")) + goto fail; + + { + /* try with file.ogg.sli=header and file.ogg=data */ + char basename[PATH_LIMIT]; + get_streamfile_basename(streamFile,basename,PATH_LIMIT); + streamData = open_streamfile_by_filename(streamFile, basename); + if (!streamData) goto fail; + + if (!check_extensions(streamData, "ogg")) + goto fail; + } #ifdef VGM_USE_VORBIS - -#include -#include "meta.h" -#include "../util.h" - -#ifdef WIN32 -#define DIRSEP '\\' + /* let the real initer do the parsing */ + vgmstream = init_vgmstream_ogg_vorbis(streamData); + if (!vgmstream) goto fail; #else -#define DIRSEP '/' + goto fail; #endif -/* .sli is a file with loop points, associated with a similarly named .ogg */ + /* find loop text */ + { + char linebuffer[PATH_LIMIT]; + size_t bytes_read; + off_t sli_offset; + int done; -VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE *streamFile) { - - VGMSTREAM * vgmstream = NULL; - STREAMFILE * streamFileOGG = NULL; - char filename[PATH_LIMIT]; - char filenameOGG[PATH_LIMIT]; - char linebuffer[PATH_LIMIT]; - off_t bytes_read; - off_t sli_offset; - int done; - int32_t loop_start = -1; - int32_t loop_length = -1; - int32_t loop_from = -1; - int32_t loop_to = -1; + sli_offset = 0; + while ((loop_start == -1 || loop_length == -1) && sli_offset < get_streamfile_size(streamFile)) { + char *endptr, *foundptr; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("sli",filename_extension(filename))) goto fail; + bytes_read = get_streamfile_text_line(sizeof(linebuffer),linebuffer,sli_offset,streamFile,&done); + if (!done) goto fail; - /* check for .OGG file */ - strcpy(filenameOGG,filename); - /* strip off .sli */ - filenameOGG[strlen(filenameOGG)-4]='\0'; + if (memcmp("LoopStart=",linebuffer,10)==0 && linebuffer[10] != '\0') { + loop_start = strtol(linebuffer+10,&endptr,10); + if (*endptr != '\0') { + loop_start = -1; /* if it didn't parse cleanly */ + } + } + else if (memcmp("LoopLength=",linebuffer,11)==0 && linebuffer[11] != '\0') { + loop_length = strtol(linebuffer+11,&endptr,10); + if (*endptr != '\0') { + loop_length = -1; /* if it didn't parse cleanly */ + } + } - streamFileOGG = streamFile->open(streamFile,filenameOGG,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!streamFileOGG) { - goto fail; + /* a completely different format (2.0?), also with .sli extension and can be handled similarly */ + if ((foundptr = strstr(linebuffer,"To=")) != NULL && isdigit(foundptr[3])) { + loop_to = strtol(foundptr+3,&endptr,10); + if (*endptr != ';') { + loop_to = -1; + } + } + if ((foundptr = strstr(linebuffer,"From=")) != NULL && isdigit(foundptr[5])) { + loop_from = strtol(foundptr+5,&endptr,10); + if (*endptr != ';') { + loop_from = -1; + } + } + + sli_offset += bytes_read; + } } - /* let the real initer do the parsing */ - vgmstream = init_vgmstream_ogg_vorbis(streamFileOGG); - if (!vgmstream) goto fail; - - close_streamfile(streamFileOGG); - streamFileOGG = NULL; - - sli_offset = 0; - while ((loop_start == -1 || loop_length == -1) && sli_offset < get_streamfile_size(streamFile)) { - char *endptr; - char *foundptr; - bytes_read=get_streamfile_text_line(sizeof(linebuffer),linebuffer,sli_offset,streamFile,&done); - if (!done) goto fail; - - if (!memcmp("LoopStart=",linebuffer,10) && linebuffer[10]!='\0') { - loop_start = strtol(linebuffer+10,&endptr,10); - if (*endptr != '\0') { - /* if it didn't parse cleanly */ - loop_start = -1; - } - } - else if (!memcmp("LoopLength=",linebuffer,11) && linebuffer[11]!='\0') { - loop_length = strtol(linebuffer+11,&endptr,10); - if (*endptr != '\0') { - /* if it didn't parse cleanly */ - loop_length = -1; - } - } - - /* a completely different format, also with .sli extension and can be handled similarly */ - if ((foundptr=strstr(linebuffer,"To="))!=NULL && isdigit(foundptr[3])) { - loop_to = strtol(foundptr+3,&endptr,10); - if (*endptr != ';') { - loop_to = -1; - } - } - if ((foundptr=strstr(linebuffer,"From="))!=NULL && isdigit(foundptr[5])) { - loop_from = strtol(foundptr+5,&endptr,10); - if (*endptr != ';') { - loop_from = -1; - } - } - - sli_offset += bytes_read; + if (loop_start != -1 && loop_length != -1) { + vgmstream_force_loop(vgmstream,1,loop_start, loop_start+loop_length); + vgmstream->meta_type = meta_OGG_SLI; + } + else if (loop_from != -1 && loop_to != -1) { + vgmstream_force_loop(vgmstream,1,loop_to, loop_from); + vgmstream->meta_type = meta_OGG_SLI2; + } + else { + goto fail; /* if there's no loop points the .sli wasn't valid */ } - if ((loop_start != -1 && loop_length != -1) || - (loop_to != -1 && loop_from != -1)) { - /* install loops */ - if (!vgmstream->loop_flag) { - vgmstream->loop_flag = 1; - vgmstream->loop_ch = calloc(vgmstream->channels, - sizeof(VGMSTREAMCHANNEL)); - if (!vgmstream->loop_ch) goto fail; - } - - if (loop_to != -1 && loop_from != -1) { - vgmstream->loop_start_sample = loop_to; - vgmstream->loop_end_sample = loop_from; - vgmstream->meta_type = meta_OGG_SLI2; - } else { - vgmstream->loop_start_sample = loop_start; - vgmstream->loop_end_sample = loop_start+loop_length; - vgmstream->meta_type = meta_OGG_SLI; - } - } else goto fail; /* if there's no loop points the .sli wasn't valid */ - + close_streamfile(streamData); return vgmstream; - /* clean up anything we may have opened */ fail: - if (streamFileOGG) close_streamfile(streamFileOGG); - if (vgmstream) close_vgmstream(vgmstream); + close_streamfile(streamData); + close_vgmstream(vgmstream); return NULL; } -#endif diff --git a/src/vgmstream.c b/src/vgmstream.c index 523e1baf..6a9ce018 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -60,9 +60,9 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_genh, #ifdef VGM_USE_VORBIS init_vgmstream_ogg_vorbis, - init_vgmstream_sli_ogg, - init_vgmstream_sfl, #endif + init_vgmstream_sli_ogg, + init_vgmstream_sfl_ogg, #if 0 init_vgmstream_mp4_aac, #endif From 92f35029bb9039ceed8616bb62b5ca7642e71a7d Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 13:46:07 +0200 Subject: [PATCH 43/55] Make generic block_update and auto-call in vgmstream_open_stream --- src/layout/blocked.c | 84 +++++++++++++++++++++----------------------- src/layout/layout.h | 1 + src/vgmstream.c | 3 ++ 3 files changed, 45 insertions(+), 43 deletions(-) diff --git a/src/layout/blocked.c b/src/layout/blocked.c index 3c436420..186275a1 100644 --- a/src/layout/blocked.c +++ b/src/layout/blocked.c @@ -2,8 +2,6 @@ #include "../vgmstream.h" -static void block_update(VGMSTREAM * vgmstream); - /* Decodes samples for blocked streams. * Data is divided into headered blocks with a bunch of data. The layout calls external helper functions * when a block is decoded, and those must parse the new block and move offsets accordingly. */ @@ -71,7 +69,7 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * /* move to next block when all samples are consumed */ if (vgmstream->samples_into_block == samples_this_block /*&& vgmstream->current_sample < vgmstream->num_samples*/) { /* don't go past last block */ //todo - block_update(vgmstream); + block_update(vgmstream->next_block_offset,vgmstream); /* update since these may change each block */ frame_size = get_vgmstream_frame_size(vgmstream); @@ -91,123 +89,123 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * } /* helper functions to parse new block */ -static void block_update(VGMSTREAM * vgmstream) { +void block_update(off_t block_offset, VGMSTREAM * vgmstream) { switch (vgmstream->layout_type) { case layout_blocked_ast: - block_update_ast(vgmstream->next_block_offset,vgmstream); + block_update_ast(block_offset,vgmstream); break; case layout_blocked_mxch: - block_update_mxch(vgmstream->next_block_offset,vgmstream); + block_update_mxch(block_offset,vgmstream); break; case layout_blocked_halpst: - block_update_halpst(vgmstream->next_block_offset,vgmstream); + block_update_halpst(block_offset,vgmstream); break; case layout_blocked_xa: - block_update_xa(vgmstream->next_block_offset,vgmstream); + block_update_xa(block_offset,vgmstream); break; case layout_blocked_ea_schl: - block_update_ea_schl(vgmstream->next_block_offset,vgmstream); + block_update_ea_schl(block_offset,vgmstream); break; case layout_blocked_ea_1snh: - block_update_ea_1snh(vgmstream->next_block_offset,vgmstream); + block_update_ea_1snh(block_offset,vgmstream); break; case layout_blocked_caf: - block_update_caf(vgmstream->next_block_offset,vgmstream); + block_update_caf(block_offset,vgmstream); break; case layout_blocked_wsi: - block_update_wsi(vgmstream->next_block_offset,vgmstream); + block_update_wsi(block_offset,vgmstream); break; case layout_blocked_str_snds: - block_update_str_snds(vgmstream->next_block_offset,vgmstream); + block_update_str_snds(block_offset,vgmstream); break; case layout_blocked_ws_aud: - block_update_ws_aud(vgmstream->next_block_offset,vgmstream); + block_update_ws_aud(block_offset,vgmstream); break; case layout_blocked_matx: - block_update_matx(vgmstream->next_block_offset,vgmstream); + block_update_matx(block_offset,vgmstream); break; case layout_blocked_dec: - block_update_dec(vgmstream->next_block_offset,vgmstream); + block_update_dec(block_offset,vgmstream); break; case layout_blocked_emff_ps2: - block_update_emff_ps2(vgmstream->next_block_offset,vgmstream); + block_update_emff_ps2(block_offset,vgmstream); break; case layout_blocked_emff_ngc: - block_update_emff_ngc(vgmstream->next_block_offset,vgmstream); + block_update_emff_ngc(block_offset,vgmstream); break; case layout_blocked_gsb: - block_update_gsb(vgmstream->next_block_offset,vgmstream); + block_update_gsb(block_offset,vgmstream); break; case layout_blocked_vs: - block_update_vs(vgmstream->next_block_offset,vgmstream); + block_update_vs(block_offset,vgmstream); break; case layout_blocked_xvas: - block_update_xvas(vgmstream->next_block_offset,vgmstream); + block_update_xvas(block_offset,vgmstream); break; case layout_blocked_thp: - block_update_thp(vgmstream->next_block_offset,vgmstream); + block_update_thp(block_offset,vgmstream); break; case layout_blocked_filp: - block_update_filp(vgmstream->next_block_offset,vgmstream); + block_update_filp(block_offset,vgmstream); break; case layout_blocked_ivaud: - block_update_ivaud(vgmstream->next_block_offset,vgmstream); + block_update_ivaud(block_offset,vgmstream); break; case layout_blocked_ea_swvr: - block_update_ea_swvr(vgmstream->next_block_offset,vgmstream); + block_update_ea_swvr(block_offset,vgmstream); break; case layout_blocked_adm: - block_update_adm(vgmstream->next_block_offset,vgmstream); + block_update_adm(block_offset,vgmstream); break; case layout_blocked_bdsp: - block_update_bdsp(vgmstream->next_block_offset,vgmstream); + block_update_bdsp(block_offset,vgmstream); break; case layout_blocked_tra: - block_update_tra(vgmstream->next_block_offset,vgmstream); + block_update_tra(block_offset,vgmstream); break; case layout_blocked_ps2_iab: - block_update_ps2_iab(vgmstream->next_block_offset,vgmstream); + block_update_ps2_iab(block_offset,vgmstream); break; case layout_blocked_ps2_strlr: - block_update_ps2_strlr(vgmstream->next_block_offset,vgmstream); + block_update_ps2_strlr(block_offset,vgmstream); break; case layout_blocked_rws: - block_update_rws(vgmstream->next_block_offset,vgmstream); + block_update_rws(block_offset,vgmstream); break; case layout_blocked_hwas: - block_update_hwas(vgmstream->next_block_offset,vgmstream); + block_update_hwas(block_offset,vgmstream); break; case layout_blocked_ea_sns: - block_update_ea_sns(vgmstream->next_block_offset,vgmstream); + block_update_ea_sns(block_offset,vgmstream); break; case layout_blocked_awc: - block_update_awc(vgmstream->next_block_offset,vgmstream); + block_update_awc(block_offset,vgmstream); break; case layout_blocked_vgs: - block_update_vgs(vgmstream->next_block_offset,vgmstream); + block_update_vgs(block_offset,vgmstream); break; case layout_blocked_vawx: - block_update_vawx(vgmstream->next_block_offset,vgmstream); + block_update_vawx(block_offset,vgmstream); break; case layout_blocked_xvag_subsong: - block_update_xvag_subsong(vgmstream->next_block_offset,vgmstream); + block_update_xvag_subsong(block_offset,vgmstream); break; case layout_blocked_ea_wve_au00: - block_update_ea_wve_au00(vgmstream->next_block_offset,vgmstream); + block_update_ea_wve_au00(block_offset,vgmstream); break; case layout_blocked_ea_wve_ad10: - block_update_ea_wve_ad10(vgmstream->next_block_offset,vgmstream); + block_update_ea_wve_ad10(block_offset,vgmstream); break; case layout_blocked_sthd: - block_update_sthd(vgmstream->next_block_offset,vgmstream); + block_update_sthd(block_offset,vgmstream); break; case layout_blocked_h4m: - block_update_h4m(vgmstream->next_block_offset,vgmstream); + block_update_h4m(block_offset,vgmstream); break; case layout_blocked_xa_aiff: - block_update_xa_aiff(vgmstream->next_block_offset,vgmstream); + block_update_xa_aiff(block_offset,vgmstream); break; - default: + default: /* not a blocked layout */ break; } } diff --git a/src/layout/layout.h b/src/layout/layout.h index b3597320..f547d677 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -6,6 +6,7 @@ /* blocked layouts */ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); +void block_update(off_t block_offset, VGMSTREAM * vgmstream); void block_update_ast(off_t block_ofset, VGMSTREAM * vgmstream); void block_update_mxch(off_t block_ofset, VGMSTREAM * vgmstream); diff --git a/src/vgmstream.c b/src/vgmstream.c index 6a9ce018..909f234d 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -2751,6 +2751,9 @@ int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t s } } + /* init first block for blocked layout (if not blocked this will do nothing) */ + block_update(start_offset, vgmstream); + /* EA-MT decoder is a bit finicky and needs this when channel offsets change */ if (vgmstream->coding_type == coding_EA_MT) { flush_ea_mt(vgmstream); From c2a0311584a84bd6906c88eaab77d8aada9a325d Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 13:47:02 +0200 Subject: [PATCH 44/55] Random tweaks --- src/meta/riff.c | 23 ++++++++++++----------- src/meta/ubi_bao.c | 8 ++++---- src/meta/wwise.c | 5 +++-- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/meta/riff.c b/src/meta/riff.c index a3b0c69a..e25b8aac 100644 --- a/src/meta/riff.c +++ b/src/meta/riff.c @@ -13,6 +13,7 @@ static VGMSTREAM *parse_riff_ogg(STREAMFILE * streamFile, off_t start_offset, si /* return milliseconds */ static long parse_adtl_marker(unsigned char * marker) { long hh,mm,ss,ms; + if (memcmp("Marker ",marker,7)) return -1; if (4 != sscanf((char*)marker+7,"%ld:%ld:%ld.%ld",&hh,&mm,&ss,&ms)) @@ -25,31 +26,31 @@ static long parse_adtl_marker(unsigned char * marker) { static void parse_adtl(off_t adtl_offset, off_t adtl_length, STREAMFILE *streamFile, long *loop_start, long *loop_end, int *loop_flag) { int loop_start_found = 0; int loop_end_found = 0; - off_t current_chunk = adtl_offset+4; + off_t current_chunk = adtl_offset+0x04; - while (current_chunk < adtl_offset+adtl_length) { - uint32_t chunk_type = read_32bitBE(current_chunk,streamFile); - off_t chunk_size = read_32bitLE(current_chunk+4,streamFile); + while (current_chunk < adtl_offset + adtl_length) { + uint32_t chunk_type = read_32bitBE(current_chunk+0x00,streamFile); + off_t chunk_size = read_32bitLE(current_chunk+0x04,streamFile); - if (current_chunk+8+chunk_size > adtl_offset+adtl_length) return; + if (current_chunk+0x08+chunk_size > adtl_offset+adtl_length) + return; switch(chunk_type) { - case 0x6c61626c: { /* labl */ - unsigned char *labelcontent; - labelcontent = malloc(chunk_size-4); + case 0x6c61626c: { /* "labl" */ + unsigned char *labelcontent = malloc(chunk_size-0x04); if (!labelcontent) return; - if (read_streamfile(labelcontent,current_chunk+0xc, chunk_size-4,streamFile)!=chunk_size-4) { + if (read_streamfile(labelcontent,current_chunk+0x0c, chunk_size-0x04,streamFile) != chunk_size-0x04) { free(labelcontent); return; } switch (read_32bitLE(current_chunk+8,streamFile)) { case 1: - if (!loop_start_found && (*loop_start = parse_adtl_marker(labelcontent))>=0) + if (!loop_start_found && (*loop_start = parse_adtl_marker(labelcontent)) >= 0) loop_start_found = 1; break; case 2: - if (!loop_end_found && (*loop_end = parse_adtl_marker(labelcontent))>=0) + if (!loop_end_found && (*loop_end = parse_adtl_marker(labelcontent)) >= 0) loop_end_found = 1; break; default: diff --git a/src/meta/ubi_bao.c b/src/meta/ubi_bao.c index e81635c2..95d8e43d 100644 --- a/src/meta/ubi_bao.c +++ b/src/meta/ubi_bao.c @@ -420,7 +420,7 @@ static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset) /* 0x18: null */ /* 0x1c: null */ descriptor_type = read_32bit(offset+0x20, streamFile); - descriptor_subtype = read_32bit(offset+header_size+0x04, streamFile); /* games may crash if changed */ + descriptor_subtype = read_32bit(offset+header_size+0x04, streamFile); /* for debugging purposes */ switch(descriptor_type) { @@ -457,7 +457,7 @@ static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset) //;VGM_ASSERT(descriptor_subtype != 0x01, "UBI BAO: subtype %x at %lx (%lx)\n", descriptor_subtype, offset, offset+header_size+0x04); /* ignore unknown subtypes */ - if (descriptor_subtype != 0x01) + if (descriptor_subtype != 0x00000001) return 1; bao->total_subsongs++; @@ -543,7 +543,7 @@ static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset) break; - case 0x00230008: /* Splinter Cell: Conviction (X360/PC) */ + case 0x00230008: /* Splinter Cell: Conviction (X360/PC)-pk */ bao->stream_size = read_32bit(offset+header_size+0x08, streamFile); bao->stream_id = read_32bit(offset+header_size+0x24, streamFile); bao->is_external = read_32bit(offset+header_size+0x38, streamFile); @@ -612,7 +612,7 @@ static int parse_bao(ubi_bao_header * bao, STREAMFILE *streamFile, off_t offset) case 0x001F0010: /* Prince of Persia 2008 (PS3/X360)-file, Far Cry 2 (PS3)-file */ case 0x00280306: /* Far Cry 3: Blood Dragon (X360)-file */ case 0x00290106: /* Splinter Cell Blacklist? */ - default: + default: /* others possibly using BAO: Avatar X360/PS3/PC, Just Dance, Watch_Dogs, Far Cry Primal, Far Cry 4 */ VGM_LOG("UBI BAO: unknown BAO version at %lx\n", offset); goto fail; } diff --git a/src/meta/wwise.c b/src/meta/wwise.c index c48c8c2c..fd8ddd85 100644 --- a/src/meta/wwise.c +++ b/src/meta/wwise.c @@ -172,8 +172,9 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) { else if (ww.format == 0x0002 && ww.block_align == 0x104 * ww.channels) { //ww.codec = SWITCH_ADPCM; /* unknown codec, found in Bayonetta 2 (Switch) - * frames of 0x104 per ch, possibly frame header is hist1(2)/hist2(2)/predictor(1) - * (may write 2 header samples + FF*2 nibbles = 0x200 samples per block?) */ + * frames of 0x104 per ch, possibly frame header is hist1(2)/hist2(2)/index(1) + * (may write 2 header samples + FF*2 nibbles = 0x200 samples per block?) + * index only goes up to ~0xb, may be a shift/scale value */ goto fail; } From bc62a689c0d924a230879ef38413c86ee0cf030b Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 13:47:48 +0200 Subject: [PATCH 45/55] Don't call block_update_x manually when using vgmstream_open_stream --- src/meta/aifc.c | 6 +--- src/meta/awc.c | 5 --- src/meta/caf.c | 3 -- src/meta/dec.c | 13 +++---- src/meta/ea_1snh.c | 5 +-- src/meta/ea_eaac.c | 4 --- src/meta/ea_schl_fixed.c | 6 ---- src/meta/ea_swvr.c | 8 ++--- src/meta/ea_wve_ad10.c | 5 ++- src/meta/ea_wve_au00.c | 6 ++-- src/meta/gsp_gsb.c | 75 ++++++++++++++++++++-------------------- src/meta/h4m.c | 7 ++-- src/meta/ivaud.c | 4 --- src/meta/nds_hwas.c | 9 +---- src/meta/ps2_adm.c | 7 ++-- src/meta/ps2_iab.c | 4 +-- src/meta/ps2_strlr.c | 13 ++++--- src/meta/psx_cdxa.c | 6 ++-- src/meta/rws.c | 5 +-- src/meta/sthd.c | 9 +++-- src/meta/vawx.c | 4 --- src/meta/vgs.c | 9 ++--- src/meta/xbox_xvas.c | 9 +++-- src/meta/xvag.c | 5 --- 24 files changed, 83 insertions(+), 144 deletions(-) diff --git a/src/meta/aifc.c b/src/meta/aifc.c index 4c61c3c0..daf2663c 100644 --- a/src/meta/aifc.c +++ b/src/meta/aifc.c @@ -2,7 +2,7 @@ #include "../layout/layout.h" -/* for reading integers inexplicably packed into 80 bit floats */ +/* for reading integers inexplicably packed into 80-bit ('double extended') floats */ static uint32_t read80bitSANE(off_t offset, STREAMFILE *streamFile) { uint8_t buf[10]; int32_t exponent; @@ -286,10 +286,6 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) { if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; - - if (vgmstream->layout_type == layout_blocked_xa_aiff) - block_update_xa_aiff(start_offset,vgmstream); - return vgmstream; fail: diff --git a/src/meta/awc.c b/src/meta/awc.c index 2990c772..451ac67a 100644 --- a/src/meta/awc.c +++ b/src/meta/awc.c @@ -156,13 +156,8 @@ VGMSTREAM * init_vgmstream_awc(STREAMFILE *streamFile) { } - /* open files; channel offsets are updated below */ if (!vgmstream_open_stream(vgmstream,streamFile,awc.stream_offset)) goto fail; - - if (vgmstream->layout_type == layout_blocked_awc) - block_update_awc(awc.stream_offset, vgmstream); - return vgmstream; fail: diff --git a/src/meta/caf.c b/src/meta/caf.c index 8180fe8e..ca1b1134 100644 --- a/src/meta/caf.c +++ b/src/meta/caf.c @@ -54,9 +54,6 @@ VGMSTREAM * init_vgmstream_caf(STREAMFILE *streamFile) { if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) ) goto fail; - - block_update_caf(start_offset,vgmstream); - return vgmstream; fail: diff --git a/src/meta/dec.c b/src/meta/dec.c index 43a3fe18..69247e15 100644 --- a/src/meta/dec.c +++ b/src/meta/dec.c @@ -13,14 +13,16 @@ VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile) { int loop_flag, channel_count, sample_rate, loop_start = 0, loop_end = 0; - /* check extension (.dec: main, .de2: Gurumin) */ + /* checks + * .dec: main, + * .de2: Gurumin (PC) */ if ( !check_extensions(streamFile,"dec,de2") ) goto fail; /* Gurumin has extra data, maybe related to rhythm (~0x50000) */ if (check_extensions(streamFile,"de2")) { /* still not sure what this is for, but consistently 0xb */ - if (read_32bitLE(0x04,streamFile) != 0xb) goto fail; + if (read_32bitLE(0x04,streamFile) != 0x0b) goto fail; /* legitimate! really! */ riff_off = 0x10 + (read_32bitLE(0x0c,streamFile) ^ read_32bitLE(0x04,streamFile)); @@ -67,6 +69,7 @@ VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile) { vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; + vgmstream->meta_type = meta_DEC; vgmstream->sample_rate = sample_rate; vgmstream->num_samples = pcm_size / 2 / channel_count; vgmstream->loop_start_sample = loop_start; @@ -76,14 +79,8 @@ VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile) { vgmstream->interleave_block_size = 0x800; vgmstream->layout_type = layout_blocked_dec; - vgmstream->meta_type = meta_DEC; - - /* open the file for reading */ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; - - block_update_dec(start_offset, vgmstream); - return vgmstream; fail: diff --git a/src/meta/ea_1snh.c b/src/meta/ea_1snh.c index ff204b9d..b7b4881d 100644 --- a/src/meta/ea_1snh.c +++ b/src/meta/ea_1snh.c @@ -97,12 +97,9 @@ VGMSTREAM * init_vgmstream_ea_1snh(STREAMFILE *streamFile) { goto fail; } - /* open files; channel offsets are updated below */ + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; - - block_update_ea_1snh(start_offset,vgmstream); - return vgmstream; fail: diff --git a/src/meta/ea_eaac.c b/src/meta/ea_eaac.c index 34f2a998..9f8604c4 100644 --- a/src/meta/ea_eaac.c +++ b/src/meta/ea_eaac.c @@ -676,10 +676,6 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST if (!vgmstream_open_stream(vgmstream,temp_streamFile ? temp_streamFile : streamData,start_offset)) goto fail; - - if (vgmstream->layout_type == layout_blocked_ea_sns) - block_update_ea_sns(start_offset, vgmstream); - close_streamfile(temp_streamFile); return vgmstream; diff --git a/src/meta/ea_schl_fixed.c b/src/meta/ea_schl_fixed.c index 1703c0ad..c374f874 100644 --- a/src/meta/ea_schl_fixed.c +++ b/src/meta/ea_schl_fixed.c @@ -75,14 +75,8 @@ VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE *streamFile) { } - /* open files; channel offsets are updated below */ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; - - /* setup first block to update offsets */ - block_update_ea_schl(start_offset,vgmstream); - - return vgmstream; fail: diff --git a/src/meta/ea_swvr.c b/src/meta/ea_swvr.c index 7321d253..55ed54d3 100644 --- a/src/meta/ea_swvr.c +++ b/src/meta/ea_swvr.c @@ -61,7 +61,7 @@ VGMSTREAM * init_vgmstream_ea_swvr(STREAMFILE *streamFile) { total_subsongs = 1; block_id = read_32bit(start_offset, streamFile); - /* files are basically headerless so we inspect blocks the first block + /* files are basically headerless so we inspect the first block * Freekstyle uses multiblocks/subsongs (though some subsongs may be clones?) */ switch(block_id) { case 0x5641474D: /* "VAGM" */ @@ -121,12 +121,12 @@ VGMSTREAM * init_vgmstream_ea_swvr(STREAMFILE *streamFile) { vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; + vgmstream->meta_type = meta_EA_SWVR; vgmstream->sample_rate = sample_rate; vgmstream->codec_endian = big_endian; vgmstream->num_streams = total_subsongs; vgmstream->stream_size = get_streamfile_size(streamFile) / total_subsongs; /* approx... */ - vgmstream->meta_type = meta_EA_SWVR; vgmstream->coding_type = coding; vgmstream->layout_type = layout_blocked_ea_swvr; /* DSP coefs are loaded per block */ @@ -141,7 +141,7 @@ VGMSTREAM * init_vgmstream_ea_swvr(STREAMFILE *streamFile) { vgmstream->stream_index = target_subsong; /* needed to skip other subsong-blocks */ vgmstream->next_block_offset = start_offset; do { - block_update_ea_swvr(vgmstream->next_block_offset,vgmstream); + block_update(vgmstream->next_block_offset,vgmstream); switch(vgmstream->coding_type) { case coding_PSX: num_samples = ps_bytes_to_samples(vgmstream->current_block_size,1); break; case coding_NGC_DSP: num_samples = dsp_bytes_to_samples(vgmstream->current_block_size,1); break; @@ -151,6 +151,7 @@ VGMSTREAM * init_vgmstream_ea_swvr(STREAMFILE *streamFile) { vgmstream->num_samples += num_samples; } while (vgmstream->next_block_offset < get_streamfile_size(streamFile)); + block_update(start_offset, vgmstream); } if (loop_flag) { @@ -158,7 +159,6 @@ VGMSTREAM * init_vgmstream_ea_swvr(STREAMFILE *streamFile) { vgmstream->loop_end_sample = vgmstream->num_samples; } - block_update_ea_swvr(start_offset, vgmstream); return vgmstream; fail: diff --git a/src/meta/ea_wve_ad10.c b/src/meta/ea_wve_ad10.c index 494a6b46..53a2a6ac 100644 --- a/src/meta/ea_wve_ad10.c +++ b/src/meta/ea_wve_ad10.c @@ -39,14 +39,13 @@ VGMSTREAM * init_vgmstream_ea_wve_ad10(STREAMFILE *streamFile) { { vgmstream->next_block_offset = start_offset; do { - block_update_ea_wve_ad10(vgmstream->next_block_offset,vgmstream); + block_update(vgmstream->next_block_offset,vgmstream); vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1); } while (vgmstream->next_block_offset < get_streamfile_size(streamFile)); + block_update(start_offset, vgmstream); } - block_update_ea_wve_ad10(start_offset, vgmstream); - return vgmstream; fail: diff --git a/src/meta/ea_wve_au00.c b/src/meta/ea_wve_au00.c index a4aea7a4..72d32849 100644 --- a/src/meta/ea_wve_au00.c +++ b/src/meta/ea_wve_au00.c @@ -28,8 +28,8 @@ VGMSTREAM * init_vgmstream_ea_wve_au00(STREAMFILE *streamFile) { vgmstream = allocate_vgmstream(channel_count, loop_flag); if (!vgmstream) goto fail; - vgmstream->sample_rate = 22050; vgmstream->meta_type = meta_EA_WVE_AU00; + vgmstream->sample_rate = 22050; /* You'd think they'd use coding_EA_XA_int but instead it's PS-ADPCM without flags and 0x0f frame size * (equivalent to configurable PS-ADPCM), surely to shoehorn EA-XA sizes into the PS1 hardware decoder */ @@ -44,13 +44,13 @@ VGMSTREAM * init_vgmstream_ea_wve_au00(STREAMFILE *streamFile) { { vgmstream->next_block_offset = start_offset; do { - block_update_ea_wve_au00(vgmstream->next_block_offset,vgmstream); + block_update(vgmstream->next_block_offset,vgmstream); vgmstream->num_samples += ps_cfg_bytes_to_samples(vgmstream->current_block_size, vgmstream->interleave_block_size, 1); } while (vgmstream->next_block_offset < get_streamfile_size(streamFile)); + block_update(start_offset, vgmstream); } - block_update_ea_wve_au00(start_offset, vgmstream); return vgmstream; fail: diff --git a/src/meta/gsp_gsb.c b/src/meta/gsp_gsb.c index d51ec240..4163db82 100644 --- a/src/meta/gsp_gsb.c +++ b/src/meta/gsp_gsb.c @@ -2,10 +2,10 @@ #include "../layout/layout.h" #include "../coding/coding.h" -/* GSP+GSB - from Tecmo's Super Swing Golf 1 & 2 (WII), Quantum Theory (PS3/X360) */ +/* GSP+GSB - from Tecmo's Super Swing Golf 1 & 2 (Wii), Quantum Theory (PS3/X360) */ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - STREAMFILE * streamFileGSP = NULL; + STREAMFILE * streamHeader = NULL; int loop_flag, channel_count; off_t start_offset, chunk_offset, first_offset; size_t datasize; @@ -16,68 +16,70 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) { if (!check_extensions(streamFile,"gsb")) goto fail; - streamFileGSP = open_streamfile_by_ext(streamFile, "gsp"); - if (!streamFileGSP) goto fail; + streamHeader = open_streamfile_by_ext(streamFile, "gsp"); + if (!streamHeader) goto fail; /* check header */ - if (read_32bitBE(0x00,streamFileGSP) != 0x47534E44) /* "GSND" */ + if (read_32bitBE(0x00,streamHeader) != 0x47534E44) /* "GSND" */ goto fail; /* 0x04: version?, 0x08: 1?, 0x0c: 0?, */ - first_offset = read_32bitBE(0x10,streamFileGSP); /* usually 0x14*/ + first_offset = read_32bitBE(0x10,streamHeader); /* usually 0x14*/ + + if (!find_chunk_be(streamHeader, 0x44415441,first_offset,1, &chunk_offset,NULL)) goto fail; /*"DATA"*/ + channel_count = read_16bitBE(chunk_offset+0x0e,streamHeader); + if (!find_chunk_be(streamHeader, 0x42534943,first_offset,1, &chunk_offset,NULL)) goto fail; /*"BSIC"*/ + loop_flag = read_8bit(chunk_offset+0x0c,streamHeader); + + start_offset = 0x00; - if (!find_chunk_be(streamFileGSP, 0x44415441,first_offset,1, &chunk_offset,NULL)) goto fail; /*"DATA"*/ - channel_count = read_16bitBE(chunk_offset+0x0e,streamFileGSP); - if (!find_chunk_be(streamFileGSP, 0x42534943,first_offset,1, &chunk_offset,NULL)) goto fail; /*"BSIC"*/ - loop_flag = read_8bit(chunk_offset+0x0c,streamFileGSP); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; + vgmstream->meta_type = meta_GSP_GSB; - if (!find_chunk_be(streamFileGSP, 0x48454144,first_offset,1, &chunk_offset,NULL)) goto fail; /*"HEAD"*/ + + if (!find_chunk_be(streamHeader, 0x48454144,first_offset,1, &chunk_offset,NULL)) goto fail; /*"HEAD"*/ /* 0x00: header_size, 0x04: num_chunks */ - if (!find_chunk_be(streamFileGSP, 0x44415441,first_offset,1, &chunk_offset,NULL)) goto fail; /*"DATA"*/ + if (!find_chunk_be(streamHeader, 0x44415441,first_offset,1, &chunk_offset,NULL)) goto fail; /*"DATA"*/ /* 0x00: filesize, 0x0c: always 10?, 0x10: always 0?, 0x18: always 0? */ - datasize = read_32bitBE(chunk_offset+0x00,streamFileGSP); - codec_id = read_32bitBE(chunk_offset+0x04,streamFileGSP); - vgmstream->sample_rate = read_32bitBE(chunk_offset+0x08,streamFileGSP); - vgmstream->channels = channel_count; /* 0x0e */ - vgmstream->num_samples = read_32bitBE(chunk_offset+0x14,streamFileGSP); + datasize = read_32bitBE(chunk_offset+0x00,streamHeader); + codec_id = read_32bitBE(chunk_offset+0x04,streamHeader); + vgmstream->sample_rate = read_32bitBE(chunk_offset+0x08,streamHeader); + vgmstream->num_samples = read_32bitBE(chunk_offset+0x14,streamHeader); /* 0x1c: unk (varies with codec_id) */ - if (!find_chunk_be(streamFileGSP, 0x42534943,first_offset,1, &chunk_offset,NULL)) goto fail; /*"BSIC"*/ + if (!find_chunk_be(streamHeader, 0x42534943,first_offset,1, &chunk_offset,NULL)) goto fail; /*"BSIC"*/ /* 0x00+: probably volume/pan/etc */ - vgmstream->loop_start_sample = read_32bitBE(chunk_offset+0x10,streamFileGSP); - vgmstream->loop_end_sample = read_32bitBE(chunk_offset+0x14,streamFileGSP); + vgmstream->loop_start_sample = read_32bitBE(chunk_offset+0x10,streamHeader); + vgmstream->loop_end_sample = read_32bitBE(chunk_offset+0x14,streamHeader); - //if (!find_chunk_be(streamFileGSP, 0x4E414D45,first_offset,1, &chunk_offset,NULL)) goto fail; /*"NAME"*/ + //if (!find_chunk_be(streamHeader, 0x4E414D45,first_offset,1, &chunk_offset,NULL)) goto fail; /*"NAME"*/ /* 0x00: name_size, 0x04+: name*/ - start_offset = 0x0; - switch (codec_id) { - case 4: { /* DSP */ + case 0x04: { /* DSP [Super Swing Golf (Wii)] */ size_t block_header_size; size_t num_blocks; vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_blocked_gsb; - if (!find_chunk_be(streamFileGSP, 0x47434558,first_offset,1, &chunk_offset,NULL)) goto fail; /*"GCEX"*/ + if (!find_chunk_be(streamHeader, 0x47434558,first_offset,1, &chunk_offset,NULL)) goto fail; /*"GCEX"*/ - //vgmstream->current_block_size = read_32bitBE(chunk_offset+0x00,streamFileGSP); - block_header_size = read_32bitBE(chunk_offset+0x04,streamFileGSP); - num_blocks = read_32bitBE(chunk_offset+0x08,streamFileGSP); + //vgmstream->current_block_size = read_32bitBE(chunk_offset+0x00,streamHeader); + block_header_size = read_32bitBE(chunk_offset+0x04,streamHeader); + num_blocks = read_32bitBE(chunk_offset+0x08,streamHeader); vgmstream->num_samples = (datasize - block_header_size * num_blocks) / 8 / vgmstream->channels * 14; /* 0x0c+: unk */ - dsp_read_coefs_be(vgmstream, streamFileGSP, chunk_offset+0x18, 0x30); + dsp_read_coefs_be(vgmstream, streamHeader, chunk_offset+0x18, 0x30); break; } #ifdef VGM_USE_FFMPEG - case 8: { /* ATRAC3 */ + case 0x08: { /* ATRAC3 [Quantum Theory (PS3)] */ ffmpeg_codec_data *ffmpeg_data = NULL; uint8_t buf[100]; int32_t bytes, block_size, encoder_delay, joint_stereo, max_samples; @@ -105,15 +107,15 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) { break; } - case 9: { /* XMA2 */ + case 0x09: { /* XMA2 [Quantum Theory (PS3)] */ ffmpeg_codec_data *ffmpeg_data = NULL; uint8_t buf[200]; int32_t bytes; - if (!find_chunk_be(streamFileGSP, 0x584D4558,first_offset,1, &chunk_offset,NULL)) goto fail; /*"XMEX"*/ + if (!find_chunk_be(streamHeader, 0x584D4558,first_offset,1, &chunk_offset,NULL)) goto fail; /*"XMEX"*/ /* 0x00: fmt0x166 header (BE), 0x34: seek table */ - bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, chunk_offset,0x34, datasize, streamFileGSP, 1); + bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, chunk_offset,0x34, datasize, streamHeader, 1); if (bytes <= 0) goto fail; ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,datasize); @@ -128,18 +130,15 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) { default: goto fail; } - vgmstream->meta_type = meta_GSP_GSB; - /* open the file for reading */ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; - - close_streamfile(streamFileGSP); + close_streamfile(streamHeader); return vgmstream; fail: - if (streamFileGSP) close_streamfile(streamFileGSP); + close_streamfile(streamHeader); close_vgmstream(vgmstream); return NULL; } diff --git a/src/meta/h4m.c b/src/meta/h4m.c index d01f21ba..80540977 100644 --- a/src/meta/h4m.c +++ b/src/meta/h4m.c @@ -89,17 +89,18 @@ VGMSTREAM * init_vgmstream_h4m(STREAMFILE *streamFile) { /* calc num_samples manually */ { + vgmstream->stream_index = target_subsong; /* extra setup for H4M */ + vgmstream->full_block_size = 0; /* extra setup for H4M */ vgmstream->next_block_offset = start_offset; do { - block_update_h4m(vgmstream->next_block_offset,vgmstream); + block_update(vgmstream->next_block_offset,vgmstream); vgmstream->num_samples += vgmstream->current_block_samples; } while (vgmstream->next_block_offset < get_streamfile_size(streamFile)); vgmstream->full_block_size = 0; /* extra cleanup for H4M */ + block_update(start_offset, vgmstream); } - block_update_h4m(start_offset, vgmstream); - return vgmstream; fail: diff --git a/src/meta/ivaud.c b/src/meta/ivaud.c index 96efa670..8a85a556 100644 --- a/src/meta/ivaud.c +++ b/src/meta/ivaud.c @@ -73,10 +73,6 @@ VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile) { if (!vgmstream_open_stream(vgmstream,streamFile,ivaud.stream_offset)) goto fail; - - if (vgmstream->layout_type == layout_blocked_ivaud) - block_update_ivaud(ivaud.stream_offset, vgmstream); - return vgmstream; fail: diff --git a/src/meta/nds_hwas.c b/src/meta/nds_hwas.c index 37d78ff2..963a8c74 100644 --- a/src/meta/nds_hwas.c +++ b/src/meta/nds_hwas.c @@ -12,8 +12,6 @@ VGMSTREAM * init_vgmstream_nds_hwas(STREAMFILE *streamFile) { /* .hwas: usually in archives but also found named (ex. Guitar Hero On Tour) */ if (!check_extensions(streamFile,"hwas")) goto fail; - - /* check header */ if (read_32bitBE(0x00,streamFile) != 0x73617768) /* "sawh" */ goto fail; @@ -27,23 +25,18 @@ VGMSTREAM * init_vgmstream_nds_hwas(STREAMFILE *streamFile) { vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; + vgmstream->meta_type = meta_NDS_HWAS; vgmstream->sample_rate = read_32bitLE(0x08,streamFile); vgmstream->num_samples = ima_bytes_to_samples(read_32bitLE(0x14,streamFile), channel_count); vgmstream->loop_start_sample = ima_bytes_to_samples(read_32bitLE(0x10,streamFile), channel_count); //assumed, always 0 vgmstream->loop_end_sample = ima_bytes_to_samples(read_32bitLE(0x18,streamFile), channel_count); - vgmstream->meta_type = meta_NDS_HWAS; - vgmstream->coding_type = coding_IMA_int; vgmstream->layout_type = layout_blocked_hwas; vgmstream->full_block_size = read_32bitLE(0x04,streamFile); /* usually 0x2000, 0x4000 or 0x8000 */ - /* open the file for reading by each channel */ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; - - block_update_hwas(start_offset, vgmstream); - return vgmstream; fail: diff --git a/src/meta/ps2_adm.c b/src/meta/ps2_adm.c index b1c6d3db..b0c5b61c 100644 --- a/src/meta/ps2_adm.c +++ b/src/meta/ps2_adm.c @@ -32,8 +32,8 @@ VGMSTREAM * init_vgmstream_ps2_adm(STREAMFILE *streamFile) { vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - vgmstream->sample_rate = 44100; vgmstream->meta_type = meta_PS2_ADM; + vgmstream->sample_rate = 44100; vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_blocked_adm; @@ -44,19 +44,18 @@ VGMSTREAM * init_vgmstream_ps2_adm(STREAMFILE *streamFile) { { vgmstream->next_block_offset = start_offset; do { - block_update_adm(vgmstream->next_block_offset,vgmstream); - + block_update(vgmstream->next_block_offset,vgmstream); if (loop_flag && vgmstream->current_block_offset == loop_start_offset) vgmstream->loop_start_sample = vgmstream->num_samples; vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1); } while (vgmstream->next_block_offset < get_streamfile_size(streamFile)); + block_update(start_offset,vgmstream); if (loop_flag) vgmstream->loop_end_sample = vgmstream->num_samples; } - block_update_adm(start_offset,vgmstream); return vgmstream; fail: diff --git a/src/meta/ps2_iab.c b/src/meta/ps2_iab.c index 593cb4f8..edae3d81 100644 --- a/src/meta/ps2_iab.c +++ b/src/meta/ps2_iab.c @@ -40,13 +40,13 @@ VGMSTREAM * init_vgmstream_ps2_iab(STREAMFILE *streamFile) { { vgmstream->next_block_offset = start_offset; do { - block_update_ps2_iab(vgmstream->next_block_offset, vgmstream); + block_update(vgmstream->next_block_offset, vgmstream); vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1); } while (vgmstream->next_block_offset < get_streamfile_size(streamFile)); + block_update(start_offset, vgmstream); } - block_update_ps2_iab(start_offset, vgmstream); return vgmstream; fail: diff --git a/src/meta/ps2_strlr.c b/src/meta/ps2_strlr.c index 9e8a42c6..83770fc4 100644 --- a/src/meta/ps2_strlr.c +++ b/src/meta/ps2_strlr.c @@ -2,7 +2,7 @@ #include "../layout/layout.h" #include "../coding/coding.h" -/* STR - The Bouncer (PS2) */ +/* .vs/STRx - from The Bouncer (PS2) */ VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; int channel_count, loop_flag; @@ -10,11 +10,11 @@ VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE *streamFile) { /* checks */ - /* .vs: real extension (from .nam container) , .str: partial header id */ + /* .vs: real extension (from .nam container) + * .str: fake, partial header id */ if (!check_extensions(streamFile, "vs,str")) goto fail; - /* check header */ if (!(read_32bitBE(0x000,streamFile) == 0x5354524C && /* "STRL" */ read_32bitBE(0x800,streamFile) == 0x53545252) && /* "STRR" */ read_32bitBE(0x00,streamFile) != 0x5354524D) /* "STRM" */ @@ -29,11 +29,10 @@ VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE *streamFile) { vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; + vgmstream->meta_type = meta_PS2_STRLR; vgmstream->sample_rate = 44100; vgmstream->coding_type = coding_PSX; - vgmstream->layout_type = layout_blocked_ps2_strlr; - vgmstream->meta_type = meta_PS2_STRLR; if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; @@ -42,13 +41,13 @@ VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE *streamFile) { { vgmstream->next_block_offset = start_offset; do { - block_update_ps2_strlr(vgmstream->next_block_offset,vgmstream); + block_update(vgmstream->next_block_offset,vgmstream); vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1); } while (vgmstream->next_block_offset < get_streamfile_size(streamFile)); + block_update(start_offset, vgmstream); } - block_update_ps2_strlr(start_offset, vgmstream); return vgmstream; fail: diff --git a/src/meta/psx_cdxa.c b/src/meta/psx_cdxa.c index fab4911a..612b5adf 100644 --- a/src/meta/psx_cdxa.c +++ b/src/meta/psx_cdxa.c @@ -158,18 +158,16 @@ VGMSTREAM * init_vgmstream_cdxa(STREAMFILE *streamFile) { /* calc num_samples as blocks may be empty or smaller than usual depending on flags */ vgmstream->next_block_offset = start_offset; do { - block_update_xa(vgmstream->next_block_offset,vgmstream); + block_update(vgmstream->next_block_offset,vgmstream); vgmstream->num_samples += vgmstream->current_block_samples; } while (vgmstream->next_block_offset < get_streamfile_size(streamFile)); - + block_update(start_offset,vgmstream); } else { vgmstream->num_samples = xa_bytes_to_samples(file_size - start_offset, channel_count, is_blocked); } - if (vgmstream->layout_type == layout_blocked_xa) - block_update_xa(start_offset,vgmstream); return vgmstream; fail: diff --git a/src/meta/rws.c b/src/meta/rws.c index eff42048..563a7058 100644 --- a/src/meta/rws.c +++ b/src/meta/rws.c @@ -242,10 +242,10 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) { vgmstream = allocate_vgmstream(rws.channel_count,loop_flag); if (!vgmstream) goto fail; + vgmstream->meta_type = meta_RWS; vgmstream->sample_rate = rws.sample_rate; vgmstream->num_streams = total_subsongs; vgmstream->stream_size = stream_size; - vgmstream->meta_type = meta_RWS; if (name_offset) read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamFile); @@ -300,9 +300,6 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) { if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; - - block_update_rws(start_offset, vgmstream); - return vgmstream; fail: diff --git a/src/meta/sthd.c b/src/meta/sthd.c index 9c83a013..5c025df6 100644 --- a/src/meta/sthd.c +++ b/src/meta/sthd.c @@ -28,8 +28,9 @@ VGMSTREAM * init_vgmstream_sthd(STREAMFILE *streamFile) { vgmstream = allocate_vgmstream(channel_count, loop_flag); if (!vgmstream) goto fail; - vgmstream->sample_rate = read_32bitLE(0x20, streamFile); /* repeated ~8 times? */ vgmstream->meta_type = meta_STHD; + vgmstream->sample_rate = read_32bitLE(0x20, streamFile); /* repeated ~8 times? */ + vgmstream->coding_type = coding_XBOX_IMA_int; vgmstream->layout_type = layout_blocked_sthd; @@ -45,8 +46,7 @@ VGMSTREAM * init_vgmstream_sthd(STREAMFILE *streamFile) { vgmstream->next_block_offset = start_offset; do { - block_update_sthd(vgmstream->next_block_offset,vgmstream); - + block_update(vgmstream->next_block_offset,vgmstream); if (block_count == loop_start_block) vgmstream->loop_start_sample = vgmstream->num_samples; if (block_count == loop_end_block) @@ -56,10 +56,9 @@ VGMSTREAM * init_vgmstream_sthd(STREAMFILE *streamFile) { block_count++; } while (vgmstream->next_block_offset < get_streamfile_size(streamFile)); + block_update(start_offset, vgmstream); } - block_update_sthd(start_offset, vgmstream); - return vgmstream; fail: diff --git a/src/meta/vawx.c b/src/meta/vawx.c index 32d89332..02a689ca 100644 --- a/src/meta/vawx.c +++ b/src/meta/vawx.c @@ -103,10 +103,6 @@ VGMSTREAM * init_vgmstream_vawx(STREAMFILE *streamFile) { if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; - - if (vgmstream->layout_type == layout_blocked_vawx) - block_update_vawx(start_offset,vgmstream); - return vgmstream; fail: diff --git a/src/meta/vgs.c b/src/meta/vgs.c index ba2e66de..db55f8fb 100644 --- a/src/meta/vgs.c +++ b/src/meta/vgs.c @@ -50,25 +50,22 @@ VGMSTREAM * init_vgmstream_vgs(STREAMFILE *streamFile) { channel_count++; } + start_offset = 0x80; + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - start_offset = 0x80; + vgmstream->meta_type = meta_VGS; vgmstream->sample_rate = sample_rate; vgmstream->num_samples = ps_bytes_to_samples(channel_size*channel_count, channel_count); vgmstream->coding_type = coding_PSX_badflags; /* flag = stream/channel number */ vgmstream->layout_type = layout_blocked_vgs; - vgmstream->meta_type = meta_VGS; - - /* open files; channel offsets are updated below */ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; - block_update_vgs(start_offset, vgmstream); - return vgmstream; fail: close_vgmstream(vgmstream); diff --git a/src/meta/xbox_xvas.c b/src/meta/xbox_xvas.c index 6ee37b86..acd09c8b 100644 --- a/src/meta/xbox_xvas.c +++ b/src/meta/xbox_xvas.c @@ -9,10 +9,10 @@ VGMSTREAM * init_vgmstream_xbox_xvas(STREAMFILE *streamFile) { int loop_flag, channel_count; size_t data_size; - /* check extension */ + + /* checks */ if (!check_extensions(streamFile,"xvas")) goto fail; - if (read_32bitLE(0x00,streamFile) != 0x69 && /* codec */ read_32bitLE(0x08,streamFile) != 0x48) /* block size (probably 0x24 for mono) */ goto fail; @@ -23,10 +23,12 @@ VGMSTREAM * init_vgmstream_xbox_xvas(STREAMFILE *streamFile) { data_size = read_32bitLE(0x24,streamFile); data_size -= (data_size / 0x20000) * 0x20; /* blocks of 0x20000 with padding */ + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; + vgmstream->meta_type = meta_XBOX_XVAS; vgmstream->sample_rate = read_32bitLE(0x0c,streamFile); vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, vgmstream->channels); if(loop_flag) { @@ -38,12 +40,9 @@ VGMSTREAM * init_vgmstream_xbox_xvas(STREAMFILE *streamFile) { vgmstream->coding_type = coding_XBOX_IMA; vgmstream->layout_type = layout_blocked_xvas; - vgmstream->meta_type = meta_XBOX_XVAS; if (!vgmstream_open_stream(vgmstream, streamFile, start_offset)) goto fail; - - block_update_xvas(start_offset,vgmstream); return vgmstream; fail: diff --git a/src/meta/xvag.c b/src/meta/xvag.c index 8847d046..27614b61 100644 --- a/src/meta/xvag.c +++ b/src/meta/xvag.c @@ -207,13 +207,8 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { } - /* open the file for reading */ if (!vgmstream_open_stream(vgmstream,temp_streamFile ? temp_streamFile : streamFile,start_offset)) goto fail; - - if (vgmstream->layout_type == layout_blocked_xvag_subsong) - block_update_xvag_subsong(start_offset, vgmstream); - close_streamfile(temp_streamFile); return vgmstream; From 5aad45ab877be02fd58f05c51f53a155c1f7e101 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 13:48:14 +0200 Subject: [PATCH 46/55] Clean AST meta --- src/layout/blocked_ast.c | 23 ++++++---- src/meta/ast.c | 98 ++++++++++++++++------------------------ 2 files changed, 51 insertions(+), 70 deletions(-) diff --git a/src/layout/blocked_ast.c b/src/layout/blocked_ast.c index 8ff32ba0..3aab1668 100644 --- a/src/layout/blocked_ast.c +++ b/src/layout/blocked_ast.c @@ -1,18 +1,21 @@ #include "layout.h" #include "../vgmstream.h" -/* set up for the block at the given offset */ +/* simple headered blocks */ void block_update_ast(off_t block_offset, VGMSTREAM * vgmstream) { + STREAMFILE* streamFile = vgmstream->ch[0].streamfile; int i; - vgmstream->current_block_offset = block_offset; - vgmstream->current_block_size = read_32bitBE( - vgmstream->current_block_offset+4, - vgmstream->ch[0].streamfile); - vgmstream->next_block_offset = vgmstream->current_block_offset + - vgmstream->current_block_size*vgmstream->channels + 0x20; + size_t block_data, header_size; - for (i=0;ichannels;i++) { - vgmstream->ch[i].offset = vgmstream->current_block_offset + - 0x20 + vgmstream->current_block_size*i; + /* 0x00: "BLCK", rest: null */ + block_data = read_32bitBE(block_offset+0x04,streamFile); + header_size = 0x20; + + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = block_data; + vgmstream->next_block_offset = block_offset + block_data*vgmstream->channels + header_size; + + for (i = 0; i < vgmstream->channels; i++) { + vgmstream->ch[i].offset = block_offset + header_size + block_data*i; } } diff --git a/src/meta/ast.c b/src/meta/ast.c index fccf95db..ede13594 100644 --- a/src/meta/ast.c +++ b/src/meta/ast.c @@ -2,82 +2,60 @@ #include "../layout/layout.h" #include "../util.h" +/* .AST - from Nintendo games [Super Mario Galaxy (Wii), Pac-Man Vs (GC)] */ VGMSTREAM * init_vgmstream_ast(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - coding_t coding_type; - - int codec_number; - int channel_count; - int loop_flag; + off_t start_offset; + int loop_flag, channel_count, codec; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("ast",filename_extension(filename))) goto fail; - - /* check header */ - if ((uint32_t)read_32bitBE(0,streamFile)!=0x5354524D || /* "STRM" */ - read_16bitBE(0xa,streamFile)!=0x10 || - /* check that file = header (0x40) + data */ - read_32bitBE(4,streamFile)+0x40!=get_streamfile_size(streamFile)) + /* checks */ + if (!check_extensions(streamFile, "ast")) goto fail; - - /* check for a first block */ - if (read_32bitBE(0x40,streamFile)!=0x424C434B) /* "BLCK" */ + if (read_32bitBE(0x00,streamFile) != 0x5354524D) /* "STRM" */ + goto fail; + if (read_16bitBE(0x0a,streamFile) != 0x10) /* ? */ goto fail; - /* check type details */ - codec_number = read_16bitBE(8,streamFile); - loop_flag = read_16bitBE(0xe,streamFile); - channel_count = read_16bitBE(0xc,streamFile); - /*max_block = read_32bitBE(0x20,streamFile);*/ + if (read_32bitBE(0x04,streamFile)+0x40 != get_streamfile_size(streamFile)) + goto fail; + codec = read_16bitBE(0x08,streamFile); + channel_count = read_16bitBE(0x0c,streamFile); + loop_flag = read_16bitBE(0x0e,streamFile); + //max_block = read_32bitBE(0x20,streamFile); - switch (codec_number) { - case 0: - coding_type = coding_NGC_AFC; + start_offset = 0x40; + if (read_32bitBE(start_offset,streamFile) != 0x424C434B) /* "BLCK" */ + goto fail; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_AST; + vgmstream->sample_rate = read_32bitBE(0x10,streamFile); + vgmstream->num_samples = read_32bitBE(0x14,streamFile); + vgmstream->loop_start_sample = read_32bitBE(0x18,streamFile); + vgmstream->loop_end_sample = read_32bitBE(0x1c,streamFile); + + vgmstream->layout_type = layout_blocked_ast; + switch (codec) { + case 0x00: /* , Pikmin 2 (GC) */ + vgmstream->coding_type = coding_NGC_AFC; break; - case 1: - coding_type = coding_PCM16BE; + case 0x01: /* Mario Kart: Double Dash!! (GC) */ + vgmstream->coding_type = coding_PCM16BE; break; default: goto fail; } - /* build the VGMSTREAM */ - - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = read_32bitBE(0x14,streamFile); - vgmstream->sample_rate = read_32bitBE(0x10,streamFile); - /* channels and loop flag are set by allocate_vgmstream */ - vgmstream->loop_start_sample = read_32bitBE(0x18,streamFile); - vgmstream->loop_end_sample = read_32bitBE(0x1c,streamFile); - - vgmstream->coding_type = coding_type; - vgmstream->layout_type = layout_blocked_ast; - vgmstream->meta_type = meta_AST; - - /* open the file for reading by each channel */ - { - int i; - for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - - if (!vgmstream->ch[i].streamfile) goto fail; - } - } - - /* start me up */ - block_update_ast(0x40,vgmstream); - + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } From 4ee39206c3330a91d97b779128b72716b4ffbecc Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 16:36:08 +0200 Subject: [PATCH 47/55] Fix Lunar 2 SCD loops/sample rate/stereo and PCM8 cleanup --- src/coding/coding.h | 8 ++-- src/coding/pcm_decoder.c | 34 ++++++++-------- src/formats.c | 3 +- src/meta/scd_pcm.c | 86 ++++++++++++++++++++-------------------- src/vgmstream.c | 32 ++++++++------- src/vgmstream.h | 2 +- 6 files changed, 85 insertions(+), 80 deletions(-) diff --git a/src/coding/coding.h b/src/coding/coding.h index 9614acb4..014f4bb8 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -62,14 +62,14 @@ void decode_ngc_dtk(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci void decode_ngc_afc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); /* pcm_decoder */ -void decode_pcm16LE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); -void decode_pcm16BE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian); void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); -void decode_pcm8_sb_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); -void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_ulaw_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); diff --git a/src/coding/pcm_decoder.c b/src/coding/pcm_decoder.c index 406f0dff..d958d4fd 100644 --- a/src/coding/pcm_decoder.c +++ b/src/coding/pcm_decoder.c @@ -2,7 +2,7 @@ #include "../util.h" #include -void decode_pcm16LE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; @@ -11,7 +11,7 @@ void decode_pcm16LE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci } } -void decode_pcm16BE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; @@ -20,6 +20,15 @@ void decode_pcm16BE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci } } +void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) { + int i, sample_count; + int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE; + + for (i=first_sample,sample_count=0; ioffset+i*2*channelspacing,stream->streamfile); + } +} + void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; @@ -38,14 +47,13 @@ void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac } } -void decode_pcm8_sb_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; for (i=first_sample,sample_count=0; ioffset+i*channelspacing,stream->streamfile); - if (v&0x80) v = 0-(v&0x7f); - outbuf[sample_count] = v*0x100; + int16_t v = (uint8_t)read_8bit(stream->offset+i,stream->streamfile); + outbuf[sample_count] = v*0x100 - 0x8000; } } @@ -59,22 +67,14 @@ void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int ch } } -void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_pcm8_sb(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; for (i=first_sample,sample_count=0; ioffset+i,stream->streamfile); - outbuf[sample_count] = v*0x100 - 0x8000; - } -} - -void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) { - int i, sample_count; - int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE; - - for (i=first_sample,sample_count=0; ioffset+i*2*channelspacing,stream->streamfile); + if (v&0x80) v = 0-(v&0x7f); + outbuf[sample_count] = v*0x100; } } diff --git a/src/formats.c b/src/formats.c index edffa2dc..d40fb921 100644 --- a/src/formats.c +++ b/src/formats.c @@ -215,6 +215,7 @@ static const char* extension_list[] = { "mihb", "mnstr", "mogg", + //"mp3", //common //"mp4", //common //"mpc", //FFmpeg, not parsed (musepack) //common "mpdsp", @@ -496,7 +497,7 @@ static const coding_info coding_info_list[] = { {coding_PCM8_int, "8-bit PCM with 1 byte interleave (block)"}, {coding_PCM8_U, "8-bit unsigned PCM"}, {coding_PCM8_U_int, "8-bit unsigned PCM with 1 byte interleave (block)"}, - {coding_PCM8_SB_int, "8-bit PCM with sign bit, 1 byte interleave (block)"}, + {coding_PCM8_SB, "8-bit PCM with sign bit"}, {coding_ULAW, "8-bit u-Law"}, {coding_ULAW_int, "8-bit u-Law with 1 byte interleave (block)"}, {coding_ALAW, "8-bit a-Law"}, diff --git a/src/meta/scd_pcm.c b/src/meta/scd_pcm.c index 1e374bed..d28c669a 100644 --- a/src/meta/scd_pcm.c +++ b/src/meta/scd_pcm.c @@ -1,63 +1,65 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* PCM (from Lunar: Eternal Blue (Sega CD) */ + +/* .PCM - from Lunar: Eternal Blue (Sega CD) */ VGMSTREAM * init_vgmstream_scd_pcm(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; off_t start_offset; + int loop_flag, channel_count; - int loop_flag; - int channel_count; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("pcm",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x00020000) + /* checks */ + if (!check_extensions(streamFile, "pcm")) goto fail; - loop_flag = (read_32bitLE(0x02,streamFile)!=0); - channel_count = 1; + if (read_16bitBE(0x00,streamFile) == 0x0002) { + channel_count = 1; + } + else if (read_16bitBE(0x00,streamFile) == 0x0001) { + channel_count = 2; /* RP025.PCM, RP039.PCM */ + } + else { + goto fail; + } + + start_offset = 0x800; + + + /* extra validations since .pcm it's kinda generic */ + { + off_t i; + /* should be empty up to start (~0x0a/~0x10 sometimes has unknown values) */ + for (i = 0x20; i < start_offset; i++) { + if (read_8bit(i, streamFile) != 0) + goto fail; + } + } + + /* loops start 0 is possible, plus all? files loops + * (even sfx/voices loop, but those set loop start in silence near the end) */ + loop_flag = (read_32bitBE(0x06,streamFile) != 0); + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = 0x200; - vgmstream->channels = channel_count; - vgmstream->sample_rate = 32000; - vgmstream->coding_type = coding_PCM8_SB_int; - vgmstream->num_samples = read_32bitBE(0x06,streamFile)*2; - if(loop_flag) { - vgmstream->loop_start_sample = read_32bitBE(0x02,streamFile)*0x400*2; - vgmstream->loop_end_sample = read_32bitBE(0x06,streamFile)*2; - } - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x1; vgmstream->meta_type = meta_SCD_PCM; + vgmstream->sample_rate = 32500; /* looks correct compared to emu/recordings */ + vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(streamFile) - start_offset, channel_count, 8); + vgmstream->loop_start_sample = read_32bitBE(0x02,streamFile)*0x400*2; + vgmstream->loop_end_sample = read_32bitBE(0x06,streamFile)*2; - /* 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->coding_type = coding_PCM8_SB; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x800; + 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); - return NULL; + close_vgmstream(vgmstream); + return NULL; } diff --git a/src/vgmstream.c b/src/vgmstream.c index 909f234d..088ea5b6 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1054,10 +1054,10 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_PCM16BE: case coding_PCM16_int: case coding_PCM8: - case coding_PCM8_U: case coding_PCM8_int: - case coding_PCM8_SB_int: + case coding_PCM8_U: case coding_PCM8_U_int: + case coding_PCM8_SB: case coding_ULAW: case coding_ULAW_int: case coding_ALAW: @@ -1238,10 +1238,10 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_PCM16_int: return 0x02; case coding_PCM8: - case coding_PCM8_U: case coding_PCM8_int: - case coding_PCM8_SB_int: + case coding_PCM8_U: case coding_PCM8_U_int: + case coding_PCM8_SB: case coding_ULAW: case coding_ULAW_int: case coding_ALAW: @@ -1446,16 +1446,17 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to chan, vgmstream->interleave_block_size); } break; + case coding_PCM16LE: for (chan=0;chanchannels;chan++) { - decode_pcm16LE(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + decode_pcm16le(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, vgmstream->channels,vgmstream->samples_into_block, samples_to_do); } break; case coding_PCM16BE: for (chan=0;chanchannels;chan++) { - decode_pcm16BE(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + decode_pcm16be(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, vgmstream->channels,vgmstream->samples_into_block, samples_to_do); } @@ -1475,13 +1476,6 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do); } break; - case coding_PCM8_U: - for (chan=0;chanchannels;chan++) { - decode_pcm8_unsigned(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); - } - break; case coding_PCM8_int: for (chan=0;chanchannels;chan++) { decode_pcm8_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, @@ -1489,9 +1483,9 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do); } break; - case coding_PCM8_SB_int: + case coding_PCM8_U: for (chan=0;chanchannels;chan++) { - decode_pcm8_sb_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + decode_pcm8_unsigned(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, vgmstream->channels,vgmstream->samples_into_block, samples_to_do); } @@ -1503,6 +1497,14 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do); } break; + case coding_PCM8_SB: + for (chan=0;chanchannels;chan++) { + decode_pcm8_sb(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; + case coding_ULAW: for (chan=0;chanchannels;chan++) { decode_ulaw(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, diff --git a/src/vgmstream.h b/src/vgmstream.h index 83661b73..a46230b4 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -77,7 +77,7 @@ typedef enum { coding_PCM8_int, /* 8-bit PCM with sample-level interleave (for blocks) */ coding_PCM8_U, /* 8-bit PCM, unsigned (0x80 = 0) */ coding_PCM8_U_int, /* 8-bit PCM, unsigned (0x80 = 0) with sample-level interleave (for blocks) */ - coding_PCM8_SB_int, /* 8-bit PCM, sign bit (others are 2's complement) with sample-level interleave (for blocks) */ + coding_PCM8_SB, /* 8-bit PCM, sign bit (others are 2's complement) */ coding_ULAW, /* 8-bit u-Law (non-linear PCM) */ coding_ULAW_int, /* 8-bit u-Law (non-linear PCM) with sample-level interleave (for blocks) */ From d94485e89ebe3db701b879998bc404d31b73852b Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 17:07:33 +0200 Subject: [PATCH 48/55] Minor decode_vgmstream cleanup --- src/coding/coding.h | 2 +- src/coding/mtaf_decoder.c | 2 +- src/vgmstream.c | 589 ++++++++++++++++---------------------- 3 files changed, 249 insertions(+), 344 deletions(-) diff --git a/src/coding/coding.h b/src/coding/coding.h index 014f4bb8..3fa15733 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -144,7 +144,7 @@ void decode_SASSC(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing void decode_lsf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); /* mtaf_decoder */ -void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int channels); +void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); /* mta2_decoder */ void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); diff --git a/src/coding/mtaf_decoder.c b/src/coding/mtaf_decoder.c index 642aa34d..322cd0d1 100644 --- a/src/coding/mtaf_decoder.c +++ b/src/coding/mtaf_decoder.c @@ -125,7 +125,7 @@ static void mtaf_block_update(VGMSTREAMCHANNEL * stream) { } #endif -void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int channels) { +void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { int32_t sample_count; int i; int c = channel%2; /* global channel to track channel */ diff --git a/src/vgmstream.c b/src/vgmstream.c index 088ea5b6..26881749 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1391,457 +1391,397 @@ int get_vgmstream_shortframe_size(VGMSTREAM * vgmstream) { /* Decode samples into the buffer. Assume that we have written samples_written into the * buffer already, and we have samples_to_do consecutive samples ahead of us. */ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to_do, sample * buffer) { - int chan; + int ch; switch (vgmstream->coding_type) { case coding_CRI_ADX: - for (chan=0;chanchannels;chan++) { - decode_adx(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_adx(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, vgmstream->interleave_block_size); } break; case coding_CRI_ADX_exp: - for (chan=0;chanchannels;chan++) { - decode_adx_exp(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_adx_exp(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, vgmstream->interleave_block_size); } break; case coding_CRI_ADX_fixed: - for (chan=0;chanchannels;chan++) { - decode_adx_fixed(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_adx_fixed(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, vgmstream->interleave_block_size); } break; case coding_CRI_ADX_enc_8: case coding_CRI_ADX_enc_9: - for (chan=0;chanchannels;chan++) { - decode_adx_enc(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_adx_enc(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, vgmstream->interleave_block_size); } break; case coding_NGC_DSP: - for (chan=0;chanchannels;chan++) { - decode_ngc_dsp(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ngc_dsp(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_NGC_DSP_subint: - for (chan=0;chanchannels;chan++) { - decode_ngc_dsp_subint(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, - chan, vgmstream->interleave_block_size); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ngc_dsp_subint(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, + ch, vgmstream->interleave_block_size); } break; case coding_PCM16LE: - for (chan=0;chanchannels;chan++) { - decode_pcm16le(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_pcm16le(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_PCM16BE: - for (chan=0;chanchannels;chan++) { - decode_pcm16be(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_pcm16be(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_PCM16_int: - for (chan=0;chanchannels;chan++) { - decode_pcm16_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_pcm16_int(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, vgmstream->codec_endian); } break; case coding_PCM8: - for (chan=0;chanchannels;chan++) { - decode_pcm8(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_pcm8(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_PCM8_int: - for (chan=0;chanchannels;chan++) { - decode_pcm8_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_pcm8_int(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_PCM8_U: - for (chan=0;chanchannels;chan++) { - decode_pcm8_unsigned(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_pcm8_unsigned(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_PCM8_U_int: - for (chan=0;chanchannels;chan++) { - decode_pcm8_unsigned_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_pcm8_unsigned_int(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_PCM8_SB: - for (chan=0;chanchannels;chan++) { - decode_pcm8_sb(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_pcm8_sb(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_ULAW: - for (chan=0;chanchannels;chan++) { - decode_ulaw(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ulaw(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_ULAW_int: - for (chan=0;chanchannels;chan++) { - decode_ulaw_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ulaw_int(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_ALAW: - for (chan=0;chanchannels;chan++) { - decode_alaw(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_alaw(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_PCMFLOAT: - for (chan=0;chanchannels;chan++) { - decode_pcmfloat(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_pcmfloat(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, vgmstream->codec_endian); } break; case coding_NDS_IMA: - for (chan=0;chanchannels;chan++) { - decode_nds_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_nds_ima(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_DAT4_IMA: - for (chan=0;chanchannels;chan++) { - decode_dat4_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_dat4_ima(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_XBOX_IMA: - for (chan=0;chanchannels;chan++) { - decode_xbox_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_xbox_ima(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_XBOX_IMA_mch: - for (chan=0;chanchannels;chan++) { - decode_xbox_ima_mch(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_xbox_ima_mch(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_XBOX_IMA_int: - for (chan=0;chanchannels;chan++) { - decode_xbox_ima_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_xbox_ima_int(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_MS_IMA: - for (chan=0;chanchannels;chan++) { - decode_ms_ima(vgmstream,&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ms_ima(vgmstream,&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_RAD_IMA: - for (chan=0;chanchannels;chan++) { - decode_rad_ima(vgmstream,&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_rad_ima(vgmstream,&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_RAD_IMA_mono: - for (chan=0;chanchannels;chan++) { - decode_rad_ima_mono(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_rad_ima_mono(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_NGC_DTK: - for (chan=0;chanchannels;chan++) { - decode_ngc_dtk(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ngc_dtk(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_G721: - for (chan=0;chanchannels;chan++) { - decode_g721(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_g721(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_NGC_AFC: - for (chan=0;chanchannels;chan++) { - decode_ngc_afc(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ngc_afc(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_PSX: - for (chan=0;chanchannels;chan++) { - decode_psx(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, 0); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_psx(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, 0); } break; case coding_PSX_badflags: - for (chan=0;chanchannels;chan++) { - decode_psx(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, 1); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_psx(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, 1); } break; case coding_PSX_cfg: - for (chan=0;chanchannels;chan++) { - decode_psx_configurable(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, vgmstream->interleave_block_size); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_psx_configurable(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, vgmstream->interleave_block_size); } break; case coding_HEVAG: - for (chan=0;chanchannels;chan++) { - decode_hevag(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_hevag(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_XA: - for (chan=0;chanchannels;chan++) { - decode_xa(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_xa(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_EA_XA: - for (chan=0;chanchannels;chan++) { - decode_ea_xa(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ea_xa(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_EA_XA_int: - for (chan=0;chanchannels;chan++) { - decode_ea_xa_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ea_xa_int(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_EA_XA_V2: - for (chan=0;chanchannels;chan++) { - decode_ea_xa_v2(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ea_xa_v2(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_MAXIS_XA: - for (chan=0;chanchannels;chan++) { - decode_maxis_xa(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_maxis_xa(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_EA_XAS: - for (chan=0;chanchannels;chan++) { - decode_ea_xas(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ea_xas(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; #ifdef VGM_USE_VORBIS case coding_OGG_VORBIS: - decode_ogg_vorbis(vgmstream->codec_data, - buffer+samples_written*vgmstream->channels,samples_to_do, - vgmstream->channels); + decode_ogg_vorbis(vgmstream->codec_data, buffer+samples_written*vgmstream->channels, + samples_to_do,vgmstream->channels); break; case coding_VORBIS_custom: - decode_vorbis_custom(vgmstream, - buffer+samples_written*vgmstream->channels,samples_to_do, - vgmstream->channels); + decode_vorbis_custom(vgmstream, buffer+samples_written*vgmstream->channels, + samples_to_do,vgmstream->channels); break; #endif case coding_CRI_HCA: - decode_hca(vgmstream->codec_data, - buffer+samples_written*vgmstream->channels,samples_to_do, - vgmstream->channels); + decode_hca(vgmstream->codec_data, buffer+samples_written*vgmstream->channels, + samples_to_do,vgmstream->channels); break; #ifdef VGM_USE_FFMPEG case coding_FFmpeg: decode_ffmpeg(vgmstream, - buffer+samples_written*vgmstream->channels, - samples_to_do, - vgmstream->channels); + buffer+samples_written*vgmstream->channels,samples_to_do,vgmstream->channels); break; #endif #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) case coding_MP4_AAC: - decode_mp4_aac(vgmstream->codec_data, - buffer+samples_written*vgmstream->channels,samples_to_do, - vgmstream->channels); + decode_mp4_aac(vgmstream->codec_data, buffer+samples_written*vgmstream->channels, + samples_to_do,vgmstream->channels); break; #endif case coding_SDX2: - for (chan=0;chanchannels;chan++) { - decode_sdx2(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_sdx2(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_SDX2_int: - for (chan=0;chanchannels;chan++) { - decode_sdx2_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_sdx2_int(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_CBD2: - for (chan=0;chanchannels;chan++) { - decode_cbd2(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_cbd2(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_CBD2_int: - for (chan=0;chanchannels;chan++) { - decode_cbd2_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_cbd2_int(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_IMA: case coding_IMA_int: case coding_DVI_IMA: case coding_DVI_IMA_int: - for (chan=0;chanchannels;chan++) { + for (ch = 0; ch < vgmstream->channels; ch++) { int is_stereo = (vgmstream->channels > 1 && vgmstream->coding_type == coding_IMA) || (vgmstream->channels > 1 && vgmstream->coding_type == coding_DVI_IMA); int is_high_first = vgmstream->coding_type == coding_DVI_IMA || vgmstream->coding_type == coding_DVI_IMA_int; - decode_standard_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, chan, is_stereo, is_high_first); + decode_standard_ima(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch, + is_stereo, is_high_first); } break; case coding_3DS_IMA: - for (chan=0;chanchannels;chan++) { - decode_3ds_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_3ds_ima(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_WV6_IMA: - for (chan=0;chanchannels;chan++) { - decode_wv6_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_wv6_ima(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_APPLE_IMA4: - for (chan=0;chanchannels;chan++) { - decode_apple_ima4(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_apple_ima4(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_SNDS_IMA: - for (chan=0;chanchannels;chan++) { - decode_snds_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_snds_ima(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_OTNS_IMA: - for (chan=0;chanchannels;chan++) { - decode_otns_ima(vgmstream, &vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_otns_ima(vgmstream, &vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_FSB_IMA: - for (chan=0;chanchannels;chan++) { - decode_fsb_ima(vgmstream, &vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_fsb_ima(vgmstream, &vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_WWISE_IMA: - for (chan=0;chanchannels;chan++) { - decode_wwise_ima(vgmstream,&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_wwise_ima(vgmstream,&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_REF_IMA: - for (chan=0;chanchannels;chan++) { - decode_ref_ima(vgmstream,&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ref_ima(vgmstream,&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_AWC_IMA: - for (chan=0;chanchannels;chan++) { - decode_awc_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_awc_ima(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_UBI_IMA: - for (chan=0;chanchannels;chan++) { - decode_ubi_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ubi_ima(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_H4M_IMA: - for (chan=0;chanchannels;chan++) { + for (ch = 0; ch < vgmstream->channels; ch++) { uint16_t frame_format = (uint16_t)((vgmstream->codec_config >> 8) & 0xFFFF); - decode_h4m_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, chan, frame_format); + decode_h4m_ima(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch, + frame_format); } break; case coding_WS: - for (chan=0;chanchannels;chan++) { - decode_ws(vgmstream,chan,buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ws(vgmstream,ch,buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; @@ -1851,194 +1791,159 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to case coding_MPEG_layer1: case coding_MPEG_layer2: case coding_MPEG_layer3: - decode_mpeg( - vgmstream, - buffer+samples_written*vgmstream->channels, - samples_to_do, - vgmstream->channels); + decode_mpeg(vgmstream,buffer+samples_written*vgmstream->channels, + samples_to_do,vgmstream->channels); break; #endif #ifdef VGM_USE_G7221 case coding_G7221: case coding_G7221C: - for (chan=0;chanchannels;chan++) { - decode_g7221(vgmstream, - buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels, - samples_to_do, - chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_g7221(vgmstream, buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,samples_to_do, ch); } break; #endif #ifdef VGM_USE_G719 case coding_G719: - for (chan=0;chanchannels;chan++) { - decode_g719(vgmstream, - buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels, - samples_to_do, - chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_g719(vgmstream, buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,samples_to_do, ch); } break; #endif #ifdef VGM_USE_MAIATRAC3PLUS case coding_AT3plus: - for (chan=0;chanchannels;chan++) { - decode_at3plus(vgmstream, - buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels, - samples_to_do, - chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_at3plus(vgmstream, buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,samples_to_do, ch); } break; #endif #ifdef VGM_USE_ATRAC9 case coding_ATRAC9: - decode_atrac9(vgmstream, - buffer+samples_written*vgmstream->channels, - samples_to_do, - vgmstream->channels); + decode_atrac9(vgmstream, buffer+samples_written*vgmstream->channels, + samples_to_do,vgmstream->channels); break; #endif #ifdef VGM_USE_CELT case coding_CELT_FSB: - decode_celt_fsb(vgmstream, - buffer+samples_written*vgmstream->channels, - samples_to_do, - vgmstream->channels); + decode_celt_fsb(vgmstream, buffer+samples_written*vgmstream->channels, + samples_to_do,vgmstream->channels); break; #endif case coding_ACM: - decode_acm(vgmstream->codec_data, - buffer+samples_written*vgmstream->channels, + decode_acm(vgmstream->codec_data, buffer+samples_written*vgmstream->channels, samples_to_do, vgmstream->channels); break; case coding_NWA: decode_nwa(((nwa_codec_data*)vgmstream->codec_data)->nwa, - buffer+samples_written*vgmstream->channels, - samples_to_do - ); + buffer+samples_written*vgmstream->channels, samples_to_do); break; case coding_MSADPCM: if (vgmstream->channels == 2) { decode_msadpcm_stereo(vgmstream,buffer+samples_written*vgmstream->channels, - vgmstream->samples_into_block, - samples_to_do); + vgmstream->samples_into_block,samples_to_do); } else if (vgmstream->channels == 1) { decode_msadpcm_mono(vgmstream,buffer+samples_written*vgmstream->channels, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,0); + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, 0); } break; case coding_MSADPCM_ck: - for (chan=0;chanchannels;chan++) { - decode_msadpcm_ck(vgmstream,buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_msadpcm_ck(vgmstream,buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_AICA: case coding_AICA_int: - for (chan=0;chanchannels;chan++) { + for (ch = 0; ch < vgmstream->channels; ch++) { int is_stereo = (vgmstream->channels > 1 && vgmstream->coding_type == coding_AICA); - decode_aica(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, chan, is_stereo); + decode_aica(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch, + is_stereo); } break; case coding_YAMAHA: - for (chan=0;chanchannels;chan++) { - decode_yamaha(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_yamaha(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); } break; case coding_YAMAHA_NXAP: - for (chan=0;chanchannels;chan++) { - decode_yamaha_nxap(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_yamaha_nxap(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_NDS_PROCYON: - for (chan=0;chanchannels;chan++) { - decode_nds_procyon(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_nds_procyon(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_L5_555: - for (chan=0;chanchannels;chan++) { - decode_l5_555(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_l5_555(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } - break; case coding_SASSC: - for (chan=0;chanchannels;chan++) { - decode_SASSC(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_SASSC(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_LSF: - for (chan=0;chanchannels;chan++) { - decode_lsf(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_lsf(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_MTAF: - for (chan=0;chanchannels;chan++) { - decode_mtaf(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels, vgmstream->samples_into_block, samples_to_do, - chan, vgmstream->channels); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_mtaf(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_MTA2: - for (chan=0;chanchannels;chan++) { - decode_mta2(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels, vgmstream->samples_into_block, samples_to_do, - chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_mta2(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_MC3: - for (chan=0;chanchannels;chan++) { - decode_mc3(vgmstream, &vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels, vgmstream->samples_into_block, samples_to_do, - chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_mc3(vgmstream, &vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; case coding_FADPCM: - for (chan=0;chanchannels;chan++) { - decode_fadpcm(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_fadpcm(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_ASF: - for (chan=0;chanchannels;chan++) { - decode_asf(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_asf(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do); } break; case coding_XMD: - for (chan=0;chanchannels;chan++) { - decode_xmd(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do, vgmstream->interleave_block_size); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_xmd(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, + vgmstream->interleave_block_size); } break; case coding_EA_MT: - for (chan=0;chanchannels;chan++) { - decode_ea_mt(vgmstream, buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels, vgmstream->samples_into_block, samples_to_do, - chan); + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_ea_mt(vgmstream, buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch); } break; default: From f2a5b5954f23f714b276668fb3961802f3e2be3c Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 17:40:40 +0200 Subject: [PATCH 49/55] Move wsi to its own file, since it's not very standard --- src/layout/blocked_wsi.c | 11 ++++ src/libvgmstream.vcproj | 12 ++-- src/libvgmstream.vcxproj | 1 + src/libvgmstream.vcxproj.filters | 3 + src/meta/ngc_dsp_std.c | 107 +------------------------------ src/meta/wsi.c | 83 ++++++++++++++++++++++++ 6 files changed, 109 insertions(+), 108 deletions(-) create mode 100644 src/meta/wsi.c diff --git a/src/layout/blocked_wsi.c b/src/layout/blocked_wsi.c index 572c6cc1..6be576fb 100644 --- a/src/layout/blocked_wsi.c +++ b/src/layout/blocked_wsi.c @@ -6,6 +6,7 @@ void block_update_wsi(off_t block_offset, VGMSTREAM * vgmstream) { STREAMFILE* streamFile = vgmstream->ch[0].streamfile; int i; off_t channel_block_size; + //int is_first_offset = /* assume that all channels have the same size for this block */ @@ -18,4 +19,14 @@ void block_update_wsi(off_t block_offset, VGMSTREAM * vgmstream) { for (i = 0; i < vgmstream->channels; i++) { vgmstream->ch[i].offset = block_offset + channel_block_size*i + 0x10; } + + /* first block has DSP header, remove */ + if (block_offset == vgmstream->ch[0].channel_start_offset) { + int i; + + vgmstream->current_block_size -= 0x60; + for (i = 0; i < vgmstream->channels; i++) { + vgmstream->ch[i].offset += 0x60; + } + } } diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index a5a403ff..1cb402a7 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -1442,10 +1442,14 @@ RelativePath=".\meta\wpd.c" > - - + + + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index c9c90487..4f0e8ff1 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -437,6 +437,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index f8443edf..5a742d03 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -883,6 +883,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files diff --git a/src/meta/ngc_dsp_std.c b/src/meta/ngc_dsp_std.c index b3ee0110..0f636fa2 100644 --- a/src/meta/ngc_dsp_std.c +++ b/src/meta/ngc_dsp_std.c @@ -93,9 +93,9 @@ static int dsp_load_header_endian(struct dsp_header* ch_header, int channels, ST fail: return 0; } -static int dsp_load_header(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) { - return dsp_load_header_endian(ch_header, channels, streamFile, offset, spacing, 1); -} +//static int dsp_load_header(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) { +// return dsp_load_header_endian(ch_header, channels, streamFile, offset, spacing, 1); +//} //static int dsp_load_header_le(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) { // return dsp_load_header_endian(ch_header, channels, streamFile, offset, spacing, 0); //} @@ -715,107 +715,6 @@ fail: return NULL; } -#define WSI_MAX_CHANNELS 2 -/* .wsi - blocked dsp [Alone in the Dark (Wii)] */ -VGMSTREAM * init_vgmstream_wsi(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - off_t start_offset, header_offset; - size_t header_spacing; - struct dsp_header ch_header[WSI_MAX_CHANNELS]; - int channel_count; - - /* checks */ - if (!check_extensions(streamFile, "wsi")) - goto fail; - - /* I don't know if this is actually the channel count, or a block type - * for the first block. Won't know until I see a mono .wsi */ - channel_count = read_32bitBE(0x04,streamFile); - if (channel_count != 2) goto fail; - - /* check for consistent block headers */ - { - off_t block_offset; - off_t block_size_has_been; - int i; - - block_offset = read_32bitBE(0x00,streamFile); - if (block_offset < 0x08) goto fail; - - block_size_has_been = block_offset; - - /* check 4 blocks, to get an idea */ - for (i = 0; i < 4*channel_count; i++) { - off_t block_size = read_32bitBE(block_offset,streamFile); - - if (block_size < 0x10) - goto fail; /* expect at least the block header */ - if (i%channel_count+1 != read_32bitBE(block_offset+0x08,streamFile)) - goto fail; /* expect the channel numbers to alternate */ - - if (i%channel_count==0) - block_size_has_been = block_size; - else if (block_size != block_size_has_been) - goto fail; /* expect every block in a set of channels to have the same size */ - - block_offset += block_size; - } - } - - start_offset = read_32bitBE(0x00, streamFile); - header_offset = start_offset + 0x10; - header_spacing = read_32bitBE(start_offset,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 / 14 * 14; /* remove incomplete last frame */ - 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; - if (vgmstream->loop_end_sample > vgmstream->num_samples) /* don't know why, but it does happen*/ - vgmstream->loop_end_sample = vgmstream->num_samples; - - vgmstream->meta_type = meta_DSP_WSI; - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_blocked_wsi; - - setup_vgmstream_dsp(vgmstream, ch_header); - - - if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) - goto fail; - - block_update_wsi(start_offset,vgmstream); - - /* first block has DSP header */ - { - int i; - - vgmstream->current_block_size -= 0x60; - for (i = 0; i < vgmstream->channels; i++) { - vgmstream->ch[i].offset += 0x60; - } - } - - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} - - /* SWD - PSF chunks + interleaved dsps [Conflict: Desert Storm 1 & 2] */ VGMSTREAM * init_vgmstream_ngc_swd(STREAMFILE *streamFile) { dsp_meta dspm = {0}; diff --git a/src/meta/wsi.c b/src/meta/wsi.c new file mode 100644 index 00000000..3f02260d --- /dev/null +++ b/src/meta/wsi.c @@ -0,0 +1,83 @@ +#include "meta.h" +#include "../coding/coding.h" + + +/* .wsi - blocked dsp [Alone in the Dark (Wii)] */ +VGMSTREAM * init_vgmstream_wsi(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset, header_offset; + size_t header_spacing; + int loop_flag, channel_count; + + + /* checks */ + if (!check_extensions(streamFile, "wsi")) + goto fail; + + channel_count = read_32bitBE(0x04,streamFile); + if (channel_count != 2) goto fail; /* assumed */ + + /* check for consistent block headers */ + { + off_t block_offset; + off_t block_size_has_been; + int i; + + block_offset = read_32bitBE(0x00,streamFile); + if (block_offset < 0x08) goto fail; + + block_size_has_been = block_offset; + + /* check 4 blocks, to get an idea */ + for (i = 0; i < 4*channel_count; i++) { + off_t block_size = read_32bitBE(block_offset,streamFile); + + if (block_size < 0x10) + goto fail; /* expect at least the block header */ + if (i%channel_count+1 != read_32bitBE(block_offset+0x08,streamFile)) + goto fail; /* expect the channel numbers to alternate */ + + if (i%channel_count==0) + block_size_has_been = block_size; + else if (block_size != block_size_has_been) + goto fail; /* expect every block in a set of channels to have the same size */ + + block_offset += block_size; + } + } + + start_offset = read_32bitBE(0x00, streamFile); + header_offset = start_offset + 0x10; + header_spacing = read_32bitBE(start_offset,streamFile); + + /* contains standard DSP header, but since it's blocked validations (start/loop ps, etc) + * will fail, so no point to handle as standard DSP */ + loop_flag = read_16bitBE(header_offset+0x0c,streamFile); + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_DSP_WSI; + vgmstream->sample_rate = read_32bitBE(header_offset+0x08,streamFile); + + vgmstream->num_samples = read_32bitBE(header_offset+0x00,streamFile) / 14 * 14; /* remove incomplete last frame */ + vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bitBE(header_offset+0x10,streamFile)); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(read_32bitBE(header_offset+0x14,streamFile))+1; + if (vgmstream->loop_end_sample > vgmstream->num_samples) /* ? */ + vgmstream->loop_end_sample = vgmstream->num_samples; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_blocked_wsi; + dsp_read_coefs_be(vgmstream, streamFile, header_offset+0x1c, header_spacing); + dsp_read_hist_be(vgmstream, streamFile, header_offset+0x40, header_spacing); + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} From ce6722181acae79a42b357087926cbeb4e63c0be Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 18:55:57 +0200 Subject: [PATCH 50/55] Move csmp to its own file, since it's not very standard either --- src/libvgmstream.vcproj | 4 ++ src/libvgmstream.vcxproj | 2 +- src/libvgmstream.vcxproj.filters | 2 +- src/meta/csmp.c | 56 +++++++++++++++++ src/meta/meta.h | 2 +- src/meta/ngc_dsp_std.c | 100 ------------------------------- src/vgmstream.c | 2 +- 7 files changed, 64 insertions(+), 104 deletions(-) create mode 100644 src/meta/csmp.c diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 1cb402a7..f06a644e 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -383,6 +383,10 @@ + + - + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 5a742d03..15da5f8c 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -229,7 +229,7 @@ meta\Source Files - + meta\Source Files diff --git a/src/meta/csmp.c b/src/meta/csmp.c new file mode 100644 index 00000000..52a55060 --- /dev/null +++ b/src/meta/csmp.c @@ -0,0 +1,56 @@ +#include "meta.h" +#include "../coding/coding.h" + + +/* CSMP - Retro Studios sample [Metroid Prime 3 (Wii), Donkey Kong Country Returns (Wii)] */ +VGMSTREAM * init_vgmstream_csmp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset, first_offset = 0x08, chunk_offset; + int loop_flag, channel_count; + + + /* checks */ + if (!check_extensions(streamFile, "csmp")) + goto fail; + if (read_32bitBE(0x00, streamFile) != 0x43534D50) /* "CSMP" */ + goto fail; + if (read_32bitBE(0x04, streamFile) != 1) /* version? */ + goto fail; + + if (!find_chunk(streamFile, 0x44415441,first_offset,0, &chunk_offset,NULL, 1, 0)) /*"DATA"*/ + goto fail; + + /* contains standard DSP header, but somehow some validations (start/loop ps) + * don't seem to work, so no point to handle as standard DSP */ + + channel_count = 1; + loop_flag = read_16bitBE(chunk_offset+0x0c,streamFile); + start_offset = chunk_offset + 0x60; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_DSP_CSMP; + vgmstream->sample_rate = read_32bitBE(chunk_offset+0x08,streamFile); + vgmstream->num_samples = read_32bitBE(chunk_offset+0x00,streamFile); + vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bitBE(chunk_offset+0x10,streamFile)); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(read_32bitBE(chunk_offset+0x14,streamFile))+1; + if (vgmstream->loop_end_sample > vgmstream->num_samples) /* ? */ + vgmstream->loop_end_sample = vgmstream->num_samples; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_none; + dsp_read_coefs_be(vgmstream, streamFile, chunk_offset+0x1c, 0x00); + dsp_read_hist_be(vgmstream, streamFile, chunk_offset+0x40, 0x00); + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + diff --git a/src/meta/meta.h b/src/meta/meta.h index 19c2376c..8f975680 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -35,7 +35,7 @@ VGMSTREAM * init_vgmstream_ngc_mpdsp(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_csmp(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ps2_ads_container(STREAMFILE *streamFile); diff --git a/src/meta/ngc_dsp_std.c b/src/meta/ngc_dsp_std.c index 0f636fa2..c7cf11f2 100644 --- a/src/meta/ngc_dsp_std.c +++ b/src/meta/ngc_dsp_std.c @@ -1063,106 +1063,6 @@ fail: return NULL; } -//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; - int chanel_count, i; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("csmp",filename_extension(filename))) goto fail; - - if (read_32bitBE(0x00, streamFile) != 0x43534D50) /* "CSMP" */ - goto fail; - if (read_32bitBE(0x04, streamFile) != 1) /* version? */ - goto fail; - - chanel_count = 1; - start_offset = 0x60; - - current_offset = 0x08; - tries = 0; - while (1) { - uint32_t chunk_id, chunk_size; - - if (tries > 4) - goto fail; - - 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; - } - - break; - } - - if (read_dsp_header(&header, current_offset, streamFile)) goto fail; - - - - /* check initial predictor/scale */ - /* Retro doesn't seem to abide by this */ - //if (header.initial_ps != (uint8_t)read_8bit(current_offset + start_offset,streamFile)) - // goto fail; - - /* check type==0 and gain==0 */ - if (header.format || header.gain) - goto fail; - - /* Retro doesn't seem to abide by this */ - /* check loop predictor/scale */ - if (header.loop_flag) { -// off_t loop_off = header.loop_start_offset/16*8; -// if (header.loop_ps != (uint8_t)read_8bit(current_offset + start_offset+loop_off,streamFile)) -// goto fail; - } - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(chanel_count,header.loop_flag); - if (!vgmstream) goto fail; - - vgmstream->sample_rate = header.sample_rate; - vgmstream->num_samples = header.sample_count; - 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) - vgmstream->loop_end_sample = vgmstream->num_samples; - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_none; - vgmstream->meta_type = meta_DSP_CSMP; - - /* coeffs */ - for (i=0;i<16;i++) - vgmstream->ch[0].adpcm_coef[i] = header.coef[i]; - 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; - - return vgmstream; - -fail: - close_vgmstream(vgmstream); - return NULL; -} - /* .mcadpcm - Custom header + full interleaved dsp [Skyrim (Switch)] */ VGMSTREAM * init_vgmstream_dsp_mcadpcm(STREAMFILE *streamFile) { dsp_meta dspm = {0}; diff --git a/src/vgmstream.c b/src/vgmstream.c index 26881749..622e38dc 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -32,7 +32,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ngc_dsp_std, init_vgmstream_ngc_dsp_std_le, init_vgmstream_ngc_mdsp_std, - init_vgmstream_ngc_dsp_csmp, + init_vgmstream_csmp, init_vgmstream_cstr, init_vgmstream_gcsw, init_vgmstream_ps2_ads, From cc537270c1f97faefaf3f854617bf2b5b22c7ca9 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 19:16:24 +0200 Subject: [PATCH 51/55] Add RFRM .csmp and cleanup [Donkey Kong Country Tropical Freeze (Wii U)] --- src/formats.c | 5 +-- src/libvgmstream.vcproj | 12 ++++--- src/libvgmstream.vcxproj | 1 + src/libvgmstream.vcxproj.filters | 3 ++ src/meta/agsc.c | 2 +- src/meta/csmp.c | 3 +- src/meta/meta.h | 2 ++ src/meta/rfrm.c | 60 ++++++++++++++++++++++++++++++++ src/meta/rs03.c | 8 ++--- src/vgmstream.c | 1 + src/vgmstream.h | 8 ++--- 11 files changed, 88 insertions(+), 17 deletions(-) create mode 100644 src/meta/rfrm.c diff --git a/src/formats.c b/src/formats.c index d40fb921..ea243db4 100644 --- a/src/formats.c +++ b/src/formats.c @@ -672,8 +672,9 @@ static const meta_info meta_info_list[] = { {meta_AIX, "CRI AIX header"}, {meta_AAX, "CRI AAX header"}, {meta_UTF_DSP, "CRI ADPCM_WII header"}, - {meta_DSP_AGSC, "Retro Studios AGSC header"}, - {meta_DSP_CSMP, "Retro Studios CSMP header"}, + {meta_AGSC, "Retro Studios AGSC header"}, + {meta_CSMP, "Retro Studios CSMP header"}, + {meta_RFRM, "Retro Studios RFRM header"}, {meta_NGC_ADPDTK, "Nintendo ADP raw header"}, {meta_RSF, "Retro Studios RSF raw header"}, {meta_AFC, "Nintendo AFC header"}, diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index f06a644e..e345af4e 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -1198,10 +1198,14 @@ RelativePath=".\meta\raw.c" > - - + + + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 8bcf4ea9..e6bfecd5 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -386,6 +386,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 15da5f8c..54567362 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -730,6 +730,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files diff --git a/src/meta/agsc.c b/src/meta/agsc.c index 72629315..e19922bc 100644 --- a/src/meta/agsc.c +++ b/src/meta/agsc.c @@ -42,7 +42,7 @@ VGMSTREAM * init_vgmstream_agsc(STREAMFILE *streamFile) { vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_none; - vgmstream->meta_type = meta_DSP_AGSC; + vgmstream->meta_type = meta_AGSC; vgmstream->allow_dual_stereo = 1; for (i=0;i<16;i++) { diff --git a/src/meta/csmp.c b/src/meta/csmp.c index 52a55060..30915b29 100644 --- a/src/meta/csmp.c +++ b/src/meta/csmp.c @@ -32,7 +32,7 @@ VGMSTREAM * init_vgmstream_csmp(STREAMFILE *streamFile) { vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - vgmstream->meta_type = meta_DSP_CSMP; + vgmstream->meta_type = meta_CSMP; vgmstream->sample_rate = read_32bitBE(chunk_offset+0x08,streamFile); vgmstream->num_samples = read_32bitBE(chunk_offset+0x00,streamFile); vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bitBE(chunk_offset+0x10,streamFile)); @@ -53,4 +53,3 @@ fail: close_vgmstream(vgmstream); return NULL; } - diff --git a/src/meta/meta.h b/src/meta/meta.h index 8f975680..ab24b8f9 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -37,6 +37,8 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_csmp(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_rfrm(STREAMFILE *streamFile); + VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ps2_ads_container(STREAMFILE *streamFile); diff --git a/src/meta/rfrm.c b/src/meta/rfrm.c new file mode 100644 index 00000000..44327a09 --- /dev/null +++ b/src/meta/rfrm.c @@ -0,0 +1,60 @@ +#include "meta.h" +#include "../coding/coding.h" + + +/* RFTM - Retro Studios format [Donkey Kong Country Tropical Freeze (WiiU)] */ +VGMSTREAM * init_vgmstream_rfrm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset, header_offset; + size_t interleave; + int loop_flag, channel_count; + + + /* checks */ + if (!check_extensions(streamFile, "csmp")) + goto fail; + + /* format uses weird-sized chunks, quick hack until I get enough files */ + + if (read_32bitBE(0x00, streamFile) != 0x5246524D) /* "RFRM" */ + goto fail; + if (read_32bitBE(0x14, streamFile) != 0x43534D50) /* "CSMP" */ + goto fail; + if (read_32bitBE(0x3d, streamFile) != 0x44415441) /* "DATA" */ + goto fail; + + channel_count = read_32bitBE(0x35, streamFile); + + header_offset = 0x58; + loop_flag = read_16bitBE(header_offset+0x0c,streamFile); + + start_offset = header_offset + 0x60; + interleave = (get_streamfile_size(streamFile) - header_offset) / channel_count; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_RFRM; + vgmstream->sample_rate = read_32bitBE(header_offset+0x08,streamFile); + vgmstream->num_samples = read_32bitBE(header_offset+0x00,streamFile); + vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bitBE(header_offset+0x10,streamFile)); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(read_32bitBE(header_offset+0x14,streamFile))+1; + if (vgmstream->loop_end_sample > vgmstream->num_samples) /* ? */ + vgmstream->loop_end_sample = vgmstream->num_samples; + + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + dsp_read_coefs_be(vgmstream, streamFile, header_offset+0x1c, interleave); + dsp_read_hist_be(vgmstream, streamFile, header_offset+0x40, interleave); + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/meta/rs03.c b/src/meta/rs03.c index 6244e2ea..127e783f 100644 --- a/src/meta/rs03.c +++ b/src/meta/rs03.c @@ -27,11 +27,11 @@ VGMSTREAM * init_vgmstream_rs03(STREAMFILE *streamFile) { vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - vgmstream->sample_rate = read_32bitBE(0xc,streamFile); - vgmstream->num_samples = read_32bitBE(8,streamFile); + vgmstream->sample_rate = read_32bitBE(0x0c,streamFile); + vgmstream->num_samples = read_32bitBE(0x08,streamFile); if (loop_flag) { - vgmstream->loop_start_sample = read_32bitBE(0x18,streamFile)/8*14; - vgmstream->loop_end_sample = read_32bitBE(0x1c,streamFile)/8*14; + vgmstream->loop_start_sample = dsp_bytes_to_samples(read_32bitBE(0x18,streamFile), 1); + vgmstream->loop_end_sample = dsp_bytes_to_samples(read_32bitBE(0x1c,streamFile), 1); } vgmstream->meta_type = meta_DSP_RS03; diff --git a/src/vgmstream.c b/src/vgmstream.c index 622e38dc..89e8558f 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -33,6 +33,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ngc_dsp_std_le, init_vgmstream_ngc_mdsp_std, init_vgmstream_csmp, + init_vgmstream_rfrm, init_vgmstream_cstr, init_vgmstream_gcsw, init_vgmstream_ps2_ads, diff --git a/src/vgmstream.h b/src/vgmstream.h index a46230b4..8f179508 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -268,13 +268,14 @@ typedef enum { /* The meta type specifies how we know what we know about the file. * We may know because of a header we read, some of it may have been guessed from filenames, etc. */ typedef enum { - /* DSP-specific */ + meta_DSP_STD, /* Nintendo standard GC ADPCM (DSP) header */ - meta_DSP_CSMP, /* Retro: Metroid Prime 3, Donkey Kong Country Returns */ meta_DSP_CSTR, /* Star Fox Assault "Cstr" */ meta_DSP_RS03, /* Retro: Metroid Prime 2 "RS03" */ meta_DSP_STM, /* Paper Mario 2 STM */ - meta_DSP_AGSC, /* Retro: Metroid Prime 2 title */ + meta_AGSC, /* Retro: Metroid Prime 2 title */ + meta_CSMP, /* Retro: Metroid Prime 3 (Wii), Donkey Kong Country Returns (Wii) */ + meta_RFRM, /* Retro: Donkey Kong Country Tropical Freeze (Wii U) */ meta_DSP_MPDSP, /* Monopoly Party single header stereo */ meta_DSP_JETTERS, /* Bomberman Jetters .dsp */ meta_DSP_MSS, /* Free Radical GC games */ @@ -289,7 +290,6 @@ typedef enum { meta_DSP_YGO, /* Konami: Yu-Gi-Oh! The Falsebound Kingdom (NGC), Hikaru no Go 3 (NGC) */ meta_DSP_SADF, /* Procyon Studio SADF - Xenoblade Chronicles 2 (Switch) */ - /* Nintendo */ meta_STRM, /* Nintendo STRM */ meta_RSTM, /* Nintendo RSTM (Revolution Stream, similar to STRM) */ meta_AFC, /* AFC */ From 751d5c5f0f6de4ee6f4a731f30b7a8f23349ab95 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 20:05:38 +0200 Subject: [PATCH 52/55] Clean DSP meta once again --- src/meta/ngc_dsp_std.c | 240 ++++++++++++++++------------------------- 1 file changed, 94 insertions(+), 146 deletions(-) diff --git a/src/meta/ngc_dsp_std.c b/src/meta/ngc_dsp_std.c index c7cf11f2..d00c1467 100644 --- a/src/meta/ngc_dsp_std.c +++ b/src/meta/ngc_dsp_std.c @@ -5,7 +5,6 @@ /* If these variables are packed properly in the struct (one after another) * then this is actually how they are laid out in the file, albeit big-endian */ - struct dsp_header { uint32_t sample_count; uint32_t nibble_count; @@ -66,180 +65,122 @@ static int read_dsp_header_le(struct dsp_header *header, off_t offset, STREAMFIL return read_dsp_header_endian(header, offset, file, 0); } - -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_endian(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing, int big_endian) { - int i; - - /* load standard dsp header per channel */ - for (i = 0; i < channels; i++) { - if (read_dsp_header_endian(&ch_header[i], offset + i*spacing, streamFile, big_endian)) - goto fail; - } - - return 1; -fail: - return 0; -} -//static int dsp_load_header(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) { -// return dsp_load_header_endian(ch_header, channels, streamFile, offset, spacing, 1); -//} -//static int dsp_load_header_le(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) { -// return dsp_load_header_endian(ch_header, channels, streamFile, offset, spacing, 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 interleave) { - int i; - - /* check initial predictor/scale */ - for (i = 0; i < channels; i++) { - off_t start_offset = offset + i*interleave; - if (ch_header[i].initial_ps != (uint8_t)read_8bit(start_offset, 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 interleave) { - 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; - if (interleave) { - loop_offset = loop_offset / 16 * 8; - loop_offset = (loop_offset / interleave * interleave * channels) + (loop_offset % interleave); - } - - if (ch_header[i].loop_ps != (uint8_t)read_8bit(offset + i*interleave + loop_offset,streamFile)) - goto fail; - } - - return 1; -fail: - return 0; -} - /* ********************************* */ -/* common parser config as most DSPs are basically the same with minor changes */ typedef struct { + /* basic config */ int little_endian; int channel_count; int max_channels; - int force_loop; /* force full loop */ - int fix_looping; /* fix loop end going past num_samples */ - int fix_loop_start; /* weird files with bad loop start */ - int single_header; /* all channels share header, thus totals are off */ - int ignore_header_agreement; /* sometimes there are minor differences between headers */ - int ignore_loop_check; /* loop info in header should match data, but sometimes it's weird */ //todo check if needed anymore - - off_t header_offset; - size_t header_spacing; - off_t start_offset; - size_t interleave; + off_t header_offset; /* standard DSP header */ + size_t header_spacing; /* distance between DSP header of other channels */ + off_t start_offset; /* data start */ + size_t interleave; /* distance between data of other channels */ meta_t meta_type; + + /* hacks */ + int force_loop; /* force full loop */ + int fix_looping; /* fix loop end going past num_samples */ + int fix_loop_start; /* weird files with bad loop start */ + int single_header; /* all channels share header, thus totals are off */ + int ignore_header_agreement; /* sometimes there are minor differences between headers */ } dsp_meta; #define COMMON_DSP_MAX_CHANNELS 6 + +/* Common parser for most DSPs that are basically the same with minor changes. + * Custom variants will just concatenate or interleave standard DSP headers and data, + * so we make sure to validate read vs expected values, based on dsp_meta config. */ static VGMSTREAM * init_vgmstream_dsp_common(STREAMFILE *streamFile, dsp_meta *dspm) { VGMSTREAM * vgmstream = NULL; + int i, j; int loop_flag; struct dsp_header ch_header[COMMON_DSP_MAX_CHANNELS]; + if (dspm->channel_count > dspm->max_channels) goto fail; if (dspm->channel_count > COMMON_DSP_MAX_CHANNELS) goto fail; - - /* read dsp */ - if (!dsp_load_header_endian(ch_header, dspm->channel_count, streamFile,dspm->header_offset,dspm->header_spacing, !dspm->little_endian)) - goto fail; - - if (dspm->fix_loop_start) { - int i; + /* load standard DSP header per channel */ + { + for (i = 0; i < dspm->channel_count; i++) { + if (read_dsp_header_endian(&ch_header[i], dspm->header_offset + i*dspm->header_spacing, streamFile, !dspm->little_endian)) + goto fail; + } + } + + /* fix bad/fixed value in loop start */ + if (dspm->fix_loop_start) { for (i = 0; i < dspm->channel_count; i++) { - /* bad/fixed value in loop start */ if (ch_header[i].loop_flag) ch_header[i].loop_start_offset = 0x00; } } - if (!check_dsp_format(ch_header, dspm->channel_count)) - goto fail; - - if (!dspm->ignore_header_agreement && !check_dsp_samples(ch_header, dspm->channel_count)) - goto fail; - - if (dspm->single_header && !check_dsp_initial_ps(ch_header, 1, streamFile,dspm->start_offset,dspm->interleave)) - goto fail; - if (!dspm->single_header && !check_dsp_initial_ps(ch_header, dspm->channel_count, streamFile,dspm->start_offset,dspm->interleave)) - goto fail; - - if (!dspm->ignore_loop_check) { - if (dspm->single_header && !check_dsp_loop_ps(ch_header, 1, streamFile,dspm->start_offset,dspm->interleave)) - goto fail; - if (!dspm->single_header && !check_dsp_loop_ps(ch_header, dspm->channel_count, streamFile,dspm->start_offset,dspm->interleave)) - goto fail; + /* check type==0 and gain==0 */ + { + for (i = 0; i < dspm->channel_count; i++) { + if (ch_header[i].format || ch_header[i].gain) + goto fail; + } } + /* check for agreement between channels */ + if (!dspm->ignore_header_agreement) { + for (i = 0; i < dspm->channel_count - 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; + } + } + } + + /* check expected initial predictor/scale */ + { + int channels = dspm->channel_count; + if (dspm->single_header) + channels = 1; + + for (i = 0; i < channels; i++) { + off_t channel_offset = dspm->start_offset + i*dspm->interleave; + if (ch_header[i].initial_ps != (uint8_t)read_8bit(channel_offset, streamFile)) + goto fail; + } + } + + /* check expected loop predictor/scale */ + if (ch_header[0].loop_flag) { + int channels = dspm->channel_count; + if (dspm->single_header) + channels = 1; + + for (i = 0; i < channels; i++) { + off_t loop_offset = ch_header[i].loop_start_offset; + if (dspm->interleave) { + loop_offset = loop_offset / 16 * 8; + loop_offset = (loop_offset / dspm->interleave * dspm->interleave * channels) + (loop_offset % dspm->interleave); + } + + if (ch_header[i].loop_ps != (uint8_t)read_8bit(dspm->start_offset + i*dspm->interleave + loop_offset,streamFile)) + goto fail; + } + } + + /* all done, must be DSP */ loop_flag = ch_header[0].loop_flag; if (dspm->force_loop) loop_flag = 1; + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(dspm->channel_count,loop_flag); if (!vgmstream) goto fail; @@ -258,7 +199,16 @@ static VGMSTREAM * init_vgmstream_dsp_common(STREAMFILE *streamFile, dsp_meta *d vgmstream->layout_type = layout_none; vgmstream->interleave_block_size = dspm->interleave; - setup_vgmstream_dsp(vgmstream, ch_header); + { + /* set coefs 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; + } + } /* don't know why, but it does happen*/ if (dspm->fix_looping && vgmstream->loop_end_sample > vgmstream->num_samples) @@ -291,7 +241,8 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) { int i, channel_count; /* checks */ - /* .dsp: standard, .adp: Dr. Muto/Battalion Wars (GC) mono files */ + /* .dsp: standard + * .adp: Dr. Muto/Battalion Wars (GC) mono files */ if (!check_extensions(streamFile, "dsp,adp")) goto fail; @@ -519,9 +470,7 @@ fail: return NULL; } - -/* Some very simple stereo variants of standard dsp just use the standard header - * twice and add interleave, or just concatenate the channels. We'll support them all here. */ +/* ********************************* */ /* .stm - Intelligent Systems + others (same programmers) full interleaved dsp [Paper Mario TTYD (GC), Fire Emblem: POR (GC), Cubivore (GC)] */ VGMSTREAM * init_vgmstream_ngc_dsp_stm(STREAMFILE *streamFile) { @@ -613,7 +562,6 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile) { goto fail; } - return init_vgmstream_dsp_common(streamFile, &dspm); fail: return NULL; From 0231d635ed2734781f6cd4e36cd35fc4fb624e52 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 22:36:36 +0200 Subject: [PATCH 53/55] Fix Next Level IDSP last interleave/jingles [Mario Strikers Charged] --- src/meta/idsp.c | 75 ------------------------------------------ src/meta/ngc_dsp_std.c | 50 ++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 77 deletions(-) diff --git a/src/meta/idsp.c b/src/meta/idsp.c index aa21bdc9..c1fdca92 100644 --- a/src/meta/idsp.c +++ b/src/meta/idsp.c @@ -92,81 +92,6 @@ fail: return NULL; } -/* IDSP - from Next Level games [Mario Strikers Charged (Wii)] */ -VGMSTREAM * init_vgmstream_idsp_nl(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - int loop_flag = 1; - int channel_count; - off_t start_offset; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("idsp",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x49445350) /* IDSP */ - goto fail; - - channel_count = read_32bitBE(0x24,streamFile); - - if (channel_count > 8) - goto fail; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - start_offset = (channel_count*0x60)+0xC; - vgmstream->sample_rate = read_32bitBE(0x14,streamFile); - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->num_samples = read_32bitBE(0x0C,streamFile); - if (loop_flag) { - vgmstream->loop_start_sample = 0; - vgmstream->loop_end_sample = (read_32bitBE(0x0C,streamFile)); - } - - vgmstream->interleave_block_size = read_32bitBE(0x04,streamFile); - vgmstream->interleave_last_block_size = ((vgmstream->num_samples/7*8)%(vgmstream->interleave_block_size)/vgmstream->channels); - vgmstream->layout_type = layout_interleave; - - vgmstream->meta_type = meta_IDSP_NL; - - if (vgmstream->coding_type == coding_NGC_DSP) { - int i; - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x28+i*2,streamFile); - } - if (vgmstream->channels) { - for (i=0;i<16;i++) { - vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x88+i*2,streamFile); - } - } - } - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - /* IDSP - from Inevitable Entertainment games [Defender (GC)] */ VGMSTREAM * init_vgmstream_idsp_ie(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; diff --git a/src/meta/ngc_dsp_std.c b/src/meta/ngc_dsp_std.c index d00c1467..7f1cdcdd 100644 --- a/src/meta/ngc_dsp_std.c +++ b/src/meta/ngc_dsp_std.c @@ -77,11 +77,13 @@ typedef struct { size_t header_spacing; /* distance between DSP header of other channels */ off_t start_offset; /* data start */ size_t interleave; /* distance between data of other channels */ + size_t interleave_last; /* same, in the last block */ meta_t meta_type; /* hacks */ int force_loop; /* force full loop */ + int force_loop_seconds; /* force loop, but must be longer than this (to catch jingles) */ int fix_looping; /* fix loop end going past num_samples */ int fix_loop_start; /* weird files with bad loop start */ int single_header; /* all channels share header, thus totals are off */ @@ -177,8 +179,13 @@ static VGMSTREAM * init_vgmstream_dsp_common(STREAMFILE *streamFile, dsp_meta *d /* all done, must be DSP */ loop_flag = ch_header[0].loop_flag; - if (dspm->force_loop) + if (!loop_flag && dspm->force_loop) { loop_flag = 1; + if (dspm->force_loop_seconds && + ch_header[0].sample_count < dspm->force_loop_seconds*ch_header[0].sample_rate) { + loop_flag = 0; + } + } /* build the VGMSTREAM */ @@ -198,6 +205,7 @@ static VGMSTREAM * init_vgmstream_dsp_common(STREAMFILE *streamFile, dsp_meta *d if (dspm->interleave == 0 || vgmstream->coding_type == coding_NGC_DSP_subint) vgmstream->layout_type = layout_none; vgmstream->interleave_block_size = dspm->interleave; + vgmstream->interleave_last_block_size = dspm->interleave_last; { /* set coefs and initial history (usually 0) */ @@ -747,6 +755,43 @@ fail: return NULL; } +/* IDSP - from Next Level games [Super Mario Strikers (GC), Mario Strikers: Charged (Wii)] */ +VGMSTREAM * init_vgmstream_idsp_nl(STREAMFILE *streamFile) { + dsp_meta dspm = {0}; + + /* checks */ + if (!check_extensions(streamFile, "idsp")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x49445350) /* "IDSP" */ + goto fail; + + dspm.channel_count = 2; + dspm.max_channels = 2; + + dspm.header_offset = 0x0c; + dspm.header_spacing = 0x60; + dspm.start_offset = dspm.header_offset + dspm.header_spacing*dspm.channel_count; + dspm.interleave = read_32bitBE(0x04,streamFile); + /* 0x08: usable channel size */ + { + size_t stream_size = get_streamfile_size(streamFile); + if (read_32bitBE(stream_size - 0x04,streamFile) == 0x30303030) + stream_size -= 0x14; /* remove padding */ + stream_size -= dspm.start_offset; + + dspm.interleave_last = (stream_size / dspm.channel_count) % dspm.interleave; + } + + dspm.fix_looping = 1; + dspm.force_loop = 1; + dspm.force_loop_seconds = 15; + + dspm.meta_type = meta_IDSP_NL; + return init_vgmstream_dsp_common(streamFile, &dspm); +fail: + return NULL; +} + /* .wsd - Custom header + full interleaved dsp [Phantom Brave (Wii)] */ VGMSTREAM * init_vgmstream_wii_wsd(STREAMFILE *streamFile) { dsp_meta dspm = {0}; @@ -889,7 +934,8 @@ fail: return NULL; } -/* Cabela's series (Magic Wand dev?) - header + interleaved dsp [Cabela's Big Game Hunt 2005 Adventures (GC), Cabela's Outdoor Adventures (GC)] */ +/* Cabela's series (Magic Wand dev?) - header + interleaved dsp + * [Cabela's Big Game Hunt 2005 Adventures (GC), Cabela's Outdoor Adventures (GC)] */ VGMSTREAM * init_vgmstream_dsp_cabelas(STREAMFILE *streamFile) { dsp_meta dspm = {0}; From bee3adc95b9f74c09fffc2ee9b062c84648071d4 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 22:37:04 +0200 Subject: [PATCH 54/55] Document SQEX SCD looping issues in MPEG --- src/meta/sqex_scd.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/meta/sqex_scd.c b/src/meta/sqex_scd.c index 406e26a1..900a32c8 100644 --- a/src/meta/sqex_scd.c +++ b/src/meta/sqex_scd.c @@ -257,11 +257,12 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) { vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data); vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data); - //todo find if this actually helps - vgmstream->num_samples -= vgmstream->num_samples%576; - vgmstream->loop_start_sample -= vgmstream->loop_start_sample%576; - vgmstream->loop_end_sample -= vgmstream->loop_end_sample%576; - + /* somehow loops offsets aren't always frame-aligned, and the code below supposedly helped, + * but there isn't much difference since MPEG loops are rough (1152-aligned). Seems it + * would help more loop_start - ~1000, loop_end + ~1000 (ex. FFXIII-2 music_SunMizu.ps3.scd) */ + //vgmstream->num_samples -= vgmstream->num_samples % 576; + //vgmstream->loop_start_sample -= vgmstream->loop_start_sample % 576; + //vgmstream->loop_end_sample -= vgmstream->loop_end_sample % 576; break; } #endif From f71e98a5ba05ac14a46a0375f1ab31efb8f0c049 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Aug 2018 22:56:31 +0200 Subject: [PATCH 55/55] Fix missing MSVC dependencies --- src/libvgmstream.vcxproj | 1 + src/libvgmstream.vcxproj.filters | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index e6bfecd5..13c4d011 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -213,6 +213,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 54567362..ea8d8e16 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -229,6 +229,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files