mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-12 09:40:51 +01:00
Merge pull request #905 from bnnm/etc-cleanup
- Add HCA key [Alchemy Stars (Android)] - Cleanup
This commit is contained in:
commit
06a7a5b920
25
Makefile
25
Makefile
@ -50,11 +50,26 @@ export RMF SHELL CC AR STRIP WINDRES DLLTOOL
|
||||
###############################################################################
|
||||
### build defs
|
||||
|
||||
DEF_CFLAGS = -ffast-math -O3 -Wall -Werror=format-security -Wdeclaration-after-statement -Wvla -Wimplicit-function-declaration -Wignored-qualifiers
|
||||
#ifdef VGM_DEBUG
|
||||
# CFLAGS += -DVGM_DEBUG_OUTPUT -O0
|
||||
# CFLAGS += -Wold-style-definition -Woverflow -Wpointer-arith -Wstrict-prototypes -pedantic -std=gnu90 -fstack-protector -Wformat
|
||||
#endif
|
||||
DEF_CFLAGS = -ffast-math -O3 -Wall -Werror=format-security -Wlogical-op -Wdeclaration-after-statement -Wvla -Wimplicit-function-declaration -Wignored-qualifiers
|
||||
|
||||
VGM_DEBUG_FLAGS = 0
|
||||
ifeq ($(VGM_DEBUG_FLAGS),1)
|
||||
#DEF_CFLAGS += -O0
|
||||
DEF_CFLAGS += -g -DVGM_DEBUG_OUTPUT
|
||||
DEF_CFLAGS += -Wall
|
||||
DEF_CFLAGS += -Wextra
|
||||
DEF_CFLAGS += -Wno-sign-compare
|
||||
#DEF_CFLAGS += -pedantic -Wconversion -std=gnu90
|
||||
#DEF_CFLAGS += -Wfloat-equal
|
||||
DEF_CFLAGS += -Wdisabled-optimization -Wunsafe-loop-optimizations -Wswitch-default
|
||||
DEF_CFLAGS += -Wcast-qual -Wpointer-arith
|
||||
DEF_CFLAGS += -Wcast-align=strict -Wduplicated-cond -Wjump-misses-init -Wnull-dereference
|
||||
DEF_CFLAGS += -Wold-style-definition -Wstrict-prototypes
|
||||
DEF_CFLAGS += -Wmultistatement-macros -Wstringop-truncation
|
||||
DEF_CFLAGS += -Wredundant-decls -Wmissing-include-dirs -Wmissing-declarations
|
||||
#DEF_CFLAGS += -Wshadow
|
||||
#DEF_CFLAGS += -Wstack-protector -fstack-protector
|
||||
endif
|
||||
|
||||
LIBS_CFLAGS=
|
||||
LIBS_LDFLAGS=
|
||||
|
10
README.md
10
README.md
@ -73,8 +73,11 @@ Put the following files somewhere Windows can find them:
|
||||
- `libcelt-0110.dll`
|
||||
- `libspeex.dll`
|
||||
|
||||
For Winamp/XMPlay/command line (`test.exe`) this means in the directory with the main `.exe`,
|
||||
or in a system directory, or any other directory in the PATH variable.
|
||||
For command line (`test.exe`) and XMPlay this means in the directory with the main `.exe`,
|
||||
or possibly a directory in the PATH variable.
|
||||
|
||||
For Winamp, the above `.dll` also go near main `winamp.exe`, but note that `in_vgmstream.dll`
|
||||
plugin itself goes in `Plugins`.
|
||||
|
||||
On other OSs like Linux/Mac, libs need to be installed before compiling, then should be used
|
||||
automatically, though not all may enabled at the moment due to build scripts issues.
|
||||
@ -84,6 +87,7 @@ automatically, though not all may enabled at the moment due to build scripts iss
|
||||
|
||||
### test.exe/vgmstream-cli (command line decoder)
|
||||
*Windows*: unzip `test.exe` and follow the above instructions for installing needed extra files.
|
||||
(`test.exe` is used for historical reasons, but you can call it `vgmstream-cli` anyway).
|
||||
|
||||
*Others*: build instructions can be found in doc/BUILD.md document in vgmstream's source
|
||||
code (can be compiled with CMake/Make/autotools).
|
||||
@ -125,7 +129,7 @@ wilcards (or leave it alone for the defaults).
|
||||
|
||||
|
||||
### in_vgmstream (Winamp plugin)
|
||||
*Windows*: drop the `in_vgmstream.dll` in your Winamp plugins directory,
|
||||
*Windows*: drop the `in_vgmstream.dll` in your Winamp Plugins directory,
|
||||
and follow the above instructions for installing needed extra files.
|
||||
|
||||
*Others*: may be possible to use through *Wine*
|
||||
|
@ -15,7 +15,7 @@ endif
|
||||
|
||||
# -DUSE_ALLOCA
|
||||
ifeq ($(TARGET_OS),Windows_NT)
|
||||
CFLAGS += -DWIN32 -I../ext_includes/ffmpeg
|
||||
CFLAGS += -DWIN32 -I../ext_libs/Getopt -I../ext_includes/ffmpeg
|
||||
endif
|
||||
|
||||
CFLAGS += $(DEF_CFLAGS) -DVAR_ARRAYS -I../ext_includes $(EXTRA_CFLAGS)
|
||||
|
@ -1,8 +1,10 @@
|
||||
#define POSIXLY_CORRECT
|
||||
|
||||
#include <getopt.h>
|
||||
#include "../src/vgmstream.h"
|
||||
#include "../src/plugins.h"
|
||||
#include "../src/util.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
@ -29,9 +31,9 @@
|
||||
* may improve write I/O in some systems as this*channels doubles as output buffer */
|
||||
#define SAMPLE_BUFFER_SIZE 32768
|
||||
|
||||
/* getopt globals (the horror...) */
|
||||
extern char* optarg;
|
||||
extern int optind, opterr, optopt;
|
||||
/* getopt globals from .h, for reference (the horror...) */
|
||||
//extern char* optarg;
|
||||
//extern int optind, opterr, optopt;
|
||||
|
||||
|
||||
static size_t make_wav_header(uint8_t* buf, size_t buf_size, int32_t sample_count, int32_t sample_rate, int channels, int smpl_chunk, int32_t loop_start, int32_t loop_end);
|
||||
@ -482,7 +484,7 @@ static void clean_filename(char* dst, int clean_paths) {
|
||||
|
||||
/* replaces a filename with "?n" (stream name), "?f" (infilename) or "?s" (subsong) wildcards
|
||||
* ("?" was chosen since it's not a valid Windows filename char and hopefully nobody uses it on Linux) */
|
||||
void replace_filename(char* dst, size_t dstsize, const char* outfilename, const char* infilename, VGMSTREAM* vgmstream) {
|
||||
static void replace_filename(char* dst, size_t dstsize, const char* outfilename, const char* infilename, VGMSTREAM* vgmstream) {
|
||||
int subsong;
|
||||
char stream_name[PATH_LIMIT];
|
||||
char buf[PATH_LIMIT];
|
||||
|
62
doc/BUILD.md
62
doc/BUILD.md
@ -9,40 +9,45 @@ Because each module has different quirks one can't use a single tool for everyth
|
||||
|
||||
64-bit support may work but has been minimally tested, since main use of vgmstream is plugins for 32-bit players (should work but extra codec libs are included for 32-bit only ATM).
|
||||
|
||||
|
||||
### GCC / Make
|
||||
Common C compiler, most development is done with this.
|
||||
|
||||
On Windows you need one of these two somewhere in PATH:
|
||||
On Windows you need one of these somewhere in PATH:
|
||||
- MinGW-w64 (32bit version): https://sourceforge.net/projects/mingw-w64/
|
||||
- Use this for easier standalone executables
|
||||
- Latest online installer with any config should work (for example: gcc-8.1.0, i686, win32, sjlj).
|
||||
https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/installer/mingw-w64-install.exe
|
||||
- Or simply download and unzip portable package:
|
||||
https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/8.1.0/threads-win32/sjlj/x86_64-8.1.0-release-win32-sjlj-rt_v6-rev0.7z
|
||||
https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/installer/mingw-w64-install.exe/download
|
||||
- Get from sourceforge page > "files" tab > scroll below > MingGW-W64-install.exe
|
||||
- Or download and unzip portable package:
|
||||
https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/8.1.0/threads-win32/sjlj/i686-8.1.0-release-win32-sjlj-rt_v6-rev0.7z/download
|
||||
- Get from sourceforge page > "files" tab > Toolchains targetting Win32 > Personal Builds > mingw-builds > some version zip
|
||||
- MSYS2 with the MinGW-w64_shell (32bit) package: https://msys2.github.io/
|
||||
|
||||
On Linux it should be included by default in the distribution, or can be easily installed using the distro's package manager (for example `sudo apt-get install gcc g++ make`).
|
||||
|
||||
|
||||
### Microsoft's Visual C++ (MSVC) / Visual Studio / MSBuild
|
||||
Alt C compiler, auto-generated builds for Windows use this.
|
||||
|
||||
Bundled in either:
|
||||
- Visual Studio (2015/2017/latest): https://www.visualstudio.com/downloads/
|
||||
|
||||
Visual Studio Community should work (free), but must register after trial period. Even after trial you can still use MSBuild, command-line tool that actually does all the building. You can also find and install "Visual C++ Build Tools" without Visual Studio IDE (link tend to move around).
|
||||
Visual Studio Community should work (free), but must register after trial period. Even after trial you can still use MSBuild, command-line tool that actually does all the building. You can also find and install "Visual C++ Build Tools" without Visual Studio IDE (try google as MS's links tend to move around).
|
||||
|
||||
Older versions of MSVC (2010 and before) have limited C support, while reportedly beta/new versions aren't always very stable. Some very odd issues affecting only MSVC have been found and fixed before. Keep in mind if you run into problems.
|
||||
|
||||
### Clang
|
||||
Reportedly works fine on Mac and may used as a replacement for GCC without issues.
|
||||
|
||||
Should be usable on Linux and possibly Windows with CMake.
|
||||
- https://releases.llvm.org/download.html
|
||||
|
||||
For other makefiles may work, though may need to set compiler vars appropriately (CC=clang AR=llvm-ar).
|
||||
|
||||
### Git
|
||||
Optional, used to generate version numbers:
|
||||
- Git for Windows: https://git-scm.com/download/win
|
||||
|
||||
Git also comes with typical Linux utils compiled for Windows (in the usr\bin dir), that can help when compiling some extra components on Windows.
|
||||
|
||||
### CMake
|
||||
Optional, can be used to compile vgmstream's modules instead of regular scripts. Needs v3.6 or later:
|
||||
@ -50,7 +55,6 @@ Optional, can be used to compile vgmstream's modules instead of regular scripts.
|
||||
|
||||
If you wish to use CMake, see [CMAKE.md](CMAKE.md). Some extra info is only mentioned in this doc though.
|
||||
|
||||
|
||||
### autotools
|
||||
Optional, used by some modules (mainly Audacious for Linux, and external libs).
|
||||
|
||||
@ -72,7 +76,6 @@ Typical usage involves `./configure` (creates makefiles) + `Make` (compiles) + `
|
||||
|
||||
External libs using autotools can be compiled on Windows too, try using `sh.exe ./configure`, `mingw32-make.exe`, `mingw32-make.exe install` instead. Also for older libs, call `sh.exe ./configure` with either `--build=mingw32`, `--host=mingw32` or `--target-os=mingw32` (varies) for older configure. You may also need to use `mingw32-make.exe LDFLAGS="-no-undefined -static-libgcc" MAKE=mingw32-make.exe` so that `.dll` are correctly generated.
|
||||
|
||||
|
||||
### Extra libs
|
||||
Optional, add codec or extra functionalities. See *External libraries* for full info.
|
||||
|
||||
@ -81,19 +84,22 @@ On Windows most libs are pre-compiled and included to simplify building (since t
|
||||
On Linux you usually need dev packages of each (for example `libao-dev` for vgmstream123, `audacious-dev` for Audacious, and so on) and they should be picked by CMake/autotool scripts.
|
||||
|
||||
|
||||
|
||||
## Compiling modules
|
||||
|
||||
### CLI (test.exe/vgmstream-cli) / Winamp plugin (in_vgmstream) / XMPlay plugin (xmp-vgmstream)
|
||||
|
||||
**With GCC**: use the *./Makefile* in the root folder, see inside for options. For compilation flags check the *Makefile* in each folder. You may need to manually rebuild if you change a *.h* file (use *make clean*).
|
||||
**With GCC/Clang**: there are various ways to build it, each with some differences; you probably want CMake described below.
|
||||
|
||||
In Linux, Makefiles can be used to cross-compile with the MingW headers, but may not be updated to generate native code at the moment. It should be fixable with some effort.
|
||||
Simplest way is using the *./Makefile* in the root folder, see inside for options. For compilation flags check the *Makefile* in each folder. You may need to manually rebuild if you change a *.h* file (use *make clean*). On Windows this will build with external libs enabled, but Linux can't ATM.
|
||||
|
||||
*Autotools* should build and install it as `vgmstream-cli`, this is explained in detail in the Audacious section. It also build with (some) extra codecs. Some Linux distributions like Arch Linux include pre-patched vgmstream with most libraries, you may want that instead:
|
||||
Also, on Linux you can't build *in_vgmstream* and *xmp-vgmstream* (given they are Windows DLLs...). Makefiles have been used in the past to cross-compile from Linux with MingW headers though, but can't generate native Win code at the moment (should be fixable with some effort).
|
||||
|
||||
*Autotools* should build and install it as `vgmstream-cli`, this is explained in detail in the Audacious section. It enables (some) extra codecs. Some Linux distributions like Arch Linux include pre-patched vgmstream with most libraries, you may want that instead:
|
||||
https://aur.archlinux.org/packages/vgmstream-kode54-git/
|
||||
|
||||
You may try CMake instead as it may be simpler and handle libs better. Some older distros may not work though (CMake version needs to recognize FILTER command). You may need to install resulting artifacts manually (check ./cli dir).
|
||||
If you use Mac (or Linux), there is a *Homebrew* script that may automate the process (uses CMake): https://formulae.brew.sh/formula/vgmstream
|
||||
|
||||
You may try CMake instead as it may be simpler and handle libs better. Some older distros may not work though (CMake version needs to recognize FILTER command). You may also need to install resulting artifacts manually (check ./cli dir). Check the *CMAKE.md* doc for some extra info too.
|
||||
```
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libmpg123-dev libvorbis-dev libspeex-dev
|
||||
@ -108,7 +114,7 @@ cmake .
|
||||
make
|
||||
```
|
||||
|
||||
Windows CMD example:
|
||||
Windows CMD example (with some debugging on):
|
||||
```
|
||||
prompt $P$G$_$S
|
||||
set PATH=C:\Program Files (x86)\Git\usr\bin;%PATH%
|
||||
@ -117,16 +123,24 @@ set PATH=C:\Program Files (x86)\mingw-w64\i686-5.4.0-win32-sjlj-rt_v5-rev0\mingw
|
||||
cd vgmstream
|
||||
|
||||
mingw32-make.exe vgmstream_cli -f Makefile ^
|
||||
VGM_ENABLE_FFMPEG=1 ^
|
||||
SHELL=sh.exe CC=gcc.exe AR=ar.exe STRIP=strip.exe DLLTOOL=dlltool.exe WINDRES=windres.exe
|
||||
VGM_ENABLE_MAIATRAC3PLUS=0 ^
|
||||
EXTRA_CFLAGS="-DVGM_DEBUG_OUTPUT -g -Wimplicit-function-declaration" ^
|
||||
SHELL=sh.exe CC=gcc.exe AR=ar.exe STRIP=strip.exe DLLTOOL=dlltool.exe WINDRES=windres.exe ^
|
||||
STRIP=echo ^
|
||||
1> ../vgmstream-stdout.txt 2> ../vgmstream-stderr.txt
|
||||
```
|
||||
|
||||
|
||||
**With MSVC**: To build in Visual Studio, run *./init-build.bat*, open *./vgmstream_full.sln* and compile. To build from the command line, run *./build.bat*.
|
||||
|
||||
The build script will automatically handle obtaining dependencies and making the project changes listed in the foobar2000 section (you may need to get some PowerShell .NET packages).
|
||||
|
||||
You can also call MSBuild directly in the command line (see the foobar2000 section for dependencies and examples)
|
||||
|
||||
#### notes
|
||||
While the official name for the CLI tool is `vgmstream-cli`, `test.exe` is used on Windows for historical reasons. If you want to reuse it for your own project it's probably better renaming to `vgmstream-cli.exe`.
|
||||
|
||||
|
||||
### foobar2000 plugin (foo\_input\_vgmstream)
|
||||
Requires MSVC (foobar/SDK only links to MSVC C++ DLLs) and these dependencies:
|
||||
- foobar2000 SDK (2018), in *(vgmstream)/dependencies/foobar/*: http://www.foobar2000.org/SDK
|
||||
@ -138,7 +152,7 @@ Requires MSVC (foobar/SDK only links to MSVC C++ DLLs) and these dependencies:
|
||||
The following project modifications are required:
|
||||
- For *foobar2000_ATL_helpers* add *../../../WTL/Include* to the compilers's *additional includes*
|
||||
|
||||
FDK-AAC/QAAC can be enabled adding *VGM_USE_MP4V2* and *VGM_USE_FDKAAC* in the compiler/linker options and the project dependencies, otherwise FFmpeg is used instead to support .mp4. Support is limited so FFmpeg is recommended.
|
||||
FDK-AAC/QAAC can be enabled adding *VGM_USE_MP4V2* and *VGM_USE_FDKAAC* in the compiler/linker options and the project dependencies, otherwise FFmpeg is used instead to support .mp4. FDK-AAC Support is limited so FFmpeg is recommended.
|
||||
|
||||
You can also manually use the command line to compile with MSBuild, if you don't want to touch the .vcxproj files, register VS after trial, get PowerShell dependencies for the build script, or only have VC++/MSBuild tools.
|
||||
|
||||
@ -252,7 +266,7 @@ make
|
||||
```
|
||||
|
||||
### vgmstream123 player
|
||||
Should be buildable with Autotools by following the same steps as listen in the Audacious section (requires libao-dev).
|
||||
Should be buildable with Autotools/CMake by following the same steps as listen in the Audacious section (requires libao-dev).
|
||||
|
||||
Windows builds are possible with `libao.dll` and `libao` includes (found elsewhere) through the `Makefile`, but some features are disabled.
|
||||
|
||||
@ -261,17 +275,17 @@ libao is licensed under the GPL v2 or later.
|
||||
|
||||
## External libraries
|
||||
Support for some codecs is done with external libs, instead of copying their code in vgmstream. There are various reasons for this:
|
||||
- each lib may have complex or conflicting ways to compile that aren't simple to duplicate
|
||||
- each lib may have complex or conflicting ways to compile that aren't simple to replicate
|
||||
- their sources can be quite big and undesirable to include in full
|
||||
- libs usually only compile with either GCC or MSVC, while vgmstream supports both compilers, so linking to the generated binary is much easier
|
||||
- libs usually only compile with either GCC or MSVC, while vgmstream supports both compilers, so linking to the generated binary (compatible) is much easier
|
||||
- not all licenses used by libs may allow to copy their code
|
||||
- simplifies maintenance and updating
|
||||
|
||||
They are compiled in their own sources, and the resulting binary is linked by vgmstream using a few of their symbols.
|
||||
|
||||
Currently only Windows builds can use external libraries, as vgmstream only includes generated 32-bit DLLs, but it should be fixable for others systems with some effort (libs are enabled on compile time). Ideally vgmstream could use libs compiled as static code (thus eliminating the need of DLLs), but involves a bunch of changes.
|
||||
Currently repo contains pre-compiled external libraries for Windows (32-bit Windows DLLs), while other systems link to system libraries. Ideally vgmstream could use libs compiled as static code (thus eliminating the need of DLLs), but involves a bunch of changes.
|
||||
|
||||
Below is a quick explanation of each library and how to compile binaries from them (for Windows, for Linux modules should include them automatically). Unless mentioned, their latest version should be ok to use, though included DLLs may be a bit older.
|
||||
Below is a quick explanation of each library and how to compile binaries from them (for Windows). Unless mentioned, their latest version should be ok to use, though included DLLs may be a bit older.
|
||||
|
||||
MSVC needs a .lib helper to link .dll files, but libs below usually only create .dll (and maybe .def). Instead, those .lib are automatically generated during build step in `ext_libs.vcxproj` from .dll+.def, using lib.exe tool.
|
||||
|
||||
@ -394,7 +408,7 @@ If all goes well, use generated .DLL in ./bin/bin (may need to rename to libspee
|
||||
### maiatrac3plus
|
||||
This lib was used as an alternate for ATRAC3PLUS decoding. Now this is handled by FFmpeg, though some code remains for now.
|
||||
|
||||
It was a straight-up decompilation from Sony's libs, without any clean-up or actual reverse engineering, thus legally and morally dubious.
|
||||
It was a straight-up decompilation from Sony's libs (presumably those found in SoundForge), without any clean-up or actual reverse engineering, thus legally and morally dubious.
|
||||
|
||||
It doesn't do encoder delay properly, but on the other hand decoding is 100% accurate unlike FFmpeg (probably inaudible though).
|
||||
|
||||
|
@ -14,12 +14,12 @@ int clHCA_isOurFile(const void *data, unsigned int size);
|
||||
typedef struct clHCA clHCA;
|
||||
|
||||
/* In case you wish to allocate and reset the structure on your own. */
|
||||
int clHCA_sizeof();
|
||||
int clHCA_sizeof(void);
|
||||
void clHCA_clear(clHCA *);
|
||||
void clHCA_done(clHCA *);
|
||||
|
||||
/* Or you could let the library allocate it. */
|
||||
clHCA * clHCA_new();
|
||||
clHCA * clHCA_new(void);
|
||||
void clHCA_delete(clHCA *);
|
||||
|
||||
/* Parses the HCA header. Must be called before any decoding may be performed,
|
||||
|
@ -364,7 +364,7 @@ static void clHCA_destructor(clHCA* hca) {
|
||||
hca->is_valid = 0;
|
||||
}
|
||||
|
||||
int clHCA_sizeof() {
|
||||
int clHCA_sizeof(void) {
|
||||
return sizeof(clHCA);
|
||||
}
|
||||
|
||||
@ -376,7 +376,7 @@ void clHCA_done(clHCA* hca) {
|
||||
clHCA_destructor(hca);
|
||||
}
|
||||
|
||||
clHCA* clHCA_new() {
|
||||
clHCA* clHCA_new(void) {
|
||||
clHCA* hca = malloc(clHCA_sizeof());
|
||||
if (hca) {
|
||||
clHCA_constructor(hca);
|
||||
@ -1941,7 +1941,6 @@ static void imdct_transform(stChannel* ch, int subframe) {
|
||||
|
||||
/* update output/imdct with overlapped window (lib fuses this with the above) */
|
||||
{
|
||||
unsigned int i;
|
||||
const float* dct = ch->spectra; //ch->dct;
|
||||
const float* prev = ch->imdct_previous;
|
||||
|
||||
|
@ -90,7 +90,7 @@ void decode_circus_adpcm(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channel
|
||||
|
||||
|
||||
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||
int8_t code = read_8bit(frame_offset+i,stream->streamfile);
|
||||
int8_t code = read_u8(frame_offset+i,stream->streamfile);
|
||||
|
||||
hist += code << scale;
|
||||
if (code == 0) {
|
||||
@ -102,6 +102,7 @@ void decode_circus_adpcm(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channel
|
||||
scale++;
|
||||
}
|
||||
outbuf[sample_pos] = hist;
|
||||
sample_pos += channelspacing;
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32 = hist;
|
||||
|
@ -35,12 +35,12 @@ void decode_rad_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* ou
|
||||
void decode_rad_ima_mono(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_apple_ima4(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_fsb_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_wwise_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_wwise_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_awc_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_ubi_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_ubi_sce_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_h4m_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, uint16_t frame_format);
|
||||
void decode_cd_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_cd_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
size_t ima_bytes_to_samples(size_t bytes, int channels);
|
||||
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels);
|
||||
size_t xbox_ima_bytes_to_samples(size_t bytes, int channels);
|
||||
@ -118,13 +118,13 @@ size_t xa_bytes_to_samples(size_t bytes, int channels, int is_blocked, int is_fo
|
||||
|
||||
/* ea_xa_decoder */
|
||||
void decode_ea_xa(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo);
|
||||
void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||
void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_maxis_xa(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
int32_t ea_xa_bytes_to_samples(size_t bytes, int channels);
|
||||
|
||||
|
||||
/* ea_xas_decoder */
|
||||
void decode_ea_xas_v0(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_ea_xas_v0(VGMSTREAMCHANNEL* stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_ea_xas_v1(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
|
||||
|
||||
@ -341,12 +341,12 @@ void free_tac(tac_codec_data* data);
|
||||
typedef struct ogg_vorbis_codec_data ogg_vorbis_codec_data;
|
||||
typedef struct { //todo simplify
|
||||
STREAMFILE *streamfile;
|
||||
ogg_int64_t start; /* file offset where the Ogg starts */
|
||||
ogg_int64_t offset; /* virtual offset, from 0 to size */
|
||||
ogg_int64_t size; /* virtual size of the Ogg */
|
||||
int64_t start; /* file offset where the Ogg starts */
|
||||
int64_t offset; /* virtual offset, from 0 to size */
|
||||
int64_t size; /* virtual size of the Ogg */
|
||||
|
||||
/* decryption setup */
|
||||
void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource);
|
||||
void (*decryption_callback)(void* ptr, size_t size, size_t nmemb, void* datasource);
|
||||
uint8_t scd_xor;
|
||||
off_t scd_xor_length;
|
||||
uint32_t xor_value;
|
||||
|
@ -557,7 +557,7 @@ struct TCompressWaveData {
|
||||
|
||||
//-----------------------------------------------------------
|
||||
//create
|
||||
TCompressWaveData* TCompressWaveData_Create() {
|
||||
TCompressWaveData* TCompressWaveData_Create(void) {
|
||||
TCompressWaveData* this = malloc(sizeof(TCompressWaveData));
|
||||
if (!this) return NULL;
|
||||
#if 0
|
||||
@ -604,7 +604,7 @@ void TCompressWaveData_Free(TCompressWaveData* this) {
|
||||
//-----------------------------------------------------------
|
||||
//outpus 44100/16bit/stereo waveform to designed buffer
|
||||
|
||||
void TCompressWaveData_Rendering_ReadPress(TCompressWaveData* this, int32_t* RFlg, int32_t* LFlg) {
|
||||
static void TCompressWaveData_Rendering_ReadPress(TCompressWaveData* this, int32_t* RFlg, int32_t* LFlg) {
|
||||
if (this->Hed.Channel == 2) {
|
||||
*RFlg = THuff_Read(this->RH); //STEREO
|
||||
*LFlg = THuff_Read(this->RH);
|
||||
@ -615,7 +615,7 @@ void TCompressWaveData_Rendering_ReadPress(TCompressWaveData* this, int32_t* RFl
|
||||
}
|
||||
}
|
||||
|
||||
void TCompressWaveData_Rendering_WriteWave(TCompressWaveData* this, int16_t** buf1, int32_t RVol, int32_t LVol) {
|
||||
static void TCompressWaveData_Rendering_WriteWave(TCompressWaveData* this, int16_t** buf1, int32_t RVol, int32_t LVol) {
|
||||
TLRWRITEBUFFER bbb = {0};
|
||||
|
||||
if (this->Hed.Sample == 44100) { //44100 STEREO/MONO
|
||||
@ -867,8 +867,8 @@ void TCompressWaveData_SetVolume(TCompressWaveData* this, float vol, float fade)
|
||||
this->FSetVolume = this->FVolume;
|
||||
}
|
||||
else { //without fade value
|
||||
this->Ffade = round(PW_MAXVOLUME / fade / 44100);
|
||||
this->FSetVolume = round(aaa * PW_MAXVOLUME);
|
||||
this->Ffade = round((double)PW_MAXVOLUME / fade / 44100);
|
||||
this->FSetVolume = round(aaa * (double)PW_MAXVOLUME);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ typedef struct TCompressWaveData TCompressWaveData;
|
||||
void TCompressWaveData_GetLoopState(TCompressWaveData* this);
|
||||
void TCompressWaveData_SetLoopState(TCompressWaveData* this);
|
||||
|
||||
TCompressWaveData* TCompressWaveData_Create();
|
||||
TCompressWaveData* TCompressWaveData_Create(void);
|
||||
void TCompressWaveData_Free(TCompressWaveData* this);
|
||||
int TCompressWaveData_Rendering(TCompressWaveData* this, int16_t* buf, uint32_t Len);
|
||||
int TCompressWaveData_LoadFromStream(TCompressWaveData* this, STREAMFILE* ss);
|
||||
|
@ -30,7 +30,7 @@ static const int EA_XA_TABLE[20] = {
|
||||
};
|
||||
|
||||
/* EA XA v2 (always mono); like v1 but with "PCM samples" flag and doesn't add 128 on expand or clamp (pre-adjusted by the encoder?) */
|
||||
void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
uint8_t frame_info;
|
||||
int32_t coef1, coef2;
|
||||
int i, sample_count, shift;
|
||||
@ -60,7 +60,7 @@ void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspac
|
||||
coef2 = EA_XA_TABLE[(frame_info >> 4) + 4];
|
||||
shift = (frame_info & 0x0F) + 8;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++, sample_count += channelspacing) {
|
||||
uint8_t sample_byte, sample_nibble;
|
||||
int32_t new_sample;
|
||||
off_t byte_offset = (stream->offset + 0x01 + i/2);
|
||||
@ -84,7 +84,7 @@ void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspac
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* later PC games use float math, though in the end sounds basically the same (decompiled from various exes) */
|
||||
/* later PC games and EAAC use float math, though in the end sounds basically the same (decompiled from various exes) */
|
||||
static const double XA_K0[16] = { 0.0, 0.9375, 1.796875, 1.53125 };
|
||||
static const double XA_K1[16] = { 0.0, 0.0, -0.8125, -0.859375 };
|
||||
/* code uses look-up table but it's equivalent to:
|
||||
@ -125,7 +125,7 @@ static const uint32_t FLOAT_TABLE_INT[256] = {
|
||||
};
|
||||
static const float* FLOAT_TABLE = (const float *)FLOAT_TABLE_INT;
|
||||
|
||||
void decode_ea_xa_v2(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_ea_xa_v2_f32(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
uint8_t frame_info;
|
||||
int i, sample_count, shift;
|
||||
|
||||
|
@ -113,7 +113,7 @@ void decode_ea_xas_v1(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspa
|
||||
|
||||
|
||||
/* EA-XAS v0 (xas0), without complex layouts and closer to EA-XA. Somewhat based on daemon1's decoder. */
|
||||
void decode_ea_xas_v0(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_ea_xas_v0(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
uint8_t frame[0x13] = {0};
|
||||
off_t frame_offset;
|
||||
int i, frames_in, samples_done = 0, sample_count = 0;
|
||||
|
@ -67,7 +67,7 @@ static int init_ffmpeg_config(ffmpeg_codec_data* data, int target_subsong, int r
|
||||
/* ******************************************** */
|
||||
|
||||
/* Global FFmpeg init */
|
||||
static void g_init_ffmpeg() {
|
||||
static void g_init_ffmpeg(void) {
|
||||
if (g_ffmpeg_initialized == 1) {
|
||||
while (g_ffmpeg_initialized < 2); /* active wait for lack of a better way */
|
||||
}
|
||||
@ -266,6 +266,9 @@ static int64_t ffmpeg_seek(void* opaque, int64_t offset, int whence) {
|
||||
case SEEK_END: /* relative to file end (should be negative) */
|
||||
offset += data->logical_size;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* clamp offset; fseek does this too */
|
||||
|
@ -784,7 +784,7 @@ static ffmpeg_codec_data* init_ffmpeg_custom_opus(STREAMFILE* sf, off_t start_of
|
||||
return init_ffmpeg_custom_opus_config(sf, start_offset, data_size, &cfg, type);
|
||||
}
|
||||
|
||||
ffmpeg_codec_data* init_ffmpeg_custom_table_opus(STREAMFILE* sf, off_t table_offset, int table_count, off_t data_offset, size_t data_size, int channels, int skip, int sample_rate, opus_type_t type) {
|
||||
static ffmpeg_codec_data* init_ffmpeg_custom_table_opus(STREAMFILE* sf, off_t table_offset, int table_count, off_t data_offset, size_t data_size, int channels, int skip, int sample_rate, opus_type_t type) {
|
||||
opus_config cfg = {0};
|
||||
cfg.channels = channels;
|
||||
cfg.skip = skip;
|
||||
|
@ -302,7 +302,7 @@ static void aes_decrypt_block(s14aes_handle* ctx, uint8_t* buf) {
|
||||
|
||||
/* **************************** */
|
||||
|
||||
s14aes_handle* s14aes_init() {
|
||||
s14aes_handle* s14aes_init(void) {
|
||||
s14aes_handle* ctx = malloc(sizeof(s14aes_handle));
|
||||
if (!ctx) goto fail;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
typedef struct s14aes_handle s14aes_handle;
|
||||
|
||||
/* init/close handle (AES-192 in ECB mode) */
|
||||
s14aes_handle* s14aes_init();
|
||||
s14aes_handle* s14aes_init(void);
|
||||
|
||||
void s14aes_close(s14aes_handle* ctx);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "coding.h"
|
||||
#include <clHCA.h>
|
||||
|
||||
|
||||
struct hca_codec_data {
|
||||
|
@ -983,7 +983,7 @@ void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t *
|
||||
}
|
||||
|
||||
/* mono XBOX-IMA with header endianness and alt nibble expand (verified vs AK test demos) */
|
||||
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_wwise_ima(VGMSTREAM* vgmstream, VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count = 0, num_frame;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -1242,7 +1242,7 @@ static inline int _clamp_s32(int value, int min, int max) {
|
||||
|
||||
/* Crystal Dynamics IMA. Original code uses mind-bending intrinsics, so this may not be fully accurate.
|
||||
* Has another table with delta_table MMX combos, and uses header sample (first nibble is always 0). */
|
||||
void decode_cd_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_cd_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
uint8_t frame[0x24] = {0};
|
||||
int i, frames_in, sample_pos = 0, block_samples, frame_size;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
|
@ -309,7 +309,7 @@ fail:
|
||||
|
||||
/* **************************************** */
|
||||
|
||||
static void decode_vima1(STREAMFILE* sf, sbuf_t* sbuf, uint8_t* buf, size_t data_left, int block_num, uint16_t* adpcm_table) {
|
||||
static void decode_vima1(sbuf_t* sbuf, uint8_t* buf, size_t data_left, int block_num, uint16_t* adpcm_table) {
|
||||
int ch, i, j, s;
|
||||
int bitpos;
|
||||
int adpcm_history[MAX_CHANNELS] = {0};
|
||||
@ -420,13 +420,13 @@ static void decode_vima1(STREAMFILE* sf, sbuf_t* sbuf, uint8_t* buf, size_t data
|
||||
sbuf->filled += data_left / sizeof(int16_t) / chs;
|
||||
}
|
||||
|
||||
static int decode_block1(STREAMFILE* sf, imuse_codec_data* data, uint8_t* block, size_t data_left) {
|
||||
static int decode_block1(imuse_codec_data* data, uint8_t* block, size_t data_left) {
|
||||
int block_num = data->current_block;
|
||||
|
||||
switch(data->block_table[block_num].flags) {
|
||||
case 0x0D:
|
||||
case 0x0F:
|
||||
decode_vima1(sf, &data->sbuf, block, data_left, block_num, data->adpcm_table);
|
||||
decode_vima1(&data->sbuf, block, data_left, block_num, data->adpcm_table);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
@ -434,7 +434,7 @@ static int decode_block1(STREAMFILE* sf, imuse_codec_data* data, uint8_t* block,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void decode_data2(STREAMFILE* sf, sbuf_t* sbuf, uint8_t* buf, size_t data_left, int block_num) {
|
||||
static void decode_data2(sbuf_t* sbuf, uint8_t* buf, size_t data_left, int block_num) {
|
||||
int i, j;
|
||||
int channels = sbuf->channels;
|
||||
|
||||
@ -453,7 +453,7 @@ static void decode_data2(STREAMFILE* sf, sbuf_t* sbuf, uint8_t* buf, size_t data
|
||||
}
|
||||
}
|
||||
|
||||
static void decode_vima2(STREAMFILE* sf, sbuf_t* sbuf, uint8_t* buf, size_t data_left, uint16_t* adpcm_table) {
|
||||
static void decode_vima2(sbuf_t* sbuf, uint8_t* buf, size_t data_left, uint16_t* adpcm_table) {
|
||||
int ch, i, s;
|
||||
int bitpos;
|
||||
int adpcm_history[MAX_CHANNELS] = {0};
|
||||
@ -554,16 +554,16 @@ static void decode_vima2(STREAMFILE* sf, sbuf_t* sbuf, uint8_t* buf, size_t data
|
||||
sbuf->filled += data_left / sizeof(int16_t) / chs;
|
||||
}
|
||||
|
||||
static int decode_block2(STREAMFILE* sf, imuse_codec_data* data, uint8_t* block, size_t data_left) {
|
||||
static int decode_block2(imuse_codec_data* data, uint8_t* block, size_t data_left) {
|
||||
int block_num = data->current_block;
|
||||
|
||||
switch(data->block_table[block_num].flags) {
|
||||
case 0x00:
|
||||
decode_data2(sf, &data->sbuf, block, data_left, block_num);
|
||||
decode_data2(&data->sbuf, block, data_left, block_num);
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
decode_vima2(sf, &data->sbuf, block, data_left, data->adpcm_table);
|
||||
decode_vima2(&data->sbuf, block, data_left, data->adpcm_table);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
@ -597,11 +597,11 @@ static int decode_block(STREAMFILE* sf, imuse_codec_data* data) {
|
||||
|
||||
switch(data->type) {
|
||||
case COMP:
|
||||
ok = decode_block1(sf, data, block, data_left);
|
||||
ok = decode_block1(data, block, data_left);
|
||||
break;
|
||||
|
||||
case MCMP:
|
||||
ok = decode_block2(sf, data, block, data_left);
|
||||
ok = decode_block2(data, block, data_left);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -3,13 +3,12 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
#include <mpg123.h>
|
||||
#include "mpeg_decoder.h"
|
||||
|
||||
|
||||
#define MPEG_DATA_BUFFER_SIZE 0x1000 /* at least one MPEG frame (max ~0x5A1 plus some more in case of free bitrate) */
|
||||
|
||||
static mpg123_handle* init_mpg123_handle();
|
||||
static mpg123_handle* init_mpg123_handle(void);
|
||||
static void decode_mpeg_standard(VGMSTREAMCHANNEL* stream, mpeg_codec_data* data, sample_t* outbuf, int32_t samples_to_do, int channels);
|
||||
static void decode_mpeg_custom(VGMSTREAM* vgmstream, mpeg_codec_data* data, sample_t* outbuf, int32_t samples_to_do, int channels);
|
||||
static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data* data, int num_stream);
|
||||
@ -185,7 +184,7 @@ fail:
|
||||
}
|
||||
|
||||
|
||||
static mpg123_handle* init_mpg123_handle() {
|
||||
static mpg123_handle* init_mpg123_handle(void) {
|
||||
mpg123_handle* m = NULL;
|
||||
int rc;
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#ifndef _MPEG_DECODER_H_
|
||||
#define _MPEG_DECODER_H_
|
||||
#include <mpg123.h>
|
||||
|
||||
#include "../vgmstream.h"
|
||||
#include "../coding/coding.h"
|
||||
|
@ -455,7 +455,7 @@ static void decode_subframe_stereo(ubi_adpcm_channel_data* ch0_state, ubi_adpcm_
|
||||
* 0xA82557DB LE = 1010 100000 100101 010101 111101 1011 ... (where last 00 | first 1010 = 001010), etc
|
||||
* Codes aren't signed but rather have a particular meaning (see decoding).
|
||||
*/
|
||||
void unpack_codes(uint8_t* data, uint8_t* codes, int code_count, int bps) {
|
||||
static void unpack_codes(uint8_t* data, uint8_t* codes, int code_count, int bps) {
|
||||
int i;
|
||||
size_t pos = 0;
|
||||
uint64_t bits = 0, input = 0;
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include "vorbis_custom_decoder.h"
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
#include <vorbis/codec.h>
|
||||
|
||||
#define VORBIS_DEFAULT_BUFFER_SIZE 0x8000 /* should be at least the size of the setup header, ~0x2000 */
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
/* used by vorbis_custom_decoder.c, but scattered in other .c files */
|
||||
#ifdef VGM_USE_VORBIS
|
||||
#include <vorbis/codec.h>
|
||||
|
||||
/* custom Vorbis without Ogg layer */
|
||||
struct vorbis_custom_codec_data {
|
||||
|
@ -77,7 +77,7 @@ int vorbis_custom_parse_packet_vid1(VGMSTREAMCHANNEL* stream, vorbis_custom_code
|
||||
|
||||
|
||||
/* get packet info the VID1 header */
|
||||
get_packet_header(stream->streamfile, &stream->offset, (uint32_t*)&data->op.bytes);
|
||||
get_packet_header(stream->streamfile, &stream->offset, (size_t*)&data->op.bytes);
|
||||
if (data->op.bytes == 0 || data->op.bytes > data->buffer_size) goto fail; /* EOF or end padding */
|
||||
|
||||
/* read raw block */
|
||||
|
@ -365,11 +365,6 @@ static int ww2ogg_generate_vorbis_packet(bitstream_t* ow, bitstream_t* iw, wpack
|
||||
/* rebuild first bits of packet type and window info (for the i-MDCT) */
|
||||
uint32_t packet_type = 0, mode_number = 0, remainder = 0;
|
||||
|
||||
if (!data->mode_blockflag) { /* config error */
|
||||
VGM_LOG("Wwise Vorbis: didn't load mode_blockflag\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* audio packet type */
|
||||
packet_type = 0;
|
||||
wv_bits(ow, 1, packet_type);
|
||||
@ -434,8 +429,8 @@ static int ww2ogg_generate_vorbis_packet(bitstream_t* ow, bitstream_t* iw, wpack
|
||||
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
//fail:
|
||||
// return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************/
|
||||
|
@ -135,6 +135,8 @@ void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channels
|
||||
samples_left_in_frame--) { /* done with reading a sample */
|
||||
outbuf[sample_count]=(hist-0x80)*0x100;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1012,7 +1012,7 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
|
||||
case coding_EA_XA_V2:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_ea_xa_v2(&vgmstream->ch[ch], buffer+ch,
|
||||
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch);
|
||||
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_MAXIS_XA:
|
||||
@ -1024,7 +1024,7 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
|
||||
case coding_EA_XAS_V0:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_ea_xas_v0(&vgmstream->ch[ch], buffer+ch,
|
||||
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch);
|
||||
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_EA_XAS_V1:
|
||||
@ -1188,7 +1188,7 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
|
||||
case coding_WWISE_IMA:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_wwise_ima(vgmstream,&vgmstream->ch[ch], buffer+ch,
|
||||
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch);
|
||||
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_REF_IMA:
|
||||
@ -1227,7 +1227,7 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
|
||||
case coding_CD_IMA:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_cd_ima(&vgmstream->ch[ch], buffer+ch,
|
||||
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch);
|
||||
vgmstream->channels, vgmstream->samples_into_block, samples_to_do);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -999,7 +999,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_LEG, "Legaia 2 - Duel Saga LEG Header"},
|
||||
{meta_FILP, "Bio Hazard - Gun Survivor FILp Header"},
|
||||
{meta_IKM, "MiCROViSiON IKM header"},
|
||||
{meta_SFS, "Baroque SFS Header"},
|
||||
{meta_SFS, "String .SFS header"},
|
||||
{meta_SAT_DVI, "Konami KCEN DVI. header"},
|
||||
{meta_DC_KCEY, "Konami KCEY KCEYCOMP header"},
|
||||
{meta_BG00, "Falcom BG00 Header"},
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
|
||||
static size_t get_channel_header_size(STREAMFILE* sf, off_t offset, int channels, int big_endian);
|
||||
static size_t get_channel_header_size(STREAMFILE* sf, off_t offset, int big_endian);
|
||||
static size_t get_block_header_size(STREAMFILE* sf, off_t offset, size_t channel_header_size, int channels, int big_endian);
|
||||
|
||||
/* AWC music chunks */
|
||||
@ -38,7 +38,7 @@ void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
* 32b * entries = global samples per frame in each block (for MPEG probably per full frame)
|
||||
*/
|
||||
|
||||
channel_header_size = get_channel_header_size(sf, block_offset, vgmstream->channels, vgmstream->codec_endian);
|
||||
channel_header_size = get_channel_header_size(sf, block_offset, vgmstream->codec_endian);
|
||||
header_size = get_block_header_size(sf, block_offset, channel_header_size, vgmstream->channels, vgmstream->codec_endian);
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = block_offset + header_size + 0x800*entries*i;
|
||||
@ -47,7 +47,7 @@ void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
|
||||
}
|
||||
|
||||
static size_t get_channel_header_size(STREAMFILE* sf, off_t offset, int channels, int big_endian) {
|
||||
static size_t get_channel_header_size(STREAMFILE* sf, off_t offset, int big_endian) {
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
|
||||
|
||||
/* later games have an smaller channel header, try to detect using
|
||||
|
@ -1,19 +1,19 @@
|
||||
#include "layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
|
||||
/* XVAG with subsongs layers, interleaves chunks of each subsong (a hack to support them) */
|
||||
void block_update_xvag_subsong(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
size_t channel_size = 0x10;
|
||||
|
||||
/* set offsets */
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = block_offset + channel_size*i;
|
||||
}
|
||||
|
||||
//vgmstream->current_block_size = ; /* fixed */
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + vgmstream->full_block_size;
|
||||
}
|
||||
#include "layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
|
||||
/* XVAG with subsongs layers, interleaves chunks of each subsong (a hack to support them) */
|
||||
void block_update_xvag_subsong(off_t block_offset, VGMSTREAM* vgmstream) {
|
||||
int i;
|
||||
size_t channel_size = 0x10;
|
||||
|
||||
/* set offsets */
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = block_offset + channel_size*i;
|
||||
}
|
||||
|
||||
//vgmstream->current_block_size = ; /* fixed */
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + vgmstream->full_block_size;
|
||||
}
|
||||
|
@ -1,48 +1,47 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .208 - from Ocean game(s?) [Last Rites (PC)] */
|
||||
VGMSTREAM * init_vgmstream_208(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count, sample_rate;
|
||||
size_t data_size;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "208"))
|
||||
goto fail;
|
||||
/* possible validation: (0x04 == 0 and 0xcc == 0x1F7D984D) or 0x04 == 0xf0 and 0xcc == 0) */
|
||||
if (!((read_32bitLE(0x04,streamFile) == 0x00 && read_32bitBE(0xcc,streamFile) == 0x1F7D984D) ||
|
||||
(read_32bitLE(0x04,streamFile) == 0xF0 && read_32bitBE(0xcc,streamFile) == 0x00000000)))
|
||||
goto fail;
|
||||
|
||||
start_offset = read_32bitLE(0x00,streamFile);
|
||||
data_size = read_32bitLE(0x0c,streamFile);
|
||||
sample_rate = read_32bitLE(0x34,streamFile);
|
||||
channel_count = read_32bitLE(0x3C,streamFile); /* assumed */
|
||||
loop_flag = 0;
|
||||
|
||||
if (start_offset + data_size != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_208;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, 8);
|
||||
vgmstream->coding_type = coding_PCM8_U;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x1;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .208 - from Ocean game(s?) [Last Rites (PC)] */
|
||||
VGMSTREAM* init_vgmstream_208(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset, data_size;
|
||||
int loop_flag, channels, sample_rate;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "208"))
|
||||
goto fail;
|
||||
/* possible validation: (0x04 == 0 and 0xcc == 0x1F7D984D) or 0x04 == 0xf0 and 0xcc == 0) */
|
||||
if (!((read_u32le(0x04,sf) == 0x00 && read_u32be(0xcc,sf) == 0x1F7D984D) ||
|
||||
(read_u32le(0x04,sf) == 0xF0 && read_u32be(0xcc,sf) == 0x00000000)))
|
||||
goto fail;
|
||||
|
||||
start_offset = read_s32le(0x00,sf);
|
||||
data_size = read_s32le(0x0c,sf);
|
||||
sample_rate = read_s32le(0x34,sf);
|
||||
channels = read_s32le(0x3C,sf); /* assumed */
|
||||
loop_flag = 0;
|
||||
|
||||
if (start_offset + data_size != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_208;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = pcm8_bytes_to_samples(data_size, channels);
|
||||
vgmstream->coding_type = coding_PCM8_U;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x1;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ fail:
|
||||
#define ACB_MAX_NAME 1024 /* even more is possible in rare cases [Senran Kagura Burst Re:Newal (PC)] */
|
||||
|
||||
|
||||
STREAMFILE* setup_acb_streamfile(STREAMFILE* sf, size_t buffer_size) {
|
||||
static STREAMFILE* setup_acb_streamfile(STREAMFILE* sf, size_t buffer_size) {
|
||||
STREAMFILE* new_sf = NULL;
|
||||
|
||||
/* buffer seems better than reopening when opening multiple subsongs at the same time with STDIO,
|
||||
|
@ -274,7 +274,7 @@ static int find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t *xor_start, uint1
|
||||
key_size = read_key_file(keybuf, sizeof(keybuf), sf);
|
||||
|
||||
if (key_size > 0) {
|
||||
int i, is_ascii = 0;
|
||||
int is_ascii = 0;
|
||||
|
||||
/* keystrings should be ASCII, also needed to tell apart 0x06 strings from derived keys */
|
||||
if (type == 8) {
|
||||
|
@ -1,51 +1,51 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .AIF - from Asobo Studio games [Ratatouille (PC), WALL-E (PC), Up (PC)] */
|
||||
VGMSTREAM * init_vgmstream_aif_asobo(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
size_t data_size;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* aif: standard, .laif/aiffl: for plugins */
|
||||
if ( !check_extensions(streamFile,"aif,laif,aiffl") )
|
||||
goto fail;
|
||||
if ((uint16_t)read_16bitLE(0x00,streamFile) != 0x69) /* Xbox codec */
|
||||
goto fail;
|
||||
|
||||
channel_count = read_16bitLE(0x02,streamFile); /* assumed, only stereo is known */
|
||||
if (channel_count != 2) goto fail;
|
||||
|
||||
/* 0x08: ? */
|
||||
if ((uint16_t)read_16bitLE(0x0c,streamFile) != 0x24*channel_count) /* Xbox block */
|
||||
goto fail;
|
||||
if ((uint16_t)read_16bitLE(0x0e,streamFile) != 0x04) /* Xbox bps */
|
||||
goto fail;
|
||||
loop_flag = 0;
|
||||
|
||||
start_offset = 0x14;
|
||||
data_size = get_streamfile_size(streamFile) - start_offset;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_AIF_ASOBO;
|
||||
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size,channel_count);
|
||||
|
||||
vgmstream->coding_type = coding_XBOX_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .AIF - from Asobo Studio games [Ratatouille (PC), WALL-E (PC), Up (PC)] */
|
||||
VGMSTREAM* init_vgmstream_aif_asobo(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
size_t data_size;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* aif: standard, .laif/aiffl: for plugins */
|
||||
if ( !check_extensions(sf,"aif,laif,aiffl") )
|
||||
goto fail;
|
||||
if ((uint16_t)read_16bitLE(0x00,sf) != 0x69) /* Xbox codec */
|
||||
goto fail;
|
||||
|
||||
channel_count = read_16bitLE(0x02,sf); /* assumed, only stereo is known */
|
||||
if (channel_count != 2) goto fail;
|
||||
|
||||
/* 0x08: ? */
|
||||
if ((uint16_t)read_16bitLE(0x0c,sf) != 0x24*channel_count) /* Xbox block */
|
||||
goto fail;
|
||||
if ((uint16_t)read_16bitLE(0x0e,sf) != 0x04) /* Xbox bps */
|
||||
goto fail;
|
||||
loop_flag = 0;
|
||||
|
||||
start_offset = 0x14;
|
||||
data_size = get_streamfile_size(sf) - start_offset;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_AIF_ASOBO;
|
||||
vgmstream->sample_rate = read_32bitLE(0x04,sf);
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size,channel_count);
|
||||
|
||||
vgmstream->coding_type = coding_XBOX_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream, sf, start_offset) )
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
116
src/meta/akb.c
116
src/meta/akb.c
@ -3,20 +3,20 @@
|
||||
|
||||
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
|
||||
/* AKB (AAC only) - found in SQEX iOS games */
|
||||
VGMSTREAM * init_vgmstream_akb_mp4(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * init_vgmstream_akb_mp4(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
|
||||
size_t filesize;
|
||||
uint32_t loop_start, loop_end;
|
||||
|
||||
if ((uint32_t)read_32bitBE(0, streamFile) != 0x414b4220) goto fail;
|
||||
if ((uint32_t)read_32bitBE(0, sf) != 0x414b4220) goto fail;
|
||||
|
||||
loop_start = read_32bitLE(0x14, streamFile);
|
||||
loop_end = read_32bitLE(0x18, streamFile);
|
||||
loop_start = read_32bitLE(0x14, sf);
|
||||
loop_end = read_32bitLE(0x18, sf);
|
||||
|
||||
filesize = get_streamfile_size( streamFile );
|
||||
filesize = get_streamfile_size( sf );
|
||||
|
||||
vgmstream = init_vgmstream_mp4_aac_offset( streamFile, 0x20, filesize - 0x20 );
|
||||
vgmstream = init_vgmstream_mp4_aac_offset( sf, 0x20, filesize - 0x20 );
|
||||
if ( !vgmstream ) goto fail;
|
||||
|
||||
if ( loop_start || loop_end ) {
|
||||
@ -34,7 +34,7 @@ fail:
|
||||
|
||||
|
||||
/* AKB - found in SQEX iOS games */
|
||||
VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * init_vgmstream_akb(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, extradata_offset = 0;
|
||||
size_t stream_size, header_size, subheader_size = 0, extradata_size = 0;
|
||||
@ -44,28 +44,28 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
|
||||
/* checks */
|
||||
/* .akb.bytes is the usual extension in later games */
|
||||
if ( !check_extensions(streamFile, "akb,bytes") )
|
||||
if ( !check_extensions(sf, "akb,bytes") )
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x414B4220) /* "AKB " */
|
||||
if (read_32bitBE(0x00,sf) != 0x414B4220) /* "AKB " */
|
||||
goto fail;
|
||||
if (read_32bitLE(0x08,streamFile) != get_streamfile_size(streamFile))
|
||||
if (read_32bitLE(0x08,sf) != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
|
||||
/* 0x04(1): version */
|
||||
header_size = read_16bitLE(0x06,streamFile);
|
||||
header_size = read_16bitLE(0x06,sf);
|
||||
|
||||
codec = read_8bit(0x0c,streamFile);
|
||||
channel_count = read_8bit(0x0d,streamFile);
|
||||
sample_rate = (uint16_t)read_16bitLE(0x0e,streamFile);
|
||||
num_samples = read_32bitLE(0x10,streamFile);
|
||||
loop_start = read_32bitLE(0x14,streamFile);
|
||||
loop_end = read_32bitLE(0x18,streamFile);
|
||||
codec = read_8bit(0x0c,sf);
|
||||
channel_count = read_8bit(0x0d,sf);
|
||||
sample_rate = (uint16_t)read_16bitLE(0x0e,sf);
|
||||
num_samples = read_32bitLE(0x10,sf);
|
||||
loop_start = read_32bitLE(0x14,sf);
|
||||
loop_end = read_32bitLE(0x18,sf);
|
||||
|
||||
/* possibly more complex, see AKB2 */
|
||||
if (header_size >= 0x44) { /* v2+ */
|
||||
extradata_size = read_16bitLE(0x1c,streamFile);
|
||||
extradata_size = read_16bitLE(0x1c,sf);
|
||||
/* 0x20+: config? (pan, volume) */
|
||||
subheader_size = read_16bitLE(0x28,streamFile);
|
||||
subheader_size = read_16bitLE(0x28,sf);
|
||||
/* 0x24: file_id? */
|
||||
/* 0x2b: encryption bitflag if version > 2? */
|
||||
extradata_offset = header_size + subheader_size;
|
||||
@ -75,7 +75,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
start_offset = header_size;
|
||||
}
|
||||
|
||||
stream_size = get_streamfile_size(streamFile) - start_offset;
|
||||
stream_size = get_streamfile_size(sf) - start_offset;
|
||||
loop_flag = (loop_end > loop_start);
|
||||
|
||||
|
||||
@ -91,14 +91,14 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
case 0x02: { /* MSADPCM [Dragon Quest II (iOS) sfx] */
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->frame_size = read_16bitLE(extradata_offset + 0x02,streamFile);
|
||||
vgmstream->frame_size = read_16bitLE(extradata_offset + 0x02,sf);
|
||||
|
||||
/* adjusted samples; bigger or smaller than base samples, akb lib uses these fields instead
|
||||
* (base samples may have more than possible and read over file size otherwise, very strange)
|
||||
* loop_end seems to exist even with loop disabled */
|
||||
vgmstream->num_samples = read_32bitLE(extradata_offset + 0x04, streamFile);
|
||||
vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, streamFile);
|
||||
vgmstream->num_samples = read_32bitLE(extradata_offset + 0x04, sf);
|
||||
vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, sf);
|
||||
vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, sf);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -112,7 +112,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
/* extradata + 0x04: Ogg loop start offset */
|
||||
/* oggs have loop info in the comments */
|
||||
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
if (ogg_vgmstream) {
|
||||
close_vgmstream(vgmstream);
|
||||
return ogg_vgmstream;
|
||||
@ -128,7 +128,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
/* Alt decoding without libvorbis (minor number of beginning samples difference).
|
||||
* Otherwise same output with (inaudible) +-1 lower byte differences due to rounding. */
|
||||
case 0x05: { /* Ogg Vorbis [Final Fantasy VI (iOS), Dragon Quest II-VI (iOS)] */
|
||||
vgmstream->codec_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
|
||||
vgmstream->codec_data = init_ffmpeg_offset(sf, start_offset,stream_size);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
@ -145,7 +145,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x06: { /* M4A with AAC [The World Ends with You (iPad)] */
|
||||
/* init_vgmstream_akb_mp4 above has priority, but this works fine too */
|
||||
vgmstream->codec_data = init_ffmpeg_offset(streamFile, start_offset,stream_size-start_offset);
|
||||
vgmstream->codec_data = init_ffmpeg_offset(sf, start_offset,stream_size-start_offset);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
@ -168,7 +168,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* open the file for reading */
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
if ( !vgmstream_open_stream(vgmstream, sf, start_offset) )
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
@ -180,22 +180,22 @@ fail:
|
||||
|
||||
|
||||
/* AKB2 - found in later SQEX iOS games */
|
||||
VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * init_vgmstream_akb2(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, material_offset, extradata_offset;
|
||||
size_t material_size, extradata_size, stream_size;
|
||||
int loop_flag = 0, channel_count, encryption_flag, codec, sample_rate, num_samples, loop_start, loop_end;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
|
||||
/* check extensions */
|
||||
/* .akb.bytes is the usual extension in later games */
|
||||
if ( !check_extensions(streamFile, "akb,bytes") )
|
||||
if ( !check_extensions(sf, "akb,bytes") )
|
||||
goto fail;
|
||||
|
||||
/* checks */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x414B4232) /* "AKB2" */
|
||||
if (read_32bitBE(0x00,sf) != 0x414B4232) /* "AKB2" */
|
||||
goto fail;
|
||||
if (read_32bitLE(0x08,streamFile) != get_streamfile_size(streamFile))
|
||||
if (read_32bitLE(0x08,sf) != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
/* 0x04: version */
|
||||
|
||||
@ -203,37 +203,37 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
{
|
||||
off_t table_offset;
|
||||
size_t table_size, entry_size;
|
||||
off_t akb_header_size = read_16bitLE(0x06, streamFile);
|
||||
int table_count = read_8bit(0x0c, streamFile);
|
||||
off_t akb_header_size = read_16bitLE(0x06, sf);
|
||||
int table_count = read_8bit(0x0c, sf);
|
||||
|
||||
/* probably each table has its type somewhere, but only seen last table = sound table */
|
||||
if (table_count > 2) /* 2 only seen in some Mobius FF sound banks */
|
||||
goto fail;
|
||||
entry_size = 0x10; /* technically every entry/table has its own size but to simplify... */
|
||||
|
||||
table_offset = read_32bitLE(akb_header_size + (table_count-1)*entry_size + 0x04, streamFile);
|
||||
table_size = read_16bitLE(table_offset + 0x02, streamFile);
|
||||
table_offset = read_32bitLE(akb_header_size + (table_count-1)*entry_size + 0x04, sf);
|
||||
table_size = read_16bitLE(table_offset + 0x02, sf);
|
||||
|
||||
total_subsongs = read_8bit(table_offset + 0x0f, streamFile); /* can contain 0 entries too */
|
||||
total_subsongs = read_8bit(table_offset + 0x0f, sf); /* can contain 0 entries too */
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
material_offset = table_offset + read_32bitLE(table_offset + table_size + (target_subsong-1)*entry_size + 0x04, streamFile);
|
||||
material_offset = table_offset + read_32bitLE(table_offset + table_size + (target_subsong-1)*entry_size + 0x04, sf);
|
||||
}
|
||||
|
||||
/** stream header (material) **/
|
||||
/* 0x00: 0? */
|
||||
codec = read_8bit(material_offset+0x01,streamFile);
|
||||
channel_count = read_8bit(material_offset+0x02,streamFile);
|
||||
encryption_flag = read_8bit(material_offset+0x03,streamFile);
|
||||
material_size = read_16bitLE(material_offset+0x04,streamFile);
|
||||
sample_rate = (uint16_t)read_16bitLE(material_offset+0x06,streamFile);
|
||||
stream_size = read_32bitLE(material_offset+0x08,streamFile);
|
||||
num_samples = read_32bitLE(material_offset+0x0c,streamFile);
|
||||
codec = read_8bit(material_offset+0x01,sf);
|
||||
channel_count = read_8bit(material_offset+0x02,sf);
|
||||
encryption_flag = read_8bit(material_offset+0x03,sf);
|
||||
material_size = read_16bitLE(material_offset+0x04,sf);
|
||||
sample_rate = (uint16_t)read_16bitLE(material_offset+0x06,sf);
|
||||
stream_size = read_32bitLE(material_offset+0x08,sf);
|
||||
num_samples = read_32bitLE(material_offset+0x0c,sf);
|
||||
|
||||
loop_start = read_32bitLE(material_offset+0x10,streamFile);
|
||||
loop_end = read_32bitLE(material_offset+0x14,streamFile);
|
||||
extradata_size = read_32bitLE(material_offset+0x18,streamFile);
|
||||
loop_start = read_32bitLE(material_offset+0x10,sf);
|
||||
loop_end = read_32bitLE(material_offset+0x14,sf);
|
||||
extradata_size = read_32bitLE(material_offset+0x18,sf);
|
||||
/* rest: ? (empty or 0x3f80) */
|
||||
|
||||
loop_flag = (loop_end > loop_start);
|
||||
@ -269,14 +269,14 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
case 0x02: { /* MSADPCM [The Irregular at Magic High School Lost Zero (Android)] */
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->frame_size = read_16bitLE(extradata_offset + 0x02, streamFile);
|
||||
vgmstream->frame_size = read_16bitLE(extradata_offset + 0x02, sf);
|
||||
|
||||
/* adjusted samples; bigger or smaller than base samples, akb lib uses these fields instead
|
||||
* (base samples may have more than possible and read over file size otherwise, very strange)
|
||||
* loop_end seems to exist even with loop disabled */
|
||||
vgmstream->num_samples = read_32bitLE(extradata_offset + 0x04, streamFile);
|
||||
vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, streamFile);
|
||||
vgmstream->num_samples = read_32bitLE(extradata_offset + 0x04, sf);
|
||||
vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, sf);
|
||||
vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, sf);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -289,7 +289,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
ovmi.total_subsongs = total_subsongs;
|
||||
ovmi.stream_size = stream_size;
|
||||
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
if (ogg_vgmstream) {
|
||||
ogg_vgmstream->num_streams = vgmstream->num_streams;
|
||||
ogg_vgmstream->stream_size = vgmstream->stream_size;
|
||||
@ -310,7 +310,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
case 0x05: { /* Ogg Vorbis [The World Ends with You (iOS / latest update)] */
|
||||
ffmpeg_codec_data *ffmpeg_data;
|
||||
|
||||
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
|
||||
ffmpeg_data = init_ffmpeg_offset(sf, start_offset,stream_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
@ -319,8 +319,8 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
|
||||
/* When loop_flag num_samples may be much larger than real num_samples (it's fine when looping is off)
|
||||
* Actual num_samples would be loop_end_sample+1, but more testing is needed */
|
||||
vgmstream->num_samples = read_32bitLE(material_offset+0x0c,streamFile);//num_samples;
|
||||
vgmstream->loop_start_sample = read_32bitLE(material_offset+0x10,streamFile);//loop_start;
|
||||
vgmstream->num_samples = read_32bitLE(material_offset+0x0c,sf);//num_samples;
|
||||
vgmstream->loop_start_sample = read_32bitLE(material_offset+0x10,sf);//loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
break;
|
||||
}
|
||||
@ -331,7 +331,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* open the file for reading */
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
if ( !vgmstream_open_stream(vgmstream, sf, start_offset) )
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
@ -27,7 +27,7 @@ VGMSTREAM* init_vgmstream_ao(STREAMFILE *sf) {
|
||||
/* AlphaOgg defines up to 16 loop points for some reason */
|
||||
|
||||
start_offset = 0xc8;
|
||||
vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, start_offset, &ovmi);
|
||||
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
|
@ -1,82 +1,82 @@
|
||||
#ifndef _BAR_STREAMFILE_H_
|
||||
#define _BAR_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
/* a streamfile wrapping another for decryption */
|
||||
|
||||
enum {BAR_KEY_LENGTH = 16};
|
||||
|
||||
// don't know if this is unique, but seems accurate
|
||||
static const uint8_t bar_key[BAR_KEY_LENGTH] = {
|
||||
0xbd,0x14,0x0e,0x0a,0x91,0xeb,0xaa,0xf6,
|
||||
0x11,0x44,0x17,0xc2,0x1c,0xe4,0x66,0x80
|
||||
};
|
||||
|
||||
typedef struct _BARSTREAMFILE {
|
||||
STREAMFILE sf;
|
||||
STREAMFILE *real_file;
|
||||
} BARSTREAMFILE;
|
||||
|
||||
|
||||
/*static*/ STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file);
|
||||
|
||||
|
||||
static size_t read_bar(BARSTREAMFILE *streamFile, uint8_t *dest, off_t offset, size_t length) {
|
||||
off_t i;
|
||||
size_t read_length = streamFile->real_file->read(streamFile->real_file, dest, offset, length);
|
||||
|
||||
for (i = 0; i < read_length; i++) {
|
||||
dest[i] = dest[i] ^ bar_key[(i+offset)%BAR_KEY_LENGTH];
|
||||
}
|
||||
|
||||
return read_length;
|
||||
}
|
||||
|
||||
static size_t get_size_bar(BARSTREAMFILE *streamFile) {
|
||||
return streamFile->real_file->get_size(streamFile->real_file);
|
||||
}
|
||||
|
||||
static size_t get_offset_bar(BARSTREAMFILE *streamFile) {
|
||||
return streamFile->real_file->get_offset(streamFile->real_file);
|
||||
}
|
||||
|
||||
static void get_name_bar(BARSTREAMFILE *streamFile, char *name, size_t length) {
|
||||
streamFile->real_file->get_name(streamFile->real_file, name, length);
|
||||
}
|
||||
|
||||
STREAMFILE *open_bar(BARSTREAMFILE *streamFile, const char * const filename, size_t buffersize) {
|
||||
STREAMFILE *newfile = streamFile->real_file->open(streamFile->real_file,filename,buffersize);
|
||||
if (!newfile)
|
||||
return NULL;
|
||||
|
||||
return wrap_bar_STREAMFILE(newfile);
|
||||
}
|
||||
|
||||
static void close_bar(BARSTREAMFILE *streamFile) {
|
||||
streamFile->real_file->close(streamFile->real_file);
|
||||
free(streamFile);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file) {
|
||||
BARSTREAMFILE *streamfile = malloc(sizeof(BARSTREAMFILE));
|
||||
|
||||
if (!streamfile)
|
||||
return NULL;
|
||||
|
||||
memset(streamfile, 0, sizeof(BARSTREAMFILE));
|
||||
|
||||
streamfile->sf.read = (void*)read_bar;
|
||||
streamfile->sf.get_size = (void*)get_size_bar;
|
||||
streamfile->sf.get_offset = (void*)get_offset_bar;
|
||||
streamfile->sf.get_name = (void*)get_name_bar;
|
||||
streamfile->sf.open = (void*)open_bar;
|
||||
streamfile->sf.close = (void*)close_bar;
|
||||
|
||||
streamfile->real_file = file;
|
||||
|
||||
return &streamfile->sf;
|
||||
}
|
||||
|
||||
#endif /* _BAR_STREAMFILE_H_ */
|
||||
#ifndef _BAR_STREAMFILE_H_
|
||||
#define _BAR_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
/* a streamfile wrapping another for decryption */
|
||||
|
||||
enum {BAR_KEY_LENGTH = 16};
|
||||
|
||||
// don't know if this is unique, but seems accurate
|
||||
static const uint8_t bar_key[BAR_KEY_LENGTH] = {
|
||||
0xbd,0x14,0x0e,0x0a,0x91,0xeb,0xaa,0xf6,
|
||||
0x11,0x44,0x17,0xc2,0x1c,0xe4,0x66,0x80
|
||||
};
|
||||
|
||||
typedef struct _BARSTREAMFILE {
|
||||
STREAMFILE sf;
|
||||
STREAMFILE *real_file;
|
||||
} BARSTREAMFILE;
|
||||
|
||||
|
||||
/*static*/ STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file);
|
||||
|
||||
|
||||
static size_t read_bar(BARSTREAMFILE *streamFile, uint8_t *dest, off_t offset, size_t length) {
|
||||
off_t i;
|
||||
size_t read_length = streamFile->real_file->read(streamFile->real_file, dest, offset, length);
|
||||
|
||||
for (i = 0; i < read_length; i++) {
|
||||
dest[i] = dest[i] ^ bar_key[(i+offset)%BAR_KEY_LENGTH];
|
||||
}
|
||||
|
||||
return read_length;
|
||||
}
|
||||
|
||||
static size_t get_size_bar(BARSTREAMFILE *streamFile) {
|
||||
return streamFile->real_file->get_size(streamFile->real_file);
|
||||
}
|
||||
|
||||
static size_t get_offset_bar(BARSTREAMFILE *streamFile) {
|
||||
return streamFile->real_file->get_offset(streamFile->real_file);
|
||||
}
|
||||
|
||||
static void get_name_bar(BARSTREAMFILE *streamFile, char *name, size_t length) {
|
||||
streamFile->real_file->get_name(streamFile->real_file, name, length);
|
||||
}
|
||||
|
||||
static STREAMFILE *open_bar(BARSTREAMFILE *streamFile, const char * const filename, size_t buffersize) {
|
||||
STREAMFILE *newfile = streamFile->real_file->open(streamFile->real_file,filename,buffersize);
|
||||
if (!newfile)
|
||||
return NULL;
|
||||
|
||||
return wrap_bar_STREAMFILE(newfile);
|
||||
}
|
||||
|
||||
static void close_bar(BARSTREAMFILE *streamFile) {
|
||||
streamFile->real_file->close(streamFile->real_file);
|
||||
free(streamFile);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file) {
|
||||
BARSTREAMFILE *streamfile = malloc(sizeof(BARSTREAMFILE));
|
||||
|
||||
if (!streamfile)
|
||||
return NULL;
|
||||
|
||||
memset(streamfile, 0, sizeof(BARSTREAMFILE));
|
||||
|
||||
streamfile->sf.read = (void*)read_bar;
|
||||
streamfile->sf.get_size = (void*)get_size_bar;
|
||||
streamfile->sf.get_offset = (void*)get_offset_bar;
|
||||
streamfile->sf.get_name = (void*)get_name_bar;
|
||||
streamfile->sf.open = (void*)open_bar;
|
||||
streamfile->sf.close = (void*)close_bar;
|
||||
|
||||
streamfile->real_file = file;
|
||||
|
||||
return &streamfile->sf;
|
||||
}
|
||||
|
||||
#endif /* _BAR_STREAMFILE_H_ */
|
||||
|
@ -2,11 +2,11 @@
|
||||
#include "../layout/layout.h"
|
||||
|
||||
#define TXT_LINE_MAX 0x1000
|
||||
static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end);
|
||||
static int get_falcom_looping(STREAMFILE* sf, int* p_loop_start, int* p_loop_end);
|
||||
|
||||
/* .DEC/DE2 - from Falcom PC games (Xanadu Next, Zwei!!, VM Japan, Gurumin) */
|
||||
VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
VGMSTREAM* init_vgmstream_dec(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
off_t riff_off = 0x00;
|
||||
size_t pcm_size = 0;
|
||||
@ -16,42 +16,42 @@ VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile) {
|
||||
/* checks
|
||||
* .dec: main,
|
||||
* .de2: Gurumin (PC) */
|
||||
if ( !check_extensions(streamFile,"dec,de2") )
|
||||
if (!check_extensions(sf,"dec,de2"))
|
||||
goto fail;
|
||||
|
||||
/* Gurumin has extra data, maybe related to rhythm (~0x50000) */
|
||||
if (check_extensions(streamFile,"de2")) {
|
||||
if (check_extensions(sf,"de2")) {
|
||||
/* still not sure what this is for, but consistently 0xb */
|
||||
if (read_32bitLE(0x04,streamFile) != 0x0b) goto fail;
|
||||
if (read_32bitLE(0x04,sf) != 0x0b) goto fail;
|
||||
|
||||
/* legitimate! really! */
|
||||
riff_off = 0x10 + (read_32bitLE(0x0c,streamFile) ^ read_32bitLE(0x04,streamFile));
|
||||
riff_off = 0x10 + (read_32bitLE(0x0c,sf) ^ read_32bitLE(0x04,sf));
|
||||
}
|
||||
|
||||
|
||||
/* fake PCM RIFF header (the original WAV's) wrapping MS-ADPCM */
|
||||
if (read_32bitBE(riff_off+0x00,streamFile) != 0x52494646 || /* "RIFF" */
|
||||
read_32bitBE(riff_off+0x08,streamFile) != 0x57415645) /* "WAVE" */
|
||||
if (!is_id32be(riff_off+0x00,sf, "RIFF") ||
|
||||
!is_id32be(riff_off+0x08,sf, "WAVE"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(riff_off+0x0c,streamFile) == 0x50414420) { /* "PAD " (Zwei!!), blank with wrong chunk size */
|
||||
if (is_id32be(riff_off+0x0c,sf, "PAD ")) { /* blank with wrong chunk size [Zwei!! ())PC)]*/
|
||||
sample_rate = 44100;
|
||||
channel_count = 2;
|
||||
pcm_size = read_32bitLE(riff_off+0x04,streamFile) - 0x24;
|
||||
pcm_size = read_32bitLE(riff_off+0x04,sf) - 0x24;
|
||||
/* somehow there is garbage at the beginning of some tracks */
|
||||
}
|
||||
else if (read_32bitBE(riff_off+0x0c,streamFile) == 0x666D7420) { /* "fmt " (rest) */
|
||||
//if (read_32bitLE(riff_off+0x10,streamFile) != 0x12) goto fail; /* 0x10 in some */
|
||||
if (read_16bitLE(riff_off+0x14,streamFile) != 0x01) goto fail; /* PCM (actually MS-ADPCM) */
|
||||
if (read_16bitLE(riff_off+0x20,streamFile) != 4 ||
|
||||
read_16bitLE(riff_off+0x22,streamFile) != 16) goto fail; /* 16-bit */
|
||||
else if (is_id32be(riff_off+0x0c,sf, "fmt ")) {
|
||||
//if (read_32bitLE(riff_off+0x10,sf) != 0x12) goto fail; /* 0x10 in some */
|
||||
if (read_16bitLE(riff_off+0x14,sf) != 0x01) goto fail; /* PCM (actually MS-ADPCM) */
|
||||
if (read_16bitLE(riff_off+0x20,sf) != 4 ||
|
||||
read_16bitLE(riff_off+0x22,sf) != 16) goto fail; /* 16-bit */
|
||||
|
||||
channel_count = read_16bitLE(riff_off+0x16,streamFile);
|
||||
sample_rate = read_32bitLE(riff_off+0x18,streamFile);
|
||||
if (read_32bitBE(riff_off+0x24,streamFile) == 0x64617461) { /* "data" size except in some Zwei!! */
|
||||
pcm_size = read_32bitLE(riff_off+0x28,streamFile);
|
||||
channel_count = read_16bitLE(riff_off+0x16,sf);
|
||||
sample_rate = read_32bitLE(riff_off+0x18,sf);
|
||||
if (read_32bitBE(riff_off+0x24,sf) == 0x64617461) { /* "data" size except in some Zwei!! */
|
||||
pcm_size = read_32bitLE(riff_off+0x28,sf);
|
||||
} else {
|
||||
pcm_size = read_32bitLE(riff_off+0x04,streamFile) - 0x24;
|
||||
pcm_size = read_32bitLE(riff_off+0x04,sf) - 0x24;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -62,7 +62,7 @@ VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
|
||||
start_offset = riff_off + 0x2c;
|
||||
loop_flag = get_falcom_looping(streamFile, &loop_start, &loop_end);
|
||||
loop_flag = get_falcom_looping(sf, &loop_start, &loop_end);
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
@ -79,7 +79,7 @@ VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile) {
|
||||
vgmstream->frame_size = 0x800;
|
||||
vgmstream->layout_type = layout_blocked_dec;
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
@ -91,7 +91,7 @@ fail:
|
||||
|
||||
/* Falcom loves loop points in external text files, here we parse them */
|
||||
typedef enum { XANADU_NEXT, ZWEI, DINOSAUR_RESURRECTION, GURUMIN } falcom_loop_t;
|
||||
static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end) {
|
||||
static int get_falcom_looping(STREAMFILE *sf, int *out_loop_start, int *out_loop_end) {
|
||||
STREAMFILE *streamText;
|
||||
off_t txt_offset = 0x00;
|
||||
falcom_loop_t type;
|
||||
@ -100,23 +100,23 @@ static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int *
|
||||
|
||||
|
||||
/* try one of the many loop files */
|
||||
if ((streamText = open_streamfile_by_filename(streamFile,"bgm.tbl")) != NULL) {
|
||||
if ((streamText = open_streamfile_by_filename(sf,"bgm.tbl")) != NULL) {
|
||||
type = XANADU_NEXT;
|
||||
}
|
||||
else if ((streamText = open_streamfile_by_filename(streamFile,"bgm.scr")) != NULL) {
|
||||
else if ((streamText = open_streamfile_by_filename(sf,"bgm.scr")) != NULL) {
|
||||
type = ZWEI;
|
||||
}
|
||||
else if ((streamText = open_streamfile_by_filename(streamFile,"loop.txt")) != NULL) { /* actual name in Shift JIS, 0x838B815B8376 */
|
||||
else if ((streamText = open_streamfile_by_filename(sf,"loop.txt")) != NULL) { /* actual name in Shift JIS, 0x838B815B8376 */
|
||||
type = DINOSAUR_RESURRECTION;
|
||||
}
|
||||
else if ((streamText = open_streamfile_by_filename(streamFile,"map.itm")) != NULL) {
|
||||
else if ((streamText = open_streamfile_by_filename(sf,"map.itm")) != NULL) {
|
||||
type = GURUMIN;
|
||||
}
|
||||
else {
|
||||
goto end;
|
||||
}
|
||||
|
||||
get_streamfile_filename(streamFile,filename,TXT_LINE_MAX);
|
||||
get_streamfile_filename(sf,filename,TXT_LINE_MAX);
|
||||
|
||||
/* read line by line */
|
||||
while (txt_offset < get_streamfile_size(streamText)) {
|
||||
@ -166,6 +166,9 @@ static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int *
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -508,7 +508,7 @@ fail:
|
||||
}
|
||||
|
||||
/* open map/mpf+mus pairs that aren't exact pairs, since EA's games can load any combo */
|
||||
static STREAMFILE *open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks) {
|
||||
static STREAMFILE *open_mapfile_pair(STREAMFILE* sf, int track /*, int num_tracks*/) {
|
||||
static const char *const mapfile_pairs[][2] = {
|
||||
/* standard cases, replace map part with mus part (from the end to preserve prefixes) */
|
||||
{"game.mpf", "Game_Stream.mus"}, /* Skate 1/2/3 */
|
||||
@ -685,7 +685,7 @@ VGMSTREAM* init_vgmstream_ea_mpf_mus_eaac(STREAMFILE* sf) {
|
||||
}
|
||||
|
||||
/* open MUS file that matches this track */
|
||||
musFile = open_mapfile_pair(sf, i, num_tracks);
|
||||
musFile = open_mapfile_pair(sf, i);//, num_tracks
|
||||
if (!musFile)
|
||||
goto fail;
|
||||
|
||||
@ -1136,6 +1136,8 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||
eaac.loop_offset = read_32bitBE(header_offset + 0x10, sf_head);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* get data offsets */
|
||||
@ -1151,6 +1153,8 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||
eaac.prefetch_offset = header_offset + header_size;
|
||||
eaac.stream_offset = start_offset;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
eaac.stream_offset = header_offset - 0x04 + header_block_size;
|
||||
@ -1340,7 +1344,7 @@ static VGMSTREAM* init_vgmstream_eaaudiocore_header(STREAMFILE* sf_head, STREAMF
|
||||
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
case EAAC_CODEC_EAMP3: { /* "EM30": EA-MP3 [Need for Speed 2015 (PS4)] */
|
||||
case EAAC_CODEC_EAMP3: { /* "EM30": EA-MP3 [Need for Speed 2015 (PS4), FIFA 2021 (PC)] */
|
||||
mpeg_custom_config cfg = {0};
|
||||
|
||||
temp_sf = setup_eaac_audio_streamfile(sf, eaac.version, eaac.codec, eaac.streamed,0,0, 0x00);
|
||||
@ -1551,6 +1555,8 @@ static STREAMFILE *setup_eaac_streamfile(eaac_header *ea, STREAMFILE* sf_head, S
|
||||
sf_segments[0] = NULL;
|
||||
sf_segments[1] = NULL;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
data_size = calculate_eaac_size(sf_head, ea, ea->num_samples, ea->stream_offset, 0);
|
||||
@ -1603,29 +1609,29 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *sf
|
||||
|
||||
switch(eaac->codec) {
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case EAAC_CODEC_EAXMA: {
|
||||
eaac_header temp_eaac = *eaac; /* equivalent to memcpy... I think */
|
||||
temp_eaac.loop_flag = 0;
|
||||
temp_eaac.num_samples = num_samples[i];
|
||||
case EAAC_CODEC_EAXMA: {
|
||||
eaac_header temp_eaac = *eaac; /* equivalent to memcpy... I think */
|
||||
temp_eaac.loop_flag = 0;
|
||||
temp_eaac.num_samples = num_samples[i];
|
||||
|
||||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||
|
||||
/* layers inside segments, how trippy */
|
||||
data->segments[i]->layout_data = build_layered_eaaudiocore(sf_data, &temp_eaac, offsets[i]);
|
||||
if (!data->segments[i]->layout_data) goto fail;
|
||||
data->segments[i]->coding_type = coding_FFmpeg;
|
||||
data->segments[i]->layout_type = layout_layered;
|
||||
break;
|
||||
}
|
||||
/* layers inside segments, how trippy */
|
||||
data->segments[i]->layout_data = build_layered_eaaudiocore(sf_data, &temp_eaac, offsets[i]);
|
||||
if (!data->segments[i]->layout_data) goto fail;
|
||||
data->segments[i]->coding_type = coding_FFmpeg;
|
||||
data->segments[i]->layout_type = layout_layered;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case EAAC_CODEC_XAS1: {
|
||||
start_offset = offsets[i];
|
||||
case EAAC_CODEC_XAS1: {
|
||||
start_offset = offsets[i];
|
||||
|
||||
data->segments[i]->coding_type = coding_EA_XAS_V1;
|
||||
data->segments[i]->layout_type = layout_blocked_ea_sns;
|
||||
break;
|
||||
}
|
||||
data->segments[i]->coding_type = coding_EA_XAS_V1;
|
||||
data->segments[i]->layout_type = layout_blocked_ea_sns;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
case EAAC_CODEC_EALAYER3_V1:
|
||||
@ -1689,8 +1695,8 @@ static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_
|
||||
data->layers[i]->loop_start_sample = eaac->loop_start;
|
||||
data->layers[i]->loop_end_sample = eaac->loop_end;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
switch(eaac->codec) {
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
/* 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) */
|
||||
case EAAC_CODEC_EAXMA: {
|
||||
@ -1743,11 +1749,10 @@ static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_
|
||||
data->layers[i]->layout_type = layout_none;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(data->layers[i], temp_sf, 0x00)) {
|
||||
goto fail;
|
||||
|
@ -637,7 +637,7 @@ fail:
|
||||
|
||||
|
||||
/* open map/mpf+mus pairs that aren't exact pairs, since EA's games can load any combo */
|
||||
static STREAMFILE* open_mapfile_pair(STREAMFILE* sf, int track, int num_tracks) {
|
||||
static STREAMFILE* open_mapfile_pair(STREAMFILE* sf, int track /*, int num_tracks*/) {
|
||||
static const char *const mapfile_pairs[][2] = {
|
||||
/* standard cases, replace map part with mus part (from the end to preserve prefixes) */
|
||||
{"MUS_CTRL.MPF", "MUS_STR.MUS"}, /* GoldenEye - Rogue Agent (PS2) */
|
||||
@ -760,7 +760,7 @@ VGMSTREAM* init_vgmstream_ea_map_mus(STREAMFILE* sf) {
|
||||
version = read_8bit(0x04, sf);
|
||||
if (version > 1) goto fail;
|
||||
|
||||
sf_mus = open_mapfile_pair(sf, 0, 1);
|
||||
sf_mus = open_mapfile_pair(sf, 0); //, 1
|
||||
if (!sf_mus) goto fail;
|
||||
|
||||
/*
|
||||
@ -994,7 +994,7 @@ VGMSTREAM* init_vgmstream_ea_mpf_mus(STREAMFILE* sf) {
|
||||
goto fail;
|
||||
|
||||
/* open MUS file that matches this track */
|
||||
sf_mus = open_mapfile_pair(sf, i, num_tracks);
|
||||
sf_mus = open_mapfile_pair(sf, i); //, num_tracks
|
||||
if (!sf_mus)
|
||||
goto fail;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef _FSB_ENCRYPTED_STREAMFILE_H_
|
||||
#define _FSB_ENCRYPTED_H_
|
||||
#define _FSB_ENCRYPTED_STREAMFILE_H_
|
||||
|
||||
#define FSB_KEY_MAX 0x10000 //0x168
|
||||
|
||||
@ -71,4 +71,4 @@ static STREAMFILE* setup_fsb_streamfile(STREAMFILE* sf, const uint8_t* key, size
|
||||
return new_sf;
|
||||
}
|
||||
|
||||
#endif /* _FSB5_STREAMFILE_H_ */
|
||||
#endif /* _FSB_ENCRYPTED_STREAMFILE_H_ */
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "hca_keys.h"
|
||||
#include "../coding/coding.h"
|
||||
#include <clHCA.h>
|
||||
|
||||
//#define HCA_BRUTEFORCE
|
||||
#ifdef HCA_BRUTEFORCE
|
||||
@ -15,7 +16,7 @@ VGMSTREAM* init_vgmstream_hca(STREAMFILE* sf) {
|
||||
}
|
||||
|
||||
VGMSTREAM* init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
hca_codec_data* hca_data = NULL;
|
||||
clHCA_stInfo* hca_info;
|
||||
|
||||
@ -152,26 +153,32 @@ static inline void test_key(hca_codec_data* hca_data, uint64_t key, uint16_t sub
|
||||
static void find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t subkey) {
|
||||
const size_t keys_length = sizeof(hcakey_list) / sizeof(hcakey_info);
|
||||
int best_score = -1;
|
||||
int i,j;
|
||||
int i;
|
||||
|
||||
*p_keycode = 0xCC55463930DBE1AB; /* defaults to PSO2 key, most common */
|
||||
|
||||
for (i = 0; i < keys_length; i++) {
|
||||
uint64_t key = hcakey_list[i].key;
|
||||
size_t subkeys_size = hcakey_list[i].subkeys_size;
|
||||
const uint16_t *subkeys = hcakey_list[i].subkeys;
|
||||
|
||||
test_key(hca_data, key, subkey, &best_score, p_keycode);
|
||||
if (best_score == 1)
|
||||
goto done;
|
||||
|
||||
if (subkeys_size > 0 && subkey == 0) {
|
||||
for (j = 0; j < subkeys_size; j++) {
|
||||
test_key(hca_data, key, subkeys[j], &best_score, p_keycode);
|
||||
if (best_score == 1)
|
||||
goto done;
|
||||
#if 0
|
||||
{
|
||||
int j;
|
||||
|
||||
size_t subkeys_size = hcakey_list[i].subkeys_size;
|
||||
const uint16_t *subkeys = hcakey_list[i].subkeys;
|
||||
if (subkeys_size > 0 && subkey == 0) {
|
||||
for (j = 0; j < subkeys_size; j++) {
|
||||
test_key(hca_data, key, subkeys[j], &best_score, p_keycode);
|
||||
if (best_score == 1)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
done:
|
||||
|
@ -5,8 +5,10 @@
|
||||
|
||||
typedef struct {
|
||||
uint64_t key; /* hca key or seed ('user') key */
|
||||
const uint16_t *subkeys; /* scramble subkey table for seed key */
|
||||
#if 0
|
||||
const uint16_t* subkeys; /* scramble subkey table for seed key */
|
||||
size_t subkeys_size; /* size of the derivation subkey table */
|
||||
#endif
|
||||
} hcakey_info;
|
||||
|
||||
|
||||
@ -410,6 +412,9 @@ static const hcakey_info hcakey_list[] = {
|
||||
/* Dragon Quest Tact (Android) */
|
||||
{3234477171400153310}, // 2CE32BD9B36A98DE
|
||||
|
||||
/* Alchemy Stars (Android) */
|
||||
{1564789515523}, // 0000016C54B92503
|
||||
|
||||
/* D4DJ Groovy Mix (Android) [base files] */
|
||||
{393410674916959300}, // 0575ACECA945A444
|
||||
/* D4DJ Groovy Mix (Android) [music_* files, per-song later mixed with subkey] */
|
||||
|
@ -3,49 +3,49 @@
|
||||
|
||||
|
||||
/* HIS - Her Interactive games [Nancy Drew series (PC)] */
|
||||
VGMSTREAM * init_vgmstream_his(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * init_vgmstream_his(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
int channel_count, loop_flag = 0, bps, sample_rate, num_samples, version;
|
||||
off_t start_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "his"))
|
||||
if (!check_extensions(sf, "his"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) == 0x48657220) { /* "Her Interactive Sound\x1a" */
|
||||
if (read_32bitBE(0x00,sf) == 0x48657220) { /* "Her Interactive Sound\x1a" */
|
||||
/* Nancy Drew: Secrets Can Kill (PC) */
|
||||
version = 0;
|
||||
channel_count = read_16bitLE(0x16,streamFile);
|
||||
sample_rate = read_32bitLE(0x18,streamFile);
|
||||
channel_count = read_16bitLE(0x16,sf);
|
||||
sample_rate = read_32bitLE(0x18,sf);
|
||||
/* 0x1c: bitrate */
|
||||
/* 0x20: block size */
|
||||
bps = read_16bitLE(0x22,streamFile);
|
||||
bps = read_16bitLE(0x22,sf);
|
||||
|
||||
if (read_32bitBE(0x24,streamFile) != 0x64617461) /* "data" */
|
||||
if (read_32bitBE(0x24,sf) != 0x64617461) /* "data" */
|
||||
goto fail;
|
||||
num_samples = pcm_bytes_to_samples(read_32bitLE(0x28,streamFile), channel_count, bps);
|
||||
num_samples = pcm_bytes_to_samples(read_32bitLE(0x28,sf), channel_count, bps);
|
||||
|
||||
start_offset = 0x2c;
|
||||
}
|
||||
else if (read_32bitBE(0x00,streamFile) == 0x48495300) { /* HIS\0 */
|
||||
else if (read_32bitBE(0x00,sf) == 0x48495300) { /* HIS\0 */
|
||||
/* most(?) others */
|
||||
version = read_32bitLE(0x04,streamFile);
|
||||
version = read_32bitLE(0x04,sf);
|
||||
/* 0x08: codec */
|
||||
channel_count = read_16bitLE(0x0a,streamFile);
|
||||
sample_rate = read_32bitLE(0x0c,streamFile);
|
||||
channel_count = read_16bitLE(0x0a,sf);
|
||||
sample_rate = read_32bitLE(0x0c,sf);
|
||||
/* 0x10: bitrate */
|
||||
/* 0x14: block size */
|
||||
bps = read_16bitLE(0x16,streamFile);
|
||||
bps = read_16bitLE(0x16,sf);
|
||||
|
||||
num_samples = pcm_bytes_to_samples(read_32bitLE(0x18,streamFile), channel_count, bps); /* true even for Ogg */
|
||||
num_samples = pcm_bytes_to_samples(read_32bitLE(0x18,sf), channel_count, bps); /* true even for Ogg */
|
||||
|
||||
/* later games use "OggS" */
|
||||
if (version == 1)
|
||||
start_offset = 0x1c; /* Nancy Drew: The Final Scene (PC) */
|
||||
else if (version == 2 && read_32bitBE(0x1e,streamFile) == 0x4F676753)
|
||||
else if (version == 2 && read_32bitBE(0x1e,sf) == 0x4F676753)
|
||||
start_offset = 0x1e; /* Nancy Drew: The Haunted Carousel (PC) */
|
||||
else if (version == 2 && read_32bitBE(0x20,streamFile) == 0x4F676753)
|
||||
else if (version == 2 && read_32bitBE(0x20,sf) == 0x4F676753)
|
||||
start_offset = 0x20; /* Nancy Drew: The Silent Spy (PC) */
|
||||
else
|
||||
goto fail;
|
||||
@ -60,7 +60,7 @@ VGMSTREAM * init_vgmstream_his(STREAMFILE *streamFile) {
|
||||
ogg_vorbis_meta_info_t ovmi = {0};
|
||||
|
||||
ovmi.meta_type = meta_HIS;
|
||||
return init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
|
||||
return init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
@ -89,7 +89,7 @@ VGMSTREAM * init_vgmstream_his(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
|
@ -80,7 +80,7 @@ VGMSTREAM* init_vgmstream_ikm_pc(STREAMFILE* sf) {
|
||||
ovmi.loop_flag = ovmi.loop_end > 0;
|
||||
ovmi.stream_size = read_s32le(0x24, sf);
|
||||
|
||||
vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, start_offset, &ovmi);
|
||||
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
|
@ -137,9 +137,11 @@ typedef struct {
|
||||
off_t scd_xor_length;
|
||||
uint32_t xor_value;
|
||||
|
||||
//ov_callbacks *callbacks
|
||||
|
||||
} ogg_vorbis_meta_info_t;
|
||||
|
||||
VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callbacks *callbacks, off_t start, const ogg_vorbis_meta_info_t *ovmi);
|
||||
VGMSTREAM* init_vgmstream_ogg_vorbis_config(STREAMFILE *sf, off_t start, const ogg_vorbis_meta_info_t* ovmi);
|
||||
#endif
|
||||
|
||||
VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile);
|
||||
|
@ -10,12 +10,12 @@
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* MOGG - Harmonix Music Systems (Guitar Hero)[Unencrypted Type] */
|
||||
VGMSTREAM * init_vgmstream_mogg(STREAMFILE *streamFile) {
|
||||
VGMSTREAM* init_vgmstream_mogg(STREAMFILE *sf) {
|
||||
#ifdef VGM_USE_VORBIS
|
||||
off_t start_offset;
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "mogg"))
|
||||
if (!check_extensions(sf, "mogg"))
|
||||
goto fail;
|
||||
|
||||
{
|
||||
@ -24,8 +24,8 @@ VGMSTREAM * init_vgmstream_mogg(STREAMFILE *streamFile) {
|
||||
|
||||
ovmi.meta_type = meta_MOGG;
|
||||
|
||||
start_offset = read_32bitLE(0x04, streamFile);
|
||||
result = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
|
||||
start_offset = read_32bitLE(0x04, sf);
|
||||
result = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
|
||||
if (result != NULL) {
|
||||
return result;
|
||||
|
@ -108,7 +108,7 @@ VGMSTREAM* init_vgmstream_msf(STREAMFILE* sf) {
|
||||
encoder_delay = 1024 + 69*2;
|
||||
block_align = (codec==4 ? 0x60 : (codec==5 ? 0x98 : 0xC0)) * vgmstream->channels;
|
||||
vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_align) - encoder_delay;
|
||||
if (vgmstream->sample_rate == 0xFFFFFFFF) /* some MSFv1 (Digi World SP) */
|
||||
if (vgmstream->sample_rate == -1) /* some MSFv1 (Digi World SP) */
|
||||
vgmstream->sample_rate = 44100; /* voice tracks seems to use 44khz, not sure about other tracks */
|
||||
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_raw(sf, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
|
@ -1,79 +1,79 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .MUS - Vicious Cycle games [Dinotopia: The Sunstone Odyssey (GC/Xbox), Robotech: Battlecry (PS2/Xbox)] */
|
||||
VGMSTREAM * init_vgmstream_mus_vc(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count, sample_rate;
|
||||
int big_endian, type;
|
||||
int32_t(*read_32bit)(off_t, STREAMFILE*) = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "mus"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x08,streamFile) != 0xBBBBBBBB &&
|
||||
read_32bitBE(0x14,streamFile) != 0xBBBBBBBB &&
|
||||
read_32bitBE(0x2c,streamFile) != 0xBEBEBEBE)
|
||||
goto fail;
|
||||
|
||||
big_endian = (read_32bitBE(0x00,streamFile) == 0xFBBFFBBF);
|
||||
read_32bit = big_endian ? read_32bitBE : read_32bitLE;
|
||||
|
||||
type = read_32bit(0x04, streamFile);
|
||||
/* 0x08: pseudo size? */
|
||||
/* other fields may be chunk sizes and lesser stuff */
|
||||
/* 0x88: codec header */
|
||||
|
||||
channel_count = read_32bit(0x54,streamFile); /* assumed */
|
||||
if (channel_count != 1) goto fail;
|
||||
sample_rate = read_32bit(0x58,streamFile);
|
||||
loop_flag = 1; /* most files repeat except small jingles, but smaller ambient tracks also repeat */
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_MUS_VC;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
switch(type) {
|
||||
case 0x01:
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(read_32bit(0xB0,streamFile), vgmstream->channels);
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
start_offset = 0xB8;
|
||||
dsp_read_coefs_be(vgmstream,streamFile,0x88,0x00);
|
||||
dsp_read_hist_be (vgmstream,streamFile,0xac,0x00);
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
vgmstream->coding_type = coding_XBOX_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bit(0x9a,streamFile), vgmstream->channels);
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
start_offset = 0x9e;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
read_string(vgmstream->stream_name,0x14, 0x34,streamFile); /* repeated at 0x64, size at 0x30/0x60 */
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .MUS - Vicious Cycle games [Dinotopia: The Sunstone Odyssey (GC/Xbox), Robotech: Battlecry (PS2/Xbox)] */
|
||||
VGMSTREAM* init_vgmstream_mus_vc(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channels, sample_rate;
|
||||
int big_endian, type;
|
||||
int32_t(*read_32bit)(off_t, STREAMFILE*) = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "mus"))
|
||||
goto fail;
|
||||
|
||||
if (read_u32be(0x08,sf) != 0xBBBBBBBB &&
|
||||
read_u32be(0x14,sf) != 0xBBBBBBBB &&
|
||||
read_u32be(0x2c,sf) != 0xBEBEBEBE)
|
||||
goto fail;
|
||||
|
||||
big_endian = (read_u32be(0x00,sf) == 0xFBBFFBBF);
|
||||
read_32bit = big_endian ? read_32bitBE : read_32bitLE;
|
||||
|
||||
type = read_32bit(0x04, sf);
|
||||
/* 0x08: pseudo size? */
|
||||
/* other fields may be chunk sizes and lesser stuff */
|
||||
/* 0x88: codec header */
|
||||
|
||||
channels = read_32bit(0x54,sf); /* assumed */
|
||||
if (channels != 1) goto fail;
|
||||
sample_rate = read_32bit(0x58,sf);
|
||||
loop_flag = 1; /* most files repeat except small jingles, but smaller ambient tracks also repeat */
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_MUS_VC;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
switch(type) {
|
||||
case 0x01:
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(read_32bit(0xB0,sf), vgmstream->channels);
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
start_offset = 0xB8;
|
||||
dsp_read_coefs_be(vgmstream,sf,0x88,0x00);
|
||||
dsp_read_hist_be (vgmstream,sf,0xac,0x00);
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
vgmstream->coding_type = coding_XBOX_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bit(0x9a,sf), vgmstream->channels);
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
start_offset = 0x9e;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
read_string(vgmstream->stream_name,0x14, 0x34,sf); /* repeated at 0x64, size at 0x30/0x60 */
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1,46 +1,46 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .str - Cauldron/Conan mini-header + interleaved dsp data [Conan (GC)] */
|
||||
VGMSTREAM * init_vgmstream_ngc_str(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int channel_count, loop_flag;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "str"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0xFAAF0001) /* header id */
|
||||
goto fail;
|
||||
|
||||
channel_count = 2; /* always loop & stereo */
|
||||
loop_flag = 1;
|
||||
start_offset = 0x60;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitBE(0x04,streamFile);
|
||||
vgmstream->num_samples = read_32bitBE(0x08,streamFile);
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->meta_type = meta_DSP_STR;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitBE(0x0C,streamFile);
|
||||
|
||||
dsp_read_coefs_be(vgmstream, streamFile, 0x10, 0x20);
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .str - Cauldron/Conan mini-header + interleaved dsp data [Conan (GC)] */
|
||||
VGMSTREAM* init_vgmstream_ngc_str(STREAMFILE *sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int channels, loop_flag;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "str"))
|
||||
goto fail;
|
||||
if (read_u32be(0x00,sf) != 0xFAAF0001) /* header id */
|
||||
goto fail;
|
||||
|
||||
channels = 2; /* always loop & stereo */
|
||||
loop_flag = 1;
|
||||
start_offset = 0x60;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_s32be(0x04,sf);
|
||||
vgmstream->num_samples = read_s32be(0x08,sf);
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->meta_type = meta_DSP_STR;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_u32be(0x0C,sf);
|
||||
|
||||
dsp_read_coefs_be(vgmstream, sf, 0x10, 0x20);
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ static STREAMFILE* setup_nus3bank_streamfile(STREAMFILE *sf, off_t start) {
|
||||
|
||||
/* find "data" */
|
||||
pos = 0x0c;
|
||||
data_pos = 0;
|
||||
while(pos < sizeof(buf)) {
|
||||
chunk_type = get_u32be(buf + pos + 0x00) ^ chunk_key;
|
||||
chunk_size = get_u32be(buf + pos + 0x04) ^ chunk_key;
|
||||
|
114
src/meta/nwav.c
114
src/meta/nwav.c
@ -1,57 +1,57 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* NWAV - from Chunsoft games [Fuurai no Shiren Gaiden: Onnakenshi Asuka Kenzan! (PC)] */
|
||||
VGMSTREAM * init_vgmstream_nwav(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .nwav: header id (no filenames in bigfiles) */
|
||||
if ( !check_extensions(streamFile,"nwav") )
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x4E574156) /* "NWAV" */
|
||||
goto fail;
|
||||
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
{
|
||||
ogg_vorbis_meta_info_t ovmi = {0};
|
||||
int channels;
|
||||
|
||||
/* 0x04: version? */
|
||||
/* 0x08: crc? */
|
||||
ovmi.stream_size = read_32bitLE(0x0c, streamFile);
|
||||
ovmi.loop_end = read_32bitLE(0x10, streamFile); /* num_samples, actually */
|
||||
/* 0x14: sample rate */
|
||||
/* 0x18: bps? (16) */
|
||||
channels = read_8bit(0x19, streamFile);
|
||||
start_offset = read_16bitLE(0x1a, streamFile);
|
||||
|
||||
ovmi.loop_flag = read_16bitLE(0x1c, streamFile) != 0; /* loop count? -1 = loops */
|
||||
/* 0x1e: always 2? */
|
||||
/* 0x20: always 1? */
|
||||
ovmi.loop_start = read_32bitLE(0x24, streamFile);
|
||||
/* 0x28: always 1? */
|
||||
/* 0x2a: always 1? */
|
||||
/* 0x2c: always null? */
|
||||
|
||||
ovmi.meta_type = meta_NWAV;
|
||||
|
||||
/* values are in resulting bytes */
|
||||
ovmi.loop_start = ovmi.loop_start / sizeof(int16_t) / channels;
|
||||
ovmi.loop_end = ovmi.loop_end / sizeof(int16_t) / channels;
|
||||
|
||||
vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* NWAV - from Chunsoft games [Fuurai no Shiren Gaiden: Onnakenshi Asuka Kenzan! (PC)] */
|
||||
VGMSTREAM * init_vgmstream_nwav(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .nwav: header id (no filenames in bigfiles) */
|
||||
if ( !check_extensions(sf,"nwav") )
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,sf) != 0x4E574156) /* "NWAV" */
|
||||
goto fail;
|
||||
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
{
|
||||
ogg_vorbis_meta_info_t ovmi = {0};
|
||||
int channels;
|
||||
|
||||
/* 0x04: version? */
|
||||
/* 0x08: crc? */
|
||||
ovmi.stream_size = read_32bitLE(0x0c, sf);
|
||||
ovmi.loop_end = read_32bitLE(0x10, sf); /* num_samples, actually */
|
||||
/* 0x14: sample rate */
|
||||
/* 0x18: bps? (16) */
|
||||
channels = read_8bit(0x19, sf);
|
||||
start_offset = read_16bitLE(0x1a, sf);
|
||||
|
||||
ovmi.loop_flag = read_16bitLE(0x1c, sf) != 0; /* loop count? -1 = loops */
|
||||
/* 0x1e: always 2? */
|
||||
/* 0x20: always 1? */
|
||||
ovmi.loop_start = read_32bitLE(0x24, sf);
|
||||
/* 0x28: always 1? */
|
||||
/* 0x2a: always 1? */
|
||||
/* 0x2c: always null? */
|
||||
|
||||
ovmi.meta_type = meta_NWAV;
|
||||
|
||||
/* values are in resulting bytes */
|
||||
ovmi.loop_start = ovmi.loop_start / sizeof(int16_t) / channels;
|
||||
ovmi.loop_end = ovmi.loop_end / sizeof(int16_t) / channels;
|
||||
|
||||
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -286,21 +286,21 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||
* 0x0c(2): PCM block size, 0x0e(2): PCM bps, 0x10: null, 0x18: samples (in PCM bytes)
|
||||
* - .isl: looping table (encrypted like the files) */
|
||||
if (isl_name) {
|
||||
STREAMFILE* islFile = NULL;
|
||||
STREAMFILE* sf_isl = NULL;
|
||||
|
||||
islFile = open_streamfile_by_filename(sf, isl_name);
|
||||
sf_isl = open_streamfile_by_filename(sf, isl_name);
|
||||
|
||||
if (!islFile) {
|
||||
if (!sf_isl) {
|
||||
/* try in ../(file) too since that's how the .isl is stored on disc */
|
||||
char isl_path[PATH_LIMIT];
|
||||
snprintf(isl_path, sizeof(isl_path), "../%s", isl_name);
|
||||
islFile = open_streamfile_by_filename(sf, isl_path);
|
||||
sf_isl = open_streamfile_by_filename(sf, isl_path);
|
||||
}
|
||||
|
||||
if (islFile) {
|
||||
if (sf_isl) {
|
||||
STREAMFILE* dec_sf = NULL;
|
||||
|
||||
dec_sf = setup_ogg_vorbis_streamfile(islFile, cfg);
|
||||
dec_sf = setup_ogg_vorbis_streamfile(sf_isl, cfg);
|
||||
if (dec_sf) {
|
||||
off_t loop_offset;
|
||||
char basename[PATH_LIMIT];
|
||||
@ -327,7 +327,7 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||
close_streamfile(dec_sf);
|
||||
}
|
||||
|
||||
close_streamfile(islFile);
|
||||
close_streamfile(sf_isl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -367,7 +367,7 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||
}
|
||||
|
||||
if (is_lse) { /* [Nippon Ichi PC games] */
|
||||
if (read_32bitBE(0x00,sf) == 0xFFFFFFFF) { /* [Operation Abyss: New Tokyo Legacy (PC)] */
|
||||
if (read_u32be(0x00,sf) == 0xFFFFFFFF) { /* [Operation Abyss: New Tokyo Legacy (PC)] */
|
||||
cfg.key[0] = 0xFF;
|
||||
cfg.key_len = 1;
|
||||
cfg.is_header_swap = 1;
|
||||
@ -416,7 +416,7 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||
ovmi.meta_type = meta_OGG_VORBIS;
|
||||
}
|
||||
|
||||
vgmstream = init_vgmstream_ogg_vorbis_callbacks(temp_sf != NULL ? temp_sf : sf, NULL, start_offset, &ovmi);
|
||||
vgmstream = init_vgmstream_ogg_vorbis_config(temp_sf != NULL ? temp_sf : sf, start_offset, &ovmi);
|
||||
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
@ -426,7 +426,7 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VGMSTREAM* init_vgmstream_ogg_vorbis_callbacks(STREAMFILE* sf, ov_callbacks* callbacks, off_t start, const ogg_vorbis_meta_info_t *ovmi) {
|
||||
VGMSTREAM* init_vgmstream_ogg_vorbis_config(STREAMFILE* sf, off_t start, const ogg_vorbis_meta_info_t* ovmi) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
ogg_vorbis_codec_data* data = NULL;
|
||||
ogg_vorbis_io io = {0};
|
||||
|
@ -27,7 +27,7 @@ VGMSTREAM* init_vgmstream_ogv_3rdeye(STREAMFILE* sf) {
|
||||
ovmi.meta_type = meta_OGV_3RDEYE;
|
||||
ovmi.stream_size = subfile_size;
|
||||
|
||||
vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, subfile_offset, &ovmi);
|
||||
vgmstream = init_vgmstream_ogg_vorbis_config(sf, subfile_offset, &ovmi);
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
|
@ -157,16 +157,16 @@ VGMSTREAM* init_vgmstream_opus_n1(STREAMFILE* sf) {
|
||||
int num_samples, loop_start, loop_end;
|
||||
|
||||
/* checks */
|
||||
if ( !check_extensions(sf,"opus,lopus"))
|
||||
if (!check_extensions(sf,"opus,lopus"))
|
||||
goto fail;
|
||||
if (!((read_32bitBE(0x04,sf) == 0x00000000 && read_32bitBE(0x0c,sf) == 0x00000000) ||
|
||||
(read_32bitBE(0x04,sf) == 0xFFFFFFFF && read_32bitBE(0x0c,sf) == 0xFFFFFFFF)))
|
||||
if (!((read_u32be(0x04,sf) == 0x00000000 && read_u32be(0x0c,sf) == 0x00000000) ||
|
||||
(read_u32be(0x04,sf) == 0xFFFFFFFF && read_u32be(0x0c,sf) == 0xFFFFFFFF)))
|
||||
goto fail;
|
||||
|
||||
offset = 0x10;
|
||||
num_samples = 0;
|
||||
loop_start = read_32bitLE(0x00,sf);
|
||||
loop_end = read_32bitLE(0x08,sf);
|
||||
loop_start = read_s32le(0x00,sf);
|
||||
loop_end = read_s32le(0x08,sf);
|
||||
|
||||
return init_vgmstream_opus(sf, meta_OPUS, offset, num_samples,loop_start,loop_end);
|
||||
fail:
|
||||
|
@ -1,64 +1,53 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* SFS (from Baroque) */
|
||||
VGMSTREAM * init_vgmstream_sfs(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
/* SFS - from Sting games [Baroque (PS2)] */
|
||||
VGMSTREAM* init_vgmstream_sfs(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
int loop_flag, channels, sample_rate;
|
||||
size_t channel_size, loop_start;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("sfs",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x53544552) /* "STER" */
|
||||
/* checks */
|
||||
/* .sfs: bigfile extension (no apparent names) */
|
||||
if (!check_extensions(sf, "sfs"))
|
||||
goto fail;
|
||||
|
||||
loop_flag = (read_32bitLE(0x08,streamFile)!=0xFFFFFFFF);
|
||||
channel_count = 2;
|
||||
|
||||
if (!is_id32be(0x00,sf, "STER"))
|
||||
goto fail;
|
||||
channel_size = read_u32le(0x04, sf);
|
||||
loop_start = read_u32le(0x08, sf); /* absolute (ex. offset 0x50 for full loops) */
|
||||
/* 0x0c: data size BE */
|
||||
sample_rate = read_s32be(0x10,sf);
|
||||
|
||||
loop_flag = loop_start != 0xFFFFFFFF;
|
||||
channels = 2;
|
||||
start_offset = 0x30;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
vgmstream = allocate_vgmstream(channels, 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 = (read_32bitLE(0x04,streamFile)*2)*28/16/channel_count;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile)*28/16/channel_count;
|
||||
vgmstream->loop_end_sample = (read_32bitLE(0x04,streamFile)*2)*28/16/channel_count;
|
||||
}
|
||||
vgmstream->meta_type = meta_SFS;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
vgmstream->num_samples = ps_bytes_to_samples(channel_size, 1);
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start - start_offset, channels);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
vgmstream->meta_type = meta_SFS;
|
||||
|
||||
/* 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;
|
||||
|
||||
}
|
||||
}
|
||||
read_string(vgmstream->stream_name,0x10+1, 0x20,sf);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -3,43 +3,43 @@
|
||||
|
||||
|
||||
/* .VAS - from Konami Jikkyou Powerful Pro Yakyuu games */
|
||||
VGMSTREAM * init_vgmstream_ps2_vas(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
VGMSTREAM* init_vgmstream_ps2_vas(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
int loop_flag, channels;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "vas"))
|
||||
if (!check_extensions(sf, "vas"))
|
||||
goto fail;
|
||||
if (read_32bitLE(0x00,streamFile) + 0x800 != get_streamfile_size(streamFile))
|
||||
if (read_u32le(0x00,sf) + 0x800 != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
|
||||
loop_flag = (read_32bitLE(0x10,streamFile) != 0);
|
||||
channel_count = 2;
|
||||
loop_flag = (read_u32le(0x10,sf) != 0);
|
||||
channels = 2;
|
||||
start_offset = 0x800;
|
||||
|
||||
/* header is too simple so test a bit */
|
||||
if (!ps_check_format(streamFile, start_offset, 0x1000))
|
||||
if (!ps_check_format(sf, start_offset, 0x1000))
|
||||
goto fail;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_PS2_VAS;
|
||||
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
|
||||
vgmstream->sample_rate = read_s32le(0x04,sf);
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x200;
|
||||
|
||||
vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x00,streamFile), channel_count);
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitLE(0x14,streamFile), channel_count);
|
||||
vgmstream->num_samples = ps_bytes_to_samples(read_u32le(0x00,sf), channels);
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(read_u32le(0x14,sf), channels);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
@ -50,35 +50,35 @@ fail:
|
||||
|
||||
|
||||
/* .VAS in containers */
|
||||
VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
VGMSTREAM* init_vgmstream_ps2_vas_container(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
off_t subfile_offset = 0;
|
||||
size_t subfile_size = 0;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "vas"))
|
||||
if (!check_extensions(sf, "vas"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00, streamFile) == 0xAB8A5A00) { /* fixed value */
|
||||
if (read_u32be(0x00, sf) == 0xAB8A5A00) { /* fixed value */
|
||||
|
||||
/* just in case */
|
||||
if (read_32bitLE(0x04, streamFile)*0x800 + 0x800 != get_streamfile_size(streamFile))
|
||||
if (read_u32le(0x04, sf) * 0x800 + 0x800 != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
|
||||
total_subsongs = read_32bitLE(0x08, streamFile); /* also at 0x10 */
|
||||
total_subsongs = read_s32le(0x08, sf); /* also at 0x10 */
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
/* check offset table flag, 0x98 has table size */
|
||||
if (read_32bitLE(0x94, streamFile)) {
|
||||
if (read_32bitLE(0x94, sf)) {
|
||||
off_t header_offset = 0x800 + 0x10*(target_subsong-1);
|
||||
|
||||
/* some values are repeats found in the file sub-header */
|
||||
subfile_offset = read_32bitLE(header_offset + 0x00,streamFile) * 0x800;
|
||||
subfile_size = read_32bitLE(header_offset + 0x08,streamFile) + 0x800;
|
||||
subfile_offset = read_32bitLE(header_offset + 0x00,sf) * 0x800;
|
||||
subfile_size = read_32bitLE(header_offset + 0x08,sf) + 0x800;
|
||||
}
|
||||
else {
|
||||
/* a bunch of files */
|
||||
@ -86,7 +86,7 @@ VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE *streamFile) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < total_subsongs; i++) {
|
||||
size_t size = read_32bitLE(offset, streamFile) + 0x800;
|
||||
size_t size = read_32bitLE(offset, sf) + 0x800;
|
||||
|
||||
if (i + 1 == target_subsong) {
|
||||
subfile_offset = offset;
|
||||
@ -102,18 +102,18 @@ VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE *streamFile) {
|
||||
}
|
||||
else {
|
||||
/* some .vas are just files pasted together, better extracted externally but whatevs */
|
||||
size_t file_size = get_streamfile_size(streamFile);
|
||||
size_t file_size = get_streamfile_size(sf);
|
||||
off_t offset = 0;
|
||||
|
||||
/* must have multiple .vas */
|
||||
if (read_32bitLE(0x00,streamFile) + 0x800 >= file_size)
|
||||
if (read_32bitLE(0x00,sf) + 0x800 >= file_size)
|
||||
goto fail;
|
||||
|
||||
total_subsongs = 0;
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
|
||||
while (offset < file_size) {
|
||||
size_t size = read_32bitLE(offset,streamFile) + 0x800;
|
||||
size_t size = read_32bitLE(offset,sf) + 0x800;
|
||||
|
||||
/* some files can be null, ignore */
|
||||
if (size > 0x800) {
|
||||
@ -136,19 +136,19 @@ VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
|
||||
if (!temp_streamFile) goto fail;
|
||||
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, NULL);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_ps2_vas(temp_streamFile);
|
||||
vgmstream = init_vgmstream_ps2_vas(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
close_streamfile(temp_sf);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -294,7 +294,7 @@ fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* sf, riff_fmt_chunk* fmt, int fact_sample_count, off_t start_offset);
|
||||
static int is_ue4_msadpcm(STREAMFILE* sf, riff_fmt_chunk* fmt, int fact_sample_count, off_t start_offset);
|
||||
static size_t get_ue4_msadpcm_interleave(STREAMFILE* sf, riff_fmt_chunk* fmt, off_t start, size_t size);
|
||||
|
||||
|
||||
@ -604,10 +604,10 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
|
||||
/* ignore Beyond Good & Evil HD PS3 evil reuse of PCM codec */
|
||||
if (fmt.coding_type == coding_PCM16LE &&
|
||||
read_32bitBE(start_offset+0x00, sf) == 0x4D534643 && /* "MSF\43" */
|
||||
read_32bitBE(start_offset+0x34, sf) == 0xFFFFFFFF && /* always */
|
||||
read_32bitBE(start_offset+0x38, sf) == 0xFFFFFFFF &&
|
||||
read_32bitBE(start_offset+0x3c, sf) == 0xFFFFFFFF)
|
||||
read_u32be(start_offset+0x00, sf) == 0x4D534643 && /* "MSF\43" */
|
||||
read_u32be(start_offset+0x34, sf) == 0xFFFFFFFF && /* always */
|
||||
read_u32be(start_offset+0x38, sf) == 0xFFFFFFFF &&
|
||||
read_u32be(start_offset+0x3c, sf) == 0xFFFFFFFF)
|
||||
goto fail;
|
||||
|
||||
/* ignore Gitaroo Man Live! (PSP) multi-RIFF (to allow chunked TXTH) */
|
||||
@ -795,7 +795,7 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
}
|
||||
|
||||
/* UE4 uses interleaved mono MSADPCM, try to autodetect without breaking normal MSADPCM */
|
||||
if (fmt.coding_type == coding_MSADPCM && is_ue4_msadpcm(vgmstream, sf, &fmt, fact_sample_count, start_offset)) {
|
||||
if (fmt.coding_type == coding_MSADPCM && is_ue4_msadpcm(sf, &fmt, fact_sample_count, start_offset)) {
|
||||
vgmstream->coding_type = coding_MSADPCM_int;
|
||||
vgmstream->codec_config = 1; /* mark as UE4 MSADPCM */
|
||||
vgmstream->frame_size = fmt.block_size;
|
||||
@ -850,6 +850,8 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start_nxbf, vgmstream->channels, 16);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -868,7 +870,7 @@ fail:
|
||||
}
|
||||
|
||||
/* UE4 MSADPCM is quite normal but has a few minor quirks we can use to detect it */
|
||||
static int is_ue4_msadpcm(VGMSTREAM* vgmstream, STREAMFILE* sf, riff_fmt_chunk* fmt, int fact_sample_count, off_t start) {
|
||||
static int is_ue4_msadpcm(STREAMFILE* sf, riff_fmt_chunk* fmt, int fact_sample_count, off_t start) {
|
||||
|
||||
/* multichannel ok */
|
||||
if (fmt->channel_count < 2)
|
||||
|
232
src/meta/rkv.c
232
src/meta/rkv.c
@ -1,115 +1,117 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* RKV - from Legacy of Kain - Blood Omen 2 (PS2) */
|
||||
VGMSTREAM * init_vgmstream_ps2_rkv(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, header_offset;
|
||||
size_t data_size;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "rkv"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x24,streamFile) != 0x00) /* quick test vs GC rkv (coef position) */
|
||||
goto fail;
|
||||
|
||||
/* some RKV got info at offset 0x00, some other at 0x0 4 */
|
||||
if (read_32bitLE(0x00,streamFile)==0)
|
||||
header_offset = 0x04;
|
||||
else
|
||||
header_offset = 0x00;
|
||||
|
||||
switch (read_32bitLE(header_offset+0x0c,streamFile)) {
|
||||
case 0x00: channel_count = 1; break;
|
||||
case 0x01: channel_count = 2; break;
|
||||
default: goto fail;
|
||||
}
|
||||
loop_flag = (read_32bitLE(header_offset+0x04,streamFile) != 0xFFFFFFFF);
|
||||
start_offset = 0x800;
|
||||
data_size = get_streamfile_size(streamFile) - start_offset;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitLE(header_offset,streamFile);
|
||||
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
|
||||
//vgmstream->num_samples = read_32bitLE(header_offset+0x08,streamFile); /* sometimes not set */
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitLE(header_offset+0x04,streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitLE(header_offset+0x08,streamFile);
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_PS2_RKV;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x400;
|
||||
if (vgmstream->interleave_block_size)
|
||||
vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* RKV - from Legacy of Kain - Blood Omen 2 (GC) */
|
||||
VGMSTREAM * init_vgmstream_ngc_rkv(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* "": empty (files have names but no extensions), .rkv: container bigfile extension, .bo2: fake extension */
|
||||
if (!check_extensions(streamFile, ",rkv,bo2"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x00)
|
||||
goto fail;
|
||||
if (read_32bitBE(0x24,streamFile) == 0x00) /* quick test vs GC rkv (coef position) */
|
||||
goto fail;
|
||||
|
||||
switch (read_32bitBE(0x10,streamFile)) {
|
||||
case 0x00: channel_count = 1; break;
|
||||
case 0x01: channel_count = 2; break;
|
||||
default: goto fail;
|
||||
}
|
||||
loop_flag = (read_32bitBE(0x08,streamFile) != 0xFFFFFFFF);
|
||||
start_offset = 0x800;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitBE(0x04,streamFile);
|
||||
vgmstream->num_samples = read_32bitBE(0x0C,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitBE(0x08,streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitBE(0x0C,streamFile);
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_NGC_RKV;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x400;
|
||||
|
||||
dsp_read_coefs_be(vgmstream,streamFile,0x24,0x2e);
|
||||
/* hist at 0x44/0x72? */
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* RKV - from Legacy of Kain - Blood Omen 2 (PS2) */
|
||||
VGMSTREAM* init_vgmstream_ps2_rkv(STREAMFILE *sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset, header_offset;
|
||||
size_t data_size;
|
||||
int loop_flag, channels;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "rkv"))
|
||||
goto fail;
|
||||
if (read_u32be(0x24,sf) != 0x00) /* quick test vs GC rkv (coef position) */
|
||||
goto fail;
|
||||
|
||||
/* some RKV got info at offset 0x00, some other at 0x0 4 */
|
||||
if (read_u32le(0x00,sf) == 0)
|
||||
header_offset = 0x04;
|
||||
else
|
||||
header_offset = 0x00;
|
||||
|
||||
switch (read_u32le(header_offset+0x0c,sf)) {
|
||||
case 0x00: channels = 1; break;
|
||||
case 0x01: channels = 2; break;
|
||||
default: goto fail;
|
||||
}
|
||||
loop_flag = (read_u32le(header_offset+0x04,sf) != 0xFFFFFFFF);
|
||||
start_offset = 0x800;
|
||||
data_size = get_streamfile_size(sf) - start_offset;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_s32le(header_offset,sf);
|
||||
vgmstream->num_samples = ps_bytes_to_samples(data_size, channels);
|
||||
//vgmstream->num_samples = read_32bitLE(header_offset+0x08,sf); /* sometimes not set */
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = read_s32le(header_offset+0x04,sf);
|
||||
vgmstream->loop_end_sample = read_s32le(header_offset+0x08,sf);
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_PS2_RKV;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x400;
|
||||
if (vgmstream->interleave_block_size)
|
||||
vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* RKV - from Legacy of Kain - Blood Omen 2 (GC) */
|
||||
VGMSTREAM* init_vgmstream_ngc_rkv(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channels;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* "": empty (files have names but no extensions)
|
||||
* .rkv: container bigfile extension
|
||||
* .bo2: fake extension */
|
||||
if (!check_extensions(sf, ",rkv,bo2"))
|
||||
goto fail;
|
||||
if (read_u32be(0x00,sf) != 0x00)
|
||||
goto fail;
|
||||
if (read_u32be(0x24,sf) == 0x00) /* quick test vs GC rkv (coef position) */
|
||||
goto fail;
|
||||
|
||||
switch (read_u32be(0x10,sf)) {
|
||||
case 0x00: channels = 1; break;
|
||||
case 0x01: channels = 2; break;
|
||||
default: goto fail;
|
||||
}
|
||||
loop_flag = (read_u32be(0x08,sf) != 0xFFFFFFFF);
|
||||
start_offset = 0x800;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_s32be(0x04,sf);
|
||||
vgmstream->num_samples = read_s32be(0x0C,sf);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = read_s32be(0x08,sf);
|
||||
vgmstream->loop_end_sample = read_s32be(0x0C,sf);
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_NGC_RKV;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x400;
|
||||
|
||||
dsp_read_coefs_be(vgmstream,sf,0x24,0x2e);
|
||||
/* hist at 0x44/0x72? */
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -3,11 +3,11 @@
|
||||
|
||||
|
||||
/* RSD - from Radical Entertainment games */
|
||||
VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
VGMSTREAM* init_vgmstream_rsd(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset, name_offset;
|
||||
size_t data_size;
|
||||
int loop_flag, channel_count, sample_rate, interleave;
|
||||
int loop_flag, channels, sample_rate, interleave;
|
||||
uint32_t codec;
|
||||
uint8_t version;
|
||||
|
||||
@ -15,22 +15,22 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
|
||||
/* checks */
|
||||
if (!check_extensions(sf,"rsd,rsp"))
|
||||
goto fail;
|
||||
if ((read_32bitBE(0x00,sf) & 0xFFFFFF00) != 0x52534400) /* "RSD\00" */
|
||||
if ((read_u32be(0x00,sf) & 0xFFFFFF00) != 0x52534400) /* "RSD\00" */
|
||||
goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
|
||||
codec = (uint32_t)read_32bitBE(0x04,sf);
|
||||
channel_count = read_32bitLE(0x08, sf);
|
||||
codec = read_u32be(0x04,sf);
|
||||
channels = read_s32le(0x08, sf);
|
||||
/* 0x0c: always 16? */
|
||||
sample_rate = read_32bitLE(0x10, sf);
|
||||
sample_rate = read_s32le(0x10, sf);
|
||||
|
||||
version = read_8bit(0x03, sf);
|
||||
switch(version) {
|
||||
case '2': /* known codecs: VAG/XADP/PCMB [The Simpsons: Road Rage] */
|
||||
case '3': /* known codecs: VAG/PCM/PCMB/GADP? [Dark Summit] */
|
||||
interleave = read_32bitLE(0x14,sf); /* VAG only, 0x04 otherwise */
|
||||
start_offset = read_32bitLE(0x18,sf);
|
||||
interleave = read_u32le(0x14,sf); /* VAG only, 0x04 otherwise */
|
||||
start_offset = read_u32le(0x18,sf);
|
||||
name_offset = 0;
|
||||
break;
|
||||
|
||||
@ -42,8 +42,8 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
|
||||
name_offset = 0;
|
||||
|
||||
/* PCMB/PCM/GADP normally start early but sometimes have padding [The Simpsons: Hit & Run (GC/Xbox)] */
|
||||
if ((codec == 0x50434D20 || codec == 0x550434D42 || codec == 0x47414450)
|
||||
&& read_32bitLE(0x80,sf) != 0x2D2D2D2D)
|
||||
if ((codec == get_id32be("PCM ") || codec == get_id32be("PCMB") || codec == get_id32be("GADP"))
|
||||
&& read_u32le(0x80,sf) != 0x2D2D2D2D)
|
||||
start_offset = 0x80;
|
||||
break;
|
||||
|
||||
@ -62,7 +62,7 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_RSD;
|
||||
@ -74,7 +74,7 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x2;
|
||||
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, 16);
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channels, 16);
|
||||
break;
|
||||
|
||||
case 0x50434D42: /* "PCMB" [The Simpsons: Road Rage (GC), Dark Summit (GC)] */
|
||||
@ -82,7 +82,7 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x2;
|
||||
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, 16);
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channels, 16);
|
||||
break;
|
||||
|
||||
case 0x56414720: /* "VAG " [The Simpsons: Road Rage (PS2), Crash Tag Team Racing (PSP)] */
|
||||
@ -90,11 +90,11 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = (interleave == 0) ? 0x10 : interleave;
|
||||
|
||||
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
|
||||
vgmstream->num_samples = ps_bytes_to_samples(data_size, channels);
|
||||
break;
|
||||
|
||||
case 0x58414450: /* "XADP" [The Simpsons: Road Rage (Xbox)], Crash Tag Team Racing (Xbox)] */
|
||||
vgmstream->coding_type = (channel_count > 2) ? coding_XBOX_IMA_mch : coding_XBOX_IMA;
|
||||
vgmstream->coding_type = (channels > 2) ? coding_XBOX_IMA_mch : coding_XBOX_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, vgmstream->channels);
|
||||
@ -107,7 +107,7 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
|
||||
dsp_read_coefs_le(vgmstream,sf,0x14,0x2e); /* LE! */
|
||||
dsp_read_hist_le (vgmstream,sf,0x38,0x2e);
|
||||
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channels);
|
||||
break;
|
||||
|
||||
case 0x57414450: /* "WADP" [Crash: Mind Over Mutant (Wii)] */
|
||||
@ -117,15 +117,15 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
|
||||
dsp_read_coefs_be(vgmstream,sf,0x1a4,0x28);
|
||||
dsp_read_hist_be (vgmstream,sf,0x1c8,0x28);
|
||||
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channels);
|
||||
break;
|
||||
|
||||
case 0x52414450: /* "RADP" [The Simpsons: Hit & Run (GC), Scarface (Wii)] */
|
||||
vgmstream->coding_type = coding_RAD_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = 0x14*channel_count;
|
||||
vgmstream->interleave_block_size = 0x14*channels;
|
||||
|
||||
vgmstream->num_samples = data_size / 0x14 / channel_count * 32; /* bytes-to-samples */
|
||||
vgmstream->num_samples = data_size / 0x14 / channels * 32; /* bytes-to-samples */
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
@ -134,7 +134,7 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
|
||||
|
||||
ovmi.meta_type = meta_RSD;
|
||||
close_vgmstream(vgmstream);
|
||||
vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, start_offset, &ovmi);
|
||||
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
if (!vgmstream) goto fail;
|
||||
break;
|
||||
}
|
||||
@ -142,17 +142,15 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x574D4120: { /* "WMA " [Scarface (Xbox)] */
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
|
||||
/* mini header + WMA header at start_offset */
|
||||
ffmpeg_data = init_ffmpeg_offset(sf, start_offset+0x08,data_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->codec_data = init_ffmpeg_offset(sf, start_offset+0x08,data_size);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = ffmpeg_get_samples(ffmpeg_data); /* an estimation, sometimes cuts files a bit early */
|
||||
//vgmstream->num_samples = read_32bitLE(start_offset + 0x00, sf) / channel_count / 2; /* may be PCM data size, but not exact */
|
||||
vgmstream->num_samples = ffmpeg_get_samples(vgmstream->codec_data); /* an estimation, sometimes cuts files a bit early */
|
||||
//vgmstream->num_samples = read_32bitLE(start_offset + 0x00, sf) / channels / 2; /* may be PCM data size, but not exact */
|
||||
vgmstream->sample_rate = read_32bitLE(start_offset + 0x04, sf);
|
||||
break;
|
||||
}
|
||||
@ -170,7 +168,6 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
|
||||
}
|
||||
|
||||
case 0x584D4120: { /* "XMA " [Crash of the Titans (X360)-v1, Crash: Mind over Mutant (X360)-v2] */
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
uint8_t buf[0x100];
|
||||
size_t bytes, xma_size, block_size, block_count;
|
||||
int xma_version;
|
||||
@ -199,15 +196,14 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *sf) {
|
||||
}
|
||||
|
||||
bytes = ffmpeg_make_riff_xma2(buf,sizeof(buf), vgmstream->num_samples, xma_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
|
||||
ffmpeg_data = init_ffmpeg_header_offset(sf, buf, bytes, start_offset, xma_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf, bytes, start_offset, xma_size);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
/* for some reason (dev trickery?) .rsd don't set skip in the bitstream, though they should */
|
||||
//xma_fix_raw_samples(vgmstream, sf, start_offset,xma_size, 0, 0,0);
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, 512+64);
|
||||
ffmpeg_set_skip_samples(vgmstream->codec_data, 512+64);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -192,7 +192,7 @@ VGMSTREAM* init_vgmstream_rxws_badrip(STREAMFILE* sf) {
|
||||
(read_32bitBE(0x10,sf) == 0x464F524D)))
|
||||
goto fail;
|
||||
|
||||
loop_flag = (read_32bitLE(0x3C,sf)!=0xFFFFFFFF);
|
||||
loop_flag = (read_u32le(0x3C,sf)!=0xFFFFFFFF);
|
||||
channels=2; /* Always stereo files */
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
@ -1,31 +1,33 @@
|
||||
#include "meta.h"
|
||||
|
||||
/* DVI - from Konami KCE Nayoga SAT games (Castlevania Symphony of the Night, Jikkyou Oshaberi Parodius - Forever with Me) */
|
||||
VGMSTREAM * init_vgmstream_sat_dvi(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
VGMSTREAM* init_vgmstream_sat_dvi(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
int loop_flag, channels;
|
||||
|
||||
/* check extension (.pcm: original, .dvi: renamed to header id) */
|
||||
if ( !check_extensions(streamFile,"pcm,dvi") )
|
||||
/* checks
|
||||
* .pcm: original
|
||||
* .dvi: header id (to be removed )*/
|
||||
if (!check_extensions(sf,"pcm,dvi"))
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x4456492E) /* "DVI." */
|
||||
if (!is_id32be(0x00,sf, "DVI."))
|
||||
goto fail;
|
||||
|
||||
start_offset = read_32bitBE(0x04,streamFile);
|
||||
loop_flag = (read_32bitBE(0x0C,streamFile) != 0xFFFFFFFF);
|
||||
channel_count = 2; /* no mono files seem to exists */
|
||||
start_offset = read_s32be(0x04,sf);
|
||||
loop_flag = (read_s32be(0x0C,sf) != -1);
|
||||
channels = 2; /* no mono files seem to exists */
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->num_samples = read_32bitBE(0x08,streamFile);
|
||||
vgmstream->loop_start_sample = read_32bitBE(0x0C,streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitBE(0x08,streamFile);
|
||||
vgmstream->num_samples = read_s32be(0x08,sf);
|
||||
vgmstream->loop_start_sample = read_s32be(0x0C,sf);
|
||||
vgmstream->loop_end_sample = read_s32be(0x08,sf);
|
||||
|
||||
vgmstream->coding_type = coding_DVI_IMA_int;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
@ -34,12 +36,11 @@ VGMSTREAM * init_vgmstream_sat_dvi(STREAMFILE *streamFile) {
|
||||
|
||||
/* at 0x10 (L) / 0x20 (R): probably ADPCM loop history @+0x00 and step @+0x17 (not init values) */
|
||||
|
||||
/* open the file for reading */
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset) )
|
||||
goto fail;
|
||||
|
||||
/* for some reason right channel goes first (tested in SOTN vs emu and PS/OST version), swap offsets */
|
||||
if (channel_count == 2) {
|
||||
if (channels == 2) {
|
||||
off_t temp = vgmstream->ch[0].offset;
|
||||
vgmstream->ch[0].channel_start_offset =
|
||||
vgmstream->ch[0].offset = vgmstream->ch[1].offset;
|
||||
|
@ -192,7 +192,7 @@ VGMSTREAM* init_vgmstream_sqex_scd(STREAMFILE* sf) {
|
||||
}
|
||||
|
||||
/* actual Ogg init */
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, start_offset, &ovmi);
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
if (ogg_vgmstream && name_offset)
|
||||
read_string(ogg_vgmstream->stream_name, PATH_LIMIT, name_offset, sf);
|
||||
return ogg_vgmstream;
|
||||
|
@ -172,7 +172,7 @@ VGMSTREAM* init_vgmstream_sqex_sead(STREAMFILE* sf) {
|
||||
/* 0x18: reserved x2 */
|
||||
/* 0x20: seek table */
|
||||
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, subfile_offset, &ovmi);
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(sf, subfile_offset, &ovmi);
|
||||
if (ogg_vgmstream) {
|
||||
ogg_vgmstream->num_streams = vgmstream->num_streams;
|
||||
ogg_vgmstream->stream_size = vgmstream->stream_size;
|
||||
|
@ -1553,7 +1553,7 @@ static int read_name_table_keyval(txth_header* txth, const char* line, char* key
|
||||
//todo names with # and subsongs don't work
|
||||
|
||||
/* ignore comments (that aren't subsongs) */
|
||||
if (line[0] == '#' && strchr(line,':') < 0)
|
||||
if (line[0] == '#' && strchr(line,':') == NULL)
|
||||
return 0;
|
||||
|
||||
/* try "(name): (val))" */
|
||||
|
@ -599,7 +599,7 @@ fail:
|
||||
}
|
||||
|
||||
|
||||
static VGMSTREAM* init_vgmstream_ubi_bao_silence(ubi_bao_header* bao, STREAMFILE* sf) {
|
||||
static VGMSTREAM* init_vgmstream_ubi_bao_silence(ubi_bao_header* bao) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
int channels, sample_rate;
|
||||
int32_t num_samples;
|
||||
@ -660,7 +660,7 @@ static VGMSTREAM* init_vgmstream_ubi_bao_header(ubi_bao_header* bao, STREAMFILE*
|
||||
break;
|
||||
|
||||
case UBI_SILENCE:
|
||||
vgmstream = init_vgmstream_ubi_bao_silence(bao, sf);
|
||||
vgmstream = init_vgmstream_ubi_bao_silence(bao);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -990,7 +990,7 @@ fail:
|
||||
}
|
||||
|
||||
/* adjust some common values */
|
||||
static int parse_values(ubi_bao_header* bao, STREAMFILE* sf) {
|
||||
static int parse_values(ubi_bao_header* bao) {
|
||||
|
||||
if (bao->type == UBI_SEQUENCE || bao->type == UBI_SILENCE)
|
||||
return 1;
|
||||
@ -1228,7 +1228,7 @@ static int parse_header(ubi_bao_header* bao, STREAMFILE* sf, off_t offset) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!parse_values(bao, sf))
|
||||
if (!parse_values(bao))
|
||||
goto fail;
|
||||
|
||||
if (!parse_offsets(bao, sf))
|
||||
|
@ -1,380 +1,385 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
static int get_loop_points(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end);
|
||||
|
||||
/* Jade RIFF - from Ubisoft Jade engine games [Beyond Good & Evil (multi), Rayman Raving Rabbids 1/2 (multi)] */
|
||||
VGMSTREAM * init_vgmstream_ubi_jade(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, first_offset = 0xc;
|
||||
off_t fmt_offset, data_offset;
|
||||
size_t fmt_size, data_size;
|
||||
int loop_flag, channel_count, sample_rate, codec, block_size;
|
||||
int loop_start = 0, loop_end = 0;
|
||||
int is_jade_v2 = 0;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .waa: ambiances, .wam: music, .wac: sfx, .wad: dialogs (usually)
|
||||
* .wav: Beyond Good & Evil HD (PS3), .psw: fake/badly extracted names [ex. Rayman Raving Rabbids (PS2)] */
|
||||
if (!check_extensions(streamFile,"waa,wac,wad,wam,wav,lwav,psw"))
|
||||
goto fail;
|
||||
|
||||
/* a slightly twisted RIFF with custom codecs */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x52494646 || /* "RIFF" */
|
||||
read_32bitBE(0x08,streamFile) != 0x57415645) /* "WAVE" */
|
||||
goto fail;
|
||||
|
||||
if (check_extensions(streamFile,"psw")) { /* .psw are incorrectly extracted missing 0x04 at the end */
|
||||
if (read_32bitLE(0x04,streamFile)+0x04 != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
if (read_32bitLE(0x04,streamFile)+0x04+0x04 != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!find_chunk(streamFile, 0x666d7420,first_offset,0, &fmt_offset,&fmt_size, 0, 0)) /* "fmt " */
|
||||
goto fail;
|
||||
if (!find_chunk(streamFile, 0x64617461,first_offset,0, &data_offset,&data_size, 0, 0)) /* "data" */
|
||||
goto fail;
|
||||
|
||||
/* ignore LyN RIFF (needed as codec 0xFFFE is reused) */
|
||||
{
|
||||
off_t fact_offset;
|
||||
size_t fact_size;
|
||||
|
||||
if (find_chunk(streamFile, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) { /* "fact" */
|
||||
if (fact_size == 0x10 && read_32bitBE(fact_offset+0x04, streamFile) == 0x4C794E20) /* "LyN " */
|
||||
goto fail; /* parsed elsewhere */
|
||||
/* Jade doesn't use "fact", though */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* parse format */
|
||||
{
|
||||
if (fmt_size < 0x10)
|
||||
goto fail;
|
||||
codec = (uint16_t)read_16bitLE(fmt_offset+0x00,streamFile);
|
||||
channel_count = read_16bitLE(fmt_offset+0x02,streamFile);
|
||||
sample_rate = read_32bitLE(fmt_offset+0x04,streamFile);
|
||||
block_size = (uint16_t)read_16bitLE(fmt_offset+0x0c,streamFile);
|
||||
/* 0x08: average bytes, 0x0e: bps, etc */
|
||||
|
||||
/* autodetect Jade "v2", uses a different interleave [Rayman Raving Rabbids (PS2/Wii)] */
|
||||
switch(codec) {
|
||||
case 0xFFFF: { /* PS2 */
|
||||
int i;
|
||||
|
||||
/* half interleave check as there is no flag (ends with the PS-ADPCM stop frame) */
|
||||
for (i = 0; i < channel_count; i++) {
|
||||
off_t end_frame = data_offset + (data_size / channel_count) * (i+1) - 0x10;
|
||||
if (read_32bitBE(end_frame+0x00,streamFile) != 0x07007777 ||
|
||||
read_32bitBE(end_frame+0x04,streamFile) != 0x77777777 ||
|
||||
read_32bitBE(end_frame+0x08,streamFile) != 0x77777777 ||
|
||||
read_32bitBE(end_frame+0x0c,streamFile) != 0x77777777) {
|
||||
is_jade_v2 = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xFFFE: /* GC/Wii */
|
||||
is_jade_v2 = (read_16bitLE(fmt_offset+0x10,streamFile) == 0); /* extra data size (0x2e*channels) */
|
||||
break;
|
||||
}
|
||||
|
||||
/* hopefully catches PC Rabbids */
|
||||
if (find_chunk(streamFile, 0x63756520,first_offset,0, NULL,NULL, 0, 0)) { /* "cue " */
|
||||
is_jade_v2 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* get loop points */
|
||||
if (is_jade_v2) {
|
||||
loop_flag = get_loop_points(streamFile, &loop_start, &loop_end); /* loops in "LIST" */
|
||||
}
|
||||
else {
|
||||
/* BG&E files don't contain looping information, so the looping is done by extension.
|
||||
* wam and waa contain ambient sounds and music, so often they contain looped music.
|
||||
* Later, if the file is too short looping will be disabled. */
|
||||
loop_flag = check_extensions(streamFile,"waa,wam");
|
||||
}
|
||||
|
||||
start_offset = data_offset;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->meta_type = meta_UBI_JADE;
|
||||
if (is_jade_v2) {
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
}
|
||||
|
||||
switch(codec) {
|
||||
|
||||
case 0x0069: /* Xbox */
|
||||
/* Peter Jackson's King Kong uses 0x14 (other versions don't) */
|
||||
if (fmt_size != 0x12 && fmt_size != 0x14) goto fail;
|
||||
if (block_size != 0x24*channel_count) goto fail;
|
||||
|
||||
vgmstream->coding_type = coding_XBOX_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, channel_count);
|
||||
if (!is_jade_v2) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0xFFFF: /* PS2 */
|
||||
if (fmt_size != 0x12) goto fail;
|
||||
if (block_size != 0x10) goto fail;
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
|
||||
if (is_jade_v2) {
|
||||
vgmstream->interleave_block_size = 0x6400;
|
||||
if (vgmstream->interleave_block_size)
|
||||
vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
|
||||
}
|
||||
else {
|
||||
vgmstream->interleave_block_size = data_size / channel_count;
|
||||
}
|
||||
|
||||
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
|
||||
if (!is_jade_v2) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0xFFFE: /* GC/Wii */
|
||||
if (fmt_size != 0x12) goto fail;
|
||||
if (block_size != 0x08) goto fail;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
|
||||
if (!is_jade_v2) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
/* coefs / interleave */
|
||||
if (is_jade_v2) {
|
||||
vgmstream->interleave_block_size = 0x6400;
|
||||
if (vgmstream->interleave_block_size)
|
||||
vgmstream->interleave_last_block_size = ((data_size % (vgmstream->interleave_block_size*vgmstream->channels))/2+7)/8*8;
|
||||
|
||||
{
|
||||
static const int16_t coef[16] = { /* default Ubisoft coefs, from ELF */
|
||||
0x04ab,0xfced,0x0789,0xfedf,0x09a2,0xfae5,0x0c90,0xfac1,
|
||||
0x084d,0xfaa4,0x0982,0xfdf7,0x0af6,0xfafa,0x0be6,0xfbf5
|
||||
};
|
||||
int i, ch;
|
||||
|
||||
for (ch = 0; ch < channel_count; ch++) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
vgmstream->ch[ch].adpcm_coef[i] = coef[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* has extra 0x2e coefs before each channel, not counted in data_size */
|
||||
vgmstream->interleave_block_size = (data_size + 0x2e*channel_count) / channel_count;
|
||||
|
||||
dsp_read_coefs_be(vgmstream, streamFile, start_offset+0x00, vgmstream->interleave_block_size);
|
||||
dsp_read_hist_be (vgmstream, streamFile, start_offset+0x20, vgmstream->interleave_block_size);
|
||||
start_offset += 0x2e;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0002: /* PC */
|
||||
if (fmt_size != 0x12) goto fail;
|
||||
if (block_size != 0x24*channel_count) goto fail;
|
||||
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->frame_size = block_size;
|
||||
|
||||
vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, vgmstream->frame_size, channel_count);
|
||||
if (!is_jade_v2) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x0001: { /* PS3 */
|
||||
VGMSTREAM *temp_vgmstream = NULL;
|
||||
STREAMFILE *temp_sf = NULL;
|
||||
|
||||
if (fmt_size != 0x10) goto fail;
|
||||
if (block_size != 0x02*channel_count) goto fail;
|
||||
|
||||
/* a MSF (usually ATRAC3) masquerading as PCM */
|
||||
if (read_32bitBE(start_offset, streamFile) != 0x4D534643) /* "MSF\43" */
|
||||
goto fail;
|
||||
|
||||
temp_sf = setup_subfile_streamfile(streamFile, start_offset, data_size, "msf");
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
temp_vgmstream = init_vgmstream_msf(temp_sf);
|
||||
close_streamfile(temp_sf);
|
||||
if (!temp_vgmstream) goto fail;
|
||||
|
||||
temp_vgmstream->meta_type = vgmstream->meta_type;
|
||||
close_vgmstream(vgmstream);
|
||||
return temp_vgmstream;
|
||||
}
|
||||
|
||||
default: /* X360 uses .XMA */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* V1 loops by extension, try to detect incorrectly looped jingles (too short) */
|
||||
if (!is_jade_v2) {
|
||||
if(loop_flag
|
||||
&& vgmstream->num_samples < 15*sample_rate) { /* in seconds */
|
||||
vgmstream->loop_flag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* extract loops from "cue /LIST", returns if loops (info from Droolie) */
|
||||
static int get_loop_points(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end) {
|
||||
off_t cue_offset, list_offset;
|
||||
size_t cue_size, list_size;
|
||||
off_t offset, first_offset = 0x0c;
|
||||
int i, cue_count, loop_id = 0, loop_start = 0, loop_end = 0;
|
||||
|
||||
|
||||
/* unlooped files may contain LIST, but also may not */
|
||||
if (!find_chunk(streamFile, 0x63756520,first_offset,0, &cue_offset,&cue_size, 0, 0)) /* "cue " */
|
||||
goto fail;
|
||||
if (!find_chunk(streamFile, 0x4C495354,first_offset,0, &list_offset,&list_size, 0, 0)) /* "LIST" */
|
||||
goto fail;
|
||||
|
||||
offset = list_offset + 0x04;
|
||||
while (offset < list_offset + list_size) {
|
||||
uint32_t chunk_id = read_32bitBE(offset+0x00, streamFile);
|
||||
uint32_t chunk_size = read_32bitLE(offset+0x04, streamFile);
|
||||
offset += 0x08;
|
||||
|
||||
switch(chunk_id) {
|
||||
case 0x6C61626C: /* "labl" */
|
||||
if (read_32bitBE(offset+0x04, streamFile) == 0x6C6F6F70) /* "loop", actually an string tho */
|
||||
loop_id = read_32bitLE(offset+0x00, streamFile);
|
||||
chunk_size += (chunk_size % 2) ? 1 : 0; /* string is even-padded after size */
|
||||
break;
|
||||
case 0x6C747874: /* "ltxt" */
|
||||
if (loop_id == read_32bitLE(offset+0x00, streamFile))
|
||||
loop_end = read_32bitLE(offset+0x04, streamFile);
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("Jade: unknown LIST chunk\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
offset += chunk_size;
|
||||
}
|
||||
|
||||
if (!loop_end)
|
||||
return 0;
|
||||
|
||||
cue_count = read_32bitLE(cue_offset+0x00, streamFile);
|
||||
for (i = 0; i < cue_count; i++) {
|
||||
if (loop_id == read_32bitLE(cue_offset+0x04 + i*0x18 + 0x00, streamFile)) {
|
||||
loop_start = read_32bitLE(cue_offset+0x04 + i*0x18 + 0x04, streamFile);
|
||||
loop_end += loop_start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*out_loop_start = loop_start;
|
||||
*out_loop_end = loop_end;
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Jade RIFF in containers */
|
||||
VGMSTREAM * init_vgmstream_ubi_jade_container(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
off_t subfile_offset;
|
||||
size_t subfile_size;
|
||||
|
||||
/* Jade packs files in bigfiles, and once extracted the sound files have extra engine data before
|
||||
* the RIFF + padding after. Most extractors don't remove the padding correctly, so here we add support. */
|
||||
|
||||
/* checks */
|
||||
/* standard Jade exts + .xma for padded XMA used in Beyond Good & Evil HD (X360) */
|
||||
if (!check_extensions(streamFile,"waa,wac,wad,wam,wav,lwav,xma"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x04,streamFile) == 0x52494646 &&
|
||||
read_32bitLE(0x00,streamFile)+0x04 == get_streamfile_size(streamFile)) {
|
||||
/* data size + RIFF + padding */
|
||||
subfile_offset = 0x04;
|
||||
}
|
||||
else if (read_32bitBE(0x00,streamFile) == 0x52494646 &&
|
||||
read_32bitLE(0x04,streamFile)+0x04+0x04 < get_streamfile_size(streamFile) &&
|
||||
(get_streamfile_size(streamFile) + 0x04) % 0x800 == 0) {
|
||||
/* RIFF + padding with data size removed (bad extraction) */
|
||||
subfile_offset = 0x00;
|
||||
}
|
||||
else if (read_32bitBE(0x04,streamFile) == 0x52494646 &&
|
||||
read_32bitLE(0x00,streamFile) == get_streamfile_size(streamFile)) {
|
||||
/* data_size + RIFF + padding - 0x04 (bad extraction) */
|
||||
subfile_offset = 0x04;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
subfile_size = read_32bitLE(subfile_offset+0x04,streamFile) + 0x04+0x04;
|
||||
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
if (check_extensions(streamFile,"xma")) {
|
||||
vgmstream = init_vgmstream_xma(temp_streamFile);
|
||||
} else {
|
||||
vgmstream = init_vgmstream_ubi_jade(temp_streamFile);
|
||||
}
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
static int get_loop_points(STREAMFILE* sf, int* p_loop_start, int* p_loop_end);
|
||||
|
||||
/* Jade RIFF - from Ubisoft Jade engine games [Beyond Good & Evil (multi), Rayman Raving Rabbids 1/2 (multi)] */
|
||||
VGMSTREAM* init_vgmstream_ubi_jade(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset, first_offset = 0xc;
|
||||
off_t fmt_offset, data_offset;
|
||||
size_t fmt_size, data_size;
|
||||
int loop_flag, channel_count, sample_rate, codec, block_size;
|
||||
int loop_start = 0, loop_end = 0;
|
||||
int is_jade_v2 = 0;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .waa: ambiances, .wam: music, .wac: sfx, .wad: dialogs (usually)
|
||||
* .wav: Beyond Good & Evil HD (PS3)
|
||||
* .psw: fake/badly extracted names [ex. Rayman Raving Rabbids (PS2)] */
|
||||
if (!check_extensions(sf,"waa,wac,wad,wam,wav,lwav,psw"))
|
||||
goto fail;
|
||||
|
||||
/* a slightly twisted RIFF with custom codecs */
|
||||
if (!is_id32be(0x00,sf, "RIFF") ||
|
||||
!is_id32be(0x08,sf, "WAVE"))
|
||||
goto fail;
|
||||
|
||||
|
||||
if (check_extensions(sf,"psw")) { /* .psw are incorrectly extracted missing 0x04 at the end */
|
||||
if (read_32bitLE(0x04,sf)+0x04 != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
if (read_32bitLE(0x04,sf)+0x04+0x04 != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!find_chunk(sf, 0x666d7420,first_offset,0, &fmt_offset,&fmt_size, 0, 0)) /* "fmt " */
|
||||
goto fail;
|
||||
if (!find_chunk(sf, 0x64617461,first_offset,0, &data_offset,&data_size, 0, 0)) /* "data" */
|
||||
goto fail;
|
||||
|
||||
/* ignore LyN RIFF (needed as codec 0xFFFE is reused) */
|
||||
{
|
||||
off_t fact_offset;
|
||||
size_t fact_size;
|
||||
|
||||
if (find_chunk(sf, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) { /* "fact" */
|
||||
if (fact_size == 0x10 && read_32bitBE(fact_offset+0x04, sf) == 0x4C794E20) /* "LyN " */
|
||||
goto fail; /* parsed elsewhere */
|
||||
/* Jade doesn't use "fact", though */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* parse format */
|
||||
{
|
||||
if (fmt_size < 0x10)
|
||||
goto fail;
|
||||
codec = (uint16_t)read_16bitLE(fmt_offset+0x00,sf);
|
||||
channel_count = read_16bitLE(fmt_offset+0x02,sf);
|
||||
sample_rate = read_32bitLE(fmt_offset+0x04,sf);
|
||||
block_size = (uint16_t)read_16bitLE(fmt_offset+0x0c,sf);
|
||||
/* 0x08: average bytes, 0x0e: bps, etc */
|
||||
|
||||
/* autodetect Jade "v2", uses a different interleave [Rayman Raving Rabbids (PS2/Wii)] */
|
||||
switch(codec) {
|
||||
case 0xFFFF: { /* PS2 */
|
||||
int i;
|
||||
|
||||
/* half interleave check as there is no flag (ends with the PS-ADPCM stop frame) */
|
||||
for (i = 0; i < channel_count; i++) {
|
||||
off_t end_frame = data_offset + (data_size / channel_count) * (i+1) - 0x10;
|
||||
if (read_32bitBE(end_frame+0x00,sf) != 0x07007777 ||
|
||||
read_32bitBE(end_frame+0x04,sf) != 0x77777777 ||
|
||||
read_32bitBE(end_frame+0x08,sf) != 0x77777777 ||
|
||||
read_32bitBE(end_frame+0x0c,sf) != 0x77777777) {
|
||||
is_jade_v2 = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xFFFE: /* GC/Wii */
|
||||
is_jade_v2 = (read_16bitLE(fmt_offset+0x10,sf) == 0); /* extra data size (0x2e*channels) */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* hopefully catches PC Rabbids */
|
||||
if (find_chunk(sf, 0x63756520,first_offset,0, NULL,NULL, 0, 0)) { /* "cue " */
|
||||
is_jade_v2 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* get loop points */
|
||||
if (is_jade_v2) {
|
||||
loop_flag = get_loop_points(sf, &loop_start, &loop_end); /* loops in "LIST" */
|
||||
}
|
||||
else {
|
||||
/* BG&E files don't contain looping information, so the looping is done by extension.
|
||||
* wam and waa contain ambient sounds and music, so often they contain looped music.
|
||||
* Later, if the file is too short looping will be disabled. */
|
||||
loop_flag = check_extensions(sf,"waa,wam");
|
||||
}
|
||||
|
||||
start_offset = data_offset;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->meta_type = meta_UBI_JADE;
|
||||
if (is_jade_v2) {
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
}
|
||||
|
||||
switch(codec) {
|
||||
|
||||
case 0x0069: /* Xbox */
|
||||
/* Peter Jackson's King Kong uses 0x14 (other versions don't) */
|
||||
if (fmt_size != 0x12 && fmt_size != 0x14) goto fail;
|
||||
if (block_size != 0x24*channel_count) goto fail;
|
||||
|
||||
vgmstream->coding_type = coding_XBOX_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, channel_count);
|
||||
if (!is_jade_v2) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0xFFFF: /* PS2 */
|
||||
if (fmt_size != 0x12) goto fail;
|
||||
if (block_size != 0x10) goto fail;
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
|
||||
if (is_jade_v2) {
|
||||
vgmstream->interleave_block_size = 0x6400;
|
||||
if (vgmstream->interleave_block_size)
|
||||
vgmstream->interleave_last_block_size = (data_size % (vgmstream->interleave_block_size*vgmstream->channels)) / vgmstream->channels;
|
||||
}
|
||||
else {
|
||||
vgmstream->interleave_block_size = data_size / channel_count;
|
||||
}
|
||||
|
||||
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
|
||||
if (!is_jade_v2) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0xFFFE: /* GC/Wii */
|
||||
if (fmt_size != 0x12) goto fail;
|
||||
if (block_size != 0x08) goto fail;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channel_count);
|
||||
if (!is_jade_v2) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
/* coefs / interleave */
|
||||
if (is_jade_v2) {
|
||||
vgmstream->interleave_block_size = 0x6400;
|
||||
if (vgmstream->interleave_block_size)
|
||||
vgmstream->interleave_last_block_size = ((data_size % (vgmstream->interleave_block_size*vgmstream->channels))/2+7)/8*8;
|
||||
|
||||
{
|
||||
static const int16_t coef[16] = { /* default Ubisoft coefs, from ELF */
|
||||
0x04ab,0xfced,0x0789,0xfedf,0x09a2,0xfae5,0x0c90,0xfac1,
|
||||
0x084d,0xfaa4,0x0982,0xfdf7,0x0af6,0xfafa,0x0be6,0xfbf5
|
||||
};
|
||||
int i, ch;
|
||||
|
||||
for (ch = 0; ch < channel_count; ch++) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
vgmstream->ch[ch].adpcm_coef[i] = coef[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* has extra 0x2e coefs before each channel, not counted in data_size */
|
||||
vgmstream->interleave_block_size = (data_size + 0x2e*channel_count) / channel_count;
|
||||
|
||||
dsp_read_coefs_be(vgmstream, sf, start_offset+0x00, vgmstream->interleave_block_size);
|
||||
dsp_read_hist_be (vgmstream, sf, start_offset+0x20, vgmstream->interleave_block_size);
|
||||
start_offset += 0x2e;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0002: /* PC */
|
||||
if (fmt_size != 0x12) goto fail;
|
||||
if (block_size != 0x24*channel_count) goto fail;
|
||||
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->frame_size = block_size;
|
||||
|
||||
vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, vgmstream->frame_size, channel_count);
|
||||
if (!is_jade_v2) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x0001: { /* PS3 */
|
||||
VGMSTREAM *temp_vgmstream = NULL;
|
||||
STREAMFILE *temp_sf = NULL;
|
||||
|
||||
if (fmt_size != 0x10) goto fail;
|
||||
if (block_size != 0x02*channel_count) goto fail;
|
||||
|
||||
/* a MSF (usually ATRAC3) masquerading as PCM */
|
||||
if (read_32bitBE(start_offset, sf) != 0x4D534643) /* "MSF\43" */
|
||||
goto fail;
|
||||
|
||||
temp_sf = setup_subfile_streamfile(sf, start_offset, data_size, "msf");
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
temp_vgmstream = init_vgmstream_msf(temp_sf);
|
||||
close_streamfile(temp_sf);
|
||||
if (!temp_vgmstream) goto fail;
|
||||
|
||||
temp_vgmstream->meta_type = vgmstream->meta_type;
|
||||
close_vgmstream(vgmstream);
|
||||
return temp_vgmstream;
|
||||
}
|
||||
|
||||
default: /* X360 uses .XMA */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* V1 loops by extension, try to detect incorrectly looped jingles (too short) */
|
||||
if (!is_jade_v2) {
|
||||
if(loop_flag
|
||||
&& vgmstream->num_samples < 15*sample_rate) { /* in seconds */
|
||||
vgmstream->loop_flag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* extract loops from "cue /LIST", returns if loops (info from Droolie) */
|
||||
static int get_loop_points(STREAMFILE *sf, int *out_loop_start, int *out_loop_end) {
|
||||
off_t cue_offset, list_offset;
|
||||
size_t cue_size, list_size;
|
||||
off_t offset, first_offset = 0x0c;
|
||||
int i, cue_count, loop_id = 0, loop_start = 0, loop_end = 0;
|
||||
|
||||
|
||||
/* unlooped files may contain LIST, but also may not */
|
||||
if (!find_chunk(sf, 0x63756520,first_offset,0, &cue_offset,&cue_size, 0, 0)) /* "cue " */
|
||||
goto fail;
|
||||
if (!find_chunk(sf, 0x4C495354,first_offset,0, &list_offset,&list_size, 0, 0)) /* "LIST" */
|
||||
goto fail;
|
||||
|
||||
offset = list_offset + 0x04;
|
||||
while (offset < list_offset + list_size) {
|
||||
uint32_t chunk_id = read_32bitBE(offset+0x00, sf);
|
||||
uint32_t chunk_size = read_32bitLE(offset+0x04, sf);
|
||||
offset += 0x08;
|
||||
|
||||
switch(chunk_id) {
|
||||
case 0x6C61626C: /* "labl" */
|
||||
if (read_32bitBE(offset+0x04, sf) == 0x6C6F6F70) /* "loop", actually an string tho */
|
||||
loop_id = read_32bitLE(offset+0x00, sf);
|
||||
chunk_size += (chunk_size % 2) ? 1 : 0; /* string is even-padded after size */
|
||||
break;
|
||||
case 0x6C747874: /* "ltxt" */
|
||||
if (loop_id == read_32bitLE(offset+0x00, sf))
|
||||
loop_end = read_32bitLE(offset+0x04, sf);
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("Jade: unknown LIST chunk\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
offset += chunk_size;
|
||||
}
|
||||
|
||||
if (!loop_end)
|
||||
return 0;
|
||||
|
||||
cue_count = read_32bitLE(cue_offset+0x00, sf);
|
||||
for (i = 0; i < cue_count; i++) {
|
||||
if (loop_id == read_32bitLE(cue_offset+0x04 + i*0x18 + 0x00, sf)) {
|
||||
loop_start = read_32bitLE(cue_offset+0x04 + i*0x18 + 0x04, sf);
|
||||
loop_end += loop_start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*out_loop_start = loop_start;
|
||||
*out_loop_end = loop_end;
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Jade RIFF in containers */
|
||||
VGMSTREAM* init_vgmstream_ubi_jade_container(STREAMFILE* sf) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
STREAMFILE *temp_sf = NULL;
|
||||
off_t subfile_offset;
|
||||
size_t subfile_size;
|
||||
|
||||
/* Jade packs files in bigfiles, and once extracted the sound files have extra engine data before
|
||||
* the RIFF + padding after. Most extractors don't remove the padding correctly, so here we add support. */
|
||||
|
||||
/* checks */
|
||||
/* standard Jade exts + .xma for padded XMA used in Beyond Good & Evil HD (X360) */
|
||||
if (!check_extensions(sf,"waa,wac,wad,wam,wav,lwav,xma"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x04,sf) == 0x52494646 &&
|
||||
read_32bitLE(0x00,sf)+0x04 == get_streamfile_size(sf)) {
|
||||
/* data size + RIFF + padding */
|
||||
subfile_offset = 0x04;
|
||||
}
|
||||
else if (read_32bitBE(0x00,sf) == 0x52494646 &&
|
||||
read_32bitLE(0x04,sf)+0x04+0x04 < get_streamfile_size(sf) &&
|
||||
(get_streamfile_size(sf) + 0x04) % 0x800 == 0) {
|
||||
/* RIFF + padding with data size removed (bad extraction) */
|
||||
subfile_offset = 0x00;
|
||||
}
|
||||
else if (read_32bitBE(0x04,sf) == 0x52494646 &&
|
||||
read_32bitLE(0x00,sf) == get_streamfile_size(sf)) {
|
||||
/* data_size + RIFF + padding - 0x04 (bad extraction) */
|
||||
subfile_offset = 0x04;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
subfile_size = read_32bitLE(subfile_offset+0x04,sf) + 0x04+0x04;
|
||||
|
||||
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, NULL);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
if (check_extensions(sf,"xma")) {
|
||||
vgmstream = init_vgmstream_xma(temp_sf);
|
||||
} else {
|
||||
vgmstream = init_vgmstream_ubi_jade(temp_sf);
|
||||
}
|
||||
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_sf);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ static int parse_dat_header(ubi_sb_header *sb, STREAMFILE *sf);
|
||||
static int parse_header(ubi_sb_header* sb, STREAMFILE* sf, off_t offset, int index);
|
||||
static int parse_sb(ubi_sb_header* sb, STREAMFILE* sf, int target_subsong);
|
||||
static VGMSTREAM* init_vgmstream_ubi_sb_header(ubi_sb_header* sb, STREAMFILE* sf_index, STREAMFILE* sf);
|
||||
static VGMSTREAM *init_vgmstream_ubi_sb_silence(ubi_sb_header *sb, STREAMFILE *sf_index, STREAMFILE *sf);
|
||||
static VGMSTREAM *init_vgmstream_ubi_sb_silence(ubi_sb_header *sb);
|
||||
static int config_sb_platform(ubi_sb_header* sb, STREAMFILE* sf);
|
||||
static int config_sb_version(ubi_sb_header* sb, STREAMFILE* sf);
|
||||
|
||||
@ -542,7 +542,7 @@ static int parse_ubi_bank_header(ubi_sb_header *sb, ubi_sb_header *sb_other, STR
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void get_ubi_bank_name(ubi_sb_header *sb, STREAMFILE *sf, int bank_number, char *bank_name) {
|
||||
static void get_ubi_bank_name(ubi_sb_header *sb, int bank_number, char *bank_name) {
|
||||
if (sb->is_bnm) {
|
||||
sprintf(bank_name, "Bnk_%d.bnm", bank_number);
|
||||
} else if (sb->is_dat) {
|
||||
@ -559,7 +559,7 @@ static int is_other_bank(ubi_sb_header *sb, STREAMFILE *sf, int bank_number) {
|
||||
char bank_name[255];
|
||||
|
||||
get_streamfile_filename(sf, current_name, PATH_LIMIT);
|
||||
get_ubi_bank_name(sb, sf, bank_number, bank_name);
|
||||
get_ubi_bank_name(sb, bank_number, bank_name);
|
||||
|
||||
return strcmp(current_name, bank_name) != 0;
|
||||
}
|
||||
@ -647,7 +647,7 @@ static VGMSTREAM *init_vgmstream_ubi_dat_main(ubi_sb_header *sb, STREAMFILE *sf_
|
||||
VGM_LOG("UBI DAT: external stream '%s' not found\n", sb->resource_name);
|
||||
strncat(sb->readable_name, " (missing)", sizeof(sb->readable_name));
|
||||
sb->duration = (float)pcm_bytes_to_samples(sb->stream_size, sb->channels, 16) / (float)sb->sample_rate;
|
||||
return init_vgmstream_ubi_sb_silence(sb, sf_index, sf);
|
||||
return init_vgmstream_ubi_sb_silence(sb);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1438,7 +1438,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_sequence(ubi_sb_header* sb, STREAMFILE*
|
||||
if (sf_bank != sf_index)
|
||||
close_streamfile(sf_bank);
|
||||
|
||||
get_ubi_bank_name(sb, sf, sb->sequence_banks[i], bank_name);
|
||||
get_ubi_bank_name(sb, sb->sequence_banks[i], bank_name);
|
||||
sf_bank = open_streamfile_by_filename(sf, bank_name);
|
||||
|
||||
/* may be worth trying in localized folder? */
|
||||
@ -1529,7 +1529,7 @@ fail:
|
||||
}
|
||||
|
||||
|
||||
static VGMSTREAM* init_vgmstream_ubi_sb_silence(ubi_sb_header* sb, STREAMFILE* sf_index, STREAMFILE* sf) {
|
||||
static VGMSTREAM* init_vgmstream_ubi_sb_silence(ubi_sb_header* sb) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
int channels, sample_rate;
|
||||
int32_t num_samples;
|
||||
@ -1585,7 +1585,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_header(ubi_sb_header* sb, STREAMFILE* sf
|
||||
break;
|
||||
|
||||
case UBI_SILENCE:
|
||||
vgmstream = init_vgmstream_ubi_sb_silence(sb, sf_index, sf);
|
||||
vgmstream = init_vgmstream_ubi_sb_silence(sb);
|
||||
break;
|
||||
|
||||
case UBI_NONE:
|
||||
|
104
src/meta/vs.c
104
src/meta/vs.c
@ -1,52 +1,52 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .VS - from Melbourne House games [Men in Black II (PS2), Grand Prix Challenge (PS2) */
|
||||
VGMSTREAM * init_vgmstream_vs(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "vs"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0xC8000000)
|
||||
goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = 2;
|
||||
start_offset = 0x08;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_VS;
|
||||
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_blocked_vs;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
/* calc num_samples */
|
||||
{
|
||||
vgmstream->next_block_offset = start_offset;
|
||||
do {
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .VS - from Melbourne House games [Men in Black II (PS2), Grand Prix Challenge (PS2) */
|
||||
VGMSTREAM* init_vgmstream_vs(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channels;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "vs"))
|
||||
goto fail;
|
||||
if (read_u32be(0x00,sf) != 0xC8000000)
|
||||
goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
channels = 2;
|
||||
start_offset = 0x08;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_VS;
|
||||
vgmstream->sample_rate = read_s32le(0x04,sf);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_blocked_vs;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
|
||||
/* calc num_samples */
|
||||
{
|
||||
vgmstream->next_block_offset = start_offset;
|
||||
do {
|
||||
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(sf));
|
||||
block_update(start_offset, vgmstream);
|
||||
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1,56 +1,56 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .vs/STRx - from The Bouncer (PS2) */
|
||||
VGMSTREAM * init_vgmstream_vs_str(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
int channel_count, loop_flag;
|
||||
off_t start_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .vs: real extension (from .nam container)
|
||||
* .str: fake, partial header id */
|
||||
if (!check_extensions(streamFile, "vs,str"))
|
||||
goto fail;
|
||||
|
||||
if (!(read_32bitBE(0x000,streamFile) == 0x5354524C && /* "STRL" */
|
||||
read_32bitBE(0x800,streamFile) == 0x53545252) && /* "STRR" */
|
||||
read_32bitBE(0x00,streamFile) != 0x5354524D) /* "STRM" */
|
||||
goto fail;
|
||||
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = (read_32bitBE(0x00,streamFile) == 0x5354524D) ? 1 : 2; /* "STRM"=mono (voices) */
|
||||
start_offset = 0x00;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_VS_STR;
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_blocked_vs_str;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
/* calc num_samples */
|
||||
{
|
||||
vgmstream->next_block_offset = start_offset;
|
||||
do {
|
||||
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);
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .vs/STRx - from The Bouncer (PS2) */
|
||||
VGMSTREAM* init_vgmstream_vs_str(STREAMFILE* sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
int channel_count, loop_flag;
|
||||
off_t start_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .vs: real extension (from .nam container)
|
||||
* .str: fake, partial header id */
|
||||
if (!check_extensions(sf, "vs,str"))
|
||||
goto fail;
|
||||
|
||||
if (!(read_32bitBE(0x000,sf) == 0x5354524C && /* "STRL" */
|
||||
read_32bitBE(0x800,sf) == 0x53545252) && /* "STRR" */
|
||||
read_32bitBE(0x00,sf) != 0x5354524D) /* "STRM" */
|
||||
goto fail;
|
||||
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = (read_32bitBE(0x00,sf) == 0x5354524D) ? 1 : 2; /* "STRM"=mono (voices) */
|
||||
start_offset = 0x00;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_VS_STR;
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_blocked_vs_str;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
|
||||
goto fail;
|
||||
|
||||
/* calc num_samples */
|
||||
{
|
||||
vgmstream->next_block_offset = start_offset;
|
||||
do {
|
||||
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(sf));
|
||||
block_update(start_offset, vgmstream);
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2,42 +2,43 @@
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* WAF - KID's earlier PC games [ever17 (PC)] (for RLE-compressed WAFs see https://github.com/dsp2003/e17p) */
|
||||
VGMSTREAM * init_vgmstream_waf(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
VGMSTREAM* init_vgmstream_waf(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
int loop_flag, channels;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "waf"))
|
||||
if (!check_extensions(sf, "waf"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) != 0x57414600) /* "WAF\0" */
|
||||
if (!is_id32be(0x00,sf, "WAF\0"))
|
||||
goto fail;
|
||||
if (read_32bitLE(0x34,streamFile) + 0x38 != get_streamfile_size(streamFile))
|
||||
if (read_u32le(0x34,sf) + 0x38 != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
|
||||
channel_count = read_16bitLE(0x06,streamFile);
|
||||
loop_flag = 0;
|
||||
channels = read_u16le(0x06,sf);
|
||||
loop_flag = 0;
|
||||
start_offset = 0x38;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_WAF;
|
||||
vgmstream->sample_rate = read_32bitLE(0x08, streamFile);
|
||||
vgmstream->sample_rate = read_s32le(0x08, sf);
|
||||
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->frame_size = read_16bitLE(0x10, streamFile);
|
||||
vgmstream->frame_size = read_u16le(0x10, sf);
|
||||
/* 0x04: null?, 0x0c: avg br, 0x12: bps, 0x14: s_p_f, 0x16~34: coefs (a modified RIFF fmt) */
|
||||
if (!msadpcm_check_coefs(streamFile, 0x16))
|
||||
if (!msadpcm_check_coefs(sf, 0x16))
|
||||
goto fail;
|
||||
|
||||
vgmstream->num_samples = msadpcm_bytes_to_samples(read_32bitLE(0x34,streamFile), vgmstream->frame_size, channel_count);
|
||||
vgmstream->num_samples = msadpcm_bytes_to_samples(read_u32le(0x34,sf), vgmstream->frame_size, channels);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
|
@ -1,220 +1,220 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
|
||||
#define MAX_SEGMENTS 4
|
||||
|
||||
/* .WAVE - "EngineBlack" games, segmented [Shantae and the Pirate's Curse (PC/3DS), TMNT: Danger of the Ooze (PS3/3DS)] */
|
||||
VGMSTREAM * init_vgmstream_wave_segmented(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t segments_offset;
|
||||
int loop_flag = 0, channel_count, sample_rate;
|
||||
int32_t num_samples, loop_start_sample = 0, loop_end_sample = 0;
|
||||
|
||||
segmented_layout_data *data = NULL;
|
||||
int segment_count, loop_start_segment = 0, loop_end_segment = 0;
|
||||
|
||||
int big_endian;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "wave"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitLE(0x00,streamFile) != 0x4DF72D4A && /* header id */
|
||||
read_32bitBE(0x00,streamFile) != 0x4DF72D4A)
|
||||
goto fail;
|
||||
if (read_8bit(0x04,streamFile) != 0x01) /* version? */
|
||||
goto fail;
|
||||
|
||||
/* PS3/X360 games */
|
||||
big_endian = read_32bitBE(0x00,streamFile) == 0x4DF72D4A;
|
||||
if (big_endian) {
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
} else {
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
}
|
||||
|
||||
channel_count = read_8bit(0x05,streamFile);
|
||||
segment_count = read_16bit(0x06,streamFile);
|
||||
if (segment_count > MAX_SEGMENTS || segment_count <= 0) goto fail;
|
||||
|
||||
loop_start_segment = read_16bit(0x08, streamFile);
|
||||
loop_end_segment = read_16bit(0x0a, streamFile);
|
||||
segments_offset = read_32bit(0x0c, streamFile);
|
||||
|
||||
sample_rate = read_32bit(0x10, streamFile);
|
||||
num_samples = read_32bit(0x14, streamFile);
|
||||
/* 0x18: unknown (usually 0, maybe some count) */
|
||||
|
||||
|
||||
/* init layout */
|
||||
data = init_layout_segmented(segment_count);
|
||||
if (!data) goto fail;
|
||||
|
||||
/* parse segments (usually: preload + intro + loop + ending, intro/ending may be skipped)
|
||||
* Often first segment is ADPCM and rest Ogg; may only have one segment. */
|
||||
{
|
||||
off_t extradata_offset, table_offset, segment_offset;
|
||||
size_t segment_size;
|
||||
int32_t segment_samples;
|
||||
int codec;
|
||||
int i, ch;
|
||||
|
||||
/* open each segment subfile */
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
codec = read_8bit(segments_offset+0x10*i+0x00, streamFile);
|
||||
/* 0x01(1): unknown (flag? usually 0x00/0x01/0x02) */
|
||||
if (read_8bit(segments_offset+0x10*i+0x02, streamFile) != 0x01) goto fail; /* unknown */
|
||||
if (read_8bit(segments_offset+0x10*i+0x03, streamFile) != 0x00) goto fail; /* unknown */
|
||||
|
||||
segment_samples = read_32bit(segments_offset+0x10*i+0x04, streamFile);
|
||||
extradata_offset = read_32bit(segments_offset+0x10*i+0x08, streamFile);
|
||||
table_offset = read_32bit(segments_offset+0x10*i+0x0c, streamFile);
|
||||
|
||||
/* create a sub-VGMSTREAM per segment
|
||||
* (we'll reopen this streamFile as needed, so each sub-VGMSTREAM is fully independent) */
|
||||
switch(codec) {
|
||||
case 0x02: { /* "adpcm" */
|
||||
data->segments[i] = allocate_vgmstream(channel_count, 0);
|
||||
if (!data->segments[i]) goto fail;
|
||||
|
||||
data->segments[i]->sample_rate = sample_rate;
|
||||
data->segments[i]->meta_type = meta_WAVE;
|
||||
data->segments[i]->coding_type = coding_IMA_int;
|
||||
data->segments[i]->layout_type = layout_none;
|
||||
data->segments[i]->num_samples = segment_samples;
|
||||
|
||||
if (!vgmstream_open_stream(data->segments[i],streamFile,0x00))
|
||||
goto fail;
|
||||
|
||||
/* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
|
||||
for (ch = 0; ch < channel_count; ch++) {
|
||||
segment_offset = read_32bit(table_offset + 0x04*ch, streamFile);
|
||||
data->segments[i]->ch[ch].channel_start_offset =
|
||||
data->segments[i]->ch[ch].offset = segment_offset;
|
||||
|
||||
/* ADPCM setup */
|
||||
data->segments[i]->ch[ch].adpcm_history1_32 = read_16bit(extradata_offset+0x04*ch+0x00, streamFile);
|
||||
data->segments[i]->ch[ch].adpcm_step_index = read_8bit(extradata_offset+0x04*ch+0x02, streamFile);
|
||||
/* 0x03: reserved */
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x03: { /* "dsp-adpcm" */
|
||||
data->segments[i] = allocate_vgmstream(channel_count, 0);
|
||||
if (!data->segments[i]) goto fail;
|
||||
|
||||
data->segments[i]->sample_rate = sample_rate;
|
||||
data->segments[i]->meta_type = meta_WAVE;
|
||||
data->segments[i]->coding_type = coding_NGC_DSP;
|
||||
data->segments[i]->layout_type = layout_none;
|
||||
data->segments[i]->num_samples = segment_samples;
|
||||
|
||||
if (!vgmstream_open_stream(data->segments[i],streamFile,0x00))
|
||||
goto fail;
|
||||
|
||||
/* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
|
||||
for (ch = 0; ch < channel_count; ch++) {
|
||||
segment_offset = read_32bit(table_offset + 0x04*ch, streamFile);
|
||||
data->segments[i]->ch[ch].channel_start_offset =
|
||||
data->segments[i]->ch[ch].offset = segment_offset;
|
||||
}
|
||||
|
||||
/* ADPCM setup: 0x06 initial ps/hist1/hist2 (per channel) + 0x20 coefs (per channel) */
|
||||
dsp_read_hist(data->segments[i], streamFile, extradata_offset+0x02, 0x06, big_endian);
|
||||
dsp_read_coefs(data->segments[i], streamFile, extradata_offset+0x06*channel_count+0x00, 0x20, big_endian);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
case 0x04: { /* "vorbis" */
|
||||
ogg_vorbis_meta_info_t ovmi = {0};
|
||||
|
||||
segment_offset = read_32bit(table_offset, streamFile);
|
||||
segment_size = read_32bitBE(segment_offset, streamFile); /* always BE */
|
||||
|
||||
ovmi.meta_type = meta_WAVE;
|
||||
ovmi.stream_size = segment_size;
|
||||
|
||||
data->segments[i] = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, segment_offset+0x04, &ovmi);
|
||||
if (!data->segments[i]) goto fail;
|
||||
|
||||
if (data->segments[i]->num_samples != segment_samples) {
|
||||
VGM_LOG("WAVE: segment %i samples != num_samples\n", i);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default: /* others: s16be/s16le/mp3 as referenced in the exe? */
|
||||
VGM_LOG("WAVE: unknown codec\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* setup segmented VGMSTREAMs */
|
||||
if (!setup_layout_segmented(data))
|
||||
goto fail;
|
||||
|
||||
|
||||
/* parse samples */
|
||||
{
|
||||
int32_t sample_count = 0;
|
||||
int i;
|
||||
|
||||
loop_flag = (loop_start_segment > 0);
|
||||
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
if (loop_flag && loop_start_segment == i) {
|
||||
loop_start_sample = sample_count;
|
||||
}
|
||||
|
||||
sample_count += data->segments[i]->num_samples;
|
||||
|
||||
if (loop_flag && loop_end_segment-1 == i) {
|
||||
loop_end_sample = sample_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_count != num_samples) {
|
||||
VGM_LOG("WAVE: total segments samples %i != num_samples %i\n", sample_count, num_samples);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = num_samples;
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
|
||||
vgmstream->meta_type = meta_WAVE_segmented;
|
||||
vgmstream->stream_size = get_streamfile_size(streamFile); /* wrong kbps otherwise */
|
||||
|
||||
/* .wave can mix codecs, usually first segment is a small ADPCM section) */
|
||||
vgmstream->coding_type = (segment_count == 1 ? data->segments[0]->coding_type : data->segments[1]->coding_type);
|
||||
vgmstream->layout_type = layout_segmented;
|
||||
vgmstream->layout_data = data;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
free_layout_segmented(data);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
|
||||
#define MAX_SEGMENTS 4
|
||||
|
||||
/* .WAVE - "EngineBlack" games, segmented [Shantae and the Pirate's Curse (PC/3DS), TMNT: Danger of the Ooze (PS3/3DS)] */
|
||||
VGMSTREAM * init_vgmstream_wave_segmented(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t segments_offset;
|
||||
int loop_flag = 0, channel_count, sample_rate;
|
||||
int32_t num_samples, loop_start_sample = 0, loop_end_sample = 0;
|
||||
|
||||
segmented_layout_data *data = NULL;
|
||||
int segment_count, loop_start_segment = 0, loop_end_segment = 0;
|
||||
|
||||
int big_endian;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "wave"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitLE(0x00,sf) != 0x4DF72D4A && /* header id */
|
||||
read_32bitBE(0x00,sf) != 0x4DF72D4A)
|
||||
goto fail;
|
||||
if (read_8bit(0x04,sf) != 0x01) /* version? */
|
||||
goto fail;
|
||||
|
||||
/* PS3/X360 games */
|
||||
big_endian = read_32bitBE(0x00,sf) == 0x4DF72D4A;
|
||||
if (big_endian) {
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
} else {
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
}
|
||||
|
||||
channel_count = read_8bit(0x05,sf);
|
||||
segment_count = read_16bit(0x06,sf);
|
||||
if (segment_count > MAX_SEGMENTS || segment_count <= 0) goto fail;
|
||||
|
||||
loop_start_segment = read_16bit(0x08, sf);
|
||||
loop_end_segment = read_16bit(0x0a, sf);
|
||||
segments_offset = read_32bit(0x0c, sf);
|
||||
|
||||
sample_rate = read_32bit(0x10, sf);
|
||||
num_samples = read_32bit(0x14, sf);
|
||||
/* 0x18: unknown (usually 0, maybe some count) */
|
||||
|
||||
|
||||
/* init layout */
|
||||
data = init_layout_segmented(segment_count);
|
||||
if (!data) goto fail;
|
||||
|
||||
/* parse segments (usually: preload + intro + loop + ending, intro/ending may be skipped)
|
||||
* Often first segment is ADPCM and rest Ogg; may only have one segment. */
|
||||
{
|
||||
off_t extradata_offset, table_offset, segment_offset;
|
||||
size_t segment_size;
|
||||
int32_t segment_samples;
|
||||
int codec;
|
||||
int i, ch;
|
||||
|
||||
/* open each segment subfile */
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
codec = read_8bit(segments_offset+0x10*i+0x00, sf);
|
||||
/* 0x01(1): unknown (flag? usually 0x00/0x01/0x02) */
|
||||
if (read_8bit(segments_offset+0x10*i+0x02, sf) != 0x01) goto fail; /* unknown */
|
||||
if (read_8bit(segments_offset+0x10*i+0x03, sf) != 0x00) goto fail; /* unknown */
|
||||
|
||||
segment_samples = read_32bit(segments_offset+0x10*i+0x04, sf);
|
||||
extradata_offset = read_32bit(segments_offset+0x10*i+0x08, sf);
|
||||
table_offset = read_32bit(segments_offset+0x10*i+0x0c, sf);
|
||||
|
||||
/* create a sub-VGMSTREAM per segment
|
||||
* (we'll reopen this sf as needed, so each sub-VGMSTREAM is fully independent) */
|
||||
switch(codec) {
|
||||
case 0x02: { /* "adpcm" */
|
||||
data->segments[i] = allocate_vgmstream(channel_count, 0);
|
||||
if (!data->segments[i]) goto fail;
|
||||
|
||||
data->segments[i]->sample_rate = sample_rate;
|
||||
data->segments[i]->meta_type = meta_WAVE;
|
||||
data->segments[i]->coding_type = coding_IMA_int;
|
||||
data->segments[i]->layout_type = layout_none;
|
||||
data->segments[i]->num_samples = segment_samples;
|
||||
|
||||
if (!vgmstream_open_stream(data->segments[i],sf,0x00))
|
||||
goto fail;
|
||||
|
||||
/* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
|
||||
for (ch = 0; ch < channel_count; ch++) {
|
||||
segment_offset = read_32bit(table_offset + 0x04*ch, sf);
|
||||
data->segments[i]->ch[ch].channel_start_offset =
|
||||
data->segments[i]->ch[ch].offset = segment_offset;
|
||||
|
||||
/* ADPCM setup */
|
||||
data->segments[i]->ch[ch].adpcm_history1_32 = read_16bit(extradata_offset+0x04*ch+0x00, sf);
|
||||
data->segments[i]->ch[ch].adpcm_step_index = read_8bit(extradata_offset+0x04*ch+0x02, sf);
|
||||
/* 0x03: reserved */
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x03: { /* "dsp-adpcm" */
|
||||
data->segments[i] = allocate_vgmstream(channel_count, 0);
|
||||
if (!data->segments[i]) goto fail;
|
||||
|
||||
data->segments[i]->sample_rate = sample_rate;
|
||||
data->segments[i]->meta_type = meta_WAVE;
|
||||
data->segments[i]->coding_type = coding_NGC_DSP;
|
||||
data->segments[i]->layout_type = layout_none;
|
||||
data->segments[i]->num_samples = segment_samples;
|
||||
|
||||
if (!vgmstream_open_stream(data->segments[i],sf,0x00))
|
||||
goto fail;
|
||||
|
||||
/* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
|
||||
for (ch = 0; ch < channel_count; ch++) {
|
||||
segment_offset = read_32bit(table_offset + 0x04*ch, sf);
|
||||
data->segments[i]->ch[ch].channel_start_offset =
|
||||
data->segments[i]->ch[ch].offset = segment_offset;
|
||||
}
|
||||
|
||||
/* ADPCM setup: 0x06 initial ps/hist1/hist2 (per channel) + 0x20 coefs (per channel) */
|
||||
dsp_read_hist(data->segments[i], sf, extradata_offset+0x02, 0x06, big_endian);
|
||||
dsp_read_coefs(data->segments[i], sf, extradata_offset+0x06*channel_count+0x00, 0x20, big_endian);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
case 0x04: { /* "vorbis" */
|
||||
ogg_vorbis_meta_info_t ovmi = {0};
|
||||
|
||||
segment_offset = read_32bit(table_offset, sf);
|
||||
segment_size = read_32bitBE(segment_offset, sf); /* always BE */
|
||||
|
||||
ovmi.meta_type = meta_WAVE;
|
||||
ovmi.stream_size = segment_size;
|
||||
|
||||
data->segments[i] = init_vgmstream_ogg_vorbis_config(sf, segment_offset+0x04, &ovmi);
|
||||
if (!data->segments[i]) goto fail;
|
||||
|
||||
if (data->segments[i]->num_samples != segment_samples) {
|
||||
VGM_LOG("WAVE: segment %i samples != num_samples\n", i);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default: /* others: s16be/s16le/mp3 as referenced in the exe? */
|
||||
VGM_LOG("WAVE: unknown codec\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* setup segmented VGMSTREAMs */
|
||||
if (!setup_layout_segmented(data))
|
||||
goto fail;
|
||||
|
||||
|
||||
/* parse samples */
|
||||
{
|
||||
int32_t sample_count = 0;
|
||||
int i;
|
||||
|
||||
loop_flag = (loop_start_segment > 0);
|
||||
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
if (loop_flag && loop_start_segment == i) {
|
||||
loop_start_sample = sample_count;
|
||||
}
|
||||
|
||||
sample_count += data->segments[i]->num_samples;
|
||||
|
||||
if (loop_flag && loop_end_segment-1 == i) {
|
||||
loop_end_sample = sample_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_count != num_samples) {
|
||||
VGM_LOG("WAVE: total segments samples %i != num_samples %i\n", sample_count, num_samples);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = num_samples;
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
|
||||
vgmstream->meta_type = meta_WAVE_segmented;
|
||||
vgmstream->stream_size = get_streamfile_size(sf); /* wrong kbps otherwise */
|
||||
|
||||
/* .wave can mix codecs, usually first segment is a small ADPCM section) */
|
||||
vgmstream->coding_type = (segment_count == 1 ? data->segments[0]->coding_type : data->segments[1]->coding_type);
|
||||
vgmstream->layout_type = layout_segmented;
|
||||
vgmstream->layout_data = data;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
free_layout_segmented(data);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1,138 +1,135 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* WBAT - Firebrand Games header [Need for Speed: The Run (3DS), Fast & Furious: Showdown (3DS)] */
|
||||
VGMSTREAM * init_vgmstream_wavebatch(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, name_offset, offset, stream_offset;
|
||||
size_t names_size, stream_size;
|
||||
int loop_flag, channel_count, sample_rate, num_samples;
|
||||
int big_endian, version, codec;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "wavebatch"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x54414257) /* "TABW" */
|
||||
goto fail;
|
||||
|
||||
/* section0: base header */
|
||||
big_endian = ((uint16_t)read_16bitBE(0x04,streamFile) == 0xFEFF); /* BOM (always LE on 3DS/Android) */
|
||||
if (big_endian) {
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
} else {
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
}
|
||||
|
||||
|
||||
version = read_16bit(0x06, streamFile); /* assumed */
|
||||
if (version != 0x06 && version != 0x07) /* v6 = NFS: The Run , v7 = F&F Showndown */
|
||||
goto fail;
|
||||
|
||||
total_subsongs = read_32bit(0x08,streamFile);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
names_size = read_32bit(0x0c,streamFile);
|
||||
/* 0x10/14: see below */
|
||||
/* 0x18: data size (all subsongs) */
|
||||
offset = 0x1c + names_size; /* skip names table */
|
||||
|
||||
/* the following 2 sections (rarely) won't match total_subsongs */
|
||||
|
||||
/* section1: unknown */
|
||||
{
|
||||
size_t unknown_size = read_32bit(0x10,streamFile);
|
||||
/* 0x00: usually 0, rarely 0x20? */
|
||||
offset += unknown_size*0x04;
|
||||
}
|
||||
|
||||
/* section2: samples */
|
||||
{
|
||||
size_t samples_size = read_32bit(0x14,streamFile);
|
||||
/* 0x00: num_samples */
|
||||
offset += samples_size*0x04;
|
||||
}
|
||||
|
||||
/* section3: headers */
|
||||
{
|
||||
off_t header_offset = offset+(target_subsong-1)*0x24;
|
||||
|
||||
name_offset = read_32bit(header_offset+0x00, streamFile) + 0x1c; /* within name table */
|
||||
codec = read_32bit(header_offset+0x04, streamFile);
|
||||
sample_rate = read_32bit(header_offset+0x08, streamFile);
|
||||
channel_count = read_32bit(header_offset+0x0c, streamFile);
|
||||
/* 0x10: index within section1/2? */
|
||||
/* 0x14: flags? 0x01 or (rarely) 0x02 */
|
||||
stream_offset = read_32bit(header_offset+0x18, streamFile);
|
||||
stream_size = read_32bit(header_offset+0x1c, streamFile); /* including DSP config */
|
||||
num_samples = read_32bit(header_offset+0x20, streamFile) / channel_count; /* nibble/PCMs */
|
||||
|
||||
offset += total_subsongs*0x24;
|
||||
}
|
||||
|
||||
loop_flag = 0;
|
||||
start_offset = offset + stream_offset;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = num_samples;
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = stream_size;
|
||||
|
||||
vgmstream->meta_type = meta_WAVEBATCH;
|
||||
|
||||
switch(codec) {
|
||||
case 0x00: /* PCM16 [NASCAR Unleashed (3DS), Solar Flux Pocket (Android)] */
|
||||
vgmstream->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
break;
|
||||
|
||||
case 0x01: /* PCM8 [Cars 2 (3DS)] */
|
||||
vgmstream->coding_type = coding_PCM8;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x01;
|
||||
break;
|
||||
|
||||
case 0x02: { /* DSP [WRC FIA World Rally Championship (3DS)] */
|
||||
size_t config_size = (0x20+0x14)*channel_count + (0x0c)*channel_count; /* coefs+hist + padding */
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = (stream_size - config_size) / channel_count; /* full interleave*/;
|
||||
|
||||
dsp_read_coefs(vgmstream,streamFile,start_offset+0x00,0x20+0x14,big_endian);
|
||||
dsp_read_hist (vgmstream,streamFile,start_offset+0x20,0x14+0x20,big_endian);
|
||||
start_offset += config_size;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
VGM_LOG("WAVEBATCH: unknown codec %x\n", codec);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
|
||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamFile); /* always null-terminated */
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* WBAT - Firebrand Games header [Need for Speed: The Run (3DS), Fast & Furious: Showdown (3DS)] */
|
||||
VGMSTREAM * init_vgmstream_wavebatch(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, name_offset, offset, stream_offset;
|
||||
size_t names_size, stream_size;
|
||||
int loop_flag, channel_count, sample_rate, num_samples;
|
||||
int big_endian, version, codec;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "wavebatch"))
|
||||
goto fail;
|
||||
if (!is_id32be(0x00,sf, "TABW"))
|
||||
goto fail;
|
||||
|
||||
/* section0: base header */
|
||||
big_endian = (read_u16be(0x04,sf) == 0xFEFF); /* BOM (always LE on 3DS/Android) */
|
||||
if (big_endian) {
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
} else {
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
}
|
||||
|
||||
|
||||
version = read_16bit(0x06, sf); /* assumed */
|
||||
if (version != 0x06 && version != 0x07) /* v6 = NFS: The Run , v7 = F&F Showndown */
|
||||
goto fail;
|
||||
|
||||
total_subsongs = read_32bit(0x08,sf);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
names_size = read_32bit(0x0c,sf);
|
||||
/* 0x10/14: see below */
|
||||
/* 0x18: data size (all subsongs) */
|
||||
offset = 0x1c + names_size; /* skip names table */
|
||||
|
||||
/* the following 2 sections (rarely) won't match total_subsongs */
|
||||
|
||||
/* section1: unknown */
|
||||
{
|
||||
size_t unknown_size = read_32bit(0x10,sf);
|
||||
/* 0x00: usually 0, rarely 0x20? */
|
||||
offset += unknown_size*0x04;
|
||||
}
|
||||
|
||||
/* section2: samples */
|
||||
{
|
||||
size_t samples_size = read_32bit(0x14,sf);
|
||||
/* 0x00: num_samples */
|
||||
offset += samples_size*0x04;
|
||||
}
|
||||
|
||||
/* section3: headers */
|
||||
{
|
||||
off_t header_offset = offset+(target_subsong-1)*0x24;
|
||||
|
||||
name_offset = read_32bit(header_offset+0x00, sf) + 0x1c; /* within name table */
|
||||
codec = read_32bit(header_offset+0x04, sf);
|
||||
sample_rate = read_32bit(header_offset+0x08, sf);
|
||||
channel_count = read_32bit(header_offset+0x0c, sf);
|
||||
/* 0x10: index within section1/2? */
|
||||
/* 0x14: flags? 0x01 or (rarely) 0x02 */
|
||||
stream_offset = read_32bit(header_offset+0x18, sf);
|
||||
stream_size = read_32bit(header_offset+0x1c, sf); /* including DSP config */
|
||||
num_samples = read_32bit(header_offset+0x20, sf) / channel_count; /* nibble/PCMs */
|
||||
|
||||
offset += total_subsongs*0x24;
|
||||
}
|
||||
|
||||
loop_flag = 0;
|
||||
start_offset = offset + stream_offset;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = num_samples;
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = stream_size;
|
||||
|
||||
vgmstream->meta_type = meta_WAVEBATCH;
|
||||
|
||||
switch(codec) {
|
||||
case 0x00: /* PCM16 [NASCAR Unleashed (3DS), Solar Flux Pocket (Android)] */
|
||||
vgmstream->coding_type = big_endian ? coding_PCM16BE : coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
break;
|
||||
|
||||
case 0x01: /* PCM8 [Cars 2 (3DS)] */
|
||||
vgmstream->coding_type = coding_PCM8;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x01;
|
||||
break;
|
||||
|
||||
case 0x02: { /* DSP [WRC FIA World Rally Championship (3DS)] */
|
||||
size_t config_size = (0x20+0x14)*channel_count + (0x0c)*channel_count; /* coefs+hist + padding */
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = (stream_size - config_size) / channel_count; /* full interleave*/;
|
||||
|
||||
dsp_read_coefs(vgmstream,sf,start_offset+0x00,0x20+0x14,big_endian);
|
||||
dsp_read_hist (vgmstream,sf,start_offset+0x20,0x14+0x20,big_endian);
|
||||
start_offset += config_size;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
VGM_LOG("WAVEBATCH: unknown codec %x\n", codec);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,sf); /* always null-terminated */
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -62,10 +62,10 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
||||
char reader_name[255+1];
|
||||
size_t string_len;
|
||||
uint8_t type_count;
|
||||
const static char* type_sound = "Microsoft.Xna.Framework.Content.SoundEffectReader"; /* partial "fmt" chunk or XMA */
|
||||
const static char* type_ogg = "SoundEffectFromOggReader"; /* has extra text info after base part */
|
||||
const static char* type_song = "Microsoft.Xna.Framework.Content.SongReader"; /* references a companion .wma */
|
||||
const static char* type_int32 = "Microsoft.Xna.Framework.Content.Int32Reader"; /* extra crap */
|
||||
static const char* type_sound = "Microsoft.Xna.Framework.Content.SoundEffectReader"; /* partial "fmt" chunk or XMA */
|
||||
static const char* type_ogg = "SoundEffectFromOggReader"; /* has extra text info after base part */
|
||||
static const char* type_song = "Microsoft.Xna.Framework.Content.SongReader"; /* references a companion .wma */
|
||||
static const char* type_int32 = "Microsoft.Xna.Framework.Content.Int32Reader"; /* extra crap */
|
||||
|
||||
type_count = read_u8(offset++, sf_h);
|
||||
|
||||
|
@ -128,6 +128,9 @@ VGMSTREAM* init_vgmstream_xssb(STREAMFILE *sf) {
|
||||
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(h.stream_size, h.channels);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, h.stream_start))
|
||||
|
@ -680,6 +680,7 @@ void mixing_push_fade(VGMSTREAM* vgmstream, int ch_dst, double vol_start, double
|
||||
}
|
||||
else if (mix_prev->time_post < 0 || mix.time_pre < 0) {
|
||||
int is_prev = 1;
|
||||
/* test if prev is really cancelled by this */
|
||||
if ((mix_prev->time_end > mix.time_start) ||
|
||||
(mix_prev->time_post >= 0 && mix_prev->time_post > mix.time_start) ||
|
||||
(mix.time_pre >= 0 && mix.time_pre < mix_prev->time_end))
|
||||
@ -687,12 +688,12 @@ void mixing_push_fade(VGMSTREAM* vgmstream, int ch_dst, double vol_start, double
|
||||
|
||||
if (is_prev) {
|
||||
/* change negative values to actual points */
|
||||
if (mix_prev->time_post < 0 && mix_prev->time_post < 0) {
|
||||
if (mix_prev->time_post < 0 && mix.time_pre < 0) {
|
||||
mix_prev->time_post = mix_prev->time_end;
|
||||
mix.time_pre = mix_prev->time_post;
|
||||
}
|
||||
if (mix_prev->time_post >= 0 && mix.time_pre < 0) {
|
||||
|
||||
if (mix_prev->time_post >= 0 && mix.time_pre < 0) {
|
||||
mix.time_pre = mix_prev->time_post;
|
||||
}
|
||||
else if (mix_prev->time_post < 0 && mix.time_pre >= 0) {
|
||||
|
@ -31,14 +31,6 @@ enum { VGMSTREAM_MAX_NUM_SAMPLES = 1000000000 }; /* no ~5h vgm hopefully */
|
||||
//#define VGM_USE_SPEEX
|
||||
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
#include <vorbis/vorbisfile.h>
|
||||
#endif
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
#include <mpg123.h>
|
||||
#endif
|
||||
|
||||
#ifdef VGM_USE_MP4V2
|
||||
#define MP4V2_NO_STDINT_DEFS
|
||||
#include <mp4v2/mp4v2.h>
|
||||
@ -48,14 +40,9 @@ enum { VGMSTREAM_MAX_NUM_SAMPLES = 1000000000 }; /* no ~5h vgm hopefully */
|
||||
#include <aacdecoder_lib.h>
|
||||
#endif
|
||||
|
||||
#ifdef VGM_USE_MAIATRAC3PLUS
|
||||
#include <maiatrac3plus.h>
|
||||
#endif
|
||||
|
||||
#include <clHCA.h>
|
||||
|
||||
#include "coding/g72x_state.h"
|
||||
#include "coding/nwa_decoder.h"
|
||||
|
||||
|
||||
/* The encoding type specifies the format the sound data itself takes */
|
||||
|
@ -16,7 +16,11 @@ endif
|
||||
### main defs
|
||||
OUTPUT_WINAMP = in_vgmstream.dll
|
||||
|
||||
CFLAGS += $(DEF_CFLAGS) -DUSE_ALLOCA -DWIN32 -I../ext_includes $(EXTRA_CFLAGS)
|
||||
ifeq ($(TARGET_OS),Windows_NT)
|
||||
CFLAGS += -m32 -DUSE_ALLOCA -DWIN32 -I../ext_includes/ffmpeg
|
||||
endif
|
||||
|
||||
CFLAGS += $(DEF_CFLAGS) -I../ext_includes $(EXTRA_CFLAGS)
|
||||
LDFLAGS += -L../src -L../ext_libs -lm -lvgmstream $(EXTRA_LDFLAGS)
|
||||
TARGET_EXT_LIBS =
|
||||
|
||||
|
@ -16,8 +16,10 @@
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <commctrl.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "../src/vgmstream.h"
|
||||
#include "../src/plugins.h"
|
||||
|
@ -16,7 +16,11 @@ endif
|
||||
### main defs
|
||||
OUTPUT_XMPLAY = xmp-vgmstream.dll
|
||||
|
||||
CFLAGS += $(DEF_CFLAGS) -DUSE_ALLOCA -DWIN32 -I../ext_includes $(EXTRA_CFLAGS)
|
||||
ifeq ($(TARGET_OS),Windows_NT)
|
||||
CFLAGS += -m32 -DUSE_ALLOCA -DWIN32 -I../ext_includes/ffmpeg
|
||||
endif
|
||||
|
||||
CFLAGS += $(DEF_CFLAGS) -I../ext_includes $(EXTRA_CFLAGS)
|
||||
LDFLAGS += -L../src -L../ext_libs -lm -lvgmstream $(EXTRA_LDFLAGS)
|
||||
TARGET_EXT_LIBS =
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user