Merge pull request #930 from bnnm/log-etc

- Add log functions to show errors to user
- Allow TXTH codec strings in name_table
- Add .wve for EA SCHl [Madden NFL 99 (PC)]
- build tweaks
This commit is contained in:
bnnm 2021-08-27 00:46:29 +02:00 committed by GitHub
commit 4cda04d025
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 756 additions and 446 deletions

View File

@ -8,7 +8,7 @@ ifeq ($(VGMSTREAM_VERSION),)
else
VGMSTREAM_VERSION=$(VGMSTREAM_VERSION)
endif
DEF_CFLAGS += -DVGMSTREAM_VERSION_AUTO
DEF_CFLAGS += -DVGMSTREAM_VERSION_AUTO -DVGM_LOG_OUTPUT
###############################################################################
### external defs

View File

@ -248,13 +248,13 @@ loop info, or apply subtle fixes, but is also limited in some ways (like ignorin
standard tags). `.vgmstream` is a catch-all extension that may work as a last resort
to make a file playable.
Some plugins have options that allow common extensions to be played, making any
Some plugins have options that allow "*common extensions*" to be played, making any
renaming unnecessary. You may need to adjust plugin priority in player's options
first. Note that vgmstream also accepts certain extension-less files as-is too.
Similarly, vgmstream has a curated list of known extensions, that plugins may take
into account and ignore unknowns. Through *TXTH* you can make unknown files playable,
but you also need to either rename or set plugin options to allow "unknown extensions"
but you also need to either rename or set plugin options to allow "*unknown extensions*"
(or, preferably, report this new extension so it can be added to the known list).
It's also possible to make a .txtp file that opens files with those common/unknown
@ -356,9 +356,8 @@ the only option is renaming the companion extension to lowercase.
A particularly nasty variation of that is that some formats load files by full
name (e.g. `STREAM.SS0`), but sometimes the actual filename is in other case
(`Stream.ss0`), and some files could even point to that with yet another case.
You could try adding *symlinks* in various upper/lower/mixed cases to handle this.
Currently there isn't any way to know what exact name is needed (other than
hex-editting), though only a few formats do this, mainly *Ubisoft* banks.
You could try adding *symlinks* in various upper/lower/mixed cases to handle this,
though only a few formats do this, mainly *Ubisoft* banks.
Regular formats without companion files should work fine in upper/lowercase.
@ -514,6 +513,20 @@ You can also choose which channels to play using *TXTP*. For example, create
a file named `song.adx#C1,2.txtp` to play only channels 1 and 2 from `song.adx`.
*TXTP* also has command to set how files are downmixed.
### Logged errors and unplayable supported files
Some formats should normally play, but somehow don't. In those cases plugins
can print vgmstream's error info to console (for example, `.fsb` with an unknown
codec, `.hca/awb` with missing decryption key, bank has no audio, `.txth` is
malformed, or `.wav` has an incorrectly ripped size).
Console location and format depends on plugin:
- *foobar2000*: found in *View menu > Console*
- *Winamp*: open vgmstream's config (*Preferences... > Plug-ins > vgmstream* + *Configure*
button) then press "Open Log"
- *Audacious*: start with `audacious -V` from terminal
- CLI utils: printed to stdout directly
Only a few errors are printed ATM but may be helpful for more common cases.
## Tagging
Some of vgmstream's plugins support simple read-only tagging via external files.

View File

@ -6,7 +6,7 @@ inputplugindir = $(plugindir)/$(INPUT_PLUGIN_DIR)
inputplugin_LTLIBRARIES = libvgmstream.la
AM_MAKEFLAGS=-f Makefile.autotools
AM_CXXFLAGS = -DVGMSTREAM_VERSION_AUTO -Wall -std=c++11 -fpermissive -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/ext_includes/ $(AUDACIOUS_CFLAGS) $(GTK_CFLAGS)
AM_CXXFLAGS = -DVGMSTREAM_VERSION_AUTO -DVGM_LOG_OUTPUT -Wall -std=c++11 -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/ext_includes/ $(AUDACIOUS_CFLAGS) $(GTK_CFLAGS)
AM_LIBS =
# sources/headers are updated automatically by ./bootstrap script (not all headers are needed though)

View File

@ -133,18 +133,29 @@ bool VgmstreamPlugin::is_our_file(const char * filename, VFSFile & file) {
return vgmstream_ctx_is_valid(filename, &cfg) > 0 ? true : false;
}
/* default output in audacious is: "INFO/DEBUG plugin.cc:xxx [(fn name)]: (msg)" */
static void vgmstream_log(int level, const char* str) {
if (level == VGM_LOG_LEVEL_DEBUG)
AUDDBG("%s", str);
else
AUDINFO("%s", str);
}
// called on startup (main thread)
bool VgmstreamPlugin::init() {
AUDINFO("plugin start\n");
AUDINFO("vgmstream plugin start\n");
vgmstream_settings_load();
vgmstream_set_log_callback(VGM_LOG_LEVEL_ALL, (void*)&vgmstream_log);
return true;
}
// called on stop (main thread)
void VgmstreamPlugin::cleanup() {
AUDINFO("plugin end\n");
AUDINFO("vgmstream plugin end\n");
vgmstream_settings_save();
}

View File

@ -4,26 +4,19 @@
# gets all files and updates .am scripts to avoid having to do manually (frowned upon by automake, whatevs)
# maybe there is a better way or place for this
VGMSTREAM_SRCS=`(cd ./src/ && ls *.c) | tr '\n' ' '`
VGMSTREAM_HDRS=`(cd ./src/ && ls *.h) | tr '\n' ' '`
CODING_SRCS=`(cd ./src/coding/ && ls *.c) | tr '\n' ' '`
CODING_HDRS=`(cd ./src/coding/ && ls *.h) | tr '\n' ' '`
LAYOUT_SRCS=`(cd ./src/layout/ && ls *.c) | tr '\n' ' '`
LAYOUT_HDRS=`(cd ./src/layout/ && ls *.h) | tr '\n' ' '`
META_SRCS=`(cd ./src/meta/ && ls *.c) | tr '\n' ' '`
META_HDRS=`(cd ./src/meta/ && ls *.h) | tr '\n' ' '`
VGMSTREAM_SRCS=`(cd ./src/ && ls *.c coding/*.c layout/*.c meta/*.c util/*.c) | tr '\n' ' '`
VGMSTREAM_HDRS=`(cd ./src/ && ls *.h coding/*.h layout/*.h meta/*.h util/*.h) | tr '\n' ' '`
AUDACIOUS_SRCS=`(cd ./audacious/ && ls *.cc) | tr '\n' ' '`
AUDACIOUS_HDRS=`(cd ./audacious/ && ls *.h) | tr '\n' ' '`
sed -i -e "s/libvgmstream_la_SOURCES =.*/libvgmstream_la_SOURCES = $VGMSTREAM_SRCS/g" ./src/Makefile.autotools.am
sed -i -e "s/EXTRA_DIST =.*/EXTRA_DIST = $VGMSTREAM_HDRS/g" ./src/Makefile.autotools.am
sed -i -e "s/libcoding_la_SOURCES =.*/libcoding_la_SOURCES = $CODING_SRCS/g" ./src/coding/Makefile.autotools.am
sed -i -e "s/EXTRA_DIST =.*/EXTRA_DIST = $CODING_HDRS/g" ./src/coding/Makefile.autotools.am
sed -i -e "s/liblayout_la_SOURCES =.*/liblayout_la_SOURCES = $LAYOUT_SRCS/g" ./src/layout/Makefile.autotools.am
sed -i -e "s/EXTRA_DIST =.*/EXTRA_DIST = $LAYOUT_HDRS/g" ./src/layout/Makefile.autotools.am
sed -i -e "s/libmeta_la_SOURCES =.*/libmeta_la_SOURCES = $META_SRCS/g" ./src/meta/Makefile.autotools.am
sed -i -e "s/EXTRA_DIST =.*/EXTRA_DIST = $META_HDRS/g" ./src/meta/Makefile.autotools.am
sed -i -e "s/libvgmstream_la_SOURCES =.*/libvgmstream_la_SOURCES = $AUDACIOUS_SRCS/g" ./audacious/Makefile.autotools.am
sed -i -e "s/EXTRA_DIST =.*/EXTRA_DIST = $AUDACIOUS_HDRS/g" ./audacious/Makefile.autotools.am
# in case some distro sed doesn't support | separator and must use /, all slashes need to be escaped first
#VGMSTREAM_SRCS=$(echo "$VGMSTREAM_SRCS" | sed 's/\//\\\//g')
sed -i -e "s|libvgmstream_la_SOURCES =.*|libvgmstream_la_SOURCES = $VGMSTREAM_SRCS|g" ./src/Makefile.autotools.am
sed -i -e "s|EXTRA_DIST =.*|EXTRA_DIST = $VGMSTREAM_HDRS|g" ./src/Makefile.autotools.am
sed -i -e "s|libvgmstream_la_SOURCES =.*|libvgmstream_la_SOURCES = $AUDACIOUS_SRCS|g" ./audacious/Makefile.autotools.am
sed -i -e "s|EXTRA_DIST =.*|EXTRA_DIST = $AUDACIOUS_HDRS|g" ./audacious/Makefile.autotools.am
# make version to show in about dialogs
# again, not very pretty

