Merge pull request #940 from bnnm/bigfile-etc

- Cleanup and logs
- Add .psb/dyx extensions
- Tweak STREAMFILES to read +2GB files
- Handle +2GB .fsb and .ktsl2asbin [Nioh 2 (PC)]
This commit is contained in:
bnnm 2021-09-05 18:08:36 +02:00 committed by GitHub
commit dfa3779ad4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 1240 additions and 1116 deletions

View File

@ -221,6 +221,7 @@ export DEF_CFLAGS LIBS_CFLAGS LIBS_LDFLAGS LIBS_TARGET_EXT_LIBS
###############################################################################
### internal defs
ifeq ($(TARGET_OS),Windows_NT)
BIN_FILE = vgmstream-$(VGMSTREAM_VERSION)-win.zip
ZIP_FILES = COPYING
ZIP_FILES += README.md
ZIP_FILES += cli/test.exe
@ -231,6 +232,7 @@ ifeq ($(TARGET_OS),Windows_NT)
ZIP_FILES_AO = cli/vgmstream123.exe
ZIP_FILES_AO += $(LIBAO_DLL_PATH)/*.dll
else
BIN_FILE = vgmstream-$(VGMSTREAM_VERSION)-bin.zip
ZIP_FILES = COPYING
ZIP_FILES += README.md
ZIP_FILES += cli/vgmstream-cli
@ -245,25 +247,28 @@ buildrelease-ex: clean bin-ex
buildfullrelease: clean sourceball bin
# make a tmp copy of git's index to avoid including dev stuff
sourceball:
rm -rf vgmstream-$(VGMSTREAM_VERSION)
git checkout-index -f -a --prefix=vgmstream-$(VGMSTREAM_VERSION)/
# git archive --format zip --output vgmstream-$(VGMSTREAM_VERSION).zip master
echo "#!/bin/sh" > vgmstream-$(VGMSTREAM_VERSION)/version-get.sh
echo "echo \"$(VGMSTREAM_VERSION)\"" >> vgmstream-$(VGMSTREAM_VERSION)/version-get.sh
tar cvzf "vgmstream-$(VGMSTREAM_VERSION)-src.tar.gz" vgmstream-$(VGMSTREAM_VERSION)/*
# echo "#!/bin/sh" > vgmstream-$(VGMSTREAM_VERSION)/version-get.sh
# echo "echo \"$(VGMSTREAM_VERSION)\"" >> vgmstream-$(VGMSTREAM_VERSION)/version-get.sh
tar cvzf "bin/vgmstream-$(VGMSTREAM_VERSION)-src.tar.gz" vgmstream-$(VGMSTREAM_VERSION)/*
# git archive --format zip --output bin/vgmstream-$(VGMSTREAM_VERSION)-src.zip master
rm -rf vgmstream-$(VGMSTREAM_VERSION)
bin: vgmstream_cli winamp xmplay
bin: vgmstream-cli winamp xmplay
mkdir -p bin
zip -FS -j "bin/vgmstream-$(VGMSTREAM_VERSION).zip" $(ZIP_FILES)
zip -FS -j "bin/$(BIN_FILE).zip" $(ZIP_FILES)
#separate since vgmstream123 is kinda untested
bin-ex: vgmstream_cli winamp xmplay vgmstream123
bin-ex: vgmstream-cli winamp xmplay vgmstream123
mkdir -p bin
zip -FS -j "bin/vgmstream-$(VGMSTREAM_VERSION).zip" $(ZIP_FILES) $(ZIP_FILES_AO)
zip -FS -j "bin/$(BIN_FILE).zip" $(ZIP_FILES) $(ZIP_FILES_AO)
vgmstream_cli: version
vgmstream_cli: vgmstream-cli
vgmstream-cli: version
$(MAKE) -C cli vgmstream_cli
vgmstream123: version
@ -286,4 +291,4 @@ clean:
$(MAKE) -C xmplay clean
$(MAKE) -C ext_libs clean
.PHONY: clean buildfullrelease buildrelease sourceball bin vgmstream_cli winamp
.PHONY: clean buildfullrelease buildrelease sourceball bin vgmstream-cli vgmstream_cli vgmstream123 winamp xmplay version

View File

@ -20,6 +20,8 @@ Latest development is here: https://github.com/vgmstream/vgmstream/
Automated builds with the latest changes: https://vgmstream.org/downloads
Common releases: https://github.com/vgmstream/vgmstream/releases
Help can be found here: https://www.hcs64.com/
More technical docs: https://github.com/vgmstream/vgmstream/tree/master/doc
@ -47,8 +49,11 @@ If the above link fails you may find alt, recent-ish versions here:
https://github.com/bnnm/vgmstream-builds/raw/master/bin/vgmstream-latest-test-u.zip
You may compile them from source as well.
For Linux and other O.S., you need to build vgmstream manually (see *vgmstream/doc/BUILD.md*
in source).
For Linux and other O.S., generally you need to build vgmstream manually (see
*vgmstream/doc/BUILD.md* in source). For a quick build call `/make-build-cmake.sh`
(for Debian/Ubuntu-style distros, installs various deps first so you may prefer to call
commands manually). Links above also distribute a static version of the CLI tool
(kernel v3.2+).
### Needed extra files (for Windows)
On Windows support for some codecs (Ogg Vorbis, MPEG audio, etc.) is done with external
@ -685,8 +690,8 @@ foobar2000 has other plugins (with write support) that may be of use:
## Virtual TXTP files
Some of vgmstream's plugins allow you to use virtual `.txtp` files, that combined
with playlists let you make quick song configs.
Some of vgmstream's plugins (and CLI) allow you to use virtual `.txtp` files, that
combined with playlists let you make quick song configs.
Normally you can create a physical .txtp file that points to another file with
config, and `.txtp` have a "mini-txtp" mode that configures files with only the

View File

@ -12,13 +12,13 @@ extern "C" {
typedef struct {
STREAMFILE sf;
VFSFile *vfsFile;
off_t offset;
offv_t offset;
char name[32768];
} VFS_STREAMFILE;
static STREAMFILE *open_vfs_by_VFSFILE(VFSFile *file, const char *path);
static size_t read_vfs(VFS_STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length) {
static size_t read_vfs(VFS_STREAMFILE *streamfile, uint8_t *dest, offv_t offset, size_t length) {
size_t bytes_read;
if (/*!streamfile->vfsFile ||*/ !dest || length <= 0 || offset < 0)
@ -73,9 +73,9 @@ STREAMFILE *open_vfs_by_VFSFILE(VFSFile *file, const char *path) {
// success, set our pointers
memset(streamfile, 0, sizeof(VFS_STREAMFILE));
streamfile->sf.read = (size_t (*)(STREAMFILE *, uint8_t *, off_t, size_t))read_vfs;
streamfile->sf.read = (size_t (*)(STREAMFILE *, uint8_t *, offv_t, size_t))read_vfs;
streamfile->sf.get_size = (size_t (*)(STREAMFILE *))get_size_vfs;
streamfile->sf.get_offset = (off_t (*)(STREAMFILE *))get_offset_vfs;
streamfile->sf.get_offset = (offv_t (*)(STREAMFILE *))get_offset_vfs;
streamfile->sf.get_name = (void (*)(STREAMFILE *, char *, size_t))get_name_vfs;
streamfile->sf.open = (STREAMFILE *(*)(STREAMFILE *, const char *, size_t))open_vfs_impl;
streamfile->sf.close = (void (*)(STREAMFILE *))close_vfs;

View File

@ -285,7 +285,7 @@ sudo apt-get install gcc g++ make git
sudo apt-get install autoconf automake libtool
# vgmstream dependencies
sudo apt-get install libmpg123-dev libvorbis-dev libspeex-dev
#sudo apt-get install libavformat-dev libavcodec-dev libavutil-dev libswresample-dev
sudo apt-get install libavformat-dev libavcodec-dev libavutil-dev libswresample-dev
# Audacious player and dependencies
sudo apt-get install audacious
sudo apt-get install audacious-dev libglib2.0-dev libgtk2.0-dev libpango1.0-dev

View File

@ -10,7 +10,8 @@
#include <shared.h>
extern "C" {
#include "../src/vgmstream.h"
#include "../src/streamfile.h"
//#include "../src/vgmstream.h"
#include "../src/util.h"
}
#include "foo_vgmstream.h"
@ -18,184 +19,183 @@ extern "C" {
/* a STREAMFILE that operates via foobar's file service using a buffer */
typedef struct {
STREAMFILE sf; /* callbacks */
STREAMFILE vt; /* callbacks */
bool m_file_opened; /* if foobar IO service opened the file */
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 */
char* name; /* IO filename */
offv_t offset; /* last read offset (info) */
offv_t buf_offset; /* current buffer data start */
uint8_t* buf; /* data buffer */
size_t buf_size; /* max buffer size */
size_t valid_size; /* current buffer size */
size_t file_size; /* buffered file size */
} FOO_STREAMFILE;
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, bool m_file_opened, const char * const filename, size_t buffersize, abort_callback * p_abort);
static STREAMFILE* open_foo_streamfile_buffer(const char* const filename, size_t buf_size, abort_callback* p_abort, t_filestats* stats);
static STREAMFILE* open_foo_streamfile_buffer_by_file(service_ptr_t<file> m_file, bool m_file_opened, const char* const filename, size_t buf_size, abort_callback* p_abort);
static size_t read_foo(FOO_STREAMFILE *streamfile, uint8_t * dest, off_t offset, size_t length) {
size_t length_read_total = 0;
static size_t foo_read(FOO_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) {
size_t read_total = 0;
if (!streamfile || !streamfile->m_file_opened || !dest || length <= 0 || offset < 0)
if (!sf || !sf->m_file_opened || !dst || length <= 0 || offset < 0)
return 0;
/* is the part of the requested length in the 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;
if (offset >= sf->buf_offset && offset < sf->buf_offset + sf->valid_size) {
size_t buf_limit;
int buf_into = (int)(offset - sf->buf_offset);
length_to_read = streamfile->validsize - offset_into_buffer;
if (length_to_read > length)
length_to_read = length;
buf_limit = sf->valid_size - buf_into;
if (buf_limit > length)
buf_limit = 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;
memcpy(dst, sf->buf + buf_into, buf_limit);
read_total += buf_limit;
length -= buf_limit;
offset += buf_limit;
dst += buf_limit;
}
/* read the rest of the requested length */
while (length > 0) {
size_t length_to_read;
size_t buf_limit;
/* 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);
if (offset >= sf->file_size) {
//offset = sf->file_size; /* seems fseek doesn't clamp offset */
//VGM_ASSERT_ONCE(offset > sf->file_size, "STDIO: reading over file_size 0x%x @ 0x%lx + 0x%x\n", sf->file_size, offset, length);
break;
}
/* position to new offset */
try {
streamfile->m_file->seek(offset,*streamfile->p_abort);
sf->m_file->seek(offset, *sf->p_abort);
} catch (...) {
break; /* this shouldn't happen in our code */
}
/* fill the buffer (offset now is beyond buffer_offset) */
/* fill the buffer (offset now is beyond buf_offset) */
try {
streamfile->buffer_offset = offset;
streamfile->validsize = streamfile->m_file->read(streamfile->buffer,streamfile->buffersize,*streamfile->p_abort);
sf->buf_offset = offset;
sf->valid_size = sf->m_file->read(sf->buf, sf->buf_size, *sf->p_abort);
} catch(...) {
break; /* improbable? */
}
/* decide how much must be read this time */
if (length > streamfile->buffersize)
length_to_read = streamfile->buffersize;
if (length > sf->buf_size)
buf_limit = sf->buf_size;
else
length_to_read = length;
buf_limit = length;
/* 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;
if (sf->valid_size < buf_limit) {
memcpy(dst, sf->buf, sf->valid_size);
offset += sf->valid_size;
read_total += sf->valid_size;
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;
memcpy(dst, sf->buf, buf_limit);
offset += buf_limit;
read_total += buf_limit;
length -= buf_limit;
dst += buf_limit;
}
streamfile->offset = offset; /* last fread offset */
return length_read_total;
sf->offset = offset; /* last fread offset */
return read_total;
}
static size_t get_size_foo(FOO_STREAMFILE * streamfile) {
return streamfile->filesize;
static size_t foo_get_size(FOO_STREAMFILE* sf) {
return sf->file_size;
}
static off_t get_offset_foo(FOO_STREAMFILE *streamfile) {
return streamfile->offset;
static offv_t foo_get_offset(FOO_STREAMFILE* sf) {
return sf->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 foo_get_name(FOO_STREAMFILE* sf, char* name, size_t name_size) {
/* Most crap only cares about the filename itself */
size_t ourlen = strlen(sf->name);
if (ourlen > name_size) {
if (name_size) strcpy(name, sf->name + ourlen - name_size + 1);
}
else {
strcpy(name, sf->name);
}
}
static void close_foo(FOO_STREAMFILE * streamfile) {
streamfile->m_file.release(); //release alloc'ed ptr
free(streamfile->name);
free(streamfile->buffer);
free(streamfile);
static void foo_close(FOO_STREAMFILE* sf) {
sf->m_file.release(); //release alloc'ed ptr
free(sf->name);
free(sf->buf);
free(sf);
}
static STREAMFILE *open_foo(FOO_STREAMFILE *streamFile,const char * const filename,size_t buffersize) {
static STREAMFILE* foo_open(FOO_STREAMFILE* sf, const char* const filename,size_t buf_size) {
service_ptr_t<file> m_file;
STREAMFILE *newstreamFile;
if (!filename)
return NULL;
// if same name, duplicate the file pointer we already have open
if (streamFile->m_file_opened && !strcmp(streamFile->name,filename)) {
m_file = streamFile->m_file; //copy?
if (sf->m_file_opened && !strcmp(sf->name,filename)) {
m_file = sf->m_file; //copy?
{
newstreamFile = open_foo_streamfile_buffer_by_file(m_file, streamFile->m_file_opened, filename, buffersize, streamFile->p_abort);
if (newstreamFile) {
return newstreamFile;
STREAMFILE* new_sf = open_foo_streamfile_buffer_by_file(m_file, sf->m_file_opened, filename, buf_size, sf->p_abort);
if (new_sf) {
return new_sf;
}
// failure, close it and try the default path (which will probably fail a second time)
}
}
// a normal open, open a new file
return open_foo_streamfile_buffer(filename,buffersize,streamFile->p_abort,NULL);
return open_foo_streamfile_buffer(filename,buf_size,sf->p_abort,NULL);
}
static STREAMFILE * open_foo_streamfile_buffer_by_file(service_ptr_t<file> m_file, bool m_file_opened, const char * const filename, size_t buffersize, abort_callback * p_abort) {
uint8_t * buffer;
FOO_STREAMFILE * streamfile;
static STREAMFILE* open_foo_streamfile_buffer_by_file(service_ptr_t<file> m_file, bool m_file_opened, const char* const filename, size_t buf_size, abort_callback* p_abort) {
uint8_t* buf;
FOO_STREAMFILE* this_sf;
buffer = (uint8_t *) calloc(buffersize,1);
if (!buffer) goto fail;
buf = (uint8_t*) calloc(buf_size, sizeof(uint8_t));
if (!buf) goto fail;
streamfile = (FOO_STREAMFILE *) calloc(1,sizeof(FOO_STREAMFILE));
if (!streamfile) goto fail;
this_sf = (FOO_STREAMFILE*) calloc(1, sizeof(FOO_STREAMFILE));
if (!this_sf) 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;
streamfile->sf.get_offset = (off_t (__cdecl *)(_STREAMFILE *)) get_offset_foo;
streamfile->sf.get_name = (void (__cdecl *)(_STREAMFILE *,char *,size_t)) get_name_foo;
streamfile->sf.open = (_STREAMFILE *(__cdecl *)(_STREAMFILE *,const char *const ,size_t)) open_foo;
streamfile->sf.close = (void (__cdecl *)(_STREAMFILE *)) close_foo;
this_sf->vt.read = (size_t (__cdecl *)(_STREAMFILE*, uint8_t*, offv_t, size_t)) foo_read;
this_sf->vt.get_size = (size_t (__cdecl *)(_STREAMFILE*)) foo_get_size;
this_sf->vt.get_offset = (offv_t (__cdecl *)(_STREAMFILE*)) foo_get_offset;
this_sf->vt.get_name = (void (__cdecl *)(_STREAMFILE*, char*, size_t)) foo_get_name;
this_sf->vt.open = (_STREAMFILE* (__cdecl *)(_STREAMFILE* ,const char* const, size_t)) foo_open;
this_sf->vt.close = (void (__cdecl *)(_STREAMFILE* )) foo_close;
streamfile->m_file_opened = m_file_opened;
streamfile->m_file = m_file;
streamfile->p_abort = p_abort;
streamfile->buffersize = buffersize;
streamfile->buffer = buffer;
this_sf->m_file_opened = m_file_opened;
this_sf->m_file = m_file;
this_sf->p_abort = p_abort;
this_sf->buf_size = buf_size;
this_sf->buf = buf;
streamfile->name = strdup(filename);
if (!streamfile->name) goto fail;
this_sf->name = strdup(filename);
if (!this_sf->name) goto fail;
/* cache filesize */
if (streamfile->m_file_opened)
streamfile->filesize = streamfile->m_file->get_size(*streamfile->p_abort);
/* cache file_size */
if (this_sf->m_file_opened)
this_sf->file_size = this_sf->m_file->get_size(*this_sf->p_abort);
else
streamfile->filesize = 0;
this_sf->file_size = 0;
return &streamfile->sf;
return &this_sf->vt;
fail:
free(buffer);
free(streamfile);
free(buf);
free(this_sf);
return NULL;
}
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(const char* const filename, size_t buf_size, abort_callback* p_abort, t_filestats* stats) {
STREAMFILE* sf = NULL;
service_ptr_t<file> infile;
bool infile_exists;
@ -213,7 +213,7 @@ static STREAMFILE* open_foo_streamfile_buffer(const char* const filename, size_t
if(stats) *stats = infile->get_stats(*p_abort);
}
sf = open_foo_streamfile_buffer_by_file(infile, infile_exists, filename, buffersize, p_abort);
sf = open_foo_streamfile_buffer_by_file(infile, infile_exists, filename, buf_size, p_abort);
if (!sf) {
//m_file.release(); //refcounted and cleaned after it goes out of scope
}

View File

@ -3,6 +3,10 @@
#define SAMPLE_BUFFER_SIZE 1024
extern "C" {
#include "../src/vgmstream.h"
}
class input_vgmstream : public input_stubs {
public:
@ -69,18 +73,18 @@ class input_vgmstream : public input_stubs {
//bool exts_unknown_on;
/* helpers */
VGMSTREAM * init_vgmstream_foo(t_uint32 p_subsong, const char * const filename, abort_callback & p_abort);
void setup_vgmstream(abort_callback & p_abort);
VGMSTREAM* init_vgmstream_foo(t_uint32 p_subsong, const char* const filename, abort_callback& p_abort);
void setup_vgmstream(abort_callback& p_abort);
void load_settings();
void get_subsong_info(t_uint32 p_subsong, pfc::string_base & title, int *length_in_ms, int *total_samples, int *loop_flag, int *loop_start, int *loop_end, int *sample_rate, int *channels, int *bitrate, pfc::string_base & description, abort_callback & p_abort);
bool get_description_tag(pfc::string_base & temp, pfc::string_base const& description, const char *tag, char delimiter = '\n');
void apply_config(VGMSTREAM * vgmstream);
void get_subsong_info(t_uint32 p_subsong, pfc::string_base& title, int* length_in_ms, int* total_samples, int* loop_flag, int *loop_start, int* loop_end, int* sample_rate, int* channels, int* bitrate, pfc::string_base& description, abort_callback& p_abort);
bool get_description_tag(pfc::string_base& temp, pfc::string_base const& description, const char* tag, char delimiter = '\n');
void apply_config(VGMSTREAM* vgmstream);
static void g_load_cfg(int *accept_unknown, int *accept_common);
static void g_load_cfg(int* accept_unknown, int* accept_common);
};
/* foo_streamfile.cpp */
STREAMFILE * open_foo_streamfile(const char * const filename, abort_callback * p_abort, t_filestats * stats);
STREAMFILE* open_foo_streamfile(const char* const filename, abort_callback* p_abort, t_filestats* stats);
#endif /*_FOO_VGMSTREAM_*/

13
make-build-cmake.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/sh
# example script that builds vgmstream with most libs enabled using CMake + make
sudo apt-get update
sudo apt-get install gcc g++ make build-essential git cmake
sudo apt-get install libao-dev audacious-dev libjansson-dev
sudo apt-get install libvorbis-dev libmpg123-dev libspeex-dev libavformat-dev libavcodec-dev libavutil-dev libswresample-dev
mkdir -p build
cd build
cmake -S .. -B .
make

View File

@ -15,18 +15,25 @@ if((Test-Path $config_file)) { . $config_file }
# - toolsets: "" (default), "v140" (MSVC 2015), "v141" (MSVC 2017), "v141_xp" (XP support), "v142" (MSVC 2019), etc
if (!$toolset) { $toolset = "" }
# - sdks: "" (default), "7.0" (Win7 SDK), "8.1" (Win8 SDK), "10.0" (Win10 SDK), etc
if (!$sdk) { $sdk = "" }
# - platforms: "" (default), "Win32"
if (!$platform) { $platform = "" }
# print compilation log
#$log = 1
# Debug or Release, usually
if (!$configuration) { $configuration = "Release" }
###############################################################################
$solution = "vgmstream_full.sln"
$dependencies = "dependencies"
$vswhere = "$dependencies/vswhere.exe"
$config = "/p:Configuration=Release"
$config = "/p:Configuration=" + $configuration
# not used ATM
$enable_aac = 0
@ -155,7 +162,7 @@ function Clean
Remove-Item -Path "cli/Release" -Recurse -ErrorAction Ignore
Remove-Item -Path "ext_libs/Debug" -Recurse -ErrorAction Ignore
Remove-Item -Path "ext_libs/Release" -Recurse -ErrorAction Ignore
Remove-Item -Path "ext_libs/Getopt/Release" -Recurse -ErrorAction Ignore
Remove-Item -Path "ext_libs/Getopt/Debug" -Recurse -ErrorAction Ignore
Remove-Item -Path "ext_libs/Getopt/Release" -Recurse -ErrorAction Ignore
Remove-Item -Path "fb2k/Debug" -Recurse -ErrorAction Ignore
Remove-Item -Path "fb2k/Release" -Recurse -ErrorAction Ignore
@ -174,48 +181,48 @@ function Clean
$fb2kFiles = @(
"ext_libs/*.dll",
"ext_libs/libspeex/*.dll",
"Release/foo_input_vgmstream.dll",
"$configuration/foo_input_vgmstream.dll",
"README.md"
)
$cliFiles = @(
"ext_libs/*.dll",
"ext_libs/libspeex/*.dll",
"Release/in_vgmstream.dll",
"Release/test.exe",
"Release/xmp-vgmstream.dll",
"$configuration/in_vgmstream.dll",
"$configuration/test.exe",
"$configuration/xmp-vgmstream.dll",
"COPYING",
"README.md"
)
$fb2kPdbFiles = @(
"Release/foo_input_vgmstream.pdb"
"$configuration/foo_input_vgmstream.pdb"
)
$cliPdbFiles = @(
"Release/in_vgmstream.pdb",
"Release/test.pdb",
"Release/xmp-vgmstream.pdb"
"$configuration/in_vgmstream.pdb",
"$configuration/test.pdb",
"$configuration/xmp-vgmstream.pdb"
)
function Package
{
Build
if(!(Test-Path "Release/test.exe")) {
if(!(Test-Path "$configuration/test.exe")) {
Write-Error "Unable to find binaries, check for compilation errors"
}
Compress-Archive $cliFiles Release/vgmstream-win.zip -Force
Compress-Archive $fb2kFiles Release/foo_input_vgmstream.zip -Force
Compress-Archive $cliPdbFiles Release/vgmstream-win.pdb.zip -Force
Compress-Archive $fb2kPdbFiles Release/foo_input_vgmstream.pdb.zip -Force
Compress-Archive $cliFiles $configuration/vgmstream-win.zip -Force
Compress-Archive $fb2kFiles $configuration/foo_input_vgmstream.zip -Force
Compress-Archive $cliPdbFiles $configuration/vgmstream-win.pdb.zip -Force
Compress-Archive $fb2kPdbFiles $configuration/foo_input_vgmstream.pdb.zip -Force
md -Force bin
Move-Item Release/vgmstream-win.zip bin/vgmstream-win.zip -Force
Move-Item Release/foo_input_vgmstream.zip bin/foo_input_vgmstream.fb2k-component -Force
Move-Item Release/vgmstream-win.pdb.zip bin/vgmstream-win.pdb.zip -Force
Move-Item Release/foo_input_vgmstream.pdb.zip bin/foo_input_vgmstream.pdb.zip -Force
Move-Item $configuration/vgmstream-win.zip bin/vgmstream-win.zip -Force
Move-Item $configuration/foo_input_vgmstream.zip bin/foo_input_vgmstream.fb2k-component -Force
Move-Item $configuration/vgmstream-win.pdb.zip bin/vgmstream-win.pdb.zip -Force
Move-Item $configuration/foo_input_vgmstream.pdb.zip bin/foo_input_vgmstream.pdb.zip -Force
}

View File

@ -682,6 +682,6 @@ int mpc_get_samples(STREAMFILE* sf, off_t offset, int32_t* p_samples, int32_t* p
/* helper to pass a wrapped, clamped, fake extension-ed, SF to another meta */
STREAMFILE* setup_subfile_streamfile(STREAMFILE* sf, off_t subfile_offset, size_t subfile_size, const char* extension);
STREAMFILE* setup_subfile_streamfile(STREAMFILE* sf, offv_t subfile_offset, size_t subfile_size, const char* extension);
#endif /*_CODING_H*/

View File

@ -1015,21 +1015,21 @@ size_t aac_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) {
/* variable-sized var reader */
static int mpc_get_size(uint8_t* header, int header_size, int pos, int32_t* p_size) {
uint8_t tmp;
int32_t size = 0;
uint8_t tmp;
int32_t size = 0;
do {
do {
if (pos >= header_size)
return pos;
tmp = header[pos];
size = (size << 7) | (tmp & 0x7F);
pos++;
}
tmp = header[pos];
size = (size << 7) | (tmp & 0x7F);
pos++;
}
while((tmp & 0x80));
*p_size = size;
return pos;
*p_size = size;
return pos;
}
int mpc_get_samples(STREAMFILE* sf, off_t offset, int32_t* p_samples, int32_t* p_delay) {
@ -1092,8 +1092,8 @@ fail:
/* CUSTOM STREAMFILES */
/* ******************************************** */
STREAMFILE* setup_subfile_streamfile(STREAMFILE* sf, off_t subfile_offset, size_t subfile_size, const char* extension) {
STREAMFILE *new_sf = NULL;
STREAMFILE* setup_subfile_streamfile(STREAMFILE* sf, offv_t subfile_offset, size_t subfile_size, const char* extension) {
STREAMFILE* new_sf = NULL;
new_sf = open_wrap_streamfile(sf);
new_sf = open_clamp_streamfile_f(new_sf, subfile_offset, subfile_size);

View File

@ -115,9 +115,9 @@ void decode_ea_mt(VGMSTREAM* vgmstream, sample_t* outbuf, int channelspacing, in
* notify the decoder when a new substream begins (even with looping disabled). */
if (ch_data->loop_sample > 0 && ch_data->samples_done == ch_data->loop_sample) {
ch_data->samples_filled = 0;
ch_data->samples_discard = 0;
ch_data->samples_discard = 0;
/* offset is usually at loop_offset here, but not always (ex. loop_sample < 432) */
/* offset is usually at loop_offset here, but not always (ex. loop_sample < 432) */
ch_data->offset = ch_data->loop_offset;
utk_set_ptr(ctx, 0, 0); /* reset the buffer reader */
utk_reset(ctx); /* decoder init (all fields must be reset, for some edge cases) */

View File

@ -322,7 +322,7 @@ ffmpeg_codec_data* init_ffmpeg_header_offset_subsong(STREAMFILE* sf, uint8_t* he
goto fail;
if (size == 0 || start + size > get_streamfile_size(sf)) {
VGM_LOG("FFMPEG: wrong start+size found: %x + %x > %x \n", (uint32_t)start, (uint32_t)size, get_streamfile_size(sf));
vgm_asserti(size != 0, "FFMPEG: wrong start+size found: %x + %x > %x \n", (uint32_t)start, (uint32_t)size, get_streamfile_size(sf));
size = get_streamfile_size(sf) - start;
}

View File

@ -72,7 +72,7 @@ fail:
}
void decode_hca(hca_codec_data* data, sample_t* outbuf, int32_t samples_to_do) {
int samples_done = 0;
int samples_done = 0;
const unsigned int channels = data->info.channelCount;
const unsigned int blockSize = data->info.blockSize;

View File

@ -30,25 +30,25 @@ void clHCA_delete(clHCA *);
int clHCA_DecodeHeader(clHCA *, const void *data, unsigned int size);
typedef struct clHCA_stInfo {
unsigned int version;
unsigned int headerSize;
unsigned int samplingRate;
unsigned int channelCount;
unsigned int blockSize;
unsigned int blockCount;
unsigned int version;
unsigned int headerSize;
unsigned int samplingRate;
unsigned int channelCount;
unsigned int blockSize;
unsigned int blockCount;
unsigned int encoderDelay; /* samples appended to the beginning */
unsigned int encoderPadding; /* samples appended to the end */
unsigned int loopEnabled;
unsigned int loopStartBlock;
unsigned int loopEndBlock;
unsigned int loopEnabled;
unsigned int loopStartBlock;
unsigned int loopEndBlock;
unsigned int loopStartDelay; /* samples in block before loop starts */
unsigned int loopEndPadding; /* samples in block after loop ends */
unsigned int samplesPerBlock; /* should be 1024 */
const char *comment;
unsigned int encryptionEnabled; /* requires keycode */
const char *comment;
unsigned int encryptionEnabled; /* requires keycode */
/* Derived sample formulas:
* - sample count: blockCount*samplesPerBlock - encoderDelay - encoderPadding;
/* Derived sample formulas:
* - sample count: blockCount*samplesPerBlock - encoderDelay - encoderPadding;
* - loop start sample = loopStartBlock*samplesPerBlock - encoderDelay + loopStartDelay
* - loop end sample = loopEndBlock*samplesPerBlock - encoderDelay + (samplesPerBlock - info.loopEndPadding)
*/

View File

@ -289,8 +289,8 @@ imuse_codec_data* init_imuse(STREAMFILE* sf, int channels) {
while (counter > 0) {
if (counter & i)
value += step;
step >>= 1;
counter >>= 1;
step >>= 1;
counter >>= 1;
}
data->adpcm_table[i + j * 64] = value; /* non sequential: all 64 [0]s, [1]s ... [88]s */

View File

@ -250,11 +250,11 @@ static void decode_mpeg_standard(VGMSTREAMCHANNEL* stream, mpeg_codec_data* data
data->bytes_in_buffer = read_streamfile(data->buffer,stream->offset,data->buffer_size,stream->streamfile);
/* end of stream, fill rest with 0s */
if (data->bytes_in_buffer <= 0) {
VGM_ASSERT(samples_to_do < samples_done, "MPEG: end of stream, filling %i\n", (samples_to_do - samples_done));
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample));
break;
}
if (data->bytes_in_buffer <= 0) {
VGM_ASSERT(samples_to_do < samples_done, "MPEG: end of stream, filling %i\n", (samples_to_do - samples_done));
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample));
break;
}
data->buffer_full = 1;
data->buffer_used = 0;

View File

@ -26,8 +26,8 @@ extern void fft(int n, float* xRe, float* xIm, float* yRe, float* yIm);
#define RELIC_MAX_SIZE RELIC_SIZE_HIGH
#define RELIC_MAX_FREQ (RELIC_MAX_SIZE / 2)
#define RELIC_MAX_FFT (RELIC_MAX_SIZE / 4)
#define RELIC_MIN_BITRATE 256
#define RELIC_MAX_BITRATE 2048
#define RELIC_MIN_BITRATE 256
#define RELIC_MAX_BITRATE 2048
//#define RELIC_MAX_FRAME_SIZE ((RELIC_MAX_BITRATE / 8) + 0x04) /* extra 0x04 for the bitreader */

View File

@ -6,24 +6,22 @@
/* Based on Valery V. Anisimovsky's WS-AUD.txt */
static char WSTable2bit[4]={-2,-1,0,1};
static char WSTable4bit[16]={-9,-8,-6,-5,-4,-3,-2,-1,
0, 1, 2, 3, 4, 5 ,6, 8};
static char WSTable2bit[4] = { -2,-1,0,1 };
static char WSTable4bit[16] = { -9,-8,-6,-5,-4,-3,-2,-1, 0, 1, 2, 3, 4, 5 ,6, 8 };
/* We pass in the VGMSTREAM here, unlike in other codings, because
the decoder has to know about the block structure. */
void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channelspacing, int32_t first_sample,
int32_t samples_to_do) {
VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]);
int16_t hist = stream->adpcm_history1_16;
int16_t hist = stream->adpcm_history1_16;
off_t offset = stream->offset;
int samples_left_in_frame = stream->samples_left_in_frame;
off_t header_off = stream->frame_header_offset;
int i;
int32_t sample_count;
int i;
int32_t sample_count;
if (vgmstream->ws_output_size == vgmstream->current_block_size) {
/* uncompressed, we just need to convert to 16-bit */
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing,offset++) {

View File

@ -164,6 +164,7 @@ static const char* extension_list[] = {
"dtk",
"dvi",
"dxh",
"dyx", //txth/reserved [Shrek 4 (iOS)]
"e4x",
"eam",
@ -392,6 +393,7 @@ static const char* extension_list[] = {
"pona",
"pos",
"ps2stm", //fake extension for .stm (renamed? to be removed?)
"psb", //txth/reserved [Legend of Mana (Switch), Senxin Aleste (AC)]
"psf",
"psh", //fake extension for .vsv (to be removed)
"psnd",
@ -853,7 +855,7 @@ static const coding_info coding_info_list[] = {
{coding_FFmpeg, "FFmpeg"},
#endif
#ifdef VGM_USE_FDKAAC
{coding_MP4_AAC, "MPEG-4 AAC"},
{coding_MP4_AAC, "MPEG-4 AAC"},
#endif
};

View File

@ -239,7 +239,7 @@ void blocked_count_samples(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t offset) {
case coding_PCM8_U_int: block_samples = pcm8_bytes_to_samples(vgmstream->current_block_size, 1); break;
case coding_XBOX_IMA: block_samples = xbox_ima_bytes_to_samples(vgmstream->current_block_size, 1); break;
case coding_NGC_DSP: block_samples = dsp_bytes_to_samples(vgmstream->current_block_size, 1); break;
case coding_PSX: block_samples = ps_bytes_to_samples(vgmstream->current_block_size,1); break;
case coding_PSX: block_samples = ps_bytes_to_samples(vgmstream->current_block_size,1); break;
default:
VGM_LOG("BLOCKED: missing codec\n");
return;

View File

@ -5,7 +5,7 @@ VGMSTREAM* init_vgmstream_adp_bos(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag = 0;
int channels;
int channels;
/* checks */
if (!check_extensions(sf,"adp"))
@ -19,7 +19,7 @@ VGMSTREAM* init_vgmstream_adp_bos(STREAMFILE* sf) {
start_offset = 0x18;
/* build the VGMSTREAM */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;

View File

@ -234,7 +234,7 @@ static void load_awb_name(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstre
}
}
/* probably loaded */
/* probably loaded */
load_acb_wave_name(sf_acb, vgmstream, waveid, port, is_memory);
close_streamfile(sf_acb);

View File

@ -1,147 +1,154 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util.h"
static int bink_get_info(STREAMFILE *streamFile, int target_subsong, int * out_total_streams, size_t *out_stream_size, int * out_channel_count, int * out_sample_rate, int * out_num_samples);
/* BINK 1/2 - RAD Game Tools movies (audio/video format) */
VGMSTREAM * init_vgmstream_bik(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int channel_count = 0, loop_flag = 0, sample_rate = 0, num_samples = 0;
int total_subsongs = 0, target_subsong = streamFile->stream_index;
size_t stream_size;
/* 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 &&
(read_32bitBE(0x00,streamFile) & 0xffffff00) != 0x4B423200 ) goto fail;
/* find target stream info and samples */
if (!bink_get_info(streamFile, target_subsong, &total_subsongs, &stream_size, &channel_count, &sample_rate, &num_samples))
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->layout_type = layout_none;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
vgmstream->meta_type = meta_BINK;
#ifdef VGM_USE_FFMPEG
{
/* target_subsong should be passed manually */
vgmstream->codec_data = init_ffmpeg_header_offset_subsong(streamFile, NULL,0, 0x0,get_streamfile_size(streamFile), target_subsong);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
}
#else
goto fail;
#endif
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/**
* Gets stream info, and number of samples in a BINK file by reading all frames' headers (as it's VBR),
* as they are not in the main header. The header for BINK1 and 2 is the same.
* (a ~3 min movie needs ~6000-7000 frames = fseeks, should be fast enough)
*/
static int bink_get_info(STREAMFILE *streamFile, int target_subsong, int * out_total_subsongs, size_t * out_stream_size, int * out_channel_count, int * out_sample_rate, int * out_num_samples) {
uint32_t *offsets = NULL;
uint32_t num_frames, num_samples_b = 0;
off_t cur_offset;
int i, j, sample_rate, channel_count;
int total_subsongs;
size_t stream_size = 0;
size_t filesize = get_streamfile_size(streamFile);
uint32_t signature = (read_32bitBE(0x00,streamFile) & 0xffffff00);
uint8_t revision = (read_32bitBE(0x00,streamFile) & 0xFF);
if (read_32bitLE(0x04,streamFile)+ 0x08 != filesize)
goto fail;
num_frames = (uint32_t)read_32bitLE(0x08,streamFile);
if (num_frames == 0 || num_frames > 0x100000) goto fail; /* something must be off (avoids big allocs below) */
/* multichannel/multilanguage audio is usually N streams of stereo/mono, no way to know channel layout */
total_subsongs = read_32bitLE(0x28,streamFile);
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1 || total_subsongs > 255) goto fail;
/* find stream info and position in offset table */
cur_offset = 0x2c;
if ((signature == 0x42494B00 && (revision == 0x6b)) || /* k */
(signature == 0x4B423200 && (revision == 0x69 || revision == 0x6a || revision == 0x6b))) /* i,j,k */
cur_offset += 0x04; /* unknown v2 header field */
cur_offset += 0x04*total_subsongs; /* skip streams max packet bytes */
sample_rate = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x00,streamFile);
channel_count = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x02,streamFile) & 0x2000 ? 2 : 1; /* stereo flag */
cur_offset += 0x04*total_subsongs; /* skip streams info */
cur_offset += 0x04*total_subsongs; /* skip streams ids */
/* read frame offsets in a buffer, to avoid fseeking to the table back and forth */
offsets = malloc(sizeof(uint32_t) * num_frames);
if (!offsets) goto fail;
for (i=0; i < num_frames; i++) {
offsets[i] = read_32bitLE(cur_offset,streamFile) & 0xFFFFFFFE; /* mask first bit (= keyframe) */
cur_offset += 0x4;
if (offsets[i] > filesize) goto fail;
}
/* after the last index is the file size, validate just in case */
if (read_32bitLE(cur_offset,streamFile) != filesize) goto fail;
/* read each frame header and sum all samples
* a frame has N audio packets with a header (one per stream) + video packet */
for (i=0; i < num_frames; i++) {
cur_offset = offsets[i];
/* read audio packet headers per stream */
for (j=0; j < total_subsongs; j++) {
uint32_t ap_size = read_32bitLE(cur_offset+0x00,streamFile); /* not counting this int */
if (j == target_subsong-1) {
stream_size += 0x04 + ap_size;
if (ap_size > 0)
num_samples_b += read_32bitLE(cur_offset+0x04,streamFile); /* decoded samples in bytes */
break; /* next frame */
}
else { /* next stream packet or frame */
cur_offset += 4 + ap_size; //todo sometimes ap_size doesn't include itself (+4), others it does?
}
}
}
free(offsets);
if (out_total_subsongs) *out_total_subsongs = total_subsongs;
if (out_stream_size) *out_stream_size = stream_size;
if (out_sample_rate) *out_sample_rate = sample_rate;
if (out_channel_count) *out_channel_count = channel_count;
//todo returns a few more samples (~48) than binkconv.exe?
if (out_num_samples) *out_num_samples = num_samples_b / (2 * channel_count);
return 1;
fail:
free(offsets);
return 0;
}
#include "meta.h"
#include "../coding/coding.h"
#include "../util.h"
static int bink_get_info(STREAMFILE* sf, int target_subsong, int* p_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples);
/* BINK 1/2 - RAD Game Tools movies (audio/video format) */
VGMSTREAM* init_vgmstream_bik(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL;
int channels = 0, loop_flag = 0, sample_rate = 0, num_samples = 0;
int total_subsongs = 0, target_subsong = sf->stream_index;
size_t stream_size;
/* checks */
/* .bik/bik2/bk2: standard
* .bika: fake extension for demuxed audio */
if (!check_extensions(sf,"bik,bik2,bk2,bika"))
goto fail;
/* check bink1/2 header, followed by version-char (audio is the same) */
if ((read_32bitBE(0x00,sf) & 0xffffff00) != get_id32be("BIK\0") &&
(read_32bitBE(0x00,sf) & 0xffffff00) != get_id32be("KB2\0"))
goto fail;
/* find target stream info and samples */
if (!bink_get_info(sf, target_subsong, &total_subsongs, &stream_size, &channels, &sample_rate, &num_samples))
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->layout_type = layout_none;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
vgmstream->meta_type = meta_BINK;
#ifdef VGM_USE_FFMPEG
{
/* target_subsong should be passed manually */
vgmstream->codec_data = init_ffmpeg_header_offset_subsong(sf, NULL,0, 0x0,0, target_subsong);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
}
#else
goto fail;
#endif
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/**
* Gets stream info, and number of samples in a BINK file by reading all frames' headers (as it's VBR),
* as they are not in the main header. The header for BINK1 and 2 is the same.
* (a ~3 min movie needs ~6000-7000 frames = fseeks, should be fast enough)
*/
static int bink_get_info(STREAMFILE* sf, int target_subsong, int* p_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples) {
uint32_t* offsets = NULL;
uint32_t num_frames, num_samples_b = 0;
off_t cur_offset;
int i, j, sample_rate, channels;
int total_subsongs;
size_t stream_size = 0;
size_t filesize = get_streamfile_size(sf);
uint32_t signature = (read_32bitBE(0x00,sf) & 0xffffff00);
uint8_t revision = (read_32bitBE(0x00,sf) & 0xFF);
if (read_32bitLE(0x04,sf) + 0x08 != filesize)
goto fail;
num_frames = (uint32_t)read_32bitLE(0x08,sf);
if (num_frames == 0 || num_frames > 0x100000) goto fail; /* something must be off (avoids big allocs below) */
/* multichannel/multilanguage audio is usually N streams of stereo/mono, no way to know channel layout */
total_subsongs = read_32bitLE(0x28,sf);
if (total_subsongs < 1) {
vgm_logi("BIK: no audio in movie (ignore)\n");
goto fail;
}
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs > 255) goto fail;
/* find stream info and position in offset table */
cur_offset = 0x2c;
if ((signature == 0x42494B00 && (revision == 0x6b)) || /* k */
(signature == 0x4B423200 && (revision == 0x69 || revision == 0x6a || revision == 0x6b))) /* i,j,k */
cur_offset += 0x04; /* unknown v2 header field */
cur_offset += 0x04*total_subsongs; /* skip streams max packet bytes */
sample_rate = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x00,sf);
channels = (uint16_t)read_16bitLE(cur_offset+0x04*(target_subsong-1)+0x02,sf) & 0x2000 ? 2 : 1; /* stereo flag */
cur_offset += 0x04*total_subsongs; /* skip streams info */
cur_offset += 0x04*total_subsongs; /* skip streams ids */
/* read frame offsets in a buffer, to avoid fseeking to the table back and forth */
offsets = malloc(sizeof(uint32_t) * num_frames);
if (!offsets) goto fail;
for (i=0; i < num_frames; i++) {
offsets[i] = read_32bitLE(cur_offset,sf) & 0xFFFFFFFE; /* mask first bit (= keyframe) */
cur_offset += 0x4;
if (offsets[i] > filesize) goto fail;
}
/* after the last index is the file size, validate just in case */
if (read_32bitLE(cur_offset,sf) != filesize) goto fail;
/* read each frame header and sum all samples
* a frame has N audio packets with a header (one per stream) + video packet */
for (i=0; i < num_frames; i++) {
cur_offset = offsets[i];
/* read audio packet headers per stream */
for (j=0; j < total_subsongs; j++) {
uint32_t ap_size = read_32bitLE(cur_offset+0x00,sf); /* not counting this int */
if (j == target_subsong-1) {
stream_size += 0x04 + ap_size;
if (ap_size > 0)
num_samples_b += read_32bitLE(cur_offset+0x04,sf); /* decoded samples in bytes */
break; /* next frame */
}
else { /* next stream packet or frame */
cur_offset += 4 + ap_size; //todo sometimes ap_size doesn't include itself (+4), others it does?
}
}
}
free(offsets);
if (p_total_subsongs) *p_total_subsongs = total_subsongs;
if (p_stream_size) *p_stream_size = stream_size;
if (p_sample_rate) *p_sample_rate = sample_rate;
if (p_channels) *p_channels = channels;
//todo returns a few more samples (~48) than binkconv.exe?
if (p_num_samples) *p_num_samples = num_samples_b / (2 * channels);
return 1;
fail:
free(offsets);
return 0;
}

View File

@ -1,5 +1,6 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util/chunks.h"
/* BKHD - Wwise soundbank container */
@ -19,9 +20,9 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) {
if (!check_extensions(sf,"bnk"))
goto fail;
if (read_u32be(0x00, sf) == 0x414B424B) /* "AKBK" [Shadowrun (X360)] */
if (is_id32be(0x00, sf, "AKBK")) /* [Shadowrun (X360)] */
base_offset = 0x0c;
if (read_u32be(base_offset + 0x00, sf) != 0x424B4844) /* "BKHD" */
if (!is_id32be(base_offset + 0x00, sf, "BKHD"))
goto fail;
big_endian = guess_endianness32bit(base_offset + 0x04, sf);
read_u32 = big_endian ? read_u32be : read_u32le;
@ -77,16 +78,41 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) {
subfile_size = read_u32(offset + 0x14, sf);
}
else {
off_t didx_offset, data_offset, offset;
size_t didx_size;
if (!find_chunk(sf, 0x44494458, 0x00,0, &didx_offset, &didx_size, big_endian, 0)) /* "DIDX" */
goto fail;
if (!find_chunk(sf, 0x44415441, 0x00,0, &data_offset, NULL, big_endian, 0)) /* "DATA" */
enum {
CHUNK_DIDX = 0x44494458, /* "DIDX" */
CHUNK_DATA = 0x44415441, /* "DATA" */
};
off_t didx_offset = 0, data_offset = 0, didx_size = 0, offset;
chunk_t rc = {0};
rc.be_size = big_endian;
rc.current = 0x00;
while (next_chunk(&rc, sf)) {
switch(rc.type) {
case CHUNK_DIDX:
didx_offset = rc.offset;
didx_size = rc.size;
break;
case CHUNK_DATA:
data_offset = rc.offset;
break;
default:
break;
}
}
if (!didx_offset || !data_offset)
goto fail;
total_subsongs = didx_size / 0x0c;
if (total_subsongs < 1) {
vgm_logi("BKHD: bank has no subsongs (ignore)\n");
goto fail;
}
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
if (target_subsong > total_subsongs) goto fail;
offset = didx_offset + (target_subsong - 1) * 0x0c;
subfile_id = read_u32(offset + 0x00, sf);

View File

@ -5,10 +5,10 @@
#define COLUMN_BITMASK_TYPE 0x0f
enum columna_flag_t {
COLUMN_FLAG_NAME = 0x10,
COLUMN_FLAG_DEFAULT = 0x20,
COLUMN_FLAG_ROW = 0x40,
COLUMN_FLAG_UNDEFINED = 0x80 /* shouldn't exist */
COLUMN_FLAG_NAME = 0x10,
COLUMN_FLAG_DEFAULT = 0x20,
COLUMN_FLAG_ROW = 0x40,
COLUMN_FLAG_UNDEFINED = 0x80 /* shouldn't exist */
};
enum column_type_t {

View File

@ -2,49 +2,47 @@
#include "../coding/coding.h"
#include "../util.h"
/* .ADX - from Xenoblade 3D */
/* Xenoblade Chronicles 3D uses an adx extension as with
* the Wii version, but it's actually DSP ADPCM. */
VGMSTREAM * init_vgmstream_dsp_adx(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int loop_flag, channel_count;
/* .ADX - from Xenoblade 3D (3DS) */
VGMSTREAM* init_vgmstream_dsp_adx(STREAMFILE *sf) {
VGMSTREAM* vgmstream = NULL;
int loop_flag, channels;
int channel_header_spacing = 0x34;
/* check extension, case insensitive */
if (!check_extensions(streamFile,"adx")) goto fail;
/* check header */
if (read_32bitBE(0,streamFile)!=0x02000000) goto fail;
/* checks */
if (!check_extensions(sf,"adx"))
goto fail;
channel_count = read_32bitLE(0, streamFile);
loop_flag = read_16bitLE(0x6e, streamFile);
if (read_u32be(0x00,sf) != 0x02000000)
goto fail;
if (channel_count > 2 || channel_count < 0) goto fail;
channels = read_32bitLE(0, sf);
loop_flag = read_16bitLE(0x6e, sf);
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (channels > 2 || channels < 0) goto fail;
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_XB3D_ADX;
vgmstream->sample_rate = read_32bitLE(0x70,streamFile);
vgmstream->num_samples = read_32bitLE(0x74, streamFile);
vgmstream->loop_start_sample = read_32bitLE(0x78, streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x7c, streamFile);
dsp_read_coefs_le(vgmstream,streamFile, 0x4, channel_header_spacing);
vgmstream->sample_rate = read_32bitLE(0x70,sf);
vgmstream->num_samples = read_32bitLE(0x74, sf);
vgmstream->loop_start_sample = read_32bitLE(0x78, sf);
vgmstream->loop_end_sample = read_32bitLE(0x7c, sf);
dsp_read_coefs_le(vgmstream,sf, 0x4, channel_header_spacing);
/* semi-interleave: manually open streams at offset */
{
char filename[PATH_LIMIT];
int i;
streamFile->get_name(streamFile,filename,sizeof(filename));
for (i = 0; i<channel_count; i++) {
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename, STREAMFILE_DEFAULT_BUFFER_SIZE);
sf->get_name(sf,filename,sizeof(filename));
for (i = 0; i<channels; i++) {
vgmstream->ch[i].streamfile = sf->open(sf, filename, STREAMFILE_DEFAULT_BUFFER_SIZE);
vgmstream->ch[i].channel_start_offset =
vgmstream->ch[i].offset = read_32bitLE(0x34+i*channel_header_spacing, streamFile);
vgmstream->ch[i].offset = read_32bitLE(0x34+i*channel_header_spacing, sf);
if (!vgmstream->ch[i].streamfile) goto fail;
}
}

View File

@ -18,28 +18,29 @@ typedef struct {
int32_t loop_end;
int loop_flag;
off_t sample_header_offset;
size_t sample_header_size;
size_t name_table_size;
size_t sample_data_size;
size_t base_header_size;
off_t extradata_offset;
size_t extradata_size;
uint32_t extradata_offset;
uint32_t extradata_size;
off_t stream_offset;
size_t stream_size;
off_t name_offset;
uint32_t stream_offset;
uint32_t stream_size;
uint32_t name_offset;
} fsb5_header;
/* ********************************************************************************** */
static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, fsb5_header* fsb5);
static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, STREAMFILE* sb, fsb5_header* fsb5);
/* FSB5 - Firelight's FMOD Studio SoundBank format */
VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sb = NULL;
fsb5_header fsb5 = {0};
uint32_t offset;
int target_subsong = sf->stream_index;
int i;
@ -53,7 +54,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
if (!is_id32be(0x00,sf, "FSB5"))
goto fail;
/* 0x00 is rare (seen in Tales from Space Vita) */
/* v0 is rare (seen in Tales from Space Vita) */
fsb5.version = read_u32le(0x04,sf);
if (fsb5.version != 0x00 && fsb5.version != 0x01)
goto fail;
@ -63,13 +64,20 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
fsb5.name_table_size = read_u32le(0x10,sf);
fsb5.sample_data_size = read_u32le(0x14,sf);
fsb5.codec = read_u32le(0x18,sf);
/* version 0x01 - 0x1c(4): zero, 0x24(16): hash, 0x34(8): unk
* version 0x00 has an extra field (always 0?) at 0x1c */
/* 0x1c: zero */
if (fsb5.version == 0x01) {
/* found by tests and assumed to be flags, no games known */
fsb5.flags = read_u32le(0x20,sf);
fsb5.flags = read_u32le(0x20,sf); /* found by tests and assumed to be flags, no games known */
/* 0x24: 128-bit hash */
/* 0x34: unknown (64-bit sub-hash?) */
fsb5.base_header_size = 0x3c;
}
else {
/* 0x20: zero/flags? */
/* 0x24: zero/flags? */
/* 0x28: 128-bit hash */
/* 0x38: unknown (64-bit sub-hash?) */
fsb5.base_header_size = 0x40;
}
fsb5.base_header_size = (fsb5.version==0x00) ? 0x40 : 0x3C;
if ((fsb5.sample_header_size + fsb5.name_table_size + fsb5.sample_data_size + fsb5.base_header_size) != get_streamfile_size(sf)) {
vgm_logi("FSB5: wrong size, expected %x + %x + %x + %x vs %x (re-rip)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, get_streamfile_size(sf));
@ -79,28 +87,25 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
if (target_subsong == 0) target_subsong = 1;
if (target_subsong > fsb5.total_subsongs || fsb5.total_subsongs <= 0) goto fail;
fsb5.sample_header_offset = fsb5.base_header_size;
/* find target stream header and data offset, and read all needed values for later use
* (reads one by one as the size of a single stream header is variable) */
offset = fsb5.base_header_size;
for (i = 0; i < fsb5.total_subsongs; i++) {
size_t stream_header_size = 0;
off_t data_offset = 0;
uint32_t sample_mode1, sample_mode2; /* maybe one uint64? */
uint32_t stream_header_size = 0;
uint32_t data_offset = 0;
uint64_t sample_mode;
sample_mode1 = read_u32le(fsb5.sample_header_offset+0x00,sf);
sample_mode2 = read_u32le(fsb5.sample_header_offset+0x04,sf);
sample_mode = read_u64le(offset+0x00,sf);
stream_header_size += 0x08;
/* get samples */
fsb5.num_samples = ((sample_mode2 >> 2) & 0x3FFFFFFF); /* bits2: 31..2 (30) */
fsb5.num_samples = ((sample_mode >> 34) & 0x3FFFFFFF); /* bits: 63..34 (30) */
/* get offset inside data section */
/* up to 0x07FFFFFF * 0x20 = full 32b offset 0xFFFFFFE0 */
data_offset = (((sample_mode2 & 0x03) << 25) | ((sample_mode1 >> 7) & 0x1FFFFFF)) << 5; /* bits2: 1..0 (2) | bits1: 31..8 (25) */
/* get offset inside data section (max 32b offset 0xFFFFFFE0) */
data_offset = ((sample_mode >> 7) & 0x07FFFFFF) << 5; /* bits: 33..8 (25) */
/* get channels */
switch ((sample_mode1 >> 5) & 0x03) { /* bits1: 7..6 (2) */
switch ((sample_mode >> 5) & 0x03) { /* bits: 7..6 (2) */
case 0: fsb5.channels = 1; break;
case 1: fsb5.channels = 2; break;
case 2: fsb5.channels = 6; break; /* some Dark Souls 2 MPEG; some IMA ADPCM */
@ -111,7 +116,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
}
/* get sample rate */
switch ((sample_mode1 >> 1) & 0x0f) { /* bits1: 5..1 (4) */
switch ((sample_mode >> 1) & 0x0f) { /* bits: 5..1 (4) */
case 0: fsb5.sample_rate = 4000; break;
case 1: fsb5.sample_rate = 8000; break;
case 2: fsb5.sample_rate = 11000; break;
@ -129,8 +134,8 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
}
/* get extra flags */
if (sample_mode1 & 0x01) { /* bits1: 0 (1) */
off_t extraflag_offset = fsb5.sample_header_offset+0x08;
if (sample_mode & 0x01) { /* bits: 0 (1) */
uint32_t extraflag_offset = offset + 0x08;
uint32_t extraflag, extraflag_type, extraflag_size, extraflag_end;
do {
@ -217,7 +222,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
fsb5.channels = fsb5.channels * fsb5.layers;
break;
default:
vgm_logi("FSB5: stream %i unknown flag 0x%x at %x + 0x04 + 0x%x (report)\n", i, extraflag_type, (uint32_t)extraflag_offset, extraflag_size);
vgm_logi("FSB5: stream %i unknown flag 0x%x at %x + 0x04 + 0x%x (report)\n", i, extraflag_type, extraflag_offset, extraflag_size);
break;
}
}
@ -242,11 +247,10 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
fsb5.stream_size = fsb5.sample_data_size - data_offset;
}
else {
off_t next_data_offset;
uint32_t next_sample_mode1, next_sample_mode2;
next_sample_mode1 = read_u32le(fsb5.sample_header_offset+stream_header_size+0x00,sf);
next_sample_mode2 = read_u32le(fsb5.sample_header_offset+stream_header_size+0x04,sf);
next_data_offset = (((next_sample_mode2 & 0x03) << 25) | ((next_sample_mode1 >> 7) & 0x1FFFFFF)) << 5;
uint32_t next_data_offset;
uint64_t next_sample_mode;
next_sample_mode = read_u64le(offset+stream_header_size+0x00,sf);
next_data_offset = ((next_sample_mode >> 7) & 0x07FFFFFF) << 5;
fsb5.stream_size = next_data_offset - data_offset;
}
@ -255,9 +259,9 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
}
/* continue searching target */
fsb5.sample_header_offset += stream_header_size;
offset += stream_header_size;
}
/* target stream not found*/
if (!fsb5.stream_offset || !fsb5.stream_size)
goto fail;
@ -268,6 +272,17 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
}
/* FSB5 can hit +2GB offsets, but since decoders aren't ready to handle that use a subfile to hide big offsets
* (some FSB5 CLI versions make buggy offsets = bad output but this was fixed later) */
if (fsb5.stream_offset > 0x7FFFFFFF) {
sb = setup_subfile_streamfile(sf, fsb5.stream_offset, fsb5.stream_size, NULL);
fsb5.stream_offset = 0x00;
}
else {
sb = sf;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(fsb5.channels, fsb5.loop_flag);
if (!vgmstream) goto fail;
@ -282,7 +297,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
vgmstream->stream_size = fsb5.stream_size;
vgmstream->meta_type = meta_FSB5;
if (fsb5.name_offset)
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, fsb5.name_offset,sf);
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, fsb5.name_offset, sf);
switch (fsb5.codec) {
case 0x00: /* FMOD_SOUND_FORMAT_NONE */
@ -325,7 +340,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = 0x02;
}
dsp_read_coefs_be(vgmstream,sf,fsb5.extradata_offset,0x2E);
dsp_read_coefs_be(vgmstream, sf, fsb5.extradata_offset, 0x2E);
break;
case 0x07: /* FMOD_SOUND_FORMAT_IMAADPCM [Skylanders] */
@ -359,12 +374,12 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
block_count = fsb5.stream_size / block_size + (fsb5.stream_size % block_size ? 1 : 0);
bytes = ffmpeg_make_riff_xma2(buf, 0x100, vgmstream->num_samples, fsb5.stream_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, fsb5.stream_offset,fsb5.stream_size);
vgmstream->codec_data = init_ffmpeg_header_offset(sb, buf,bytes, fsb5.stream_offset, fsb5.stream_size);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
xma_fix_raw_samples(vgmstream, sf, fsb5.stream_offset,fsb5.stream_size, 0, 0,0); /* samples look ok */
xma_fix_raw_samples(vgmstream, sb, fsb5.stream_offset, fsb5.stream_size, 0, 0,0); /* samples look ok */
break;
}
#endif
@ -375,7 +390,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
cfg.fsb_padding = (vgmstream->channels > 2 ? 16 : 4); /* observed default */
vgmstream->codec_data = init_mpeg_custom(sf, fsb5.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
vgmstream->codec_data = init_mpeg_custom(sb, fsb5.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
break;
@ -387,7 +402,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
fsb5.layers = (fsb5.channels <= 2) ? 1 : (fsb5.channels+1) / 2;
if (fsb5.layers > 1) {
vgmstream->layout_data = build_layered_fsb5(sf, &fsb5);
vgmstream->layout_data = build_layered_fsb5(sf, sb, &fsb5);
if (!vgmstream->layout_data) goto fail;
vgmstream->coding_type = coding_CELT_FSB;
vgmstream->layout_type = layout_layered;
@ -415,7 +430,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
if (fsb5.layers > 1) {
/* multichannel made of various layers [Little Big Planet (Vita)] */
vgmstream->layout_data = build_layered_fsb5(sf, &fsb5);
vgmstream->layout_data = build_layered_fsb5(sf, sb, &fsb5);
if (!vgmstream->layout_data) goto fail;
vgmstream->coding_type = coding_ATRAC9;
vgmstream->layout_type = layout_layered;
@ -449,7 +464,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
/* XWMA encoder only does up to 6ch (doesn't use FSB multistreams for more) */
bytes = ffmpeg_make_riff_xwma(buf,0x100, format, fsb5.stream_size, vgmstream->channels, vgmstream->sample_rate, average_bps, block_align);
vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, fsb5.stream_offset,fsb5.stream_size);
vgmstream->codec_data = init_ffmpeg_header_offset(sb, buf,bytes, fsb5.stream_offset, fsb5.stream_size);
if ( !vgmstream->codec_data ) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
@ -465,7 +480,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
cfg.sample_rate = fsb5.sample_rate;
cfg.setup_id = read_u32le(fsb5.extradata_offset,sf);
vgmstream->codec_data = init_vorbis_custom(sf, fsb5.stream_offset, VORBIS_FSB, &cfg);
vgmstream->codec_data = init_vorbis_custom(sb, fsb5.stream_offset, VORBIS_FSB, &cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_VORBIS_custom;
vgmstream->layout_type = layout_none;
@ -479,13 +494,13 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
vgmstream->interleave_block_size = 0x8c;
break;
#if 0 //disabled until some game is found, can be created in the GUI tool
#if 0 //disabled until some game is found, can be created in the GUI tool
#ifdef VGM_USE_FFMPEG
case 0x11: { /* FMOD_SOUND_FORMAT_OPUS */
int skip = 312; //fsb_opus_get_encoder_delay(fsb5.stream_offset, sf); /* returns 120 but this seems correct */
int skip = 312; //fsb_opus_get_encoder_delay(fsb5.stream_offset, sb); /* returns 120 but this seems correct */
//vgmstream->num_samples -= skip;
vgmstream->codec_data = init_ffmpeg_fsb_opus(sf, fsb5.stream_offset, fsb5.stream_size, vgmstream->channels, skip, vgmstream->sample_rate);
vgmstream->codec_data = init_ffmpeg_fsb_opus(sb, fsb5.stream_offset, fsb5.stream_size, vgmstream->channels, skip, vgmstream->sample_rate);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
@ -498,18 +513,20 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
goto fail;
}
if (!vgmstream_open_stream(vgmstream,sf,fsb5.stream_offset))
if (!vgmstream_open_stream(vgmstream, sb, fsb5.stream_offset))
goto fail;
if (sb != sf) close_streamfile(sb);
return vgmstream;
fail:
if (sb != sf) close_streamfile(sb);
close_vgmstream(vgmstream);
return NULL;
}
static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, fsb5_header* fsb5) {
static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, STREAMFILE* sb, fsb5_header* fsb5) {
layered_layout_data* data = NULL;
STREAMFILE* temp_sf = NULL;
size_t interleave, config = 0;
@ -526,9 +543,9 @@ static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, fsb5_header* fsb5
/* 2ch+2ch..+1ch or 2ch+2ch..+2ch = check last layer */
layer_channels = (i+1 == fsb5->layers && fsb5->channels % 2 == 1) ? 1 : 2;
if (read_u32be(fsb5->stream_offset+0x00,sf) != 0x17C30DF3) /* FSB CELT frame ID */
if (read_u32be(fsb5->stream_offset+0x00,sb) != 0x17C30DF3) /* FSB CELT frame ID */
goto fail;
interleave = 0x04+0x04+read_u32le(fsb5->stream_offset+0x04,sf); /* frame size */
interleave = 0x04+0x04+read_u32le(fsb5->stream_offset+0x04,sb); /* frame size */
//todo unknown interleave for max quality odd channel streams (found in test files)
/* FSB5 odd channels use 2ch+2ch...+1ch streams, and the last only goes up to 0x17a, and other
@ -609,7 +626,7 @@ static layered_layout_data* build_layered_fsb5(STREAMFILE* sf, fsb5_header* fsb5
}
temp_sf = setup_fsb5_streamfile(sf, fsb5->stream_offset, fsb5->stream_size, fsb5->layers, i, interleave);
temp_sf = setup_fsb5_streamfile(sb, fsb5->stream_offset, fsb5->stream_size, fsb5->layers, i, interleave);
if (!temp_sf) goto fail;
if (!vgmstream_open_stream(data->layers[i], temp_sf, 0x00))

View File

@ -128,7 +128,7 @@ VGMSTREAM* init_vgmstream_fsb5_fev_bank(STREAMFILE* sf) {
}
}
//;VGM_LOG("FSB5 FEV: offset=%lx, size=%x\n", subfile_offset,subfile_size);
//;VGM_LOG("FSB5 FEV: offset=%lx, size=%x\n", subfile_offset,subfile_size);
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, "fsb");
if (!temp_sf) goto fail;

View File

@ -23,8 +23,8 @@ typedef struct {
uint32_t channel_layout;
int is_external;
off_t stream_offsets[MAX_CHANNELS];
size_t stream_sizes[MAX_CHANNELS];
uint32_t stream_offsets[MAX_CHANNELS];
uint32_t stream_sizes[MAX_CHANNELS];
off_t sound_name_offset;
off_t config_name_offset;

View File

@ -1,187 +1,192 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util.h"
static int smacker_get_info(STREAMFILE *streamFile, int target_subsong, int * out_total_streams, size_t *out_stream_size, int * out_channel_count, int * out_sample_rate, int * out_num_samples);
/* SMK - RAD Game Tools Smacker movies (audio/video format) */
VGMSTREAM * init_vgmstream_smk(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int channel_count = 0, loop_flag = 0, sample_rate = 0, num_samples = 0;
int total_subsongs = 0, target_subsong = streamFile->stream_index;
size_t stream_size;
/* checks */
if (!check_extensions(streamFile,"smk"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x534D4B32 && /* "SMK2" */
read_32bitBE(0x00,streamFile) != 0x534D4B34) /* "SMK4" */
goto fail;
/* find target stream info */
if (!smacker_get_info(streamFile, target_subsong, &total_subsongs, &stream_size, &channel_count, &sample_rate, &num_samples))
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->layout_type = layout_none;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
vgmstream->meta_type = meta_SMACKER;
{
#ifdef VGM_USE_FFMPEG
/* target_subsong should be passed manually */
vgmstream->codec_data = init_ffmpeg_header_offset_subsong(streamFile, NULL,0, 0x0,get_streamfile_size(streamFile), target_subsong);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
#else
goto fail;
#endif
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
typedef enum {
SMK_AUDIO_PACKED = (1<<7),
SMK_AUDIO_PRESENT = (1<<6),
SMK_AUDIO_16BITS = (1<<5),
SMK_AUDIO_STEREO = (1<<4),
SMK_AUDIO_BINK_RDFT = (1<<3),
SMK_AUDIO_BINK_DCT = (1<<2),
//SMK_AUD_UNUSED1 = (1<<1),
//SMK_AUD_UNUSED0 = (1<<0),
} smk_audio_flag;
//todo test multilang streams and codecs other than SMACKAUD
/* Gets stream info, and number of samples in a file by reading frames
* info: https://wiki.multimedia.cx/index.php/Smacker */
static int smacker_get_info(STREAMFILE *sf, int target_subsong, int * out_total_subsongs, size_t * out_stream_size, int * out_channel_count, int * out_sample_rate, int * out_num_samples) {
STREAMFILE *sf_index = NULL;
uint32_t flags, total_frames, trees_sizes;
off_t size_offset, type_offset, data_offset;
int i, j, sample_rate = 0, channel_count = 0, num_samples = 0;
int total_subsongs, target_stream = 0;
size_t stream_size = 0;
uint8_t stream_flags = 0;
/* rough format:
* - header (id, frames, video info/config, audio info)
* - frame sizes table
* - frame info table
* - huffman trees
* - frame data
*/
/* read header */
total_frames = read_u32le(0x0c,sf);
if (total_frames <= 0 || total_frames > 0x100000) goto fail; /* something must be off */
flags = read_u32le(0x14,sf);
if (flags & 1) /* extra "ring frame" */
total_frames += 1;
trees_sizes = read_u32le(0x34,sf);
if (target_subsong == 0) target_subsong = 1;
total_subsongs = 0;
for (i = 0; i < 7; i++) { /* up to 7 audio (multilang?) streams */
uint32_t audio_info = read_u32le(0x48 + 0x04*i,sf);
uint8_t audio_flags = (audio_info >> 24) & 0xFF;
int audio_rate = audio_info & 0x00FFFFFF;
if (audio_flags & SMK_AUDIO_PRESENT) {
total_subsongs++;
if (target_subsong == total_subsongs) {
target_stream = i;
sample_rate = audio_rate & 0x00FFFFFF;
channel_count = (audio_flags & SMK_AUDIO_STEREO) ? 2 : 1;
stream_flags = audio_flags;
}
}
}
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
if (sample_rate == 0 || channel_count == 0) goto fail;
/* read size and type tables into buffer */
sf_index = reopen_streamfile(sf, total_frames*0x04 + total_frames*0x01);
if (!sf_index) goto fail;
/* read frames and sum all samples, since some codecs are VBR */
size_offset = 0x68;
type_offset = size_offset + total_frames*0x04;
data_offset = type_offset + total_frames*0x01 + trees_sizes;
for (i=0; i < total_frames; i++) {
uint32_t frame_size = read_u32le(size_offset,sf_index) & 0xFFFFFFFC; /* last 2 bits are keyframe flags */
uint8_t frame_type = read_u8 (type_offset,sf_index); /* 0: has palette, 1..7: has stream N) */
off_t offset = data_offset;
/* skip palette */
if (frame_type & (1<<0)) {
uint8_t palette_size = read_u8(offset,sf);
offset += palette_size * 4;
}
/* read target audio packet and ignore rest (though probably all streams are the same) */
for (j = 0; j < 7; j++) {
uint32_t audio_size;
/* check if stream N exists in this frame (supposedly streams can be go in separate frames) */
if ( !(frame_type & (1<<(j+1))) )
continue;
audio_size = read_u32le(offset,sf);
if (j == target_stream) {
/* resulting PCM bytes to samples */
if (stream_flags & SMK_AUDIO_PACKED) { /* Smacker and maybe Bink codecs */
uint32_t unpacked_size = read_u32le(offset+0x04,sf);
num_samples += unpacked_size / (0x02 * channel_count);
}
else if (stream_flags & SMK_AUDIO_16BITS) { /* PCM16 */
num_samples += (audio_size - 0x04) / (0x02 * channel_count);
}
else { /* PCM8 */
num_samples += (audio_size - 0x04) / (0x01 * channel_count);
}
}
stream_size += audio_size;
offset += audio_size;
}
/* rest is video packet (size = offset - data_offset) */
size_offset += 0x04;
type_offset += 0x01;
data_offset += frame_size;
}
if (out_total_subsongs) *out_total_subsongs = total_subsongs;
if (out_stream_size) *out_stream_size = stream_size;
if (out_sample_rate) *out_sample_rate = sample_rate;
if (out_channel_count) *out_channel_count = channel_count;
if (out_num_samples) *out_num_samples = num_samples;
close_streamfile(sf_index);
return 1;
fail:
close_streamfile(sf_index);
return 0;
}
#include "meta.h"
#include "../coding/coding.h"
#include "../util.h"
static int smacker_get_info(STREAMFILE* sf, int target_subsong, int* p_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples);
/* SMK - RAD Game Tools older Smacker movies (audio/video format) */
VGMSTREAM* init_vgmstream_smk(STREAMFILE *sf) {
VGMSTREAM* vgmstream = NULL;
int channels = 0, loop_flag = 0, sample_rate = 0, num_samples = 0;
int total_subsongs = 0, target_subsong = sf->stream_index;
size_t stream_size;
/* checks */
if (!check_extensions(sf,"smk"))
goto fail;
if (!is_id32be(0x00,sf, "SMK2") &&
!is_id32be(0x00,sf, "SMK4"))
goto fail;
/* find target stream info */
if (!smacker_get_info(sf, target_subsong, &total_subsongs, &stream_size, &channels, &sample_rate, &num_samples))
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_SMACKER;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
{
#ifdef VGM_USE_FFMPEG
/* target_subsong should be passed manually */
vgmstream->codec_data = init_ffmpeg_header_offset_subsong(sf, NULL,0, 0x00, 0, target_subsong);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
#else
goto fail;
#endif
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
typedef enum {
SMK_AUDIO_PACKED = (1<<7),
SMK_AUDIO_PRESENT = (1<<6),
SMK_AUDIO_16BITS = (1<<5),
SMK_AUDIO_STEREO = (1<<4),
SMK_AUDIO_BINK_RDFT = (1<<3),
SMK_AUDIO_BINK_DCT = (1<<2),
//SMK_AUD_UNUSED1 = (1<<1),
//SMK_AUD_UNUSED0 = (1<<0),
} smk_audio_flag;
//todo test multilang streams and codecs other than SMACKAUD
/* Gets stream info, and number of samples in a file by reading frames
* info: https://wiki.multimedia.cx/index.php/Smacker */
static int smacker_get_info(STREAMFILE* sf, int target_subsong, int* out_total_subsongs, size_t* p_stream_size, int* p_channels, int* p_sample_rate, int* p_num_samples) {
STREAMFILE* sf_index = NULL;
uint32_t flags, total_frames, trees_sizes;
off_t size_offset, type_offset, data_offset;
int i, j, sample_rate = 0, channels = 0, num_samples = 0;
int total_subsongs, target_stream = 0;
size_t stream_size = 0;
uint8_t stream_flags = 0;
/* rough format:
* - header (id, frames, video info/config, audio info)
* - frame sizes table
* - frame info table
* - huffman trees
* - frame data
*/
/* read header */
total_frames = read_u32le(0x0c,sf);
if (total_frames <= 0 || total_frames > 0x100000) goto fail; /* something must be off */
flags = read_u32le(0x14,sf);
if (flags & 1) /* extra "ring frame" */
total_frames += 1;
trees_sizes = read_u32le(0x34,sf);
if (target_subsong == 0) target_subsong = 1;
total_subsongs = 0;
for (i = 0; i < 7; i++) { /* up to 7 audio (multilang?) streams */
uint32_t audio_info = read_u32le(0x48 + 0x04*i,sf);
uint8_t audio_flags = (audio_info >> 24) & 0xFF;
int audio_rate = audio_info & 0x00FFFFFF;
if (audio_flags & SMK_AUDIO_PRESENT) {
total_subsongs++;
if (target_subsong == total_subsongs) {
target_stream = i;
sample_rate = audio_rate & 0x00FFFFFF;
channels = (audio_flags & SMK_AUDIO_STEREO) ? 2 : 1;
stream_flags = audio_flags;
}
}
}
if (total_subsongs < 1) {
vgm_logi("SMK: no audio in movie (ignore)\n");
goto fail;
}
if (target_subsong < 0 || target_subsong > total_subsongs) goto fail;
if (sample_rate == 0 || channels == 0) goto fail;
/* read size and type tables into buffer */
sf_index = reopen_streamfile(sf, total_frames*0x04 + total_frames*0x01);
if (!sf_index) goto fail;
/* read frames and sum all samples, since some codecs are VBR */
size_offset = 0x68;
type_offset = size_offset + total_frames*0x04;
data_offset = type_offset + total_frames*0x01 + trees_sizes;
for (i = 0; i < total_frames; i++) {
uint32_t frame_size = read_u32le(size_offset,sf_index) & 0xFFFFFFFC; /* last 2 bits are keyframe flags */
uint8_t frame_type = read_u8 (type_offset,sf_index); /* 0: has palette, 1..7: has stream N) */
off_t offset = data_offset;
/* skip palette */
if (frame_type & (1<<0)) {
uint8_t palette_size = read_u8(offset,sf);
offset += palette_size * 4;
}
/* read target audio packet and ignore rest (though probably all streams are the same) */
for (j = 0; j < 7; j++) {
uint32_t audio_size;
/* check if stream N exists in this frame (supposedly streams can be go in separate frames) */
if ( !(frame_type & (1<<(j+1))) )
continue;
audio_size = read_u32le(offset,sf);
if (j == target_stream) {
/* resulting PCM bytes to samples */
if (stream_flags & SMK_AUDIO_PACKED) { /* Smacker and maybe Bink codecs */
uint32_t unpacked_size = read_u32le(offset+0x04,sf);
num_samples += unpacked_size / (0x02 * channels);
}
else if (stream_flags & SMK_AUDIO_16BITS) { /* PCM16 */
num_samples += (audio_size - 0x04) / (0x02 * channels);
}
else { /* PCM8 */
num_samples += (audio_size - 0x04) / (0x01 * channels);
}
}
stream_size += audio_size;
offset += audio_size;
}
/* rest is video packet (size = offset - data_offset) */
size_offset += 0x04;
type_offset += 0x01;
data_offset += frame_size;
}
if (out_total_subsongs) *out_total_subsongs = total_subsongs;
if (p_stream_size) *p_stream_size = stream_size;
if (p_sample_rate) *p_sample_rate = sample_rate;
if (p_channels) *p_channels = channels;
if (p_num_samples) *p_num_samples = num_samples;
close_streamfile(sf_index);
return 1;
fail:
close_streamfile(sf_index);
return 0;
}

View File

@ -8,7 +8,7 @@ VGMSTREAM* init_vgmstream_wii_bns(STREAMFILE* sf) {
off_t bns_offset;
uint32_t info_offset = 0, data_offset = 0;
uint32_t channel_info_offset_list_offset;
int channels, loop_flag, sample_rate;
int channels, loop_flag, sample_rate;
uint32_t sample_count, loop_start;
/* checks */
@ -106,7 +106,7 @@ VGMSTREAM* init_vgmstream_wii_bns(STREAMFILE* sf) {
channel_info_offset_list_offset = info_offset + read_u32be(info_offset+0x10,sf);
}
/* build the VGMSTREAM */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;

View File

@ -510,7 +510,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
if (ww.bits_per_sample != 16) goto fail;
/* original data_size doesn't look related to samples or anything */
ww.data_size = ww.file_size - ww.data_offset;
ww.data_size = ww.file_size - ww.data_offset;
vgmstream->codec_data = init_ffmpeg_offset(sf, ww.data_offset, ww.data_size);
if (!vgmstream->codec_data) goto fail;
@ -682,7 +682,7 @@ static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_o
* - .bnk would be memory banks = full
* - otherwise small-ish sizes, stereo, with initial predictors for the
* second channel matching half size = full
* some files aren't detectable like this though, when predictors are 0
* some files aren't detectable like this though, when predictors are 0
* (but since memory wem aren't that used this shouldn't be too common) */
if (ww->truncated)
@ -960,7 +960,7 @@ fail:
0x14 (4): LoopInfo.dwLoopEndPacketOffset?
0x18 (4): dwSeekTableSize (0 = no seek table)
0x1c (4): dwVorbisDataOffset (offset within data)
0x20 (2): uMaxPacketSize (not including header)
0x20 (2): uMaxPacketSize (not including header)
0x22 (2): uLastGranuleExtra (0..~0x100)
0x24 (4): dwDecodeAllocSize (0~0x5000)
0x28 (4): dwDecodeX64AllocSize (mid, 0~0x5000)
@ -976,7 +976,7 @@ fail:
0x0c (2): ? (small, 0..~0x400) [(4) when size is 0x2C]
0x10 (4): dwSeekTableSize (0 = no seek table)
0x14 (4): dwVorbisDataOffset (offset within data)
0x18 (2): uMaxPacketSize (not including header)
0x18 (2): uMaxPacketSize (not including header)
0x1a (2): uLastGranuleExtra (0..~0x100) [(4) when size is 0x2C]
0x1c (4): dwDecodeAllocSize (0~0x5000)
0x20 (4): dwDecodeX64AllocSize (0~0x5000)
@ -993,7 +993,7 @@ fail:
0x26 (2): LoopInfo.uLoopEndExtra (extra samples after seek?)
0x28 (4): dwSeekTableSize (0 = no seek table)
0x2c (4): dwVorbisDataOffset (offset within data)
0x30 (2): uMaxPacketSize (not including header)
0x30 (2): uMaxPacketSize (not including header)
0x32 (2): uLastGranuleExtra (small, 0..~0x100)
0x34 (4): dwDecodeAllocSize (mid, 0~0x5000)
0x38 (4): dwDecodeX64AllocSize (mid, 0~0x5000)

View File

@ -190,7 +190,7 @@ static int lz4mg_decompress(lz4mg_stream_t* strm) {
default:
goto fail;
}
}
}
buffer_end:
strm->next_out += dst_pos;
@ -208,16 +208,16 @@ fail:
#if 0
/* non-streamed form for reference, assumes buffers are big enough */
static void decompress_lz4mg(uint8_t* dst, size_t dst_size, const uint8_t* src, size_t src_size) {
size_t src_pos = 0;
size_t dst_pos = 0;
size_t src_pos = 0;
size_t dst_pos = 0;
uint8_t token;
int literal_len, match_len, next_len;
int match_pos, match_offset;
int i;
while (src_pos < src_size && dst_pos < dst_size) {
while (src_pos < src_size && dst_pos < dst_size) {
token = src[src_pos++];
token = src[src_pos++];
if (src_pos > src_size)
break;
@ -259,7 +259,7 @@ static void decompress_lz4mg(uint8_t* dst, size_t dst_size, const uint8_t* src,
for(i = 0; i < match_len; i++) {
dst[dst_pos++] = dst[match_pos++]; /* note RLE with short offsets */
}
}
}
}
#endif

View File

@ -26,8 +26,8 @@ typedef struct {
off_t stream_offset;
} xvag_header;
static int init_xvag_atrac9(STREAMFILE* sf, VGMSTREAM* vgmstream, xvag_header * xvag, off_t chunk_offset);
static layered_layout_data* build_layered_xvag(STREAMFILE* sf, xvag_header * xvag, off_t chunk_offset, off_t start_offset);
static int init_xvag_atrac9(STREAMFILE* sf, VGMSTREAM* vgmstream, xvag_header* xvag, off_t chunk_offset);
static layered_layout_data* build_layered_xvag(STREAMFILE* sf, xvag_header* xvag, off_t chunk_offset, off_t start_offset);
/* XVAG - Sony's Scream Tool/Stream Creator format (God of War III, Ratchet & Clank Future, The Last of Us, Uncharted) */
VGMSTREAM* init_vgmstream_xvag(STREAMFILE* sf) {
@ -42,7 +42,7 @@ VGMSTREAM* init_vgmstream_xvag(STREAMFILE* sf) {
/* checks */
/* .xvag: standard
* (extensionless): The Last Of Us (PS3) speech files */
* (extensionless): The Last of Us (PS3) speech files */
if (!check_extensions(sf,"xvag,"))
goto fail;
if (!is_id32be(0x00,sf, "XVAG"))
@ -254,7 +254,7 @@ fail:
}
#ifdef VGM_USE_ATRAC9
static int init_xvag_atrac9(STREAMFILE* sf, VGMSTREAM* vgmstream, xvag_header * xvag, off_t chunk_offset) {
static int init_xvag_atrac9(STREAMFILE* sf, VGMSTREAM* vgmstream, xvag_header* xvag, off_t chunk_offset) {
int32_t (*read_32bit)(off_t,STREAMFILE*) = xvag->big_endian ? read_32bitBE : read_32bitLE;
atrac9_config cfg = {0};
@ -265,7 +265,7 @@ static int init_xvag_atrac9(STREAMFILE* sf, VGMSTREAM* vgmstream, xvag_header *
/* 0x08: data size (layer only) */
/* 0x10: decoder delay? */
cfg.encoder_delay = read_32bit(chunk_offset+0x14,sf);
/* sometimes ATRAC9 data starts with a fake RIFF, that has total channels rather than layer channels */
/* sometimes ATRAC9 data starts with a fake RIFF, that has total channels rather than layer channels */
vgmstream->codec_data = init_atrac9(&cfg);
if (!vgmstream->codec_data) goto fail;
@ -278,7 +278,7 @@ fail:
}
#endif
static layered_layout_data* build_layered_xvag(STREAMFILE* sf, xvag_header * xvag, off_t chunk_offset, off_t start_offset) {
static layered_layout_data* build_layered_xvag(STREAMFILE* sf, xvag_header* xvag, off_t chunk_offset, off_t start_offset) {
layered_layout_data* data = NULL;
STREAMFILE* temp_sf = NULL;
int32_t (*read_32bit)(off_t,STREAMFILE*) = xvag->big_endian ? read_32bitBE : read_32bitLE;
@ -309,7 +309,7 @@ static layered_layout_data* build_layered_xvag(STREAMFILE* sf, xvag_header * xva
if (!init_xvag_atrac9(sf, data->layers[i], xvag, chunk_offset))
goto fail;
/* interleaves N layers for custom multichannel, may rarely use subsongs [Days Gone (PS4) multilayer test]
/* interleaves N layers for custom multichannel, may rarely use subsongs [Days Gone (PS4) multilayer test]
* ex. 2 layers, 1 subsong : [L1][L2][L1][L2]
* ex. 2 layers, 2 subsongs: [L1S1][L2S1][L1S2][L2S2] (assumed, could be [L1S1][L1S2][L2S1][L2S2]) */
chunk = i + xvag->subsongs * (xvag->target_subsong - 1); /* [L1S1][L2S1][L1S2][L2S2] */

View File

@ -518,7 +518,7 @@ static void seek_force_loop(VGMSTREAM* vgmstream, int loop_count) {
return;
/* pretend decoder reached loop end so state is set to loop start */
vgmstream->loop_count = loop_count - 1; /* seeking to first loop musy become ++ > 0 */
vgmstream->loop_count = loop_count - 1; /* seeking to first loop must become ++ > 0 */
vgmstream->current_sample = vgmstream->loop_end_sample;
vgmstream_do_loop(vgmstream);
}

File diff suppressed because it is too large Load Diff

View File

@ -19,40 +19,34 @@
/* MSVC fixes (though mingw uses MSVCRT but not MSC_VER, maybe use AND?) */
#if defined(__MSVCRT__) || defined(_MSC_VER)
#include <io.h>
#include <io.h>
#ifndef fseeko
#define fseeko fseek
#endif
#ifndef ftello
#define ftello ftell
#endif
#define dup _dup
#ifdef fileno
#undef fileno
#endif
#define fileno _fileno
#define fdopen _fdopen
// #ifndef off64_t
// #define off_t __int64
// #endif
#endif
#if defined(XBMC)
#define fseeko fseek
#ifndef off64_t
#define off_t __int64
#endif
#endif
#ifndef DIR_SEPARATOR
#if defined (_WIN32) || defined (WIN32)
#define DIR_SEPARATOR '\\'
#else
#define DIR_SEPARATOR '/'
#endif
#if defined (_WIN32) || defined (WIN32)
#define DIR_SEPARATOR '\\'
#else
#define DIR_SEPARATOR '/'
#endif
#endif
/* 64-bit offset is needed for banks that hit +2.5GB (like .fsb or .ktsl2stbin).
* Leave as typedef to toggle since it's theoretically slower when compiled as 32-bit.
* ATM it's only used in choice places until more performance tests are done.
* uint32_t could be an option but needs to test when/how neg offsets are used.
*
* On POSIX 32-bit off_t can become off64_t by passing -D_FILE_OFFSET_BITS=64,
* but not on MSVC as it doesn't have proper POSIX support, so a custom type is needed.
* fseeks/tells also need to be adjusted for 64-bit support.
*/
typedef int64_t offv_t; //off64_t
//typedef int64_t sizev_t; // size_t int64_t off64_t
/* Streamfiles normally use an internal buffer to increase performance, configurable
* but usually of this size. Lower increases the number of freads/system calls (slower).
* However some formats need to jump around causing more buffer trashing than usual,
@ -65,17 +59,26 @@
* to do file operations, as plugins may need to provide their own callbacks.
* Reads from arbitrary offsets, meaning internally may need fseek equivalents during reads. */
typedef struct _STREAMFILE {
size_t (*read)(struct _STREAMFILE*, uint8_t* dst, off_t offset, size_t length);
size_t (*get_size)(struct _STREAMFILE*);
off_t (*get_offset)(struct _STREAMFILE*); //todo: DO NOT USE, NOT RESET PROPERLY (remove?)
/* for dual-file support */
void (*get_name)(struct _STREAMFILE*, char* name, size_t length);
struct _STREAMFILE* (*open)(struct _STREAMFILE*, const char* const filename, size_t buffersize);
/* read 'length' data at 'offset' to 'dst' */
size_t (*read)(struct _STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length);
/* get max offset */
size_t (*get_size)(struct _STREAMFILE* sf);
//todo: DO NOT USE, NOT RESET PROPERLY (remove?)
offv_t (*get_offset)(struct _STREAMFILE*);
/* copy current filename to name buf */
void (*get_name)(struct _STREAMFILE* sf, char* name, size_t name_size);
/* open another streamfile from filename */
struct _STREAMFILE* (*open)(struct _STREAMFILE* sf, const char* const filename, size_t buffer_size);
/* free current STREAMFILE */
void (*close)(struct _STREAMFILE*);
/* Substream selection for files with subsongs. Manually used in metas if supported.
* Not ideal here, but it's the simplest way to pass to all init_vgmstream_x functions. */
/* Substream selection for formats with subsongs.
* Not ideal here, but it was the simplest way to pass to all init_vgmstream_x functions. */
int stream_index; /* 0=default/auto (first), 1=first, N=Nth */
} STREAMFILE;
@ -105,8 +108,8 @@ STREAMFILE* open_wrap_streamfile_f(STREAMFILE* sf);
/* Opens a STREAMFILE that clamps reads to a section of a larger streamfile.
* Can be used with subfiles inside a bigger file (to fool metas, or to simplify custom IO). */
STREAMFILE* open_clamp_streamfile(STREAMFILE* sf, off_t start, size_t size);
STREAMFILE* open_clamp_streamfile_f(STREAMFILE* sf, off_t start, size_t size);
STREAMFILE* open_clamp_streamfile(STREAMFILE* sf, offv_t start, size_t size);
STREAMFILE* open_clamp_streamfile_f(STREAMFILE* sf, offv_t start, size_t size);
/* Opens a STREAMFILE that uses custom IO for streamfile reads.
* Can be used to modify data on the fly (ex. decryption), or even transform it from a format to another.
@ -156,8 +159,8 @@ static inline void close_streamfile(STREAMFILE* sf) {
}
/* read from a file, returns number of bytes read */
static inline size_t read_streamfile(uint8_t *dst, off_t offset, size_t length, STREAMFILE* sf) {
return sf->read(sf, dst, offset,length);
static inline size_t read_streamfile(uint8_t* dst, offv_t offset, size_t length, STREAMFILE* sf) {
return sf->read(sf, dst, offset, length);
}
/* return file size */

View File

@ -11,7 +11,7 @@
/* ************************************* */
/* opens a utf16 (unicode) path */
static FILE* wa_fopen(const in_char *wpath) {
static FILE* wa_fopen(const in_char* wpath) {
#ifdef UNICODE_INPUT_PLUGIN
return _wfopen(wpath,L"rb");
#else
@ -34,23 +34,23 @@ static FILE* wa_fdopen(int fd) {
/* a STREAMFILE that operates via STDIOSTREAMFILE but handles Winamp's unicode (in_char) paths */
typedef struct {
STREAMFILE sf;
STREAMFILE *stdiosf;
FILE *infile_ref; /* pointer to the infile in stdiosf (partially handled by stdiosf) */
STREAMFILE vt;
STREAMFILE* stdiosf;
FILE* infile_ref; /* pointer to the infile in stdiosf (partially handled by stdiosf) */
} WINAMP_STREAMFILE;
static STREAMFILE *open_winamp_streamfile_by_file(FILE *infile, const char * path);
//static STREAMFILE *open_winamp_streamfile_by_ipath(const in_char *wpath);
static STREAMFILE* open_winamp_streamfile_by_file(FILE* infile, const char* path);
//static STREAMFILE* open_winamp_streamfile_by_ipath(const in_char* wpath);
static size_t wasf_read(WINAMP_STREAMFILE* sf, uint8_t* dest, off_t offset, size_t length) {
return sf->stdiosf->read(sf->stdiosf, dest, offset, length);
static size_t wasf_read(WINAMP_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) {
return sf->stdiosf->read(sf->stdiosf, dst, offset, length);
}
static off_t wasf_get_size(WINAMP_STREAMFILE* sf) {
static size_t wasf_get_size(WINAMP_STREAMFILE* sf) {
return sf->stdiosf->get_size(sf->stdiosf);
}
static off_t wasf_get_offset(WINAMP_STREAMFILE* sf) {
static offv_t wasf_get_offset(WINAMP_STREAMFILE* sf) {
return sf->stdiosf->get_offset(sf->stdiosf);
}
@ -58,7 +58,7 @@ static void wasf_get_name(WINAMP_STREAMFILE* sf, char* buffer, size_t length) {
sf->stdiosf->get_name(sf->stdiosf, buffer, length);
}
static STREAMFILE *wasf_open(WINAMP_STREAMFILE* sf, const char* const filename, size_t buffersize) {
static STREAMFILE* wasf_open(WINAMP_STREAMFILE* sf, const char* const filename, size_t buffersize) {
in_char wpath[PATH_LIMIT];
if (!filename)
@ -77,7 +77,7 @@ static STREAMFILE *wasf_open(WINAMP_STREAMFILE* sf, const char* const filename,
FILE *new_file;
if (((new_fd = dup(fileno(sf->infile_ref))) >= 0) && (new_file = wa_fdopen(new_fd))) {
STREAMFILE *new_sf = open_winamp_streamfile_by_file(new_file, filename);
STREAMFILE* new_sf = open_winamp_streamfile_by_file(new_file, filename);
if (new_sf)
return new_sf;
fclose(new_file);
@ -101,7 +101,7 @@ static void wasf_close(WINAMP_STREAMFILE* sf) {
free(sf); /* and the current struct */
}
static STREAMFILE *open_winamp_streamfile_by_file(FILE* file, const char* path) {
static STREAMFILE* open_winamp_streamfile_by_file(FILE* file, const char* path) {
WINAMP_STREAMFILE* this_sf = NULL;
STREAMFILE* stdiosf = NULL;
@ -111,17 +111,17 @@ static STREAMFILE *open_winamp_streamfile_by_file(FILE* file, const char* path)
stdiosf = open_stdio_streamfile_by_file(file, path);
if (!stdiosf) goto fail;
this_sf->sf.read = (void*)wasf_read;
this_sf->sf.get_size = (void*)wasf_get_size;
this_sf->sf.get_offset = (void*)wasf_get_offset;
this_sf->sf.get_name = (void*)wasf_get_name;
this_sf->sf.open = (void*)wasf_open;
this_sf->sf.close = (void*)wasf_close;
this_sf->vt.read = (void*)wasf_read;
this_sf->vt.get_size = (void*)wasf_get_size;
this_sf->vt.get_offset = (void*)wasf_get_offset;
this_sf->vt.get_name = (void*)wasf_get_name;
this_sf->vt.open = (void*)wasf_open;
this_sf->vt.close = (void*)wasf_close;
this_sf->stdiosf = stdiosf;
this_sf->infile_ref = file;
return &this_sf->sf; /* pointer to STREAMFILE start = rest of the custom data follows */
return &this_sf->vt;
fail:
close_streamfile(stdiosf);