Merge pull request #289 from bnnm/cleanup-eaxma-xvag-psh-vag-mib-etc

cleanup, eaxma, xvag, psh, vag, mib, etc
This commit is contained in:
Christopher Snowhill 2018-08-26 20:40:30 -07:00 committed by GitHub
commit 72d0b7a3b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
127 changed files with 3400 additions and 3637 deletions

View File

@ -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).
@ -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).

View File

@ -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

View File

@ -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```.

View File

@ -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,42 +14,38 @@ 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)
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 =
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
### 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

View File

@ -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"

View File

@ -71,7 +71,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../ext_libs/Getopt;../ext_includes;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;VGM_USE_ATRAC9;VGM_USE_CELT;_DEBUG;_WINDOWS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<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)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -97,7 +97,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>../ext_libs/Getopt;../ext_includes;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_MP4V2;VGM_USE_FDKAAC;VGM_USE_ATRAC9;VGM_USE_CELT;NDEBUG;_WINDOWS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<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)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>

View File

@ -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);
}

View File

@ -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 <exe>: 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
@ -138,9 +141,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=%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

View File

@ -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])]
)

View File

@ -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

View File

@ -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 @@
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../ext_includes"
PreprocessorDefinitions="WIN32;VGM_USE_FFMPEG;VGM_USE_G719;VGM_USE_G7221;NDEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS"
PreprocessorDefinitions="WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G719;VGM_USE_G7221;NDEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"

View File

@ -71,7 +71,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../ext_includes;$(DependenciesDir)/WTL/Include;$(DependenciesDir)/foobar/foobar2000/SDK;$(DependenciesDir)/foobar/foobar2000/shared;$(DependenciesDir)/foobar/foobar2000;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>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)</PreprocessorDefinitions>
<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)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -98,7 +98,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>../ext_includes;$(DependenciesDir)/WTL/Include;$(DependenciesDir)/foobar/foobar2000/SDK;$(DependenciesDir)/foobar/foobar2000/shared;$(DependenciesDir)/foobar/foobar2000;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>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)</PreprocessorDefinitions>
<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)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>

View File

@ -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<file> 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<file> 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<file> 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<file> 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<file> 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<file> 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);
}

View File

@ -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

View File

@ -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);
@ -222,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,
@ -252,5 +238,5 @@ int atrac9_parse_config(uint32_t atrac9_config, int *out_sample_rate, int *out_c
fail:
return 0;
}
#endif
#endif

View File

@ -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);
@ -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);
@ -142,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);
@ -242,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
@ -269,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);

View File

@ -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;
}

View File

@ -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_*/

View File

@ -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

View File

@ -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 */

View File

@ -2,7 +2,7 @@
#include "../util.h"
#include <math.h>
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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
outbuf[sample_count]=read_16bit(stream->offset+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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int16_t v = (uint8_t)read_8bit(stream->offset+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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int16_t v = (uint8_t)read_8bit(stream->offset+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; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
outbuf[sample_count]=read_16bit(stream->offset+i*2*channelspacing,stream->streamfile);
if (v&0x80) v = 0-(v&0x7f);
outbuf[sample_count] = v*0x100;
}
}

View File

@ -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;
}

View File

@ -79,9 +79,7 @@ static const char* extension_list[] = {
"bik",
"bika",
"bik2",
"bik2a",
"bk2",
"bk2a",
"bmdx",
"bms",
"bnk",
@ -108,6 +106,7 @@ static const char* extension_list[] = {
"cxs",
"da",
"dax",
"dbm",
"dcs",
"ddsp",
@ -216,6 +215,7 @@ static const char* extension_list[] = {
"mihb",
"mnstr",
"mogg",
//"mp3", //common
//"mp4", //common
//"mpc", //FFmpeg, not parsed (musepack) //common
"mpdsp",
@ -497,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"},
@ -616,7 +616,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"},
@ -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"},
@ -697,7 +698,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"},
@ -707,11 +708,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 +822,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"},
@ -953,10 +952,9 @@ 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 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"},

View File

@ -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

View File

@ -1,16 +1,18 @@
#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 +21,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 +38,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 +67,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 */
block_update(vgmstream);
if (vgmstream->samples_into_block == samples_this_block
/*&& vgmstream->current_sample < vgmstream->num_samples*/) { /* don't go past last block */ //todo
block_update(vgmstream->next_block_offset,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,124 +88,124 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
}
}
static void block_update(VGMSTREAM * vgmstream) {
/* helper functions to parse new block */
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;
}
}

View File

@ -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;i<vgmstream->channels;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;
}
}

View File

@ -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 */

View File

@ -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);

View File

@ -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;

View File

@ -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;
}
}
}

39
src/layout/flat.c Normal file
View File

@ -0,0 +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_per_frame, samples_this_block;
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
samples_this_block = vgmstream->num_samples; /* do all samples if possible */
while (samples_written < sample_count) {
int samples_to_do;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
/* handle looping */
continue;
}
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written;
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;
}
}

View File

@ -1,64 +1,92 @@
#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_written<sample_count) {
/* 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;
if (vgmstream->loop_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;
if (samples_this_block == 0 && vgmstream->channels == 1)
samples_this_block = vgmstream->num_samples;
}
continue;
}
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;
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);
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;chan<vgmstream->channels;chan++)
vgmstream->ch[chan].offset+=vgmstream->interleave_block_size*(vgmstream->channels-chan)+vgmstream->interleave_last_block_size*chan;
} else {
if (samples_this_block == 0 && vgmstream->channels == 1)
samples_this_block = vgmstream->num_samples;
for (chan=0;chan<vgmstream->channels;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;
}
}

View File

@ -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 */
}
}

View File

@ -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);
@ -49,7 +50,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);

View File

@ -1,33 +0,0 @@
#include "layout.h"
#include "../vgmstream.h"
void render_vgmstream_nolayout(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written=0;
const int samples_this_block = vgmstream->num_samples;
int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
while (samples_written<sample_count) {
int samples_to_do;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
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) {
memset(buffer + samples_written * vgmstream->channels, 0, sizeof(sample) * vgmstream->channels * (sample_count - samples_written));
return;
}
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;
}
}

View File

@ -2,35 +2,54 @@
#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_written<sample_count) {
while (samples_written < sample_count) {
int samples_to_do;
int samples_this_block = data->segments[data->current_segment]->num_samples;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
//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;
}
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;
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;
/* 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 +59,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;
}
}

View File

@ -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 @@
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../ext_includes"
PreprocessorDefinitions="WIN32;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_G719;USE_ALLOCA;NDEBUG;_LIB;"
PreprocessorDefinitions="WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G7221;VGM_USE_G719;USE_ALLOCA;NDEBUG;_LIB;"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
@ -240,6 +240,10 @@
RelativePath=".\meta\fsb5_interleave_streamfile.h"
>
</File>
<File
RelativePath=".\meta\kma9_streamfile.h"
>
</File>
<File
RelativePath=".\meta\opus_interleave_streamfile.h"
>
@ -248,6 +252,10 @@
RelativePath=".\meta\ppst_streamfile.h"
>
</File>
<File
RelativePath=".\meta\ps2_psh_streamfile.h"
>
</File>
<File
RelativePath=".\meta\sqex_scd_streamfile.h"
>
@ -255,6 +263,10 @@
<File
RelativePath=".\meta\ubi_lyn_ogg_streamfile.h"
>
</File>
<File
RelativePath=".\meta\xvag_streamfile.h"
>
</File>
</Filter>
<Filter
@ -371,6 +383,10 @@
<File
RelativePath=".\meta\ck.c"
>
</File>
<File
RelativePath=".\meta\csmp.c"
>
</File>
<File
RelativePath=".\meta\cstr.c"
@ -576,6 +592,10 @@
RelativePath=".\meta\mca.c"
>
</File>
<File
RelativePath=".\meta\mib_mih.c"
>
</File>
<File
RelativePath=".\meta\mn_str.c"
>
@ -963,7 +983,7 @@
>
</File>
<File
RelativePath=".\meta\ps2_mib.c"
RelativePath=".\meta\ps_headerless.c"
>
</File>
<File
@ -1138,10 +1158,6 @@
RelativePath=".\meta\ps3_ivag.c"
>
</File>
<File
RelativePath=".\meta\ps3_klbs.c"
>
</File>
<File
RelativePath=".\meta\ps3_msf.c"
>
@ -1182,10 +1198,14 @@
RelativePath=".\meta\raw.c"
>
</File>
<File
RelativePath=".\meta\redspark.c"
>
</File>
<File
RelativePath=".\meta\redspark.c"
>
</File>
<File
RelativePath=".\meta\rfrm.c"
>
</File>
<File
RelativePath=".\meta\riff.c"
>
@ -1430,10 +1450,14 @@
RelativePath=".\meta\wpd.c"
>
</File>
<File
RelativePath=".\meta\ws_aud.c"
>
</File>
<File
RelativePath=".\meta\ws_aud.c"
>
</File>
<File
RelativePath=".\meta\wsi.c"
>
</File>
<File
RelativePath=".\meta\wv6.c"
>
@ -1618,10 +1642,6 @@
RelativePath=".\coding\ffmpeg_decoder_utils_ea_schl.c"
>
</File>
<File
RelativePath=".\coding\ffmpeg_decoder_utils_ea_xma.c"
>
</File>
<File
RelativePath=".\coding\ffmpeg_decoder_utils_switch_opus.c"
>
@ -1895,7 +1915,7 @@
>
</File>
<File
RelativePath=".\layout\nolayout.c"
RelativePath=".\layout\flat.c"
>
</File>
<File

View File

@ -59,7 +59,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../ext_includes;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>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)</PreprocessorDefinitions>
<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)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -73,7 +73,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>../ext_includes;$(DependenciesDir)/qaac/mp4v2/include;$(DependenciesDir)/fdk-aac/libSYS/include;$(DependenciesDir)/fdk-aac/libAACdec/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_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)</PreprocessorDefinitions>
<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)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
@ -102,10 +102,12 @@
<ClInclude Include="meta\ea_schl_streamfile.h" />
<ClInclude Include="meta\fsb_interleave_streamfile.h" />
<ClInclude Include="meta\fsb5_interleave_streamfile.h" />
<ClInclude Include="meta\kma9_streamfile.h" />
<ClInclude Include="meta\ppst_streamfile.h" />
<ClInclude Include="meta\ps2_psh_streamfile.h" />
<ClInclude Include="meta\opus_interleave_streamfile.h" />
<ClInclude Include="meta\sqex_scd_streamfile.h" />
<ClInclude Include="meta\ubi_lyn_ogg_streamfile.h" />
<ClInclude Include="meta\xvag_streamfile.h" />
<ClInclude Include="meta\meta.h" />
<ClInclude Include="meta\hca_keys.h" />
<ClInclude Include="meta\fsb_keys.h" />
@ -123,7 +125,6 @@
<ClCompile Include="coding\celt_fsb_decoder.c" />
<ClCompile Include="coding\coding_utils.c" />
<ClCompile Include="coding\ffmpeg_decoder.c" />
<ClCompile Include="coding\ffmpeg_decoder_utils_ea_xma.c" />
<ClCompile Include="coding\ffmpeg_decoder_utils_switch_opus.c" />
<ClCompile Include="coding\ffmpeg_decoder_utils.c" />
<ClCompile Include="coding\lsf_decoder.c" />
@ -147,6 +148,7 @@
<ClCompile Include="meta\ktss.c" />
<ClCompile Include="meta\lsf.c" />
<ClCompile Include="meta\mattel_hyperscan.c" />
<ClCompile Include="meta\mib_mih.c" />
<ClCompile Include="meta\mn_str.c" />
<ClCompile Include="meta\mogg.c" />
<ClCompile Include="meta\mp4.c" />
@ -167,7 +169,6 @@
<ClCompile Include="meta\ps2_strlr.c" />
<ClCompile Include="meta\ps2_wmus.c" />
<ClCompile Include="meta\ps3_ivag.c" />
<ClCompile Include="meta\ps3_klbs.c" />
<ClCompile Include="meta\ps3_past.c" />
<ClCompile Include="meta\sgxd.c" />
<ClCompile Include="meta\sk_aud.c" />
@ -213,6 +214,7 @@
<ClCompile Include="meta\btsnd.c" />
<ClCompile Include="meta\capdsp.c" />
<ClCompile Include="meta\ck.c" />
<ClCompile Include="meta\csmp.c" />
<ClCompile Include="meta\cstr.c" />
<ClCompile Include="meta\dc_asd.c" />
<ClCompile Include="meta\dc_dcsw_dcs.c" />
@ -341,7 +343,7 @@
<ClCompile Include="meta\ps2_leg.c" />
<ClCompile Include="meta\ps2_lpcm.c" />
<ClCompile Include="meta\ps2_mcg.c" />
<ClCompile Include="meta\ps2_mib.c" />
<ClCompile Include="meta\ps_headerless.c" />
<ClCompile Include="meta\ps2_mic.c" />
<ClCompile Include="meta\ps2_mihb.c" />
<ClCompile Include="meta\ps2_msa.c" />
@ -385,6 +387,7 @@
<ClCompile Include="meta\ea_swvr.c" />
<ClCompile Include="meta\raw.c" />
<ClCompile Include="meta\redspark.c" />
<ClCompile Include="meta\rfrm.c" />
<ClCompile Include="meta\riff.c" />
<ClCompile Include="meta\rkv.c" />
<ClCompile Include="meta\rs03.c" />
@ -436,6 +439,7 @@
<ClCompile Include="meta\wii_sng.c" />
<ClCompile Include="meta\wii_sts.c" />
<ClCompile Include="meta\ws_aud.c" />
<ClCompile Include="meta\wsi.c" />
<ClCompile Include="meta\wv6.c" />
<ClCompile Include="meta\wvs.c" />
<ClCompile Include="meta\wwise.c" />
@ -522,7 +526,7 @@
<ClCompile Include="layout\interleave.c" />
<ClCompile Include="layout\blocked_ivaud.c" />
<ClCompile Include="layout\blocked_mxch.c" />
<ClCompile Include="layout\nolayout.c" />
<ClCompile Include="layout\flat.c" />
<ClCompile Include="layout\blocked_adm.c" />
<ClCompile Include="layout\blocked_ea_swvr.c" />
<ClCompile Include="layout\blocked_rws.c" />

View File

@ -86,18 +86,27 @@
<ClInclude Include="meta\fsb5_interleave_streamfile.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
<ClInclude Include="meta\kma9_streamfile.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
<ClInclude Include="meta\opus_interleave_streamfile.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
<ClInclude Include="meta\ppst_streamfile.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
<ClInclude Include="meta\ps2_psh_streamfile.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
<ClInclude Include="meta\sqex_scd_streamfile.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
<ClInclude Include="meta\ubi_lyn_ogg_streamfile.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
<ClInclude Include="meta\xvag_streamfile.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
<ClInclude Include="meta\meta.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
@ -223,6 +232,9 @@
<ClCompile Include="meta\ck.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\csmp.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\cstr.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -589,7 +601,7 @@
<ClCompile Include="meta\ps2_mcg.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps2_mib.c">
<ClCompile Include="meta\ps_headerless.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps2_mic.c">
@ -721,6 +733,9 @@
<ClCompile Include="meta\redspark.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\rfrm.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\riff.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -874,6 +889,9 @@
<ClCompile Include="meta\ws_aud.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\wsi.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\wv6.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -1126,7 +1144,7 @@
<ClCompile Include="layout\blocked_mxch.c">
<Filter>layout\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\nolayout.c">
<ClCompile Include="layout\flat.c">
<Filter>layout\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\blocked_adm.c">
@ -1252,9 +1270,6 @@
<ClCompile Include="meta\excitebots.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps3_klbs.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\mtaf_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
@ -1273,6 +1288,9 @@
<ClCompile Include="meta\wpd.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\mib_mih.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\mn_str.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -1336,9 +1354,6 @@
<ClCompile Include="coding\ffmpeg_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\ffmpeg_decoder_utils_ea_xma.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\ffmpeg_decoder_utils_switch_opus.c">
<Filter>coding\Source Files</Filter>
</ClCompile>

View File

@ -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

View File

@ -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;

View File

@ -42,7 +42,8 @@ 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++) {
vgmstream->ch[0].adpcm_coef[i]=read_16bitBE(header_offset+0xf6+i*2,streamFile);

View File

@ -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:

View File

@ -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;i<channel_count;i++) {
vgmstream->ch[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;
}

View File

@ -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;

View File

@ -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:

View File

@ -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 */

View File

@ -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 &&

View File

@ -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, 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) {
#ifdef VGM_USE_ATRAC9
case 0x02:
case 0x05:
if (read_32bitLE(start_offset+0x08,streamFile) + 0x08 != extradata_size) /* repeat? */
/* 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) {
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_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) {
#ifdef VGM_USE_ATRAC9
case 0x02:
case 0x05:
if (read_32bitLE(start_offset+0x10,streamFile) + 0x10 != extradata_size) /* repeat? */
switch(type) {
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? */
loop_length = read_32bitLE(start_offset+0x24,streamFile);
loop_start = read_32bitLE(start_offset+0x28,streamFile);
/* 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);
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 */
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)

View File

@ -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:

55
src/meta/csmp.c Normal file
View File

@ -0,0 +1,55 @@
#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_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;
}

View File

@ -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:

View File

@ -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) */
@ -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:
@ -127,7 +124,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 +133,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 +195,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);

View File

@ -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
@ -638,7 +620,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 +641,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 +649,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;
@ -694,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;
@ -729,7 +707,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 +717,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);
@ -774,8 +751,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:
@ -784,3 +759,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;
}

View File

@ -2,141 +2,184 @@
#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) {
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; 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;
}
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 0x0a: /* EATrax */
data->skip_size = 0x08;
data->data_size = read_32bitBE(data->physical_offset+0x04,streamfile); /* also block_size - 0x08 */
break;
#if 0
case 0x03:
data_size = block_size - ???;
extra_size = (data_size % 0x800); /* deflated padding */
skip_size = 0x08 + 0x04*data->stream_count;
break;
case 0x0c: /* EA Opus */
data->skip_size = 0x08;
data->data_size = data->block_size - data->skip_size;
break;
#endif
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;
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) {
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;
}
dest += bytes_read;
offset += bytes_read;
length -= bytes_read;
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;
}
/* block fully read, go next */
if (intradata_offset + bytes_read == data_size) {
data->physical_offset += block_size;
data->logical_offset += data_size;
total_read += bytes_done;
dest += bytes_done;
offset += bytes_done;
length -= bytes_done;
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,15 +188,21 @@ 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; 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 */
case 0x06: /* EALayer3 v2 "PCM" */
case 0x07: /* EALayer3 v2 "Spike" */
@ -161,46 +210,62 @@ 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;
/* 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->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 */
/* setup subfile */
new_streamFile = open_wrap_streamfile(streamFile);

View File

@ -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;
}
}
}

View File

@ -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:

View File

@ -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:

View File

@ -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:

View File

@ -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:

View File

@ -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 */
{

View File

@ -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) )

View File

@ -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;
}

View File

@ -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;
@ -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:

View File

@ -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;i<channel_count;i++) {
vgmstream->ch[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;

View File

@ -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:

View File

@ -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,9 @@ VGMSTREAM * init_vgmstream_kma9(STREAMFILE *streamFile) {
{
atrac9_config cfg = {0};
cfg.type = ATRAC9_KMA9;
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 +60,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;
}

148
src/meta/kma9_streamfile.h Normal file
View File

@ -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_ */

View File

@ -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 */
{

View File

@ -35,7 +35,9 @@ 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_rfrm(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ps2_ads_container(STREAMFILE *streamFile);
@ -59,13 +61,15 @@ 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);
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);
@ -107,8 +111,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);
@ -127,7 +129,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);
@ -563,8 +567,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);

60
src/meta/mib_mih.c Normal file
View File

@ -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;
}

View File

@ -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;
@ -93,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;

View File

@ -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:

View File

@ -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,179 +65,128 @@ 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 */
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 */
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)
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 */
vgmstream = allocate_vgmstream(dspm->channel_count,loop_flag);
@ -257,8 +205,18 @@ 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;
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 +249,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;
@ -348,6 +307,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;
@ -518,9 +478,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) {
@ -612,7 +570,6 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile) {
goto fail;
}
return init_vgmstream_dsp_common(streamFile, &dspm);
fail:
return NULL;
@ -714,107 +671,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};
@ -899,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};
@ -1041,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};
@ -1163,106 +1057,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};

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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;i<channel_count;i++) {
vgmstream->ch[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;
}

View File

@ -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:

View File

@ -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;

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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;

View File

@ -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:

View File

@ -1,111 +1,66 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
//#include <windows.h>
//#include <tchar.h>
/* 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;i<channel_count;i++)
{
vgmstream->ch[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;
}

View File

@ -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;i<channel_count;i++) {
vgmstream->ch[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;
}

View File

@ -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;i<channel_count;i++) {
vgmstream->ch[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;
}

View File

@ -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 * init_vgmstream_ps_headerless(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,14 @@ 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_PS_HEADERLESS;
vgmstream->allow_dual_stereo = 1;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
close_streamfile(streamFileMIH);
return vgmstream;
fail:
close_streamfile(streamFileMIH);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -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:

60
src/meta/rfrm.c Normal file
View File

@ -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;
}

View File

@ -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:
@ -254,19 +255,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;
}

View File

@ -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;

View File

@ -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:

View File

@ -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;

View File

@ -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;i<channel_count;i++) {
vgmstream->ch[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;
}

View File

@ -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

View File

@ -1,121 +1,99 @@
#include "../vgmstream.h"
#include "meta.h"
#include <ctype.h>
/* .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 <ctype.h>
#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

Some files were not shown because too many files have changed in this diff Show More