View File

@ -3,6 +3,16 @@
add_executable(vgmstream_cli
vgmstream_cli.c)
if(WIN32)
set_target_properties(vgmstream_cli PROPERTIES
PREFIX ""
OUTPUT_NAME "test")
else()
set_target_properties(vgmstream_cli PROPERTIES
PREFIX ""
OUTPUT_NAME "vgmstream-cli")
endif()
# Link to the vgmstream library
target_link_libraries(vgmstream_cli libvgmstream)

View File

@ -6,7 +6,7 @@ if HAVE_LIBAO
bin_PROGRAMS += vgmstream123
endif
AM_CFLAGS = -DVGMSTREAM_VERSION_AUTO -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/ext_includes/ $(AO_CFLAGS)
AM_CFLAGS = -DVGMSTREAM_VERSION_AUTO -DVGM_LOG_OUTPUT -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/ext_includes/ $(AO_CFLAGS)
AM_MAKEFLAGS = -f Makefile.autotools
vgmstream_cli_SOURCES = vgmstream_cli.c

View File

@ -272,6 +272,8 @@ static int play_vgmstream(const char* filename, song_settings_t* cfg) {
return -1;
}
vgmstream_set_log_stdout(VGM_LOG_LEVEL_ALL);
sf->stream_index = cfg->stream_index;
vgmstream = init_vgmstream_from_STREAMFILE(sf);
close_streamfile(sf);

View File

@ -694,6 +694,8 @@ static int convert_file(cli_config* cfg) {
goto fail;
}
vgmstream_set_log_stdout(VGM_LOG_LEVEL_ALL);
sf->stream_index = cfg->subsong_index;
vgmstream = init_vgmstream_from_STREAMFILE(sf);
close_streamfile(sf);

View File

@ -24,6 +24,8 @@ macro(setup_target TARGET)
target_link_libraries(${TARGET} m)
endif()
target_compile_definitions(${TARGET} PRIVATE VGM_LOG_OUTPUT)
if(USE_MPEG)
target_compile_definitions(${TARGET} PRIVATE VGM_USE_MPEG)
if(WIN32)

View File

@ -88,9 +88,6 @@ AC_PATH_XTRA
AC_OUTPUT([
Makefile.autotools
src/Makefile.autotools
src/coding/Makefile.autotools
src/layout/Makefile.autotools
src/meta/Makefile.autotools
audacious/Makefile.autotools
cli/Makefile.autotools
])

View File

@ -117,10 +117,10 @@ All of these options are of type BOOL and can be set to either `ON` or `OFF`. Mo
- **USE_FFMPEG**: Chooses if you wish to use FFmpeg for support of many codecs. The default is `ON`. `FFMPEG_PATH` can also be given, so it can use official/external SDK instead of the one used in vgmstream project.
- **USE_MAIATRAC3PLUS**: Chooses if you wish to use MAIATRAC3+ for support of ATRAC3+. The default is `OFF`. It is not recommended to enable.
- **USE_G7221**: Chooses if you wish to use G7221 for support of ITU-T G.722.1 annex C. The default is `ON`.
- **USE_G719**: Chooses if you wish to use libg719_decode for support ITU-T G.719. The default is `ON`.
The following options are currently only available for Windows:
- **USE_G719**: Chooses if you wish to use libg719_decode for support ITU-T G.719. The default is `ON`.
- **USE_ATRAC9**: Chooses if you wish to use LibAtrac9 for support of ATRAC9. The default is `ON`.
- **USE_CELT**: Chooses if you wish to use libcelt for support of FSB CELT versions 0.6.1 and 0.11.0. The default is `ON`.
- **USE_SPEEX**: Chooses if you wish to use libspeex for support of SPEEX. The default is `ON`.

View File

@ -449,7 +449,7 @@ Inside the table you define lines mapping a filename to a bunch of values, in th
# put no name before the : to set default values
: (value1), (...), (valueN)
```
Then I'll find your current file name, and you can then reference its numbers from the list as a `name_value` field, like `base_offset = name_value`, `start_offset = 0x1000 + name_value1`, `interleave = name_value5`, etc. `(filename)` can be with or without extension (like `bgm01.vag` or just `bgm01`), and if the file's name isn't found it'll use default values, and if those aren't defined you'll get 0 instead. Being "values" they can use math or offsets too (`bgm05: 5*0x010`).
Then I'll find your current file name, and you can then reference its numbers from the list as a `name_value` field, like `base_offset = name_value`, `start_offset = 0x1000 + name_value1`, `interleave = name_value5`, etc. `(filename)` can be with or without extension (like `bgm01.vag` or just `bgm01`), and if the file's name isn't found it'll use default values, and if those aren't defined you'll get 0 instead. Being "values" they can use math or offsets too (`bgm05: 5*0x010`). You can also set a codec string too (`bgm01: PCM16LE`; `codec = name_value`).
You can use wildcards to match multiple names too (it stops on first name that matches), and UTF-8 names should work, case insensitive even.
```

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.18)
cmake_minimum_required(VERSION 3.5)
project(libg719_decode)
file(GLOB_RECURSE SOURCES "reference_code/*.c")

View File

@ -39,6 +39,10 @@ extern "C" {
#define PLUGIN_FILENAME "foo_input_vgmstream.dll"
static void log_callback(int level, const char* str) {
console::formatter() /*<< "vgmstream: "*/ << str;
}
// called every time a file is added to the playlist (to get info) or when playing
input_vgmstream::input_vgmstream() {
vgmstream = NULL;
@ -64,6 +68,8 @@ input_vgmstream::input_vgmstream() {
override_title = false;
load_settings();
vgmstream_set_log_callback(VGM_LOG_LEVEL_ALL, &log_callback);
}
// called on stop or when playlist info has been read

View File

@ -4,6 +4,8 @@ file(GLOB LAYOUT_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/layout/*.h")
file(GLOB LAYOUT_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/layout/*.c")
file(GLOB META_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/meta/*.h")
file(GLOB META_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/meta/*.c")
file(GLOB UTIL_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/util/*.h")
file(GLOB UTIL_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/util/*.c")
set(EXT_HEADERS
${VGM_SOURCE_DIR}/ext_includes/pstdint.h)
file(GLOB MAIN_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
@ -16,10 +18,12 @@ list(REMOVE_ITEM MAIN_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/stack_alloc.h)
source_group("Header Files\\coding" FILES ${CODING_HEADERS})
source_group("Header Files\\layout" FILES ${LAYOUT_HEADERS})
source_group("Header Files\\meta" FILES ${META_HEADERS})
source_group("Header Files\\util" FILES ${UTIL_HEADERS})
source_group("Header Files\\ext" FILES ${EXT_HEADERS})
source_group("Source Files\\coding" FILES ${CODING_SOURCES})
source_group("Source Files\\layout" FILES ${LAYOUT_SOURCES})
source_group("Source Files\\meta" FILES ${META_SOURCES})
source_group("Source Files\\util" FILES ${UTIL_SOURCES})
add_library(libvgmstream STATIC
${CODING_HEADERS}
@ -28,6 +32,8 @@ add_library(libvgmstream STATIC
${LAYOUT_SOURCES}
${META_HEADERS}
${META_SOURCES}
${UTIL_HEADERS}
${UTIL_SOURCES}
${EXT_HEADERS}
${MAIN_HEADERS}
${MAIN_SOURCES})
@ -39,4 +45,5 @@ target_include_directories(libvgmstream PRIVATE
${VGM_SOURCE_DIR}/ext_includes
coding
layout
meta)
meta
util)

View File

@ -21,9 +21,9 @@ META_SRCS = $(wildcard meta/*.c)
META_OBJS = $(patsubst %.c,%.o,$(META_SRCS))
OBJECTS += $(META_OBJS)
EXT_LIBS_SRCS = $(wildcard ../ext_libs/*.c)
EXT_LIBS_OBJS = $(patsubst %.c,%.o,$(EXT_LIBS_SRCS))
OBJECTS += $(EXT_LIBS_OBJS)
UTIL_SRCS = $(wildcard util/*.c)
UTIL_OBJS = $(patsubst %.c,%.o,$(UTIL_SRCS))
OBJECTS += $(UTIL_OBJS)
libvgmstream.a: $(OBJECTS)

View File

@ -1,18 +1,21 @@
## vgmstream autotools script
#noinst_LTLIBRARIES = libvgmstream.la
lib_LTLIBRARIES = libvgmstream.la
AM_CFLAGS = -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/ext_includes/
AM_MAKEFLAGS=-f Makefile.autotools
SUBDIRS = coding layout meta
SUBDIRS =
# sources/headers are updated automatically by ./bootstrap script (not all headers are needed though)
libvgmstream_la_LDFLAGS = coding/libcoding.la layout/liblayout.la meta/libmeta.la
libvgmstream_la_LDFLAGS =
libvgmstream_la_SOURCES = (auto-updated)
libvgmstream_la_LIBADD = -lm
EXTRA_DIST = (auto-updated)
AM_CFLAGS += -DVGM_LOG_OUTPUT
AM_CFLAGS += -DVGM_USE_G7221
if HAVE_VORBIS

View File

@ -1,31 +0,0 @@
## vgmstream autotools script
noinst_LTLIBRARIES = libcoding.la
AM_CFLAGS = -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/ext_includes/
AM_MAKEFLAGS=-f Makefile.autotools
# sources/headers are updated automatically by ./bootstrap script (not all headers are needed though)
libcoding_la_LDFLAGS =
libcoding_la_SOURCES = (auto-updated)
EXTRA_DIST = (auto-updated)
AM_CFLAGS += -DVGM_USE_G7221
if HAVE_VORBIS
if HAVE_VORBISFILE
AM_CFLAGS += -DVGM_USE_VORBIS
endif
endif
if HAVE_LIBMPG123
AM_CFLAGS += -DVGM_USE_MPEG
endif
if HAVE_LIBSPEEX
AM_CFLAGS += -DVGM_USE_SPEEX
endif
if HAVE_FFMPEG
AM_CFLAGS += -DVGM_USE_FFMPEG
endif

View File

@ -1,31 +0,0 @@
## vgmstream autotools script
noinst_LTLIBRARIES = liblayout.la
AM_CFLAGS = -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/ext_includes/
AM_MAKEFLAGS=-f Makefile.autotools
# sources/headers are updated automatically by ./bootstrap script (not all headers are needed though)
liblayout_la_LDFLAGS =
liblayout_la_SOURCES = (auto-updated)
EXTRA_DIST = (auto-updated)
AM_CFLAGS += -DVGM_USE_G7221
if HAVE_VORBIS
if HAVE_VORBISFILE
AM_CFLAGS += -DVGM_USE_VORBIS
endif
endif
if HAVE_LIBMPG123
AM_CFLAGS += -DVGM_USE_MPEG
endif
if HAVE_LIBSPEEX
AM_CFLAGS += -DVGM_USE_SPEEX
endif
if HAVE_FFMPEG
AM_CFLAGS += -DVGM_USE_FFMPEG
endif

View File

@ -59,7 +59,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../ext_includes;../ext_includes/ffmpeg;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;VGMSTREAM_VERSION_AUTO;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_G719;VGM_USE_ATRAC9;VGM_USE_CELT;VGM_USE_SPEEX;USE_ALLOCA;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;VGMSTREAM_VERSION_AUTO;VGM_LOG_OUTPUT;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_G719;VGM_USE_ATRAC9;VGM_USE_CELT;VGM_USE_SPEEX;USE_ALLOCA;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader>
@ -72,7 +72,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>../ext_includes;../ext_includes/ffmpeg;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WIN32_WINNT=0x501;WIN32;VGMSTREAM_VERSION_AUTO;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_G719;VGM_USE_ATRAC9;VGM_USE_CELT;VGM_USE_SPEEX;USE_ALLOCA;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_WIN32_WINNT=0x501;WIN32;VGMSTREAM_VERSION_AUTO;VGM_LOG_OUTPUT;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_G719;VGM_USE_ATRAC9;VGM_USE_CELT;VGM_USE_SPEEX;USE_ALLOCA;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
@ -168,6 +168,8 @@
<ClInclude Include="coding\tac_decoder_lib_data.h" />
<ClInclude Include="coding\tac_decoder_lib_ops.h" />
<ClInclude Include="layout\layout.h" />
<ClInclude Include="util\chunks.h" />
<ClInclude Include="util\log.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="coding\at3plus_decoder.c" />
@ -708,6 +710,8 @@
<ClCompile Include="layout\blocked_xa.c" />
<ClCompile Include="layout\blocked_xa_aiff.c" />
<ClCompile Include="layout\blocked_xvas.c" />
<ClCompile Include="util\chunks.c" />
<ClCompile Include="util\log.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@ -302,6 +302,12 @@
<ClInclude Include="meta\encrypted_bgm_streamfile.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="util\chunks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="util\log.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="formats.c">
@ -1918,5 +1924,11 @@
<ClCompile Include="meta\sbk.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="util\chunks.c">
<Filter>util\Source Files</Filter>
</ClCompile>
<ClCompile Include="util\log.c">
<Filter>util\Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,31 +0,0 @@
## vgmstream autotools script
noinst_LTLIBRARIES = libmeta.la
AM_CFLAGS = -DVAR_ARRAYS -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/ext_includes/
AM_MAKEFLAGS=-f Makefile.autotools
# sources/headers are updated automatically by ./bootstrap script (not all headers are needed though)
libmeta_la_LDFLAGS =
libmeta_la_SOURCES = (auto-updated)
EXTRA_DIST = (auto-updated)
AM_CFLAGS += -DVGM_USE_G7221
if HAVE_VORBIS
if HAVE_VORBISFILE
AM_CFLAGS += -DVGM_USE_VORBIS
endif
endif
if HAVE_LIBMPG123
AM_CFLAGS += -DVGM_USE_MPEG
endif
if HAVE_LIBSPEEX
AM_CFLAGS += -DVGM_USE_SPEEX
endif
if HAVE_FFMPEG
AM_CFLAGS += -DVGM_USE_FFMPEG
endif

View File

@ -83,14 +83,14 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) {
coding_type = coding_CRI_ADX_enc_8;
version = 0x0400;
}
VGM_ASSERT(version != 0x0400, "ADX: keystring not found\n");
vgm_asserti(version != 0x0400, "ADX: decryption keystring not found\n");
}
else if (version == 0x0409) {
if (find_adx_key(sf, 9, &xor_start, &xor_mult, &xor_add, subkey)) {
coding_type = coding_CRI_ADX_enc_9;
version = 0x0400;
}
VGM_ASSERT(version != 0x0400, "ADX: keycode not found\n");
vgm_asserti(version != 0x0400, "ADX: decryption keycode not found\n");
}
/* version + extra data */

View File

@ -166,7 +166,7 @@ static void find_bnsf_key(STREAMFILE* sf, off_t start, g7221_codec_data* data, u
}
VGM_ASSERT(best_score > 0, "BNSF: best key=%.24s (score=%i)\n", best_key, best_score);
VGM_ASSERT(best_score < 0, "BNSF: key not found\n");
vgm_asserti(best_score < 0 , "BNSF: decryption key not found\n");
}
#define BNSF_MIN_KEY_LEN 3

View File

@ -1,68 +1,53 @@
/*
Wii U boot sound file for each game/app.
*/
#include "meta.h"
#include "../util.h"
VGMSTREAM * init_vgmstream_btsnd(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
int channel_count = 2;
int loop_flag;
off_t start_offset = 0x8;
/* check extension, case insensitive */
streamFile->get_name(streamFile, filename, sizeof(filename));
if (strcasecmp("btsnd", filename_extension(filename)))
goto fail;
/* Checking for loop start */
if (read_32bitBE(0x4, streamFile) > 0)
loop_flag = 1;
else
loop_flag = 0;
if (channel_count < 1) goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->sample_rate = 48000;
/* channels and loop flag are set by allocate_vgmstream */
// There's probably a better way to get the sample count...
vgmstream->num_samples = vgmstream->loop_end_sample = (get_streamfile_size(streamFile) - 8) / 4;
vgmstream->loop_start_sample = read_32bitBE(0x4, streamFile);
vgmstream->coding_type = coding_PCM16BE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x2; // Constant for this format
vgmstream->meta_type = meta_WIIU_BTSND;
/* open the file for reading by each channel */
{
int i;
for (i = 0; i<channel_count; i++) {
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!vgmstream->ch[i].streamfile) goto fail;
vgmstream->ch[i].channel_start_offset =
vgmstream->ch[i].offset =
start_offset + i*vgmstream->interleave_block_size;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
/* .btsnd - Wii U boot sound file for each game/app */
VGMSTREAM* init_vgmstream_btsnd(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
int channels, loop_flag;
off_t start_offset, data_size;
int32_t num_samples, loop_start;
/* checks */
if (!check_extensions(sf, "btsnd"))
goto fail;
if (read_u32be(0x00,sf) != 0x02)
goto fail;
loop_start = read_s32be(0x04, sf);
start_offset = 0x08;
channels = 2;
loop_flag = loop_start > 0;
/* extra check since format is so simple */
data_size = get_streamfile_size(sf);
num_samples = pcm16_bytes_to_samples(data_size - start_offset, channels);
if (loop_start >= num_samples)
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_WIIU_BTSND;
vgmstream->sample_rate = 48000;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->coding_type = coding_PCM16BE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,4 +1,5 @@
#include "cri_utf.h"
#include "../util/log.h"
#define COLUMN_BITMASK_FLAG 0xf0
#define COLUMN_BITMASK_TYPE 0x0f
@ -113,7 +114,7 @@ utf_context* utf_open(STREAMFILE* sf, uint32_t table_offset, int* p_rows, const
/* 00: early (32b rows_offset?), 01: +2017 (no apparent differences) */
if (utf->version != 0x00 && utf->version != 0x01) {
VGM_LOG("@UTF: unknown version\n");
vgm_logi("@UTF: unknown version\n");
}
if (utf->table_offset + utf->table_size > get_streamfile_size(sf))
goto fail;
@ -169,7 +170,7 @@ utf_context* utf_open(STREAMFILE* sf, uint32_t table_offset, int* p_rows, const
!(utf->schema[i].flag & COLUMN_FLAG_NAME) ||
((utf->schema[i].flag & COLUMN_FLAG_DEFAULT) && (utf->schema[i].flag & COLUMN_FLAG_ROW)) ||
(utf->schema[i].flag & COLUMN_FLAG_UNDEFINED) ) {
VGM_LOG("@UTF: unknown column flag combo found\n");
vgm_logi("@UTF: unknown column flag combo found\n");
goto fail;
}
@ -197,7 +198,7 @@ utf_context* utf_open(STREAMFILE* sf, uint32_t table_offset, int* p_rows, const
//case COLUMN_TYPE_UINT128:
// value_size = 0x16;
default:
VGM_LOG("@UTF: unknown column type\n");
vgm_logi("@UTF: unknown column type\n");
goto fail;
}
@ -228,7 +229,7 @@ utf_context* utf_open(STREAMFILE* sf, uint32_t table_offset, int* p_rows, const
return utf;
fail:
utf_close(utf);
VGM_LOG("@UTF: fail\n");
vgm_logi("@UTF: init failure\n");
return NULL;
}

View File

@ -1,4 +1,5 @@
#include "deblock_streamfile.h"
#include "../util/log.h"
//todo move to utils or something

View File

@ -1,48 +1,6 @@
#include "meta.h"
#include "../coding/coding.h"
typedef struct {
uint32_t type;
uint32_t size;
uint32_t offset;
off_t current;
off_t max;
int le_type;
int be_size;
int full_size;
} chunk_t;
static int next_chunk(chunk_t* chunk, STREAMFILE* sf) {
uint32_t (*read_u32type)(off_t,STREAMFILE*) = !chunk->le_type ? read_u32be : read_u32le;
uint32_t (*read_u32size)(off_t,STREAMFILE*) = chunk->be_size ? read_u32be : read_u32le;
if (chunk->max == 0)
chunk->max = get_streamfile_size(sf);
if (chunk->current >= chunk->max)
return 0;
/* can be used to signal "stop" */
if (chunk->current < 0)
return 0;
chunk->type = read_u32type(chunk->current + 0x00,sf);
chunk->size = read_u32size(chunk->current + 0x04,sf);
chunk->offset = chunk->current + 0x04 + 0x04;
chunk->current += chunk->full_size ? chunk->size : 0x08 + chunk->size;
//;VGM_LOG("CHUNK: %x, %x, %x\n", dc.offset, chunk->type, chunk->size);
/* read past data */
if (chunk->type == 0xFFFFFFFF || chunk->size == 0xFFFFFFFF)
return 0;
/* empty chunk with 0 size, seen in some formats (XVAG uses it as end marker, Wwise doesn't) */
if (chunk->type == 0 || chunk->size == 0)
return 0;
/* more chunks remain */
return 1;
}
#include "../util/chunks.h"
enum {
CHUNK_RIFF = 0x52494646, /* "RIFF" */

View File

@ -193,13 +193,14 @@ VGMSTREAM* init_vgmstream_ea_schl_video(STREAMFILE* sf) {
/* check extension */
/* .uv: early */
/* .dct: early-mid [ex. Need for Speed II SE (PC), FIFA 98 (PC)] */
/* .wve: early-mid [Madden NFL 99 (PC)] */
/* .mad: mid */
/* .vp6: late */
if (check_extensions(sf, "uv,dct")) {
/* starts with audio header block */
if (read_32bitBE(0x00, sf) != EA_BLOCKID_HEADER) /* "SCHl" */
goto fail;
} else if (check_extensions(sf, "mad")) {
} else if (check_extensions(sf, "mad,wve")) {
/* check initial movie block id */
if (read_32bitBE(0x00, sf) != 0x4D41446B) /* "MADk" */
goto fail;

View File

@ -72,7 +72,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
fsb5.base_header_size = (fsb5.version==0x00) ? 0x40 : 0x3C;
if ((fsb5.sample_header_size + fsb5.name_table_size + fsb5.sample_data_size + fsb5.base_header_size) != get_streamfile_size(sf)) {
VGM_LOG("FSB5: bad size (%x + %x + %x + %x != %x)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, get_streamfile_size(sf));
vgm_logi("FSB5: wrong size, expected %x + %x + %x + %x vs %x (re-rip)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, get_streamfile_size(sf));
goto fail;
}
@ -217,7 +217,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
fsb5.channels = fsb5.channels * fsb5.layers;
break;
default:
VGM_LOG("FSB5: stream %i unknown flag 0x%x at %x + 0x04 (size 0x%x)\n", i, extraflag_type, (uint32_t)extraflag_offset, extraflag_size);
vgm_logi("FSB5: stream %i unknown flag 0x%x at %x + 0x04 + 0x%x (report)\n", i, extraflag_type, (uint32_t)extraflag_offset, extraflag_size);
break;
}
}
@ -301,11 +301,11 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
break;
case 0x03: /* FMOD_SOUND_FORMAT_PCM24 */
VGM_LOG("FSB5: FMOD_SOUND_FORMAT_PCM24 found\n");
vgm_logi("FSB5: FMOD_SOUND_FORMAT_PCM24 found (report)\n");
goto fail;
case 0x04: /* FMOD_SOUND_FORMAT_PCM32 */
VGM_LOG("FSB5: FMOD_SOUND_FORMAT_PCM32 found\n");
vgm_logi("FSB5: FMOD_SOUND_FORMAT_PCM32 found (report)\n");
goto fail;
case 0x05: /* FMOD_SOUND_FORMAT_PCMFLOAT [Anima: Gate of Memories (PC)] */
@ -494,7 +494,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
#endif
#endif
default:
VGM_LOG("FSB5: unknown codec %x found\n", fsb5.codec);
vgm_logi("FSB5: unknown codec 0x%x (report)\n", fsb5.codec);
goto fail;
}

View File

@ -30,7 +30,10 @@ VGMSTREAM* init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey) {
/* init vgmstream and library's context, will validate the HCA */
hca_data = init_hca(sf);
if (!hca_data) goto fail;
if (!hca_data) {
vgm_logi("HCA: unknown format (report)\n");
goto fail;
}
hca_info = hca_get_info(hca_data);
@ -184,7 +187,7 @@ static void find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t
done:
VGM_ASSERT(best_score > 1, "HCA: best key=%08x%08x (score=%i)\n",
(uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), best_score);
VGM_ASSERT(best_score < 0, "HCA: key not found\n");
vgm_asserti(best_score < 0, "HCA: decryption key not found\n");
}
#ifdef HCA_BRUTEFORCE

View File

@ -1,50 +1,50 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
/* MUSC - from Krome's PS2 games (The Legend of Spyro, Ty the Tasmanian Tiger) */
VGMSTREAM * init_vgmstream_musc(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int loop_flag, channel_count;
off_t start_offset;
size_t data_size;
/* .mus is the real extension, .musc is the header ID */
if (!check_extensions(streamFile,"mus,musc"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4D555343) /* "MUSC" */
goto fail;
start_offset = read_32bitLE(0x10,streamFile);
data_size = read_32bitLE(0x14,streamFile);
if (start_offset + data_size != get_streamfile_size(streamFile))
goto fail;
/* always does full loops unless it ends in silence */
loop_flag = read_32bitBE(get_streamfile_size(streamFile) - 0x10,streamFile) != 0x0C000000;
channel_count = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x06,streamFile);
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->meta_type = meta_MUSC;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitLE(0x18,streamFile) / 2;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
/* MUSC - from Krome's PS2 games (The Legend of Spyro, Ty the Tasmanian Tiger) */
VGMSTREAM* init_vgmstream_musc(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
int loop_flag, channels;
off_t start_offset;
size_t data_size;
/* checks */
/* .mus: actual extension
* .musc: header ID */
if (!check_extensions(sf,"mus,musc"))
goto fail;
if (!is_id32be(0x00,sf, "MUSC"))
goto fail;
start_offset = read_u32le(0x10,sf);
data_size = read_u32le(0x14,sf);
if (start_offset + data_size != get_streamfile_size(sf))
goto fail;
/* always does full loops unless it ends in silence */
loop_flag = read_u32be(get_streamfile_size(sf) - 0x10,sf) != 0x0C000000;
channels = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_u16le(0x06,sf);
vgmstream->num_samples = ps_bytes_to_samples(data_size, channels);
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->meta_type = meta_MUSC;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_u32le(0x18,sf) / 2;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -279,6 +279,8 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk
}
default:
/* FFmpeg may play it */
//vgm_logi("WWISE: unknown codec 0x%04x (report)\n", fmt->format);
goto fail;
}
@ -418,8 +420,10 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
}
/* check for truncated RIFF */
if (file_size != riff_size + 0x08)
if (file_size != riff_size + 0x08) {
vgm_logi("RIFF: wrong expected size (report/re-rip?)\n");
goto fail;
}
/* read through chunks to verify format and find metadata */
{

View File

@ -100,8 +100,12 @@ VGMSTREAM* init_vgmstream_sqex_scd(STREAMFILE* sf) {
target_entry = i;
}
}
if (meta_offset == 0) goto fail;
/* SCD can contain 0 entries too */
if (meta_offset == 0) {
vgm_logi("SQEX SCD: bank has no subsongs (ignore)\n");
goto fail;
}
}
/** stream header **/

View File

@ -765,7 +765,7 @@ static void parse_sead_sab_name(sead_header *sead, STREAMFILE *sf) {
}
static int parse_sead(sead_header *sead, STREAMFILE *sf) {
static int parse_sead(sead_header* sead, STREAMFILE* sf) {
uint32_t (*read_u32)(off_t,STREAMFILE*) = sead->big_endian ? read_u32be : read_u32le;
uint16_t (*read_u16)(off_t,STREAMFILE*) = sead->big_endian ? read_u16be : read_u16le;
@ -856,8 +856,10 @@ static int parse_sead(sead_header *sead, STREAMFILE *sf) {
}
/* SAB can contain 0 entries too */
if (sead->mtrl_offset == 0)
if (sead->mtrl_offset == 0) {
vgm_logi("SQEX SEAD: bank has no subsongs (ignore)\n");
goto fail;
}
}
/** stream header **/

View File

@ -40,12 +40,14 @@ typedef enum {
ASF = 30, /* Argonaut ASF 4-bit ADPCM */
EAXA = 31, /* Electronic Arts EA-XA 4-bit ADPCM v1 */
OKI4S = 32, /* OKI ADPCM with 16-bit output (unlike OKI/VOX/Dialogic ADPCM's 12-bit) */
} txth_type;
UNKNOWN = 99,
} txth_codec_t;
typedef enum { DEFAULT, NEGATIVE, POSITIVE, INVERTED } txth_loop_t;
typedef struct {
txth_type codec;
txth_codec_t codec;
uint32_t codec_mode;
uint32_t value_mul;
@ -196,6 +198,25 @@ VGMSTREAM* init_vgmstream_txth(STREAMFILE* sf) {
}
/* set common interleaves to simplify usage
* (maybe should ignore if manually overwritten, possibly with 0 on purpose?) */
if (txth.interleave == 0) {
uint32_t interleave = 0;
switch(txth.codec) {
case PSX: interleave = 0x10; break;
case PSX_bf: interleave = 0x10; break;
case NGC_DSP: interleave = 0x08; break;
case PCM16LE: interleave = 0x02; break;
case PCM16BE: interleave = 0x02; break;
case PCM8: interleave = 0x01; break;
case PCM8_U: interleave = 0x01; break;
default:
break;
}
txth.interleave = interleave;
}
/* type to coding conversion */
switch (txth.codec) {
case PSX: coding = coding_PSX; break;
@ -881,63 +902,61 @@ fail:
return 0;
}
static txth_codec_t parse_codec(txth_header* txth, const char* val) {
if (is_string(val,"PSX")) return PSX;
else if (is_string(val,"XBOX")) return XBOX;
else if (is_string(val,"NGC_DTK")) return NGC_DTK;
else if (is_string(val,"DTK")) return NGC_DTK;
else if (is_string(val,"PCM16BE")) return PCM16BE;
else if (is_string(val,"PCM16LE")) return PCM16LE;
else if (is_string(val,"PCM8")) return PCM8;
else if (is_string(val,"SDX2")) return SDX2;
else if (is_string(val,"DVI_IMA")) return DVI_IMA;
else if (is_string(val,"MPEG")) return MPEG;
else if (is_string(val,"IMA")) return IMA;
else if (is_string(val,"AICA")) return AICA;
else if (is_string(val,"MSADPCM")) return MSADPCM;
else if (is_string(val,"NGC_DSP")) return NGC_DSP;
else if (is_string(val,"DSP")) return NGC_DSP;
else if (is_string(val,"PCM8_U_int")) return PCM8_U_int;
else if (is_string(val,"PSX_bf")) return PSX_bf;
else if (is_string(val,"MS_IMA")) return MS_IMA;
else if (is_string(val,"PCM8_U")) return PCM8_U;
else if (is_string(val,"APPLE_IMA4")) return APPLE_IMA4;
else if (is_string(val,"ATRAC3")) return ATRAC3;
else if (is_string(val,"ATRAC3PLUS")) return ATRAC3PLUS;
else if (is_string(val,"XMA1")) return XMA1;
else if (is_string(val,"XMA2")) return XMA2;
else if (is_string(val,"FFMPEG")) return FFMPEG;
else if (is_string(val,"AC3")) return AC3;
else if (is_string(val,"PCFX")) return PCFX;
else if (is_string(val,"PCM4")) return PCM4;
else if (is_string(val,"PCM4_U")) return PCM4_U;
else if (is_string(val,"OKI16")) return OKI16;
else if (is_string(val,"OKI4S")) return OKI4S;
else if (is_string(val,"AAC")) return AAC;
else if (is_string(val,"TGC")) return TGC;
else if (is_string(val,"GCOM_ADPCM")) return TGC;
else if (is_string(val,"ASF")) return ASF;
else if (is_string(val,"EAXA")) return EAXA;
/* special handling */
else if (is_string(val,"name_value")) return txth->name_values[0];
else if (is_string(val,"name_value1")) return txth->name_values[0];
else if (is_string(val,"name_value2")) return txth->name_values[1];
else if (is_string(val,"name_value3")) return txth->name_values[2];
//todo rest (handle in function)
return UNKNOWN;
}
static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, char* val) {
//;VGM_LOG("TXTH: key=%s, val=%s\n", key, val);
/* CODEC */
if (is_string(key,"codec")) {
if (is_string(val,"PSX")) txth->codec = PSX;
else if (is_string(val,"XBOX")) txth->codec = XBOX;
else if (is_string(val,"NGC_DTK")) txth->codec = NGC_DTK;
else if (is_string(val,"DTK")) txth->codec = NGC_DTK;
else if (is_string(val,"PCM16BE")) txth->codec = PCM16BE;
else if (is_string(val,"PCM16LE")) txth->codec = PCM16LE;
else if (is_string(val,"PCM8")) txth->codec = PCM8;
else if (is_string(val,"SDX2")) txth->codec = SDX2;
else if (is_string(val,"DVI_IMA")) txth->codec = DVI_IMA;
else if (is_string(val,"MPEG")) txth->codec = MPEG;
else if (is_string(val,"IMA")) txth->codec = IMA;
else if (is_string(val,"AICA")) txth->codec = AICA;
else if (is_string(val,"MSADPCM")) txth->codec = MSADPCM;
else if (is_string(val,"NGC_DSP")) txth->codec = NGC_DSP;
else if (is_string(val,"DSP")) txth->codec = NGC_DSP;
else if (is_string(val,"PCM8_U_int")) txth->codec = PCM8_U_int;
else if (is_string(val,"PSX_bf")) txth->codec = PSX_bf;
else if (is_string(val,"MS_IMA")) txth->codec = MS_IMA;
else if (is_string(val,"PCM8_U")) txth->codec = PCM8_U;
else if (is_string(val,"APPLE_IMA4")) txth->codec = APPLE_IMA4;
else if (is_string(val,"ATRAC3")) txth->codec = ATRAC3;
else if (is_string(val,"ATRAC3PLUS")) txth->codec = ATRAC3PLUS;
else if (is_string(val,"XMA1")) txth->codec = XMA1;
else if (is_string(val,"XMA2")) txth->codec = XMA2;
else if (is_string(val,"FFMPEG")) txth->codec = FFMPEG;
else if (is_string(val,"AC3")) txth->codec = AC3;
else if (is_string(val,"PCFX")) txth->codec = PCFX;
else if (is_string(val,"PCM4")) txth->codec = PCM4;
else if (is_string(val,"PCM4_U")) txth->codec = PCM4_U;
else if (is_string(val,"OKI16")) txth->codec = OKI16;
else if (is_string(val,"OKI4S")) txth->codec = OKI4S;
else if (is_string(val,"AAC")) txth->codec = AAC;
else if (is_string(val,"TGC")) txth->codec = TGC;
else if (is_string(val,"GCOM_ADPCM")) txth->codec = TGC;
else if (is_string(val,"ASF")) txth->codec = ASF;
else if (is_string(val,"EAXA")) txth->codec = EAXA;
else goto fail;
/* set common interleaves to simplify usage
* (do it here to in case it's overwritten later, possibly with 0 on purpose) */
if (txth->interleave == 0) {
switch(txth->codec) {
case PSX: txth->interleave = 0x10; break;
case PSX_bf: txth->interleave = 0x10; break;
case NGC_DSP: txth->interleave = 0x08; break;
case PCM16LE: txth->interleave = 0x02; break;
case PCM16BE: txth->interleave = 0x02; break;
case PCM8: txth->interleave = 0x01; break;
case PCM8_U: txth->interleave = 0x01; break;
default: break;
}
}
txth->codec = parse_codec(txth, val);
if (txth->codec == UNKNOWN)
goto fail;
}
else if (is_string(key,"codec_mode")) {
if (!parse_num(txth->sf_head,txth,val, &txth->codec_mode)) goto fail;
@ -1372,7 +1391,7 @@ static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, cha
return 1;
fail:
VGM_LOG("TXTH: error parsing key=%s, val=%s\n", key, val);
vgm_logi("TXTH: error parsing key=%s, val=%s\n", key, val);
return 0;
}
@ -1589,6 +1608,26 @@ static int read_name_table_keyval(txth_header* txth, const char* line, char* key
return 0;
}
static int parse_name_val(txth_header* txth, char* subval) {
int ok;
ok = parse_num(txth->sf_head, txth, subval, &txth->name_values[txth->name_values_count]);
if (!ok) {
/* in rare cases may set codec */
txth_codec_t codec = parse_codec(txth, subval);
if (codec == UNKNOWN)
goto fail;
txth->name_values[txth->name_values_count] = codec;
}
txth->name_values_count++;
if (txth->name_values_count >= 16) /* surely nobody needs that many */
goto fail;
return 1;
fail:
return 0;
}
static int parse_name_table(txth_header* txth, char* name_list) {
STREAMFILE* sf_names = NULL;
off_t txt_offset, file_size;
@ -1666,9 +1705,7 @@ static int parse_name_table(txth_header* txth, char* name_list) {
if (current[0] == ',')
current++;
if (!parse_num(txth->sf_head,txth,subval, &txth->name_values[txth->name_values_count])) goto fail;
txth->name_values_count++;
if (txth->name_values_count >= 16) /* surely nobody needs that many */
if (!parse_name_val(txth, subval))
goto fail;
}
@ -1806,7 +1843,7 @@ static int parse_num(STREAMFILE* sf, txth_header* txth, const char* val, uint32_
offset += txth->base_offset;
if (/*offset < 0 ||*/ offset > get_streamfile_size(sf)) {
VGM_LOG("TXTH: wrong offset %x + %x\n", offset - txth->base_offset, txth->base_offset);
vgm_logi("TXTH: wrong offset over file size (%x + %x)\n", offset - txth->base_offset, txth->base_offset);
goto fail;
}
@ -1920,7 +1957,7 @@ static int parse_num(STREAMFILE* sf, txth_header* txth, const char* val, uint32_
//;VGM_LOG("TXTH: final result %u (0x%x)\n", result, result);
return 1;
fail:
VGM_LOG("TXTH: error parsing num '%s'\n", val);
//VGM_LOG("TXTH: error parsing num '%s'\n", val);
return 0;
}

View File

@ -634,7 +634,7 @@ static VGMSTREAM* init_vgmstream_ubi_bao_header(ubi_bao_header* bao, STREAMFILE*
VGMSTREAM* vgmstream = NULL;
if (bao->total_subsongs <= 0) {
VGM_LOG("UBI BAO: no subsongs\n");
vgm_logi("UBI BAO: bank has no subsongs (ignore)\n");
goto fail; /* not uncommon */
}
@ -1473,7 +1473,10 @@ static STREAMFILE* setup_bao_streamfile(ubi_bao_header* bao, STREAMFILE* sf) {
if (bao->stream_size - bao->prefetch_size != 0) {
new_sf = open_streamfile_by_filename(sf, bao->resource_name);
if (!new_sf) { VGM_LOG("UBI BAO: external stream '%s' not found\n", bao->resource_name); goto fail; }
if (!new_sf) {
vgm_logi("UBI BAO: external file '%s' not found (put together)\n", bao->resource_name);
goto fail;
}
stream_segments[1] = new_sf;
new_sf = open_clamp_streamfile(stream_segments[1], bao->stream_offset, (bao->stream_size - bao->prefetch_size));
@ -1495,7 +1498,10 @@ static STREAMFILE* setup_bao_streamfile(ubi_bao_header* bao, STREAMFILE* sf) {
}
else if (bao->is_external) {
new_sf = open_streamfile_by_filename(sf, bao->resource_name);
if (!new_sf) { VGM_LOG("UBI BAO: external stream '%s' not found\n", bao->resource_name); goto fail; }
if (!new_sf) {
vgm_logi("UBI BAO: external file '%s' not found (put together)\n", bao->resource_name);
goto fail;
}
temp_sf = new_sf;
new_sf = open_clamp_streamfile(temp_sf, bao->stream_offset, bao->stream_size);
@ -1884,11 +1890,10 @@ static int config_bao_version(ubi_bao_header* bao, STREAMFILE* sf) {
* - 0x94: stream id? 0x9C: extra size */
case 0x002A0300: /* Watch Dogs (Wii U) */
/* similar to SC:B */
default: /* others possibly using BAO: Just Dance, Watch_Dogs, Far Cry Primal, Far Cry 4 */
VGM_LOG("UBI BAO: unknown BAO version %08x\n", bao->version);
default: /* others possibly using BAO: Watch_Dogs, Far Cry Primal, Far Cry 4 */
vgm_logi("UBI BAO: unknown BAO version %08x\n", bao->version);
return 0;
}
VGM_LOG("UBI BAO: unknown BAO version %08x\n", bao->version);
return 0;
}

View File

@ -644,7 +644,7 @@ static VGMSTREAM *init_vgmstream_ubi_dat_main(ubi_sb_header *sb, STREAMFILE *sf_
sf_data = open_streamfile_by_filename(sf, sb->resource_name);
if (!sf_data) {
/* play silence if external file is not found since Rayman 2 seems to rely on this behavior */
VGM_LOG("UBI DAT: external stream '%s' not found\n", sb->resource_name);
vgm_logi("UBI DAT: external file '%s' not found (put together)\n", sb->resource_name);
strncat(sb->readable_name, " (missing)", sizeof(sb->readable_name));
sb->duration = (float)pcm_bytes_to_samples(sb->stream_size, sb->channels, 16) / (float)sb->sample_rate;
return init_vgmstream_ubi_sb_silence(sb);
@ -1301,10 +1301,11 @@ static VGMSTREAM* init_vgmstream_ubi_sb_audio(ubi_sb_header* sb, STREAMFILE* sf_
if (sb->is_external) {
sf_data = open_streamfile_by_filename(sf, sb->resource_name);
if (sf_data == NULL) {
VGM_LOG("UBI SB: external stream '%s' not found\n", sb->resource_name);
vgm_logi("UBI SB: external file '%s' not found (put together)\n", sb->resource_name);
goto fail;
}
} else {
}
else {
sf_data = sf;
}
@ -1341,7 +1342,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_layer(ubi_sb_header* sb, STREAMFILE* sf_
if (sb->is_external) {
sf_data = open_streamfile_by_filename(sf,sb->resource_name);
if (sf_data == NULL) {
VGM_LOG("UBI SB: external stream '%s' not found\n", sb->resource_name);
vgm_logi("UBI SB: external file '%s' not found (put together)\n", sb->resource_name);
goto fail;
}
}
@ -1563,7 +1564,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_header(ubi_sb_header* sb, STREAMFILE* sf
VGMSTREAM* vgmstream = NULL;
if (sb->total_subsongs == 0) {
VGM_LOG("UBI SB: no subsongs\n");
vgm_logi("UBI SB: bank has no subsongs (ignore)\n");
goto fail;
}
@ -4042,6 +4043,6 @@ static int config_sb_version(ubi_sb_header* sb, STREAMFILE* sf) {
return 1;
}
VGM_LOG("UBI SB: unknown SB/SM version+platform %08x\n", sb->version);
vgm_logi("UBI SB: unknown SB/SM version+platform %08x (report)\n", sb->version);
return 0;
}

View File

@ -592,8 +592,8 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
vgmstream->layout_type = layout_none;
break;
}
#endif
case HEVAG: /* PSV */
/* changed values, another bizarre Wwise quirk */
//ww.block_align /* unknown (1ch=2, 2ch=4) */
@ -644,6 +644,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
break;
}
#endif
case PTADPCM: /* newer ADPCM [Bayonetta 2 (Switch), Genshin Impact (PC)] */
if (ww.bits_per_sample != 4) goto fail;
if (ww.block_align != 0x24 * ww.channels && ww.block_align != 0x104 * ww.channels) goto fail;
@ -885,6 +886,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
case 0x3041: ww->codec = OPUSWW; break; /* "OPUS_WEM", added on Wwise 2019.2.3, replaces OPUS */
case 0x8311: ww->codec = PTADPCM; break; /* added on Wwise 2019.1, replaces IMA */
default:
vgm_logi("WWISE: unknown codec 0x%04x (report)\n", ww->format);
goto fail;
}
@ -893,11 +895,14 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
if (ww->extra_size == 0x0c + ww->channels * 0x2e) {
/* newer Wwise DSP with coefs [Epic Mickey 2 (Wii), Batman Arkham Origins Blackgate (3DS)] */
ww->codec = DSP;
} else if (ww->extra_size == 0x0a && ww->wiih_offset) { /* WiiH */
}
else if (ww->extra_size == 0x0a && ww->wiih_offset) { /* WiiH */
/* few older Wwise DSP with num_samples in extra_size [Tony Hawk: Shred (Wii)] */
ww->codec = DSP;
} else if (ww->block_align == 0x104 * ww->channels) {
ww->codec = PTADPCM; /* Bayonetta 2 (Switch) */
}
else if (ww->block_align == 0x104 * ww->channels) {
/* Bayonetta 2 (Switch) */
ww->codec = PTADPCM;
}
}
@ -911,7 +916,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
/* catch wrong rips as truncated tracks' file_size should be much smaller than data_size,
* but it's possible to pre-fetch small files too [Punch Out!! (Wii)] */
if (ww->data_offset + ww->data_size - ww->file_size < 0x5000 && ww->file_size > 0x10000) {
VGM_LOG("WWISE: wrong expected data_size\n");
vgm_logi("WWISE: wrong expected size (re-rip?)\n");
goto fail;
}
@ -919,7 +924,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
ww->codec == OPUSNX || ww->codec == OPUS || ww->codec == OPUSWW || ww->codec == PTADPCM) {
ww->truncated = 1; /* only seen those, probably all exist (XWMA, AAC, HEVAG, ATRAC9?) */
} else {
VGM_LOG("WWISE: wrong size, maybe truncated\n");
vgm_logi("WWISE: wrong expected size, maybe truncated (report)\n");
goto fail;
}
}

View File

@ -96,7 +96,7 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
sf_body = open_streamfile_by_filename(sf,filename);
if (!sf_body) {
VGM_LOG("XSH: can't find %s\n", filename);
vgm_logi("XSH: external file '%s' not found (put together)\n", filename);
goto fail;
}
@ -116,7 +116,7 @@ VGMSTREAM* init_vgmstream_xsh_xsd_xss(STREAMFILE* sf) {
snprintf(filename, sizeof(filename), "%s", "STREAMS.XSS");
sf_body = open_streamfile_by_filename(sf,filename);
if (!sf_body) {
VGM_LOG("XSH: can't find %s\n", filename);
vgm_logi("XSH: external file '%s' not found (put together)\n", filename);
goto fail;
}
break;

View File

@ -1,6 +1,7 @@
#include "vgmstream.h"
#include "plugins.h"
#include "mixing.h"
#include "util/log.h"
/* ****************************************** */
@ -546,3 +547,16 @@ void vgmstream_mixing_stereo_only(VGMSTREAM *vgmstream, int start) {
/* remove channels after stereo */
mixing_push_killmix(vgmstream, start + 2);
}
/* ****************************************** */
/* LOG: log */
/* ****************************************** */
void vgmstream_set_log_callback(int level, void* callback) {
vgm_log_set_callback(NULL, level, 0, callback);
}
void vgmstream_set_log_stdout(int level) {
vgm_log_set_callback(NULL, level, 1, NULL);
}

View File

@ -77,6 +77,14 @@ typedef struct {
/* get a simple title for plugins */
void vgmstream_get_title(char* buf, int buf_len, const char* filename, VGMSTREAM* vgmstream, vgmstream_title_t* cfg);
enum {
VGM_LOG_LEVEL_INFO = 1,
VGM_LOG_LEVEL_DEBUG = 2,
VGM_LOG_LEVEL_ALL = 100,
};
// CB: void (*callback)(int level, const char* str)
void vgmstream_set_log_callback(int level, void* callback);
void vgmstream_set_log_stdout(int level);
#if 0

View File

@ -136,49 +136,4 @@ void swap_samples_le(sample_t *buf, int count);
void concatn(int length, char * dst, const char * src);
/* Simple stdout logging for debugging and regression testing purposes.
* Needs C99 variadic macros, uses do..while to force ";" as statement */
#ifdef VGM_DEBUG_OUTPUT
/* equivalent to printf when condition is true */
#define VGM_ASSERT(condition, ...) \
do { if (condition) {printf(__VA_ARGS__);} } while (0)
#define VGM_ASSERT_ONCE(condition, ...) \
do { static int written; if (!written) { if (condition) {printf(__VA_ARGS__); written = 1;} } } while (0)
/* equivalent to printf */
#define VGM_LOG(...) \
do { printf(__VA_ARGS__); } while (0)
#define VGM_LOG_ONCE(...) \
do { static int written; if (!written) { printf(__VA_ARGS__); written = 1; } } while (0)
/* prints file/line/func */
#define VGM_LOGF() \
do { printf("%s:%i '%s'\n", __FILE__, __LINE__, __func__); } while (0)
/* prints to a file */
#define VGM_LOGT(txt, ...) \
do { FILE *fl = fopen(txt,"a+"); if(fl){fprintf(fl,__VA_ARGS__); fflush(fl);} fclose(fl); } while(0)
/* prints a buffer/array */
#define VGM_LOGB(buf, buf_size, bytes_per_line) \
do { \
int i; \
for (i=0; i < buf_size; i++) { \
printf("%02x",buf[i]); \
if (bytes_per_line && (i+1) % bytes_per_line == 0) printf("\n"); \
} \
printf("\n"); \
} while (0)
#else/*VGM_DEBUG_OUTPUT*/
#define VGM_ASSERT(condition, ...) /* nothing */
#define VGM_ASSERT_ONCE(condition, ...) /* nothing */
#define VGM_LOG(...) /* nothing */
#define VGM_LOG_ONCE(...) /* nothing */
#define VGM_LOGF() /* nothing */
#define VGM_LOGT() /* nothing */
#define VGM_LOGB(buf, buf_size, bytes_per_line) /* nothing */
#endif/*VGM_DEBUG_OUTPUT*/
#endif

35
src/util/chunks.c Normal file
View File

@ -0,0 +1,35 @@
#include "chunks.h"
//#include "log.h"
int next_chunk(chunk_t* chunk, STREAMFILE* sf) {
uint32_t (*read_u32type)(off_t,STREAMFILE*) = !chunk->le_type ? read_u32be : read_u32le;
uint32_t (*read_u32size)(off_t,STREAMFILE*) = chunk->be_size ? read_u32be : read_u32le;
if (chunk->max == 0)
chunk->max = get_streamfile_size(sf);
if (chunk->current >= chunk->max)
return 0;
/* can be used to signal "stop" */
if (chunk->current < 0)
return 0;
chunk->type = read_u32type(chunk->current + 0x00,sf);
chunk->size = read_u32size(chunk->current + 0x04,sf);
chunk->offset = chunk->current + 0x04 + 0x04;
chunk->current += chunk->full_size ? chunk->size : 0x08 + chunk->size;
//;VGM_LOG("CHUNK: %x, %x, %x\n", dc.offset, chunk->type, chunk->size);
/* read past data */
if (chunk->type == 0xFFFFFFFF || chunk->size == 0xFFFFFFFF)
return 0;
/* empty chunk with 0 size, seen in some formats (XVAG uses it as end marker, Wwise doesn't) */
if (chunk->type == 0 || chunk->size == 0)
return 0;
/* more chunks remain */
return 1;
}

27
src/util/chunks.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef _UTIL_CHUNKS_H
#define _UTIL_CHUNKS_H
#include "../streamfile.h"
typedef struct {
uint32_t type; /* chunk id/fourcc */
uint32_t size; /* chunk size */
uint32_t offset; /* chunk offset (after type/size) */
off_t current; /* start position, or next chunk after size (set to -1 to break) */
off_t max; /* max offset, or filesize if not set */
int le_type; /* read type as LE instead of more common BE */
int be_size; /* read type as BE instead of more common LE */
int full_size; /* chunk size includes type+size */
} chunk_t;
int next_chunk(chunk_t* chunk, STREAMFILE* sf);
#if 0
enum {
CHUNK_RIFF = 0x52494646, /* "RIFF" */
CHUNK_LIST = 0x4C495354, /* "LIST" */
};
#endif
#endif

90
src/util/log.c Normal file
View File

@ -0,0 +1,90 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* log context; should probably make a unique instance and pass to metas/decoders/etc, but for the time being use global */
//extern ...* log;
typedef struct {
int level;
void (*callback)(int level, const char* str);
} logger_t;
logger_t log_impl = {0};
//void* log = &log_impl;
enum {
LOG_LEVEL_INFO = 1,
LOG_LEVEL_DEBUG = 2,
LOG_LEVEL_ALL = 100,
};
static void vgm_log_callback_printf(int level, const char* str) {
printf("%s", str);
}
void vgm_log_set_callback(void* ctx_p, int level, int type, void* callback) {
logger_t* ctx = ctx_p;
if (!ctx) ctx = &log_impl;
ctx->level = level;
switch(type) {
case 0:
ctx->callback = callback;
break;
case 1:
ctx->callback = vgm_log_callback_printf;
break;
default:
break;
}
}
static void log_internal(void* ctx_p, int level, const char* fmt, va_list args) {
char line[255];
int out;
logger_t* ctx = ctx_p;
if (!ctx) ctx = &log_impl;
if (!ctx->callback)
return;
if (level > ctx->level)
return;
out = vsnprintf(line, sizeof(line), fmt, args);
if (out < 0 || out > sizeof(line))
strcpy(line, "(ignored log)"); //to-do something better, meh
ctx->callback(level, line);
}
void vgm_logd(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
log_internal(NULL, LOG_LEVEL_DEBUG, fmt, args);
va_end(args);
}
void vgm_logi(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
log_internal(NULL, LOG_LEVEL_INFO, fmt, args);
va_end(args);
}
void vgm_asserti(int condition, const char* fmt, ...) {
if (!condition)
return;
{
va_list args;
va_start(args, fmt);
log_internal(NULL, LOG_LEVEL_INFO, fmt, args);
va_end(args);
}
}

78
src/util/log.h Normal file
View File

@ -0,0 +1,78 @@
#ifndef _UTIL_LOG_H
#define _UTIL_LOG_H
/* Dumb logger utils (tuned for simplicity). Notes:
* - must set callback/defaults to print anything
* - mainly used to print info for users, like format detected but wrong size
* (don't clutter by logging code that happens most of the time, since log may be shared with other plugins)
* - callbacks receive formed string for simplicity (to be adjusted)
* - DO NOT put logs in tight loops (like decoders), slow fn calls and clutter
* (metas are usually fine but also consider cluttering)
* - as compiler must support variable args, needs to pass VGM_LOG_OUTPUT flag to enable
* - debug logs are removed unless VGM_DEBUG_OUTPUT is passed to compiler args
* (passing either of them works)
* - callback should be thread-safe (no internal checks and only one log ATM)
* - still WIP, some stuff not working ATM or may change
*/
// void (*callback)(int level, const char* str);
void vgm_log_set_callback(void* ctx_p, int level, int type, void* callback);
#if defined(VGM_LOG_OUTPUT) || defined(VGM_DEBUG_OUTPUT)
void vgm_logi(/*void* ctx,*/ const char* fmt, ...);
void vgm_asserti(/*void* ctx,*/ int condition, const char* fmt, ...);
//void vgm_logi_once(/*void* ctx, int* once_flag, */ const char* fmt, ...);
#else
#define vgm_logi(...) /* nothing */
#define vgm_asserti(...) /* nothing */
#endif
#ifdef VGM_DEBUG_OUTPUT
void vgm_logd(/*void* ctx,*/ const char* fmt, ...);
#define VGM_LOG(...) do { vgm_logd(__VA_ARGS__); } while (0)
#define VGM_ASSERT(condition, ...) do { if (condition) {vgm_logd(__VA_ARGS__);} } while (0)
#else
#define vgm_logd(...) /* nothing */
#define VGM_LOG(...) /* nothing */
#define VGM_ASSERT(condition, ...) /* nothing */
#endif
/* original stdout logging for debugging and regression testing purposes, may be removed later.
* Needs C99 variadic macros, uses do..while to force ";" as statement */
#ifdef VGM_DEBUG_OUTPUT
#define VGM_LOG_ONCE(...) \
do { static int written; if (!written) { printf(__VA_ARGS__); written = 1; } } while (0)
#define VGM_ASSERT_ONCE(condition, ...) \
do { static int written; if (!written) { if (condition) {printf(__VA_ARGS__); written = 1;} } } while (0)
/* prints to a file */
#define VGM_LOGT(txt, ...) \
do { FILE *fl = fopen(txt,"a+"); if(fl){fprintf(fl,__VA_ARGS__); fflush(fl);} fclose(fl); } while(0)
/* prints a buffer/array */
#define VGM_LOGB(buf, buf_size, bytes_per_line) \
do { \
int i; \
for (i=0; i < buf_size; i++) { \
printf("%02x",buf[i]); \
if (bytes_per_line && (i+1) % bytes_per_line == 0) printf("\n"); \
} \
printf("\n"); \
} while (0)
#else /* VGM_DEBUG_OUTPUT */
#define VGM_LOG_ONCE(...) /* nothing */
#define VGM_ASSERT_ONCE(condition, ...) /* nothing */
#define VGM_LOGT() /* nothing */
#define VGM_LOGB(buf, buf_size, bytes_per_line) /* nothing */
#endif /*VGM_DEBUG_OUTPUT*/
#endif

View File

@ -24,7 +24,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_bfwav,
init_vgmstream_bfstm,
init_vgmstream_mca,
init_vgmstream_btsnd,
init_vgmstream_nds_strm,
init_vgmstream_agsc,
init_vgmstream_ngc_adpdtk,
@ -533,6 +532,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
init_vgmstream_encrypted, /* encrypted stuff */
init_vgmstream_btsnd, /* semi-headerless */
init_vgmstream_raw_int, /* .int raw PCM */
init_vgmstream_ps_headerless, /* tries to detect a bunch of PS-ADPCM formats */
init_vgmstream_raw_snds, /* .snds raw SNDS IMA (*after* ps_headerless) */

View File

@ -17,6 +17,7 @@ enum {
};
#include "streamfile.h"
#include "util/log.h"
/* 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 */

View File

@ -347,6 +347,36 @@ INT_PTR CALLBACK configDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara
break;
}
case IDC_LOG_BUTTON: { /* shows log */
TCHAR wbuf[257*32];
char buf[257*32];
size_t buf_size = 257*32;
int i, max = 0;
const char** lines = logger_get_lines(&max);
/* could use some nice scrollable text but I don't know arcane Windows crap */
if (lines == NULL) {
snprintf(buf, 257, "%s\n", "couldn't read log");
}
else if (max == 0) {
snprintf(buf, 257, "%s\n", "(empty)");
}
else {
//todo improve
char* tmp = buf;
for (i = 0; i < max; i++) {
int done = snprintf(tmp, 256, "%s", lines[i]);
if (done < 0 || done >= 256)
break;
tmp += (done); // + 1
}
}
cfg_char_to_wchar(wbuf, buf_size, buf);
MessageBox(hDlg, buf, TEXT("vgmstream log"), MB_OK);
break;
}
default:
return FALSE;
}
@ -370,3 +400,82 @@ INT_PTR CALLBACK configDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara
return TRUE;
}
/* ************************************* */
/* IN_LOG */
/* ************************************* */
/* could just write to file but to avoid leaving temp crap just log to memory and print what when requested */
winamp_log_t* walog;
#define WALOG_MAX_LINES 32
#define WALOG_MAX_CHARS 256
struct winamp_log_t {
char data[WALOG_MAX_LINES * WALOG_MAX_CHARS];
int logged;
const char* lines[WALOG_MAX_LINES];
} ;
void logger_init() {
walog = malloc(sizeof(winamp_log_t));
if (!walog) return;
walog->logged = 0;
}
void logger_free() {
free(walog);
walog = NULL;
}
/* logs to data as a sort of circular buffer. example if max_lines is 6:
* - log 0 = "msg1"
* ...
* - log 5 = "msg5" > limit reached, next will overwrite 0
* - log 0 = "msg6" (max 6 logs, but can only write las 6)
* - when requested lines should go from current to: 1,2,3,4,5,0
*/
void logger_callback(int level, const char* str) {
char* buf;
int pos;
if (!walog)
return;
pos = (walog->logged % WALOG_MAX_LINES) * WALOG_MAX_CHARS;
buf = &walog->data[pos];
snprintf(buf, WALOG_MAX_CHARS, "%s", str);
walog->logged++;
/* ??? */
if (walog->logged >= 0x7FFFFFFF)
walog->logged = 0;
}
const char** logger_get_lines(int* p_max) {
int i, from, max;
if (!walog) {
*p_max = 0;
return NULL;
}
if (walog->logged > WALOG_MAX_LINES) {
from = (walog->logged % WALOG_MAX_LINES);
max = WALOG_MAX_LINES;
}
else {
from = 0;
max = walog->logged;
}
for (i = 0; i < max; i++) {
int pos = ((from + i) % WALOG_MAX_LINES) * WALOG_MAX_CHARS;
walog->lines[i] = &walog->data[pos];
}
*p_max = max;
return walog->lines;
}

View File

@ -344,6 +344,9 @@ void winamp_Init() {
settings.is_xmplay = is_xmplay();
logger_init();
vgmstream_set_log_callback(VGM_LOG_LEVEL_ALL, logger_callback);
/* get ini config */
load_defaults(&defaults);
load_config(&input_module, &settings, &defaults);
@ -359,6 +362,7 @@ void winamp_Init() {
/* called at program quit */
void winamp_Quit() {
logger_free();
}
/* called before extension checks, to allow detection of mms://, etc */

View File

@ -74,6 +74,16 @@ void load_config(In_Module* input_module, winamp_settings_t* settings, winamp_se
INT_PTR CALLBACK configDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
/* logger */
typedef struct winamp_log_t winamp_log_t;
void logger_init();
void logger_free();
void logger_callback(int level, const char* str);
const char** logger_get_lines(int* p_max);
extern winamp_log_t* walog;
/* ************************************* */
/* IN_UNICODE */
/* ************************************* */

View File

@ -16,3 +16,4 @@
#define IDC_EXTS_UNKNOWN_ON 1015
#define IDC_EXTS_COMMON_ON 1016
#define IDC_FORCE_TITLE 1017
#define IDC_LOG_BUTTON 1018

View File

@ -4,7 +4,7 @@
#define IDC_STATIC -1
//elements: text, id, x, y, width, height [, style [, extended-style]]
IDD_CONFIG DIALOGEX 0, 0, 187, 196
IDD_CONFIG DIALOGEX 0, 0, 188, 220
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "in_vgmstream configuration"
FONT 8, "MS Sans Serif", 0, 0, 0x0
@ -44,12 +44,14 @@ BEGIN
LTEXT "Downmix",IDC_STATIC,7,115,48,12
EDITTEXT IDC_DOWNMIX_CHANNELS,52,112,37,14,ES_AUTOHSCROLL
CONTROL "Disable tagfile",IDC_TAGFILE_DISABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,131,87,10
CONTROL "Disable tagfile",IDC_TAGFILE_DISABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,132,87,10
CONTROL "Force internal title",IDC_FORCE_TITLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,147,87,10
CONTROL "Force internal title",IDC_FORCE_TITLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,148,87,10
CONTROL "Enable unknown exts",IDC_EXTS_UNKNOWN_ON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,163,87,10
CONTROL "Enable unknown exts",IDC_EXTS_UNKNOWN_ON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,164,87,10
CONTROL "Enable common exts",IDC_EXTS_COMMON_ON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,179,87,10
CONTROL "Enable common exts",IDC_EXTS_COMMON_ON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,180,87,10
PUSHBUTTON "Open Log",IDC_LOG_BUTTON,7,196,50,14
END