mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 08:20:54 +01:00
Merge pull request #910 from bnnm/relic-build
- Fix some Relic decoder issues - Add Relic .wxd+wxh and .bnk [Homeworld (PC)] - Fix some .sts issues [Shikigami no Shiro 3 (Wii)] - Remove unused .vcproj (use CMake if needed) - misc cleanup - misc build fixes and tweaks
This commit is contained in:
commit
17afbab199
10
.gitattributes
vendored
Normal file
10
.gitattributes
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
# don't set for now (too many fixes at once)
|
||||
#* text=auto
|
||||
#*.c text=auto
|
||||
#*.h text=auto
|
||||
* -text
|
||||
|
||||
*.sh text eol=lf
|
||||
*.bat text eol=crlf
|
||||
*.vcxproj text eol=crlf
|
||||
*.vcxproj.filters text eol=crlf
|
28
.github/workflows/vs-win.yml
vendored
28
.github/workflows/vs-win.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
# This workflow contains a single job called "build"
|
||||
build:
|
||||
name: VS 2017
|
||||
|
||||
|
||||
# The type of runner that the job will run on
|
||||
runs-on: windows-2016
|
||||
|
||||
@ -23,16 +23,16 @@ jobs:
|
||||
- name: Fetch Git tags
|
||||
shell: cmd
|
||||
run: git fetch --prune --unshallow --tags
|
||||
|
||||
|
||||
- name: Initialize Build Environment
|
||||
shell: cmd
|
||||
run: powershell -ExecutionPolicy Bypass -NoProfile -File .\build.ps1 Init
|
||||
run: powershell -ExecutionPolicy Bypass -NoProfile -File .\msvc-build.ps1 Init
|
||||
|
||||
# Runs a single command using the runners shell
|
||||
- name: Build
|
||||
shell: cmd
|
||||
run: powershell -ExecutionPolicy Bypass -NoProfile -File .\build.ps1 Build
|
||||
|
||||
run: powershell -ExecutionPolicy Bypass -NoProfile -File .\msvc-build.ps1 Build
|
||||
|
||||
- name: Prepare Files For Packaging
|
||||
shell: powershell
|
||||
run: |
|
||||
@ -62,47 +62,47 @@ jobs:
|
||||
"Release/test.pdb",
|
||||
"Release/xmp-vgmstream.pdb"
|
||||
)
|
||||
|
||||
|
||||
Compress-Archive $cliFiles Release/vgmstream-win.zip -Force
|
||||
Compress-Archive $fb2kFiles Release/foo_input_vgmstream.zip -Force
|
||||
Move-Item Release/foo_input_vgmstream.zip Release/foo_input_vgmstream.fb2k-component -Force
|
||||
Compress-Archive $cliPdbFiles Release/test.pdb.zip -Force
|
||||
Compress-Archive $fb2kPdbFiles Release/foo_input_vgmstream.pdb.zip -Force
|
||||
|
||||
|
||||
mkdir tmp/cli
|
||||
mkdir tmp/fb2k
|
||||
mkdir tmp/cli-p
|
||||
mkdir tmp/fb2k-p
|
||||
|
||||
|
||||
Copy-Item $cliFiles tmp/cli/ -Recurse -Force
|
||||
Copy-Item $fb2kFiles tmp/fb2k/ -Recurse -Force
|
||||
Copy-Item $cliPdbFiles tmp/cli-p/ -Recurse -Force
|
||||
Copy-Item $fb2kPdbFiles tmp/fb2k-p/ -Recurse -Force
|
||||
|
||||
|
||||
- name: Upload foobar2000 Component Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: foo_input_vgmstream.fb2k-component
|
||||
path: ${{github.workspace}}\tmp\fb2k
|
||||
|
||||
|
||||
- name: Upload CLI Tools Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: test
|
||||
path: ${{github.workspace}}\tmp\cli
|
||||
|
||||
|
||||
- name: Upload foobar2000 Component Debug Symbols Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: foo_input_vgmstream.pdb
|
||||
path: ${{github.workspace}}\tmp\fb2k-p
|
||||
|
||||
|
||||
- name: Upload CLI Tools Debug Symbols Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: test.pdb
|
||||
path: ${{github.workspace}}\tmp\cli-p
|
||||
|
||||
|
||||
- name: Upload Artifacts to S3
|
||||
if: github.event_name != 'pull_request'
|
||||
working-directory: ${{github.workspace}}
|
||||
@ -120,7 +120,7 @@ jobs:
|
||||
git describe --always | tee latest_ver
|
||||
aws s3 cp latest_id s3://vgmstream-builds/ --acl public-read
|
||||
aws s3 cp latest_ver s3://vgmstream-builds/ --acl public-read
|
||||
|
||||
|
||||
- name: Web Request Action
|
||||
uses: Satak/webrequest-action@v1.2.3
|
||||
if: github.event_name != 'pull_request'
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -45,7 +45,7 @@ Release
|
||||
/xmplay/*.dll
|
||||
/dependencies
|
||||
/version.h
|
||||
/version.mk
|
||||
/msvc-build.config.ps1
|
||||
|
||||
/**/vgmstream-win.zip
|
||||
/**/foo_input_vgmstream.fb2k-component
|
||||
|
@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.5)
|
||||
project(vgmstream C)
|
||||
enable_language(CXX)
|
||||
|
||||
# TODO defautl out-of-source-builds not working properly?
|
||||
# (like "cmake .." from ./build subdir creates makefiles on ./, unless using "cmake -S ..")
|
||||
get_directory_property(hasParent PARENT_DIRECTORY)
|
||||
if(hasParent)
|
||||
set(VGM_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE)
|
||||
@ -12,6 +14,13 @@ set(VGM_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(CMAKE_MODULE_PATH ${VGM_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH})
|
||||
include(vgmstream)
|
||||
|
||||
# Defaults for Windows, otherwise may be Program Files/vgmstream
|
||||
if(WIN32)
|
||||
IF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
SET(CMAKE_INSTALL_PREFIX ${VGM_SOURCE_DIR} CACHE PATH "..." FORCE)
|
||||
ENDIF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
endif()
|
||||
|
||||
function(set_mpeg onoff useForce)
|
||||
if(useForce)
|
||||
set(USE_FORCE_ FORCE)
|
||||
@ -51,10 +60,12 @@ endif()
|
||||
# Build choices
|
||||
option(BUILD_CLI "Build vgmstream CLI" ON)
|
||||
if(WIN32)
|
||||
option(BUILD_FB2K "Build foobar2000 component" ON)
|
||||
set(FB2K_SDK_PATH CACHE PATH "Path to foobar2000 SDK")
|
||||
set(WTL_INCLUDE_PATH CACHE PATH "Path to WTL include directory")
|
||||
set(FB2K_COMPONENT_INSTALL_PREFIX CACHE PATH "Path to foobar2000 component installation directory")
|
||||
if(MSVC)
|
||||
option(BUILD_FB2K "Build foobar2000 component" ON)
|
||||
set(FB2K_SDK_PATH CACHE PATH "Path to foobar2000 SDK")
|
||||
set(WTL_INCLUDE_PATH CACHE PATH "Path to WTL include directory")
|
||||
set(FB2K_COMPONENT_INSTALL_PREFIX CACHE PATH "Path to foobar2000 component installation directory")
|
||||
endif()
|
||||
option(BUILD_WINAMP "Build Winamp plugin" ON)
|
||||
set(WINAMP_INSTALL_PREFIX CACHE PATH "Path to Winamp installation directory")
|
||||
option(BUILD_XMPLAY "Build XMPlay plugin" ON)
|
||||
@ -63,6 +74,26 @@ else()
|
||||
option(BUILD_AUDACIOUS "Build Audacious plugin" ON)
|
||||
endif()
|
||||
|
||||
# Autodetect some paths
|
||||
if(MSVC AND NOT FB2K_SDK_PATH AND IS_DIRECTORY "${VGM_SOURCE_DIR}/dependencies/foobar/")
|
||||
set(FB2K_SDK_PATH "${VGM_SOURCE_DIR}/dependencies/foobar/" CACHE PATH "..." FORCE)
|
||||
endif()
|
||||
if(MSVC AND NOT WTL_INCLUDE_PATH AND IS_DIRECTORY "${VGM_SOURCE_DIR}/dependencies/wtl/")
|
||||
set(WTL_INCLUDE_PATH "${VGM_SOURCE_DIR}/dependencies/wtl/" CACHE PATH "..." FORCE)
|
||||
endif()
|
||||
|
||||
# Set autogenerated version
|
||||
if(MSVC)
|
||||
set(VGM_VERSION_GENERATOR version-make.bat)
|
||||
else()
|
||||
set(VGM_VERSION_GENERATOR version-make.sh)
|
||||
endif()
|
||||
add_custom_command(OUTPUT ${VGM_SOURCE_DIR}/version.h
|
||||
COMMAND "${VGM_SOURCE_DIR}/${VGM_VERSION_GENERATOR}"
|
||||
DEPENDS ${VGM_SOURCE_DIR}/${VGM_VERSION_GENERATOR})
|
||||
add_custom_target(version_h ALL DEPENDS ${VGM_SOURCE_DIR}/version.h)
|
||||
|
||||
# FFmpeg detection
|
||||
if(USE_FFMPEG)
|
||||
find_package(FFmpeg)
|
||||
if(NOT FFMPEG_LIBRARIES)
|
||||
@ -89,33 +120,9 @@ if(WIN32)
|
||||
set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>")
|
||||
endif(MINGW)
|
||||
|
||||
# Update the version
|
||||
set(CMAKE_EXECUTABLE_SUFFIX .exe)
|
||||
if(MSVC)
|
||||
file(TO_NATIVE_PATH "${VGM_BINARY_DIR}/version.h" VERSION_H_PATH)
|
||||
add_custom_command(OUTPUT ${VGM_BINARY_DIR}/version.h
|
||||
COMMAND "${VGM_SOURCE_DIR}/version.bat"
|
||||
ARGS ${VERSION_H_PATH} VERSION
|
||||
DEPENDS ${VGM_SOURCE_DIR}/version.bat)
|
||||
add_custom_target(version_h DEPENDS ${VGM_BINARY_DIR}/version.h)
|
||||
else()
|
||||
find_package(Git)
|
||||
if(GIT_FOUND)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
|
||||
WORKING_DIRECTORY ${VGM_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE VGMSTREAM_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
else()
|
||||
# Update the version
|
||||
find_package(Git)
|
||||
if(GIT_FOUND)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
|
||||
WORKING_DIRECTORY ${VGM_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE VGMSTREAM_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif()
|
||||
|
||||
# Find the relevant packages
|
||||
if(USE_MPEG)
|
||||
@ -134,8 +141,11 @@ else()
|
||||
# If building the CLI, we need to include AO as well
|
||||
if(BUILD_CLI)
|
||||
find_package(AO)
|
||||
if(NOT AO_FOUND)
|
||||
message(FATAL_ERROR "Cannot build vgmstream123 without libao")
|
||||
if(AO_FOUND)
|
||||
set(USE_V123 ON)
|
||||
else (AO_FOUND)
|
||||
#TODO: add proper separate option
|
||||
set(USE_V123 OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -277,7 +287,8 @@ if(WIN32)
|
||||
message(STATUS " Winamp plugin: ${BUILD_WINAMP}")
|
||||
message(STATUS " XMPlay plugin: ${BUILD_XMPLAY}")
|
||||
else()
|
||||
message(STATUS "CLI/vgmstream123: ${BUILD_CLI}")
|
||||
message(STATUS " CLI: ${BUILD_CLI}")
|
||||
message(STATUS " vgmstream123: ${USE_V123}")
|
||||
message(STATUS " JSON dumping: ${USE_JANSSON}")
|
||||
message(STATUS "Audacious plugin: ${BUILD_AUDACIOUS}")
|
||||
endif()
|
||||
|
33
Makefile
33
Makefile
@ -2,6 +2,19 @@
|
||||
# vgmstream makefile
|
||||
###############################
|
||||
|
||||
ifeq ($(VGMSTREAM_VERSION),)
|
||||
# for current dir (expanded later)
|
||||
VGMSTREAM_VERSION_CURR=`./version-get.sh`
|
||||
# for subdirs (expanded later)
|
||||
VGMSTREAM_VERSION_PREV=`../version-get.sh`
|
||||
else
|
||||
VGMSTREAM_VERSION_CURR=$(VGMSTREAM_VERSION)
|
||||
VGMSTREAM_VERSION_PREV=$(VGMSTREAM_VERSION)
|
||||
endif
|
||||
|
||||
export VGMSTREAM_VERSION_PREV
|
||||
|
||||
|
||||
###############################################################################
|
||||
### external defs
|
||||
# currently aimed to WIN32 builds but vgmstream_cli should work for others (or use autotools instead)
|
||||
@ -50,7 +63,7 @@ export RMF SHELL CC AR STRIP WINDRES DLLTOOL
|
||||
###############################################################################
|
||||
### build defs
|
||||
|
||||
DEF_CFLAGS = -ffast-math -O3 -Wall -Werror=format-security -Wlogical-op -Wdeclaration-after-statement -Wvla -Wimplicit-function-declaration -Wignored-qualifiers
|
||||
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)
|
||||
@ -167,20 +180,20 @@ buildrelease-ex: clean bin-ex
|
||||
buildfullrelease: clean sourceball bin
|
||||
|
||||
sourceball:
|
||||
rm -rf vgmstream-`./version.sh`
|
||||
git checkout-index -f -a --prefix=vgmstream-`./version.sh`/
|
||||
# git archive --format zip --output vgmstream-`./version.sh`.zip master
|
||||
echo "#!/bin/sh" > vgmstream-`./version.sh`/version.sh
|
||||
echo "echo \"`./version.sh`\"" >> vgmstream-`./version.sh`/version.sh
|
||||
tar cvzf "vgmstream-`./version.sh`.tar.gz" vgmstream-`./version.sh`/*
|
||||
rm -rf vgmstream-`./version.sh`
|
||||
rm -rf vgmstream-$(VGMSTREAM_VERSION_CURR)
|
||||
git checkout-index -f -a --prefix=vgmstream-$(VGMSTREAM_VERSION_CURR)/
|
||||
# git archive --format zip --output vgmstream-$(VGMSTREAM_VERSION_CURR).zip master
|
||||
echo "#!/bin/sh" > vgmstream-$(VGMSTREAM_VERSION_CURR)/version-get.sh
|
||||
echo "echo \"$(VGMSTREAM_VERSION_CURR)\"" >> vgmstream-$(VGMSTREAM_VERSION_CURR)/version-get.sh
|
||||
tar cvzf "vgmstream-$(VGMSTREAM_VERSION_CURR).tar.gz" vgmstream-$(VGMSTREAM_VERSION_CURR)/*
|
||||
rm -rf vgmstream-$(VGMSTREAM_VERSION_CURR)
|
||||
|
||||
bin mingwbin: vgmstream_cli winamp xmplay
|
||||
zip -FS -j "vgmstream-`./version.sh`-test.zip" $(ZIP_FILES)
|
||||
zip -FS -j "vgmstream-$(VGMSTREAM_VERSION_CURR)-test.zip" $(ZIP_FILES)
|
||||
|
||||
#separate since vgmstream123 is kinda untested
|
||||
bin-ex mingwbin-ex: vgmstream_cli winamp xmplay vgmstream123
|
||||
zip -FS -j "vgmstream-`./version.sh`-test.zip" $(ZIP_FILES) $(ZIP_FILES_AO)
|
||||
zip -FS -j "vgmstream-$(VGMSTREAM_VERSION_CURR)-test.zip" $(ZIP_FILES) $(ZIP_FILES_AO)
|
||||
|
||||
vgmstream_cli mingw_test:
|
||||
$(MAKE) -C cli vgmstream_cli
|
||||
|
82
README.md
82
README.md
@ -1,5 +1,4 @@
|
||||
# vgmstream
|
||||
|
||||
This is vgmstream, a library for playing streamed (pre-recorded) audio from
|
||||
video games.
|
||||
|
||||
@ -8,7 +7,7 @@ Some of vgmstream's features:
|
||||
obscure single-game codecs, aiming for high accuracy and compatibility.
|
||||
- support for looped BGM, using file's internal metadata for smooth transitions,
|
||||
with accurate sample counts
|
||||
- subsongs, playing a format's multiple internal songs separatedly
|
||||
- subsongs, playing a format's multiple internal songs separately
|
||||
- encryption keys, audio split in multiple files, internal stream names, and many
|
||||
other unusual cases found in game audio
|
||||
- TXTH function, to support extra formats (including raw audio in many forms)
|
||||
@ -40,24 +39,24 @@ above components are what you use to actually get sound. See *components* below
|
||||
explanations about each one.
|
||||
|
||||
### Files
|
||||
On Windows, after compiling with the build scripts you should get `vgmstream-win.zip`
|
||||
(bundle of various components) and `foo_input_vgmstream.fb2k-component` (installable
|
||||
foobar2000 plugin).
|
||||
|
||||
For Linux and similar O.S., you need to build them manually.
|
||||
|
||||
You can find automatically pre-built binaries in https://vgmstream.org/downloads
|
||||
On Windows, you should get `vgmstream-win.zip` (bundle of various components) or
|
||||
`foo_input_vgmstream.fb2k-component` (installable foobar2000 plugin) from the
|
||||
pre-built binaries: https://vgmstream.org/downloads
|
||||
|
||||
If the above link fails you may find alt, recent-ish versions here:
|
||||
https://github.com/bnnm/vgmstream-builds/raw/master/bin/vgmstream-latest-test-u.zip
|
||||
You may compile them from source as well.
|
||||
|
||||
For Linux and other O.S., you need to build vgmstream manually (see *vgmstream/doc/BUILD.md*
|
||||
in source).
|
||||
|
||||
### Needed extra files (for Windows)
|
||||
On Windows support for some codecs (Ogg Vorbis, MPEG audio, etc) is done with external
|
||||
On Windows support for some codecs (Ogg Vorbis, MPEG audio, etc.) is done with external
|
||||
libraries, so you will need to have certain DLL files.
|
||||
|
||||
In the case of components like foobar2000 they are all bundled for convenience,
|
||||
while other components include them but must be installed manually.
|
||||
You can also get them here: https://github.com/vgmstream/vgmstream/tree/master/ext_libs
|
||||
while other components include them but must be installed manually. You can also
|
||||
get them here: https://github.com/vgmstream/vgmstream/tree/master/ext_libs
|
||||
or compile them manually, even (see tech docs).
|
||||
|
||||
Put the following files somewhere Windows can find them:
|
||||
@ -87,7 +86,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).
|
||||
`test.exe` is used for historical reasons, but you can call it `vgmstream-cli.exe`, anyway.
|
||||
|
||||
*Others*: build instructions can be found in doc/BUILD.md document in vgmstream's source
|
||||
code (can be compiled with CMake/Make/autotools).
|
||||
@ -120,10 +119,10 @@ Default output filename is `?f.wav`, or `?f#?s.wav` if you set subsongs (`-s/S`)
|
||||
For files containing multiple subsongs, you can write them all using some flags.
|
||||
**WARNING, MAY TAKE A LOT OF SPACE!** Some files have been observed to contain +20000
|
||||
subsongs, so don't use this lightly. Remember to set an output name (`-o`) with subsong
|
||||
wilcards (or leave it alone for the defaults).
|
||||
wildcards (or leave it alone for the defaults).
|
||||
- `test.exe -s 1 -S 100 file.bank`: writes from subsong 1 to subsong 100
|
||||
- `test.exe -s 101 -S 0 file.bank`: writes from subsong 101 to max subsong
|
||||
- `test.exe -S 0 file.bank`: writes from subsong 1 to max subsong (automatically changes 0 to max)
|
||||
- `test.exe -s 101 -S 0 file.bank`: writes from subsong 101 to max subsong (automatically changes 0 to max)
|
||||
- `test.exe -S 0 file.bank`: writes from subsong 1 to max subsong
|
||||
- `test.exe -s 1 -S 5 -o bgm.wav file.bank`: writes 5 subsongs, but all overwrite the same file = wrong.
|
||||
- `test.exe -s 1 -S 5 -o bgm_?02s.wav file.bank`: writes 5 subsongs, each named differently = correct.
|
||||
|
||||
@ -135,7 +134,9 @@ and follow the above instructions for installing needed extra files.
|
||||
*Others*: may be possible to use through *Wine*
|
||||
|
||||
Once installed, supported files should be playable. There is a simple config
|
||||
menu to tweak some options too.
|
||||
menu to tweak some options too. If the *Preferences... > Plug-ins > Input* shows
|
||||
vgmstream as *"NOT LOADED"* that means extra DLL files aren't in the correct
|
||||
place.
|
||||
|
||||
|
||||
### xmp-vgmstream (XMPlay plugin)
|
||||
@ -174,14 +175,14 @@ document in vgmstream's source code (can be done with CMake or autotools).
|
||||
|
||||
|
||||
### vgmstream123 (command line player)
|
||||
*Windows/Linux*: needs to be manually built. Instructions can be found in doc/BUILD.md
|
||||
document in vgmstream's source code (can be done with CMake or autotools).
|
||||
On Windows it needs `libao.dll` and appropriate includes.
|
||||
*Windows/Linux*: needs to be manually built. Instructions can be found in the
|
||||
*doc/BUILD.md* document in vgmstream's source code. On Windows it needs `libao.dll`
|
||||
and appropriate includes.
|
||||
|
||||
Usage: `vgmstream123 [options] INFILE ...`
|
||||
|
||||
The program is meant to be a simple stand-alone player, supporting playback
|
||||
of vgmstream files through libao. Files compressed with gzip/bzip2/xz also
|
||||
The program is meant to be a simple stand-alone player, supporting playback of
|
||||
vgmstream files through libao. On Linux, files compressed with gzip/bzip2/xz also
|
||||
work, as identified by a `.gz/.bz2/.xz` extension. The file will be decompressed
|
||||
to a temp dir using the respective utility program (which must be installed
|
||||
and accessible) and then loaded.
|
||||
@ -219,8 +220,8 @@ subsongs to `txtp_maker.py` (it has CLI options to control output too).
|
||||
|
||||
### Common and unknown extensions
|
||||
A few extensions that vgmstream supports clash with common ones. Since players
|
||||
like foobar or Winamp don't react well to that, they may be renamed to make
|
||||
them playable through vgmstream.
|
||||
like foobar or Winamp don't react well to that, they may be renamed to these
|
||||
"designated fake extensions" to make them playable through vgmstream.
|
||||
- `.aac` to `.laac` (tri-Ace games)
|
||||
- `.ac3` to `.lac3` (standard AC3)
|
||||
- `.aif` to `.laif` (standard Mac AIF, Asobo AIF, Ogg)
|
||||
@ -260,13 +261,13 @@ It's also possible to make a .txtp file that opens files with those common/unkno
|
||||
extensions as a way to force them into vgmstream without renaming.
|
||||
|
||||
#### Related issues
|
||||
Also be aware that other plugins (not vgmstream's) can tell the player they
|
||||
handle some extension, then not actually play it. This makes the file unplayable
|
||||
as vgmstream doesn't even get the chance to parse that file, so you may need to
|
||||
Also be aware that other plugins (not vgmstream) can tell the player they handle
|
||||
some extension, then not actually play it. This makes the file unplayable as
|
||||
vgmstream doesn't even get the chance to parse that file, so you may need to
|
||||
disable the offending plugin or rename the file (for example this may happen with
|
||||
`.asf` in foobar2000).
|
||||
`.asf` in foobar2000/Winamp, may be fixed in newer versions).
|
||||
|
||||
When extracting from a bigfile, sometimes internal files don't have an proper
|
||||
When extracting from a bigfile, sometimes internal files don't have a proper
|
||||
extension. Those should be renamed to its correct one when possible, as the
|
||||
extractor program may guess wrong (like `.wav` instead of `.at3` or `.wem`).
|
||||
If there is no known extension, usually the header id/magic string may be used instead.
|
||||
@ -388,7 +389,7 @@ Creation of these files is meant for advanced users, full docs can be found in
|
||||
vgmstream source.
|
||||
|
||||
#### GENH
|
||||
A byte header placed right before the original data, modyfing it.
|
||||
A byte header placed right before the original data, modifying it.
|
||||
The resulting file must be `(name).genh`. Contains static header data.
|
||||
|
||||
Programs like VGMToolbox can help to create *GENH*, but consider using *TXTH*
|
||||
@ -414,7 +415,6 @@ start_offset = 0x10
|
||||
num_samples = data_size #auto
|
||||
```
|
||||
|
||||
|
||||
#### TXTP
|
||||
Text files with player configuration, named `(name).txtp`.
|
||||
|
||||
@ -456,7 +456,6 @@ song02.mp3 #I 10.0
|
||||
music01.bfstm #C3,4
|
||||
```
|
||||
|
||||
|
||||
#### TXTM
|
||||
A text file named `.txtm` for some formats with companion files. It lists
|
||||
name combos determining which companion files to load for each main file.
|
||||
@ -481,7 +480,6 @@ bgm.awb: bgm.acb
|
||||
bgm_DLC1.awb: bgm.acb
|
||||
```
|
||||
|
||||
|
||||
### Plugin conflicts
|
||||
Since vgmstream supports a huge amount of formats it's possibly that some of
|
||||
them are also supported in other plugins, and this sometimes causes conflicts.
|
||||
@ -537,7 +535,7 @@ filename1
|
||||
# %LOCAL_TAG text (applies to next track only)
|
||||
filename2
|
||||
```
|
||||
Accepted tags depend on the player (foobar: any; winamp: see ATF config, Audacious:
|
||||
Accepted tags depend on the player (foobar: any; Winamp: see ATF config, Audacious:
|
||||
few standard ones), typically *ALBUM/ARTIST/TITLE/DISC/TRACK/COMPOSER/etc*, lower
|
||||
or uppercase, separated by one or multiple spaces. Repeated tags overwrite previous
|
||||
(ex.- may define *@COMPOSER* multiple times for "sections"). It only reads up to
|
||||
@ -655,18 +653,18 @@ to make sure *options > titles > advanced title formatting* checkbox is set and
|
||||
the format defined.
|
||||
|
||||
When tags change behavior varies depending on player:
|
||||
- *Winamp*: should refresh tags when file is played again.
|
||||
- *Winamp*: should refresh tags when a different file is played.
|
||||
- *foobar2000*: needs to force refresh (for reasons outside vgmstream's control)
|
||||
- **select songs > shift + right click > Tagging > Reload info from file(s)**.
|
||||
- *Audacious*: files need to be readded to the playlist
|
||||
- *Audacious*: files need to be re-added to the playlist
|
||||
|
||||
Currently there is no tool to aid in the creation of these tags, but you can create
|
||||
a base `.m3u` and edit as a text file. You may try this python script to make the
|
||||
base file: https://pastebin.com/Sdu82SAp
|
||||
base file: https://raw.githubusercontent.com/bnnm/vgm-tools/master/py/tags-maker.py
|
||||
|
||||
vgmstream's "m3u tagging" is meant to be simple to make and share (just a text
|
||||
file), easier to support in multiple players (rather than needing a custom plugin),
|
||||
allow OST-like ordering but also combinable with other `.m3u`, and be flexible enough
|
||||
allow OST-like ordering but also mixable with other `.m3u`, and be flexible enough
|
||||
to have commands. If you are not satisfied with vgmstream's tagging format,
|
||||
foobar2000 has other plugins (with write support) that may be of use:
|
||||
- m-TAGS: http://www.m-tags.org/
|
||||
@ -712,7 +710,7 @@ test.exe -o btl_koopa1_44k_lp.wav "btl_koopa1_44k_lp.brstm #h22050.txtp"
|
||||
```
|
||||
|
||||
Support for this feature is limited by player itself, as foobar and Winamp allow
|
||||
non-existant files referenced in a `.m3u`, while other players may filter them
|
||||
non-existent files referenced in a `.m3u`, while other players may filter them
|
||||
first.
|
||||
|
||||
You can use this python script to autogenerate one `.txtp` per virtual-txtp:
|
||||
@ -722,7 +720,7 @@ to control output too).
|
||||
|
||||
|
||||
## Supported codec types
|
||||
Quick list of codecs vgmstream supports, including many obscure ones that
|
||||
Quick list of most codecs vgmstream supports, including many obscure ones that
|
||||
are used in few games.
|
||||
|
||||
- PCM 16-bit
|
||||
@ -740,7 +738,7 @@ are used in few games.
|
||||
- Sony HEVAG
|
||||
- Electronic Arts EA-XA (stereo, mono, Maxis)
|
||||
- Electronic Arts EA-XAS (v0, v1)
|
||||
- DVI/IMA ADPCM (stereo/mono + high/low nibble, 3DS, Omikron, SNDS, etc)
|
||||
- DVI/IMA ADPCM (stereo/mono + high/low nibble, 3DS, Quantic Dream, SNDS, etc)
|
||||
- Microsoft MS IMA ADPCM (standard, Xbox, NDS, Radical, Wwise, FSB, WV6, etc)
|
||||
- Microsoft MS ADPCM (standard, Cricket Audio)
|
||||
- Westwood VBR ADPCM
|
||||
@ -1052,6 +1050,6 @@ This list is not complete and many other files are supported.
|
||||
- .hcakey (decryption key for .hca)
|
||||
- .fsbkey (decryption key for .fsb)
|
||||
- .bnsfkey (decryption key for .bnsf)
|
||||
- .txtp (per song segment/layer handler and player configurator)
|
||||
- .txtp (per song segment/layer handler and player configuration)
|
||||
|
||||
Enjoy! *hcs*
|
||||
|
@ -40,7 +40,7 @@ extract_non_defines(GTK_CFLAGS_OTHER GTK_CFLAGS_OTHER)
|
||||
target_compile_definitions(audacious_vgmstream PRIVATE
|
||||
${AUDACIOUS_DEFINES}
|
||||
${GTK_DEFINES}
|
||||
VERSION="${VGMSTREAM_VERSION}")
|
||||
VGMSTREAM_VERSION="${VGMSTREAM_VERSION}")
|
||||
|
||||
# Include compile flags for Audacious and GTK
|
||||
set_target_properties(audacious_vgmstream PROPERTIES
|
||||
|
@ -6,7 +6,7 @@ inputplugindir = $(plugindir)/$(INPUT_PLUGIN_DIR)
|
||||
inputplugin_LTLIBRARIES = libvgmstream.la
|
||||
|
||||
AM_MAKEFLAGS=-f Makefile.autotools
|
||||
AM_CXXFLAGS = -DVERSION=\"VGMSTREAM_VERSION\" -Wall -std=c++11 -fpermissive -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/ext_includes/ $(AUDACIOUS_CFLAGS) $(GTK_CFLAGS)
|
||||
AM_CXXFLAGS = -DVGMSTREAM_VERSION=\"VGMSTREAM_VERSION\" -Wall -std=c++11 -fpermissive -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/ext_includes/ $(AUDACIOUS_CFLAGS) $(GTK_CFLAGS)
|
||||
AM_LIBS =
|
||||
|
||||
# sources/headers are updated automatically by ./bootstrap script (not all headers are needed though)
|
||||
|
@ -22,11 +22,11 @@ extern "C" {
|
||||
#include "vfs.h"
|
||||
|
||||
|
||||
#ifndef VERSION
|
||||
#include "version.h"
|
||||
#ifndef VGMSTREAM_VERSION
|
||||
#include "../version.h"
|
||||
#endif
|
||||
#ifndef VERSION
|
||||
#define VERSION "(unknown version)"
|
||||
#ifndef VGMSTREAM_VERSION
|
||||
#define VGMSTREAM_VERSION "(unknown-version)"
|
||||
#endif
|
||||
|
||||
#define CFG_ID "vgmstream" // ID for storing in audacious
|
||||
@ -64,7 +64,7 @@ const char *const VgmstreamPlugin::defaults[] = {
|
||||
|
||||
// N_(...) for i18n but not much point here
|
||||
const char VgmstreamPlugin::about[] =
|
||||
"vgmstream plugin " VERSION " " __DATE__ "\n"
|
||||
"vgmstream plugin " VGMSTREAM_VERSION " " __DATE__ "\n"
|
||||
"by hcs, FastElbja, manakoAT, bxaimc, snakemeat, soneek, kode54, bnnm and many others\n"
|
||||
"\n"
|
||||
"Audacious plugin:\n"
|
||||
|
@ -27,7 +27,7 @@ sed -i -e "s/EXTRA_DIST =.*/EXTRA_DIST = $AUDACIOUS_HDRS/g" ./audacious/Makefile
|
||||
|
||||
# get version to show in about dialogs
|
||||
# again, not very pretty
|
||||
VGMSTREAM_VERSION=`./version.sh`
|
||||
VGMSTREAM_VERSION=`./version-get.sh`
|
||||
sed -i -e "s/VGMSTREAM_VERSION/$VGMSTREAM_VERSION/g" ./audacious/Makefile.autotools.am
|
||||
sed -i -e "s/VGMSTREAM_VERSION/$VGMSTREAM_VERSION/g" ./cli/Makefile.autotools.am
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
powershell -ExecutionPolicy Bypass -NoProfile -File .\build.ps1 Build
|
93
build.ps1
93
build.ps1
@ -1,93 +0,0 @@
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[Parameter(Position=0, mandatory=$true)]
|
||||
[ValidateSet("Init", "Build")]
|
||||
[string]$Task
|
||||
)
|
||||
|
||||
# https://stackoverflow.com/a/41618979/9919772
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
|
||||
$solution = "vgmstream_full.sln"
|
||||
$vswhere = "dependencies/vswhere.exe"
|
||||
$config = "/p:Configuration=Release"
|
||||
|
||||
function Unzip
|
||||
{
|
||||
param([string]$zipfile, [string]$outpath)
|
||||
Write-Output "Extracting $zipfile"
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath)
|
||||
}
|
||||
|
||||
function Download
|
||||
{
|
||||
param([string]$uri, [string]$outfile)
|
||||
Write-Output "Downloading $uri"
|
||||
$wc = New-Object net.webclient
|
||||
$wc.Downloadfile($uri, $outfile)
|
||||
}
|
||||
|
||||
function Init
|
||||
{
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
|
||||
Remove-Item -Path "dependencies" -Recurse -ErrorAction Ignore
|
||||
New-Item dependencies -Type directory -Force | out-null
|
||||
|
||||
#Download "https://github.com/kode54/fdk-aac/archive/master.zip" "dependencies\fdk-aac.zip"
|
||||
#Download "https://github.com/kode54/qaac/archive/master.zip" "dependencies\qaac.zip"
|
||||
Download "https://www.nuget.org/api/v2/package/wtl/9.1.1" "dependencies\wtl.zip"
|
||||
Download "https://github.com/Microsoft/vswhere/releases/download/2.6.7/vswhere.exe" "dependencies\vswhere.exe"
|
||||
|
||||
# foobar anti-hotlink (random link) defeater
|
||||
#Download "https://www.foobar2000.org/SDK" "dependencies\SDK"
|
||||
#$key = (Select-String -Path dependencies\SDK -Pattern "\/([a-f0-9]+)\/SDK-2018-01-11\.zip").matches.groups[1]
|
||||
#Remove-Item -Path "dependencies\SDK"
|
||||
#Download "https://www.foobar2000.org/files/$key/SDK-2018-01-11.zip" "dependencies\foobar.zip"
|
||||
|
||||
# foobar direct link, but 2019< sdks gone ATM
|
||||
#Download "https://www.foobar2000.org/files/SDK-2018-01-11.zip" "dependencies\foobar.zip"
|
||||
|
||||
# mirror
|
||||
Download "https://github.com/vgmstream/vgmstream-deps/raw/master/foobar2000/SDK-2018-02-05.zip" "dependencies\foobar.zip"
|
||||
|
||||
#Unzip "dependencies\fdk-aac.zip" "dependencies\fdk-aac_tmp"
|
||||
#Unzip "dependencies\qaac.zip" "dependencies\qaac_tmp"
|
||||
Unzip "dependencies\wtl.zip" "dependencies\wtl_tmp"
|
||||
Unzip "dependencies\foobar.zip" "dependencies\foobar"
|
||||
|
||||
#Move-Item "dependencies\fdk-aac_tmp\fdk-aac-master" "dependencies\fdk-aac"
|
||||
#Move-Item "dependencies\qaac_tmp\qaac-master" "dependencies\qaac"
|
||||
Move-Item "dependencies\wtl_tmp\lib\native" "dependencies\wtl"
|
||||
|
||||
#Remove-Item -Path "dependencies\fdk-aac_tmp" -Recurse
|
||||
#Remove-Item -Path "dependencies\qaac_tmp" -Recurse
|
||||
Remove-Item -Path "dependencies\wtl_tmp" -Recurse
|
||||
|
||||
[xml]$proj = Get-Content dependencies\foobar\foobar2000\ATLHelpers\foobar2000_ATL_helpers.vcxproj
|
||||
$proj.project.ItemDefinitionGroup | ForEach-Object {
|
||||
$includes = $proj.CreateElement("AdditionalIncludeDirectories", $proj.project.NamespaceURI)
|
||||
$includes.InnerText = "../../../wtl/include"
|
||||
$_.ClCompile.AppendChild($includes)
|
||||
}
|
||||
$proj.Save("dependencies\foobar\foobar2000\ATLHelpers\foobar2000_ATL_helpers.vcxproj")
|
||||
}
|
||||
|
||||
function Build
|
||||
{
|
||||
if(!(Test-Path $vswhere)) { Init }
|
||||
|
||||
$msbuild = & $vswhere -latest -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe
|
||||
|
||||
if(!($msbuild -and $(Test-Path $msbuild))) {
|
||||
Write-Error "Unable to find MSBuild. Is Visual Studio installed?"
|
||||
}
|
||||
|
||||
& $msbuild $solution $config /m
|
||||
}
|
||||
|
||||
switch ($Task)
|
||||
{
|
||||
"Init" { Init }
|
||||
"Build" { Build }
|
||||
}
|
@ -31,7 +31,7 @@ if(WIN32)
|
||||
add_dependencies(vgmstream_cli version_h)
|
||||
elseif(MINGW)
|
||||
if(VGMSTREAM_VERSION)
|
||||
target_compile_definitions(vgmstream_cli PRIVATE VERSION="${VGMSTREAM_VERSION}")
|
||||
target_compile_definitions(vgmstream_cli PRIVATE VGMSTREAM_VERSION="${VGMSTREAM_VERSION}")
|
||||
endif()
|
||||
|
||||
# Also, on MinGW when using GCC, these flags need to be included to prevent requiring MinGW's runtime DLLs from being included, which does unfortunately increase the size of the EXE
|
||||
@ -45,7 +45,7 @@ if(WIN32)
|
||||
install_dlls(${CMAKE_INSTALL_PREFIX}/bin)
|
||||
elseif(VGMSTREAM_VERSION)
|
||||
# Include the version string
|
||||
target_compile_definitions(vgmstream_cli PRIVATE VERSION="${VGMSTREAM_VERSION}")
|
||||
target_compile_definitions(vgmstream_cli PRIVATE VGMSTREAM_VERSION="${VGMSTREAM_VERSION}")
|
||||
endif()
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ install(TARGETS vgmstream_cli
|
||||
|
||||
# TODO: Make it so vgmstream123 can build with Windows (this probably needs a libao.dll included with vgmstream, though)
|
||||
|
||||
if(NOT WIN32)
|
||||
if(NOT WIN32 AND AO_FOUND)
|
||||
# vgmstream123
|
||||
|
||||
add_executable(vgmstream123
|
||||
@ -74,7 +74,7 @@ if(NOT WIN32)
|
||||
${AO_INCLUDE_DIR})
|
||||
|
||||
# Include the version string
|
||||
target_compile_definitions(vgmstream123 PRIVATE VERSION="${VGMSTREAM_VERSION}")
|
||||
target_compile_definitions(vgmstream123 PRIVATE VGMSTREAM_VERSION="${VGMSTREAM_VERSION}")
|
||||
|
||||
|
||||
|
||||
|
@ -19,7 +19,7 @@ ifeq ($(TARGET_OS),Windows_NT)
|
||||
endif
|
||||
|
||||
CFLAGS += $(DEF_CFLAGS) -DVAR_ARRAYS -I../ext_includes $(EXTRA_CFLAGS)
|
||||
LDFLAGS += -L../src -L../ext_libs -lm -lvgmstream $(EXTRA_LDFLAGS)
|
||||
LDFLAGS += -L../src -L../ext_libs -lvgmstream -lm $(EXTRA_LDFLAGS)
|
||||
TARGET_EXT_LIBS =
|
||||
|
||||
CFLAGS += $(LIBS_CFLAGS)
|
||||
@ -37,11 +37,11 @@ export CFLAGS LDFLAGS
|
||||
### targets
|
||||
|
||||
vgmstream_cli: libvgmstream.a $(TARGET_EXT_LIBS)
|
||||
$(CC) $(CFLAGS) "-DVERSION=\"`../version.sh`\"" vgmstream_cli.c $(LDFLAGS) -o $(OUTPUT_CLI)
|
||||
$(CC) $(CFLAGS) "-DVGMSTREAM_VERSION=\"$(VGMSTREAM_VERSION_PREV)\"" vgmstream_cli.c $(LDFLAGS) -o $(OUTPUT_CLI)
|
||||
$(STRIP) $(OUTPUT_CLI)
|
||||
|
||||
vgmstream123: libvgmstream.a $(TARGET_EXT_LIBS)
|
||||
$(CC) $(CFLAGS) -I$(LIBAO_INC_PATH) "-DVERSION=\"`../version.sh`\"" vgmstream123.c $(LDFLAGS) -L$(LIBAO_LIB_PATH) -lao -o $(OUTPUT_123)
|
||||
$(CC) $(CFLAGS) -I$(LIBAO_INC_PATH) "-DVGMSTREAM_VERSION=\"$(VGMSTREAM_VERSION_PREV)\"" vgmstream123.c $(LDFLAGS) -L$(LIBAO_LIB_PATH) -lao -o $(OUTPUT_123)
|
||||
$(STRIP) $(OUTPUT_123)
|
||||
|
||||
libvgmstream.a:
|
||||
|
@ -6,7 +6,7 @@ if HAVE_LIBAO
|
||||
bin_PROGRAMS += vgmstream123
|
||||
endif
|
||||
|
||||
AM_CFLAGS = -DVERSION=\"VGMSTREAM_VERSION\" -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/ext_includes/ $(AO_CFLAGS)
|
||||
AM_CFLAGS = -DVGMSTREAM_VERSION=\"VGMSTREAM_VERSION\" -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/ext_includes/ $(AO_CFLAGS)
|
||||
AM_MAKEFLAGS = -f Makefile.autotools
|
||||
|
||||
vgmstream_cli_SOURCES = vgmstream_cli.c
|
||||
|
@ -26,6 +26,11 @@ class Cli(object):
|
||||
" - make full txtp rather than mini-txtp\n (may overwrite files when using subsongs)\n\n"
|
||||
" %(prog)s lines.txt -s sound \n"
|
||||
" - make .txtp per line, setting a subdir\n\n"
|
||||
"text file example:\n"
|
||||
" # creates a mini txtp as-is\n"
|
||||
" bgm.fsb #1 .txtp\n"
|
||||
" # creates a txtp using the name after ':' with the body before it\n"
|
||||
" bgm.fsb #2 : bgm_field.txtp\n"
|
||||
)
|
||||
|
||||
p = argparse.ArgumentParser(description=description, epilog=epilog, formatter_class=argparse.RawTextHelpFormatter)
|
||||
@ -50,6 +55,7 @@ class App(object):
|
||||
self.args = args
|
||||
|
||||
def start(self):
|
||||
print("TXTP dumper start")
|
||||
filenames = []
|
||||
for filename in self.args.files:
|
||||
filenames += glob.glob(filename)
|
||||
@ -61,8 +67,9 @@ class App(object):
|
||||
os.makedirs(self.args.output)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
with open(filename) as fi:
|
||||
|
||||
count = 0
|
||||
with open(filename,'r', encoding='utf-8-sig') as fi:
|
||||
for line in fi:
|
||||
line = line.strip()
|
||||
line = line.rstrip()
|
||||
@ -77,8 +84,15 @@ class App(object):
|
||||
|
||||
line.replace('\\', '/')
|
||||
|
||||
|
||||
subdir = self.args.subdir
|
||||
if self.args.maxitxtp or subdir:
|
||||
if ':' in line:
|
||||
index = line.find(':') #internal txtp : txtp name
|
||||
|
||||
text = line[0:index].strip()
|
||||
name = line[index+1:].strip()
|
||||
|
||||
elif self.args.maxitxtp or subdir:
|
||||
index = line.find('.') #first extension
|
||||
|
||||
if line[index:].startswith('.txtp'): #???
|
||||
@ -102,6 +116,12 @@ class App(object):
|
||||
if text:
|
||||
fo.write(text)
|
||||
pass
|
||||
count += 1
|
||||
|
||||
if not count:
|
||||
print("%s: no .txtp found" % (filename, count))
|
||||
else:
|
||||
print("%s: total %i .txtp" % (filename, count))
|
||||
|
||||
if __name__ == "__main__":
|
||||
Cli().start()
|
||||
|
@ -39,11 +39,11 @@
|
||||
#include "../src/vgmstream.h"
|
||||
#include "../src/plugins.h"
|
||||
|
||||
#ifndef VERSION
|
||||
# include "version.h"
|
||||
#ifndef VGMSTREAM_VERSION
|
||||
# include "../version.h"
|
||||
#endif
|
||||
#ifndef VERSION
|
||||
# define VERSION "(unknown version)"
|
||||
#ifndef VGMSTREAM_VERSION
|
||||
# define VGMSTREAM_VERSION "(unknown version)"
|
||||
#endif
|
||||
|
||||
|
||||
@ -134,7 +134,7 @@ static void usage(const char *progname) {
|
||||
default_driver = info->short_name;
|
||||
}
|
||||
|
||||
printf("vgmstream123 " VERSION ", built " __DATE__ "\n"
|
||||
printf("vgmstream123 " VGMSTREAM_VERSION ", built " __DATE__ "\n"
|
||||
"\n"
|
||||
"Usage: %s [options] INFILE ...\n"
|
||||
"Play streamed audio from video games.\n"
|
||||
|
@ -16,11 +16,11 @@
|
||||
#define STDOUT_FILENO 1
|
||||
#endif
|
||||
|
||||
#ifndef VERSION
|
||||
#include "version.h"
|
||||
#ifndef VGMSTREAM_VERSION
|
||||
#include "../version.h"
|
||||
#endif
|
||||
#ifndef VERSION
|
||||
#define VERSION "(unknown version)"
|
||||
#ifndef VGMSTREAM_VERSION
|
||||
#define VGMSTREAM_VERSION "(unknown version)"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_JSON
|
||||
@ -39,7 +39,7 @@
|
||||
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);
|
||||
|
||||
static void usage(const char* name, int is_full) {
|
||||
fprintf(stderr,"vgmstream CLI decoder " VERSION " " __DATE__ "\n"
|
||||
fprintf(stderr,"vgmstream CLI decoder " VGMSTREAM_VERSION " " __DATE__ "\n"
|
||||
"Usage: %s [-o <outfile.wav>] [options] <infile>\n"
|
||||
"Options:\n"
|
||||
" -o <outfile.wav>: name of output .wav file, default <infile>.wav\n"
|
||||
@ -278,7 +278,8 @@ static int parse_config(cli_config* cfg, int argc, char** argv) {
|
||||
cfg->infilenames = &argv[optind];
|
||||
cfg->infilenames_count = argc - optind;
|
||||
if (cfg->infilenames_count <= 0) {
|
||||
fprintf(stderr, "missing input file\n");
|
||||
usage(argv[0], 0);
|
||||
//fprintf(stderr, "missing input file\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -456,7 +457,7 @@ void print_json_version() {
|
||||
json_array_append(cext_list, cext);
|
||||
}
|
||||
|
||||
json_t* version_string = json_string(VERSION);
|
||||
json_t* version_string = json_string(VGMSTREAM_VERSION);
|
||||
|
||||
json_t* final_object = json_object();
|
||||
json_object_set(final_object, "version", version_string);
|
||||
@ -484,7 +485,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) */
|
||||
static 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, cli_config* cfg, VGMSTREAM* vgmstream) {
|
||||
int subsong;
|
||||
char stream_name[PATH_LIMIT];
|
||||
char buf[PATH_LIMIT];
|
||||
@ -493,7 +494,7 @@ static void replace_filename(char* dst, size_t dstsize, const char* outfilename,
|
||||
|
||||
|
||||
/* file has a "%" > temp replace for sprintf */
|
||||
strcpy(buf, outfilename);
|
||||
strcpy(buf, cfg->outfilename_config);
|
||||
for (i = 0; i < strlen(buf); i++) {
|
||||
if (buf[i] == '%')
|
||||
buf[i] = '|'; /* non-valid filename, not used in format */
|
||||
@ -501,8 +502,8 @@ static void replace_filename(char* dst, size_t dstsize, const char* outfilename,
|
||||
|
||||
/* init config */
|
||||
subsong = vgmstream->stream_index;
|
||||
if (subsong > vgmstream->num_streams) {
|
||||
subsong = 0; /* for games without subsongs */
|
||||
if (subsong > vgmstream->num_streams || subsong != cfg->subsong_index) {
|
||||
subsong = 0; /* for games without subsongs / bad config */
|
||||
}
|
||||
|
||||
if (vgmstream->stream_name && vgmstream->stream_name[0] != '\0') {
|
||||
@ -510,7 +511,7 @@ static void replace_filename(char* dst, size_t dstsize, const char* outfilename,
|
||||
clean_filename(stream_name, 1); /* clean subsong name's subdirs */
|
||||
}
|
||||
else {
|
||||
snprintf(stream_name, sizeof(stream_name), "%s", infilename);
|
||||
snprintf(stream_name, sizeof(stream_name), "%s", cfg->infilename);
|
||||
clean_filename(stream_name, 0); /* don't clean user's subdirs */
|
||||
}
|
||||
|
||||
@ -529,7 +530,7 @@ static void replace_filename(char* dst, size_t dstsize, const char* outfilename,
|
||||
else if (pos[1] == 'f') {
|
||||
pos[0] = '%';
|
||||
pos[1] = 's'; /* use %s */
|
||||
snprintf(tmp, sizeof(tmp), buf, infilename);
|
||||
snprintf(tmp, sizeof(tmp), buf, cfg->infilename);
|
||||
}
|
||||
else if (pos[1] == 's') {
|
||||
pos[0] = '%';
|
||||
@ -617,7 +618,7 @@ fail:
|
||||
}
|
||||
|
||||
static int convert_subsongs(cli_config* cfg) {
|
||||
int res;
|
||||
int res, oks, kos;
|
||||
int subsong;
|
||||
/* restore original values in case of multiple parsed files */
|
||||
int start_temp = cfg->subsong_index;
|
||||
@ -633,11 +634,17 @@ static int convert_subsongs(cli_config* cfg) {
|
||||
//;VGM_LOG("CLI: subsongs %i to %i\n", cfg->subsong_index, cfg->subsong_end + 1);
|
||||
|
||||
/* convert subsong range */
|
||||
oks = 0;
|
||||
kos = 0 ;
|
||||
for (subsong = cfg->subsong_index; subsong < cfg->subsong_end + 1; subsong++) {
|
||||
cfg->subsong_index = subsong;
|
||||
|
||||
res = convert_file(cfg);
|
||||
if (!res) goto fail;
|
||||
if (!res) kos++;
|
||||
}
|
||||
|
||||
if (kos) {
|
||||
fprintf(stderr, "failed %i of %i subsongs\n", kos, oks);
|
||||
}
|
||||
|
||||
cfg->subsong_index = start_temp;
|
||||
@ -732,7 +739,9 @@ static int convert_file(cli_config* cfg) {
|
||||
|
||||
if (!cfg->outfilename_config && !cfg->outfilename) {
|
||||
/* defaults */
|
||||
cfg->outfilename_config = (cfg->subsong_index >= 1) ?
|
||||
int has_subsongs = (cfg->subsong_index >= 1 && vgmstream->num_streams >= 1);
|
||||
|
||||
cfg->outfilename_config = has_subsongs ?
|
||||
"?f#?s.wav" :
|
||||
"?f.wav";
|
||||
/* maybe should avoid overwriting with this auto-name, for the unlikely
|
||||
@ -741,7 +750,7 @@ static int convert_file(cli_config* cfg) {
|
||||
|
||||
if (cfg->outfilename_config) {
|
||||
/* special substitution */
|
||||
replace_filename(outfilename_temp, sizeof(outfilename_temp), cfg->outfilename_config, cfg->infilename, vgmstream);
|
||||
replace_filename(outfilename_temp, sizeof(outfilename_temp), cfg, vgmstream);
|
||||
cfg->outfilename = outfilename_temp;
|
||||
}
|
||||
|
||||
@ -906,7 +915,7 @@ fail:
|
||||
|
||||
#ifdef HAVE_JSON
|
||||
static void print_json_info(VGMSTREAM* vgm, cli_config* cfg) {
|
||||
json_t* version_string = json_string(VERSION);
|
||||
json_t* version_string = json_string(VGMSTREAM_VERSION);
|
||||
vgmstream_info info;
|
||||
describe_vgmstream_info(vgm, &info);
|
||||
|
||||
|
@ -1,204 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="test"
|
||||
ProjectGUID="{AF7D88A0-3CB1-4CD8-BAD1-0305EB996D69}"
|
||||
RootNamespace="test"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
CommandLine="$(SolutionDir)version.bat"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\ext_libs\Getopt;..\ext_includes"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
ForcedIncludeFiles="$(SolutionDir)VERSION.H"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="libg719_decode.lib libmpg123-0.lib libvorbis.lib"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories="..\ext_libs"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
CommandLine="$(SolutionDir)version.bat"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
AdditionalIncludeDirectories="..\ext_libs\Getopt;..\ext_includes"
|
||||
PreprocessorDefinitions="WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_G7221;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
ForcedIncludeFiles="$(SolutionDir)VERSION.H"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="libg719_decode.lib libmpg123-0.lib libvorbis.lib"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories="..\ext_libs"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\vgmstream_cli.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@ -88,10 +88,10 @@
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>"$(ProjectDir)..\version.bat" "$(ProjectDir)..\version.h" VERSION</Command>
|
||||
<Command>"$(ProjectDir)..\version-make.bat"</Command>
|
||||
</PreBuildEvent>
|
||||
<PreBuildEvent>
|
||||
<Message>Generating version.h</Message>
|
||||
<Message>Generating version</Message>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@ -116,10 +116,10 @@
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>"$(ProjectDir)..\version.bat" "$(ProjectDir)..\version.h" VERSION</Command>
|
||||
<Command>"$(ProjectDir)..\version-make.bat"</Command>
|
||||
</PreBuildEvent>
|
||||
<PreBuildEvent>
|
||||
<Message>Generating version.h</Message>
|
||||
<Message>Generating version</Message>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
231
doc/BUILD.md
231
doc/BUILD.md
@ -1,15 +1,21 @@
|
||||
# vgmstream build help
|
||||
|
||||
This document explains how to build each of vgmstream's components and libs.
|
||||
|
||||
|
||||
## Compilation requirements
|
||||
Because each module has different quirks one can't use a single tool for everything. You should be able to build most using a standard *compiler* (GCC/MSVC/Clang) using common *build systems* (scripts/CMake/autotools) in any typical *OS* (Windows/Linux/Mac).
|
||||
|
||||
Because each module has different quirks one can't use a single tool for everything. You should be able to build most using a standard compiler (GCC/MSVC/Clang) in any typical OS (Windows/Linux/Mac) using common build helpers (scripts/CMake/autotools).
|
||||
64-bit support may work but has been minimally tested, since main use of vgmstream is plugins for 32-bit players (extra codec libs for Windows are included for 32-bit only ATM, and there may be bugs in some codecs and formats).
|
||||
|
||||
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).
|
||||
Components are detailed below, but if you are new to development you probably want:
|
||||
- Windows: Visual Studio + simple scripts
|
||||
- Linux: GCC + CMake
|
||||
- Max: Clang + CMake
|
||||
|
||||
### GCC / Make
|
||||
Though it's rather flexible (like using Windows with GCC and autotools), some combos may be a bit more complex to get working depending on your system and other factors.
|
||||
|
||||
|
||||
### GCC / Make (compiler)
|
||||
Common C compiler, most development is done with this.
|
||||
|
||||
On Windows you need one of these somewhere in PATH:
|
||||
@ -22,66 +28,95 @@ On Windows you need one of these somewhere in PATH:
|
||||
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/
|
||||
- Resulting binaries may depend on `msys*.dll`.
|
||||
|
||||
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.
|
||||
On Mac may be installed with a package manager like *Homebrew*, but using *Clang* is probably easier.
|
||||
|
||||
Bundled in either:
|
||||
- Visual Studio (2015/2017/latest): https://www.visualstudio.com/downloads/
|
||||
Any not-too-ancient versions should work, since vgmstream uses standard C. GCC usually comes with *Make*, a program that can be used to build vgmstream.
|
||||
|
||||
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).
|
||||
### Microsoft's Visual C++ (MSVC) / Visual Studio / MSBuild (compiler)
|
||||
Alt C compiler (Windows only), auto-generated builds for Windows use this. Bundled in:
|
||||
- Visual Studio (2015/2017/2019/latest): https://www.visualstudio.com/downloads/
|
||||
|
||||
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.
|
||||
Visual Studio Community (free) should work, but you may need to register after a trial period. Even after trial you can still use *MSBuild*, command-line tool that actually does all the building, calling the *MSVC* compiler (Visual Studio itself is just an IDE for development and not actually needed).
|
||||
|
||||
### Clang
|
||||
Reportedly works fine on Mac and may used as a replacement for GCC without issues.
|
||||
Instead of the full (usually huge) Visual Studio, you can also get "Build Tools for Visual Studio", variation that only installs *MSBuild* and necessary files without the IDE. Usually found in the above link, under "Tools for Visual Studio" (or google as MS's links tend to move around).
|
||||
|
||||
Should be usable on Linux and possibly Windows with CMake.
|
||||
When installing check the "Desktop development with C++" group, and optionally select "MFC support" and "ATL support" sub-options to build foobar2000 plugin (you can modify that or re-install IDE later, by running installed "Visual Studio Installer"). You could include MSVC v141 (2017) compatibility too just in case, since it's mainly tested with that.
|
||||
|
||||
Older versions of MSVC (2010 and earlier) have limited C support and may not work with latest commits, while reportedly beta/new versions aren't always very stable. Also, only projects (`.vcxproj`) for VS2015+ are included (CMake may be able to generate older `.vcproj` if you really need them). Some very odd issues affecting MSVC only have been found and fixed before. Keep in mind all of this if you run into problems.
|
||||
|
||||
### Clang (compiler)
|
||||
Alt C compiler, reportedly works fine on Mac and may used as a replacement of GCC without issues.
|
||||
- https://releases.llvm.org/download.html
|
||||
|
||||
For other makefiles may work, though may need to set compiler vars appropriately (CC=clang AR=llvm-ar).
|
||||
Should be usable on Linux and possibly Windows with CMake. For default Makefiles may need to set compiler vars appropriately (CC=clang AR=llvm-ar and so on).
|
||||
|
||||
### Git
|
||||
Optional, used to generate version numbers:
|
||||
- Git for Windows: https://git-scm.com/download/win
|
||||
### Simple scripts (builds)
|
||||
Default build scripts included in source that can compile vgmstream, though limited in some ways.
|
||||
|
||||
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.
|
||||
**For MSVC**: there is a default Visual Studio `.sln` that should be up to date (run `./msvc-build-init.bat` first, or see the foobar section to get extra dependencies manually, then open). A PowerShell script also automates compilation (on Windows 7 may need recent .NET framework and PowerShell versions), simply run `./msvc-build.bat`.
|
||||
|
||||
First you may need to either open the `.sln` and change project compiler (*PlatformToolset*) and SDK (*WindowsTargetPlatformVersion*) to your installed version, or edit `msvc-build.ps1` and set the variables near *CONFIG*. To avoid modifying files you can also create a file named `msvc-build.config.ps1` with:
|
||||
```
|
||||
# - toolsets: "" (p), "v140" (MSVC 2015), "v141" (MSVC 2017), "v141_xp" (XP support), "v142" (MSVC 2019), etc
|
||||
# - sdks: "" (default), "7.0" (Win7 SDK), "8.1" (Win8 SDK), "10.0" (Win10 SDK), etc
|
||||
$toolset = "142"
|
||||
$sdk = "10.0"
|
||||
```
|
||||
It's also possible to call MSBuild and pass those values from the CMD, see foobar section for an example.
|
||||
|
||||
### CMake
|
||||
Optional, can be used to compile vgmstream's modules instead of regular scripts. Needs v3.6 or later:
|
||||
Once finished resulting binaries are in the *./Release* folder. Remember you need to copy extra `.dll` to run them (see [README.md](../README.md)).
|
||||
|
||||
**For GCC/CLang**: there are basic Makefiles that work like usual with *make* (like `make vgmstream_cli EXTRA_CFLAGS="-DVGM_DEBUG_OUTPUT`). On Windows this compiles with extra libs enabled, but not on Linux (try CMake or autotools for those). Artifacts are usually in their subdir (*./cli*, *./winamp*, etc).
|
||||
|
||||
### CMake (builds)
|
||||
Tool used to generate common build files (for *make*, *VS/MSBuild*, etc), that in turn can be used to compile vgmstream's modules instead of existing scripts/files. Needs v3.6 or later:
|
||||
- https://cmake.org/download/
|
||||
|
||||
If you wish to use CMake, see [CMAKE.md](CMAKE.md). Some extra info is only mentioned in this doc though.
|
||||
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).
|
||||
Note that doing in-source builds of CMake (`cmake .` / selecting `./vgmstream` as output dir) is not recommended and may clobber default build files.
|
||||
|
||||
For Windows you must include GCC, and Linux's sh tool in some form in PATH. The simplest would be installing MinGW-w64 for GCC.exe, and Git for sh.exe, and making PATH point their bin dir.
|
||||
- ex. `C:\i686-8.1.0-release-win32-sjlj-rt_v6-rev0\mingw32\bin` and `C:\Git\usr\bin`
|
||||
### autotools (builds)
|
||||
Autogenerated *make* scripts, used by some modules (mainly Audacious for Linux, and external libs).
|
||||
|
||||
For Windows you must include GCC, and Linux's sh tool in some form in PATH. Simplest would be installing *MinGW-w64* for `gcc.exe` (and related tools), and *Git* for `sh.exe`, and making PATH point their bin dir.
|
||||
- ex. `C:\mingw\i686-8.1.0-release-win32-sjlj-rt_v6-rev0\mingw32\bin` and `C:\Git\usr\bin`
|
||||
- Both must be installed/copied in a dir without spaces (with spaces autoconf seemingly works but creates buggy files)
|
||||
- If you don't have Git, try compiled GNU tools for Windows (http://gnuwin32.sourceforge.net/packages.html)
|
||||
|
||||
A useful trick for Windows is that you can alter PATH variable temporarly in `.bat` scripts (PATH is used to call programs in Windows without having to write full path to .exe)
|
||||
A trick on Windows is that you can temporary alter PATH variable in `.bat` scripts (PATH is used to call programs in Windows without having to write full path to .exe)
|
||||
```
|
||||
set PATH=%PATH%;C:\i686-8.1.0-release-win32-sjlj-rt_v6-rev0\mingw32\bin
|
||||
set PATH=%PATH%;C:\mingw\i686-8.1.0-release-win32-sjlj-rt_v6-rev0\mingw32\bin
|
||||
set PATH=%PATH%;C:\Git\usr\bin
|
||||
gcc.exe (...)
|
||||
```
|
||||
|
||||
For Linux, those may be included already, or install with a package manager (`sudo apt-get install autoconf automake libtool`).
|
||||
For Linux, GCC/make/autotools should be included already, or install with a package manager (`sudo apt-get install gcc g++ make autoconf automake libtool`), also depends on *Make*.
|
||||
|
||||
Typical usage involves `./configure` (creates makefiles) + `Make` (compiles) + `Make install` (copies results), but varies slightly depending on module/lib (explained later).
|
||||
Typical usage involves `./configure` (creates Makefiles) + `make` (compiles) + `make install` (copies results), but varies slightly depending on module/lib (explained later).
|
||||
|
||||
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.
|
||||
### Git (extras)
|
||||
Code version control for development. Optional, used to auto-generate version numbers:
|
||||
- https://git-scm.com/download
|
||||
|
||||
Remember Git can only be used if you clone the vgmstream repo (not with `.zip` sources).
|
||||
|
||||
On Windows, Git also comes with typical Linux utils (in the usr\bin dir), that can help when compiling some extra components.
|
||||
|
||||
### Extra libs (extras)
|
||||
Optional codec. See *External libraries* for full info.
|
||||
|
||||
On Windows most libs are pre-compiled and included to simplify building (since they can be quite involved to compile).
|
||||
|
||||
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.
|
||||
On Linux you usually need dev packages of each (for example `libao-dev` for vgmstream123, `libvorbis-dev` for Vorbis, and so on) and they should be picked by CMake/autotool scripts.
|
||||
|
||||
With no extra libs (or only some) enabled vgmstream works fine, but some advanced formats/codecs won't play. See *External libraries* for info about those extra codecs.
|
||||
|
||||
|
||||
## Compiling modules
|
||||
@ -90,18 +125,20 @@ On Linux you usually need dev packages of each (for example `libao-dev` for vgms
|
||||
|
||||
**With GCC/Clang**: there are various ways to build it, each with some differences; you probably want CMake described below.
|
||||
|
||||
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.
|
||||
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 (`make clean`). On Windows this will build with external libs enabled, but Linux can't ATM.
|
||||
|
||||
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/
|
||||
- https://aur.archlinux.org/packages/vgmstream-git/
|
||||
|
||||
If you use Mac (or Linux), there is a *Homebrew* script that may automate the process (uses CMake): https://formulae.brew.sh/formula/vgmstream
|
||||
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.
|
||||
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 the *CMAKE.md* doc for some extra info too.
|
||||
```
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc g++ make build-essential
|
||||
sudo apt-get install -y libmpg123-dev libvorbis-dev libspeex-dev
|
||||
sudo apt-get install -y libavformat-dev libavcodec-dev libavutil-dev libswresample-dev
|
||||
sudo apt-get install -y libao-dev audacious-dev
|
||||
@ -110,11 +147,12 @@ sudo apt-get install -y cmake
|
||||
git clone https://github.com/vgmstream/vgmstream
|
||||
cd vgmstream
|
||||
|
||||
cmake .
|
||||
# for older versions try "cmake ." instead
|
||||
cmake -S . -B build
|
||||
make
|
||||
```
|
||||
|
||||
Windows CMD example (with some debugging on):
|
||||
Windows CMD .bat example (with some debugging on):
|
||||
```
|
||||
prompt $P$G$_$S
|
||||
set PATH=C:\Program Files (x86)\Git\usr\bin;%PATH%
|
||||
@ -130,37 +168,45 @@ mingw32-make.exe vgmstream_cli -f Makefile ^
|
||||
1> ../vgmstream-stdout.txt 2> ../vgmstream-stderr.txt
|
||||
```
|
||||
|
||||
**With MSVC**: To build in Visual Studio, run `./msvc-build-init.bat`, open `vgmstream_full.sln` and compile. To build from the command line, just run `./msvc-build.bat`.
|
||||
|
||||
**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 install some PowerShell .NET packages). You could also call MSBuild directly in the command line (see the foobar2000 section for dependencies and examples).
|
||||
|
||||
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).
|
||||
If you get build errors, remember you need to adjust compiler/SDK in the `.sln`. See *Simple scripts* above or CMD example in the foobar section.
|
||||
|
||||
You can also call MSBuild directly in the command line (see the foobar2000 section for dependencies and examples)
|
||||
CMake can also be used instead to create project files (no particular benefit).
|
||||
|
||||
#### 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:
|
||||
Requires MSVC (foobar/SDK only links to MSVC C++ DLLs). To build in Visual Studio, run `./msvc-build-init.bat`, open `vgmstream_full.sln` and compile. To build from the command line, just run `./msvc-build.bat`.
|
||||
|
||||
foobar has multiple dependencies. Build script downloads them automatically, but here they are:
|
||||
- foobar2000 SDK (2018), in *(vgmstream)/dependencies/foobar/*: http://www.foobar2000.org/SDK
|
||||
- (optional) FDK-AAC, in *(vgmstream)/dependencies/fdk-aac/*: https://github.com/kode54/fdk-aac
|
||||
- (optional) QAAC, in *(vgmstream)/dependencies/qaac/*: https://github.com/kode54/qaac
|
||||
- WTL (if needed), in *(vgmstream)/dependencies/WTL/*: http://wtl.sourceforge.net/
|
||||
- may need to install ATL and MFC libraries (can be installed in Visual Studio Installer)
|
||||
- may need to install ATL and MFC libraries if not included by default (can be added from the Visual Studio installer)
|
||||
|
||||
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. 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.
|
||||
In theory any foobar SDK should work, but there may be issues when using versions past `2018-02-05`. Mirror in case official site is down: https://github.com/vgmstream/vgmstream-deps/raw/master/foobar2000/SDK-2018-02-05.zip
|
||||
|
||||
Windows CMD example for foobar2000:
|
||||
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.
|
||||
|
||||
Windows CMD example for foobar2000 (manual build):
|
||||
```
|
||||
prompt $P$G$_$S
|
||||
set PATH=C:\Program Files (x86)\Git\usr\bin;%PATH%
|
||||
set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH%
|
||||
|
||||
REM MSVC ~2015
|
||||
REM set PATH=%PATH%;C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH%
|
||||
REM Latest(?) MSVC
|
||||
set PATH=%PATH%;C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin
|
||||
|
||||
cd vgmstream
|
||||
|
||||
@ -170,20 +216,25 @@ set LINK="C:\projects\foobar\foobar2000\shared\shared.lib"
|
||||
msbuild fb2k/foo_input_vgmstream.vcxproj ^
|
||||
/t:Clean
|
||||
|
||||
REM depending on your installed Visual Studio build tools you may need to change:
|
||||
REM - PlatformToolset: v140=MSVC 2015, v141=MSVC 2017, v141_xp=same with XP support, v142=MSVC 2019, etc
|
||||
REM - WindowsTargetPlatformVersion: 7.0=Win7 SDK, 8.1=Win8 SDK, 10.0=Win10 SDK, etc
|
||||
|
||||
msbuild fb2k/foo_input_vgmstream.vcxproj ^
|
||||
/t:Build ^
|
||||
/p:Platform=Win32 ^
|
||||
/p:PlatformToolset=v140 ^
|
||||
/p:PlatformToolset=v142 ^
|
||||
/p:WindowsTargetPlatformVersion=10.0 ^
|
||||
/p:Configuration=Release ^
|
||||
/p:DependenciesDir=../..
|
||||
```
|
||||
|
||||
### Audacious plugin
|
||||
Requires the dev version of Audacious (and dependencies), automake/autoconf or CMake, and gcc/make (C++11). It must be compiled and installed into Audacious, where it should appear in the plugin list as "vgmstream".
|
||||
Requires the dev version of Audacious (and dependencies), autotools (automake/autoconf) or CMake, and gcc/make (C++11). It must be compiled and installed into Audacious, where it should appear in the plugin list as "vgmstream".
|
||||
|
||||
The plugin needs Audacious 3.5 or higher. New Audacious releases can break plugin compatibility so it may not work with the latest version unless adapted first.
|
||||
|
||||
libvorbis/libmpg123/libspeex will be used if found, while FFmpeg and other external libraries aren't enabled at the moment, thus some formats won't work (build scripts need to be fixed).
|
||||
CMake should handle all correctly, while when using autotools, libvorbis/libmpg123/libspeex will be used if found, while FFmpeg and other external libraries aren't enabled at the moment, thus some formats won't work (build scripts need to be fixed).
|
||||
|
||||
Windows builds aren't supported at the moment (should be possible but there are complex dependency chains).
|
||||
|
||||
@ -192,7 +243,24 @@ If you get errors during the build phase we probably forgot some `#ifdef` needed
|
||||
Take note of other plugins stealing extensions (see README). To change Audacious's default priority for vgmstream you can make with CFLAG `AUDACIOUS_VGMSTREAM_PRIORITY n` (where `N` is a number where 10=lowest)
|
||||
|
||||
|
||||
Terminal example, assuming a Ubuntu-based Linux distribution:
|
||||
You can try building with CMake. Some older distros may not work though (CMake version needs to recognize FILTER command), and may need to install resulting artifacts manually (check ./audacious dir).
|
||||
```
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc g++ make build-essential
|
||||
sudo apt-get install -y libmpg123-dev libvorbis-dev libspeex-dev
|
||||
sudo apt-get install -y libavformat-dev libavcodec-dev libavutil-dev libswresample-dev
|
||||
sudo apt-get install -y libao-dev audacious-dev
|
||||
sudo apt-get install -y cmake
|
||||
|
||||
git clone https://github.com/vgmstream/vgmstream
|
||||
cd vgmstream
|
||||
|
||||
# for older versions try "cmake ." instead
|
||||
cmake -S . -B build
|
||||
make
|
||||
```
|
||||
|
||||
Instead of CMake you can use autotools. Terminal example, assuming a Ubuntu-based Linux distribution:
|
||||
```
|
||||
# build setup
|
||||
|
||||
@ -248,29 +316,34 @@ find . -name ".deps" -type d -exec rm -r "{}" \;
|
||||
## WARNING, removes *all* untracked files not in .gitignore
|
||||
git clean -fd
|
||||
```
|
||||
To update vgmstream it's probably easiest to remove the `vgmstream` folder and start again from *base vgmstream build* step, since updates often require a full rebuild anyway.
|
||||
|
||||
Instead of autotools you can try building with CMake. Some older distros may not work though (CMake version needs to recognize FILTER command). You may need to install resulting artifacts manually (check ./audacious dir).
|
||||
```
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libmpg123-dev libvorbis-dev libspeex-dev
|
||||
sudo apt-get install -y libavformat-dev libavcodec-dev libavutil-dev libswresample-dev
|
||||
sudo apt-get install -y libao-dev audacious-dev
|
||||
sudo apt-get install -y cmake
|
||||
|
||||
git clone https://github.com/vgmstream/vgmstream
|
||||
cd vgmstream
|
||||
|
||||
cmake .
|
||||
make
|
||||
```
|
||||
To update vgmstream it's probably easiest to remove the `vgmstream` folder and start again from *base vgmstream build* step, since updates often require a full rebuild anyway, or call `git clean -fd` or maybe `git reset --hard`.
|
||||
|
||||
### vgmstream123 player
|
||||
Should be buildable with Autotools/CMake 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.
|
||||
|
||||
libao is licensed under the GPL v2 or later.
|
||||
*libao* is licensed under the GPL v2 or later.
|
||||
|
||||
|
||||
## Shared lib
|
||||
Currently there isn't an official way to make vgmstream a shared lib (`.so`/`.dll`), but it can be achieved with some effort.
|
||||
|
||||
For example with the basic makefiles:
|
||||
```
|
||||
# build all of the intermediates with relocatable code
|
||||
# *note*: quick hack with performance penalty, needs better dependency rules
|
||||
make vgmstream_cli EXTRA_CFLAGS=-fPIC
|
||||
|
||||
# build the actual shared library
|
||||
make -C src libvgmstream.so
|
||||
```
|
||||
|
||||
May also need to take `vgmstream.h`, `streamfile.h` and `plugins.h`, and trim them somewhat to use as includes for the `.so`.
|
||||
|
||||
For MSVC, you could add `__declspec(dllexport)` to exported functions in the "public" API of the above `.h`, and set `<ConfigurationType>DynamicLibrary</ConfigurationType>` in `libvgmstream.vcxproj`, plus add a `<Link>` under `<ClCompile>` to those libs (copy from `vgmstream_cli.vcxproj`).
|
||||
|
||||
A cleaner API/.h and build methods is planned for the future (low priority though).
|
||||
|
||||
|
||||
## External libraries
|
||||
@ -291,7 +364,7 @@ MSVC needs a .lib helper to link .dll files, but libs below usually only create
|
||||
|
||||
|
||||
### libvorbis
|
||||
Adds support for Vorbis (inside Ogg and custom containers).
|
||||
Adds support for Vorbis, inside Ogg as `.ogg` (plain or encrypted) or custom variations like `.wem`, `.fsb`, `.ogl`, etc.
|
||||
- Source: http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.6.zip
|
||||
- DLL: `libvorbis.dll`
|
||||
- licensed under the 3-clause BSD license.
|
||||
@ -300,7 +373,7 @@ Should be buildable with MSVC (in /win32 dir are .sln files) or autotools (use `
|
||||
|
||||
|
||||
### mpg123
|
||||
Adds support for MPEG (MP1/MP2/MP3).
|
||||
Adds support for MPEG (MP1/MP2/MP3), used in formats that may have custom MPEG like `.ahx`, `.msf`, `.xvag`, `.scd`, etc.
|
||||
- Source: https://sourceforge.net/projects/mpg123/files/mpg123/1.25.10/
|
||||
- Builds: http://www.mpg123.de/download/win32/1.25.10/
|
||||
- DLL: `libmpg123-0.dll`
|
||||
@ -310,7 +383,7 @@ Must use autotools (sh configure, make, make install), though some scripts simpl
|
||||
|
||||
|
||||
### libg719_decode
|
||||
Adds support for ITU-T G.719 (standardization of Polycom Siren 22).
|
||||
Adds support for ITU-T G.719 (standardization of Polycom Siren 22), used in a few Namco `.bnsf` games.
|
||||
- Source: https://github.com/kode54/libg719_decode
|
||||
- DLL: `libg719_decode.dll`
|
||||
- unknown license (possibly invalid and Polycom's)
|
||||
@ -319,12 +392,12 @@ Use MSVC (use `g719.sln`). It can be built with GCC too, but you'll need to manu
|
||||
|
||||
|
||||
### FFmpeg
|
||||
Adds support for multiple codecs: ATRAC3, ATRAC3plus, XMA1/2, WMA v1, WMA v2, WMAPro, AAC, Bink, AC3/SPDIF, Opus, Musepack, FLAC, etc (also Vorbis and MPEG for certain cases).
|
||||
Adds support for multiple codecs: ATRAC3 (`.at3`), ATRAC3plus (`.at3`), XMA1/2 (`.xma`), WMA v1 (`.wma`), WMA v2 (`.wma`), WMAPro (`.xwma`), AAC (`.mp4`, `.aac`), Bink (`.bik`), AC3/SPDIF (`.ac3`), Opus (`.opus`), Musepack (`.mpc`), FLAC (`.flac`), etc.
|
||||
- Source: https://github.com/FFmpeg/FFmpeg/
|
||||
- DLLs: `avcodec-vgmstream-58.dll`, `avformat-vgmstream-58.dll`, `avutil-vgmstream-56.dll`, `swresample-vgmstream-3.dll`
|
||||
- primarily licensed under the LGPL v2.1 or later, with portions licensed under the GPL v2
|
||||
|
||||
vgmstream's FFmpeg builds remove many unnecessary parts of FFmpeg to trim down its gigantic size, and are also built with the "vgmstream-" preffix (to avoid clashing with other plugins). Current options can be seen in `ffmpeg_options.txt`.
|
||||
vgmstream's FFmpeg builds for Windows remove many unnecessary parts of FFmpeg to trim down its gigantic size, and are also built with the "vgmstream-" prefix to avoid clashing with other plugins. Current options can be seen in `ffmpeg_options.txt`. Linux usually links to the system's FFmpeg without issues.
|
||||
|
||||
For GCC simply use autotools (configure, make, make install), passing to `configure` the above options.
|
||||
|
||||
@ -334,7 +407,7 @@ Both may need yasm somewhere in PATH to properly compile: https://yasm.tortall.n
|
||||
|
||||
|
||||
### LibAtrac9
|
||||
Adds support for ATRAC9.
|
||||
Adds support for ATRAC9, used in `.at9` and other formats for the PS4 and Vita.
|
||||
- Source: https://github.com/Thealexbarney/LibAtrac9
|
||||
- DLL: `libatrac9.dll`
|
||||
- licensed under the MIT license
|
||||
@ -343,7 +416,7 @@ Use MSCV and `libatrac9.sln`, or GCC and the Makefile included.
|
||||
|
||||
|
||||
### libcelt
|
||||
Adds support for FSB CELT versions 0.6.1 and 0.11.0.
|
||||
Adds support for FSB CELT versions 0.6.1 and 0.11.0, used in a handful of older `.fsb`.
|
||||
- Source (0.6.1): http://downloads.us.xiph.org/releases/celt/celt-0.6.1.tar.gz
|
||||
- Source (0.11.0): http://downloads.xiph.org/releases/celt/celt-0.11.0.tar.gz
|
||||
- DLL: `libcelt-0061.dll`, `libcelt-0110.dll`
|
||||
@ -381,9 +454,11 @@ To compile we'll use autotools with GCC preprocessor renaming:
|
||||
- you need to create a .def file for those DLL with the renamed simbol names above
|
||||
- finally the includes. libcelt gives "celt.h" "celt_types.h" "celt_header.h", but since we renamed a few functions we have a simpler custom .h with minimal renamed symbols.
|
||||
|
||||
For Linux, an option is using AUR's scripts (https://aur.archlinux.org/packages/vgmstream-git/) that similarly patch celt libs in PKGBUILD.
|
||||
|
||||
|
||||
### libspeex
|
||||
Adds support for Speex (inside custom containers).
|
||||
Adds support for Speex (inside custom containers), used in a few *EA* formats (`.sns`, `.sps`) for voices.
|
||||
- Source: http://downloads.us.xiph.org/releases/speex/speex-1.2.0.tar.gz
|
||||
- DLL: `libspeex.dll`
|
||||
- licensed under the Xiph.Org variant of the BSD license.
|
||||
@ -395,8 +470,8 @@ You can also find a release on Github (https://github.com/xiph/speex/releases/ta
|
||||
|
||||
Windows CMD example:
|
||||
```
|
||||
set PATH=%PATH%;C:\mingw\i686-8.1.0-release-win32-sjlj-rt_v6-rev0\mingw32\bin
|
||||
set PATH=%PATH%;C:\Git\usr\bin
|
||||
set PATH=%PATH%;C:\i686-8.1.0-release-win32-sjlj-rt_v6-rev0\mingw32\bin
|
||||
|
||||
sh ./configure --host=mingw32 --prefix=/c/celt-0.11.0/bin/ --exec-prefix=/c/celt-0.11.0/bin/
|
||||
mingw32-make.exe LDFLAGS="-no-undefined -static-libgcc" MAKE=mingw32-make.exe
|
||||
|
31
doc/CMAKE.md
31
doc/CMAKE.md
@ -15,11 +15,9 @@
|
||||
- Windows: https://www.visualstudio.com/downloads/
|
||||
|
||||
If building the CLI for *nix-based OSes, vgmstream123 also needs the following:
|
||||
|
||||
- **LibAO**
|
||||
|
||||
If building for *nix-based OSes, the following libraries are optional:
|
||||
|
||||
- **libmpg123**
|
||||
- **libvorbis** (really libvorbisfile, though)
|
||||
- **FFmpeg**
|
||||
@ -37,7 +35,7 @@ First you will need to run CMake to generate the build setup. You can use either
|
||||
|
||||
### CMake GUI
|
||||
|
||||
If you have access to the CMake GUI, you can use that to create your build setup. Select where the source code is (that should be the directory just above this one) and where you wish to build to.
|
||||
If you have access to the CMake GUI, you can use that to create your build setup. Select where the source code is (that should be the directory just above this one) and where you wish to build to (preferably a directory outside source).
|
||||
|
||||
You may have to add some entries before configuring will succeed. See the [CMake Cache Entries](#cmake-cache-entries) section for details on the entries.
|
||||
|
||||
@ -50,6 +48,8 @@ Generating done
|
||||
|
||||
Before that you'll see what options are enabled and disabled, what is going to be built and where they will be installed to.
|
||||
|
||||
You may need to select a Generator first, depending on your installed tools (for example, Visual Studio 16 2019 or MingW Make on Windows). If you need to change it later, select *File > Delete Cache*.
|
||||
|
||||
If you decided to build for a project-based GUI, you can click on Open Project to open that. (NOTE: Only Visual Studio has been tested as a project-based GUI.) If you decided to build for a command line build system, you can open up the command line for the build directory and run your build system.
|
||||
|
||||
### CMake command line
|
||||
@ -60,11 +60,31 @@ If you don't have access to the CMake GUI or would prefer to only use the comman
|
||||
cmake -G "<generator>" <options> <path to source code>
|
||||
```
|
||||
|
||||
Replace `<generator>` with the CMake generator you wish to use as your build system. Make note of the quotes, and use `cmake -h` to get a list of generators for your system.
|
||||
Replace `<generator>` with the CMake generator you wish to use as your build system (for example `Unix Makefiles`, or don't set for default). Make note of the quotes, and use `cmake -h` to get a list of generators for your system.
|
||||
|
||||
You may have to add some entries before configuring will success. See the [CMake Cache Entries](#cmake-cache-entries) section for details on the entries.
|
||||
|
||||
Place your entries in the `<options>` section of the above command, with each option in the form of `-D<optionname>:<type>=<value>`. Replace `<path to source code>` with the path where the source code is (that should be the directory just above this one).
|
||||
Place your entries in the `<options>` section of the above command, with each option in the form of `-D<optionname>:<type>=<value>`. Replace `<path to source code>` with the path where the source code is (that should be the directory just above this one), may need to se `-S <path to source> -B <output dir>` instead. Example:
|
||||
```
|
||||
git clone https://github.com/vgmstream/vgmstream.git
|
||||
cd vgmstream
|
||||
cmake -DUSE_FFMPEG=ON -DBUILD_AUDACIOUS=OFF -S . -B build
|
||||
```
|
||||
|
||||
You may need to install appropriate packages first (see [BUILD.md)(BUILD.md) for more info), for example:
|
||||
```
|
||||
sudo apt-get update
|
||||
# basic compilation
|
||||
sudo apt-get install -y gcc g++ make build-essential
|
||||
# extra libs
|
||||
sudo apt-get install -y libmpg123-dev libvorbis-dev libspeex-dev
|
||||
# extra libs
|
||||
sudo apt-get install -y libavformat-dev libavcodec-dev libavutil-dev libswresample-dev
|
||||
# for vgmstream123 and audacious
|
||||
sudo apt-get install -y libao-dev audacious-dev
|
||||
# actual cmake
|
||||
sudo apt-get install -y cmake
|
||||
```
|
||||
|
||||
Once you have run the command, as long as there are no errors, you should see the following at the bottom of the window:
|
||||
|
||||
@ -92,7 +112,6 @@ If not using a project-based GUI, then you will also need to set what build type
|
||||
|
||||
All of these options are of type BOOL and can be set to either `ON` or `OFF`. Most of the details on these libraries can be found in the [External Libraries section of BUILD.md](BUILD.md#external-libraries).
|
||||
|
||||
- **USE_FDKAAC**: Chooses if you wish to use FDK-AAC/QAAC for support of MP4 AAC. Note that this requires `QAAC_PATH` and `FDK_AAC_PATH` to also be given if the option is `ON`. The default for is `ON`. See the foobar2000 plugin section of [BUILD.md](BUILD.md) for more information on this.
|
||||
- **USE_MPEG**: Chooses if you wish to use libmpg123 for support of MP1/MP2/MP3. The default is `ON`.
|
||||
- **USE_VORBIS**: Chooses if you wish to use libvorbis for support of Vorbis. The default is `ON`.
|
||||
- **USE_FFMPEG**: Chooses if you wish to use FFmpeg for support of many codecs. The default is `ON`. `FFMPEG_PATH` can also be given, so it can use official/external SDK instead of the one used in vgmstream project.
|
||||
|
10
doc/TXTH.md
10
doc/TXTH.md
@ -388,7 +388,7 @@ Sets the name of the stream, most useful when used with subsongs. TXTH will read
|
||||
|
||||
`name_size` defaults to 0, which reads until null-terminator or a non-ascii character is found.
|
||||
|
||||
`name_offset` can be a (number) value, but being an offset it's also adjusted by `subsong_spacing`. If you need to point to some absolute offset (for example a subsong pointings to name in another table) that doesn't depend on subsong (must not be changed by `subsong_spacing`), use `name_offset_absolute`.
|
||||
`name_offset` can be a (number) value, but being an offset it's also adjusted by `subsong_spacing`. If you need to point to some absolute offset (for example a subsong pointing to name in another table) that doesn't depend on subsong (must not be changed by `subsong_spacing`), use `name_offset_absolute`.
|
||||
```
|
||||
name_offset = (value)
|
||||
name_size = (value)
|
||||
@ -518,9 +518,9 @@ multi_txth = ../.main.txth
|
||||
## Complex usages
|
||||
|
||||
### Order and temporary values
|
||||
Most commands are evaluated and calculated immediatedly, every time they are found. This is by design, as it can be used to adjust and trick for certain calculations.
|
||||
Most commands are evaluated and calculated immediately, every time they are found. This is by design, as it can be used to adjust and trick for certain calculations.
|
||||
|
||||
It does make TXTHs a bit harder to follow, as they are order dependant, but otherwise it's hard to accomplish some things or others become ambiguous.
|
||||
It does make TXTHs a bit harder to follow, as they are order dependent, but otherwise it's hard to accomplish some things or others become ambiguous.
|
||||
|
||||
|
||||
For example, normally you are given a data_size in bytes, that can be used to calculate num_samples for all channels.
|
||||
@ -547,7 +547,7 @@ num_samples = @0x10 * channels # resulting bytes is transformed to samples
|
||||
Do note when using special values/strings like `data_size` in `num_samples` and `loop_end_samples` they must be alone to trigger.
|
||||
```
|
||||
data_size = @0x100
|
||||
num_samples = data_size * 2 # doesn't tranform bytes-to-samples (do it before? after?)
|
||||
num_samples = data_size * 2 # doesn't transform bytes-to-samples (do it before? after?)
|
||||
```
|
||||
```
|
||||
data_size = @0x100 * 2
|
||||
@ -665,7 +665,7 @@ Sometimes a file is just a wrapper for another common format. In those cases you
|
||||
```
|
||||
subfile_offset = 0x20 # tell TXTH to parse a full file (ex. .ogg) at this offset
|
||||
subfile_size = @0x10 # defaults to (file size - subfile_offset) if not set
|
||||
subfile_extension = ogg # may be ommited if subfile extension is the same
|
||||
subfile_extension = ogg # may be omitted if subfile extension is the same
|
||||
|
||||
# many fields are ignored
|
||||
codec = PCM16LE
|
||||
|
20
doc/TXTP.md
20
doc/TXTP.md
@ -50,7 +50,7 @@ file#12 # set "subsong" command for single file
|
||||
sounds/bgm.fsb #s2 #i #for file inside subdir: play subsong 2 + disable looping
|
||||
```
|
||||
|
||||
You can mix any kind of files (including different formats and codecs), as long as vgmstream plays them separatedly too. If you have problem getting a TXTP to play try playing file by file first and make a simpler TXTP then add more. There are technicals limits in total files (usually hundreds but varies per O.S.) and layered channels though. Also see explanations below for some per-mode limitations too.
|
||||
You can mix any kind of files (including different formats and codecs), as long as vgmstream plays them separately too. If you have problem getting a TXTP to play try playing file by file first and make a simpler TXTP then add more. There are technical limits in total files (usually hundreds but varies per O.S.) and layered channels though. Also see explanations below for some per-mode limitations too.
|
||||
|
||||
|
||||
### Segments mode
|
||||
@ -218,7 +218,7 @@ group = -S2 #segment prev 2 (will start from pos.1 = bgm1+2, makes group of bgm
|
||||
```
|
||||
|
||||
### Pseudo-random groups
|
||||
Group `R` is meant to help with games that randomly select a file in a group. You can set with `>N` which file will be selected. This way you can quickly edit the TXTP and change the file (you could just comment files too, this is just for convenience in complex cases and testing). You can also set `>-`, meaning "play all", basically turning `R` into `S` (this can be ommited, but it's clearer). Files do need to exist and are parsed before being selected, and it can select groups too.
|
||||
Group `R` is meant to help with games that randomly select a file in a group. You can set with `>N` which file will be selected. This way you can quickly edit the TXTP and change the file (you could just comment files too, this is just for convenience in complex cases and testing). You can also set `>-`, meaning "play all", basically turning `R` into `S` (this can be omitted, but it's clearer). Files do need to exist and are parsed before being selected, and it can select groups too.
|
||||
```
|
||||
bgm1.adx
|
||||
bgm2.adx
|
||||
@ -279,7 +279,7 @@ mainB_2ch.at3
|
||||
group = -L2 #@layer-v
|
||||
|
||||
# finally resulting layers are played as segments (2ch, 2ch)
|
||||
# (could set a group = S and ommit mode here, too)
|
||||
# (could set a group = S and omit mode here, too)
|
||||
mode = segments
|
||||
|
||||
# if the last group joins all as segments you can use loop_start
|
||||
@ -392,7 +392,7 @@ Usage details:
|
||||
Processing goes like this:
|
||||
- order: `pad-begin > trim-begin > body > (trim-end) > (fade-delay) > fade-period > pad-end`
|
||||
- `pad-begin` adds silence before anything else
|
||||
- `trim-begin` gets audio from `body`, but immediately removes it (substracts time from body)
|
||||
- `trim-begin` gets audio from `body`, but immediately removes it (subtracts time from body)
|
||||
- `body` is the main audio decode, possibly including N loops or silence
|
||||
- `fade-delay` waits after body (decode actually continues so it's an extension of `body`)
|
||||
- `fade-period` fades-out last decoded part
|
||||
@ -452,7 +452,7 @@ boss2_3ningumi_ver6.adx #b 100.0s #f 10.0 #plays for 100s + 10s seconds
|
||||
|
||||
|
||||
### Trim file
|
||||
**`#t(time)`**: trims the file so base sample duration (before applying loops/fades/etc) is `(time)`. If value is negative substracts `(time)` to duration.
|
||||
**`#t(time)`**: trims the file so base sample duration (before applying loops/fades/etc) is `(time)`. If value is negative subtracts `(time)` to duration.
|
||||
|
||||
*(time)* can be `M:S(.n)` (minutes and seconds), `S.n` (seconds with dot), `0xN` (samples in hex format) or `N` (samples). Beware of 10.0 (ten seconds) vs 10 (ten samples).
|
||||
|
||||
@ -485,7 +485,7 @@ If you need to remove very few samples (like 1) to get smooth transitions it may
|
||||
|
||||
|
||||
### Install loops
|
||||
**`#I(loop start time) [loop end time]`**: force/override looping values (same as .pos but nicer). Loop end is optional and defaults to total samples.
|
||||
**`#I(loop start time) [loop end time]`**: force/override looping values. Loop end is optional and defaults to total samples.
|
||||
|
||||
*(time)* can be `M:S(.n)` (minutes and seconds), `S.n` (seconds with dot), `0xN` (samples in hex format) or `N` (samples). Beware of 10.0 (ten seconds) vs 10 (ten samples).
|
||||
|
||||
@ -609,7 +609,7 @@ Possible operations:
|
||||
* between `(time-pre)` and `(time-start)` song uses `(volume-start)`
|
||||
* between `(time-start)` and `(time-end)` song gradually changes `(volume-start)` to `(volume-end)` (depending on `(shape)`)
|
||||
* between `(time-end)` and `(time-post)` song uses `(volume-end)`
|
||||
* `time-pre/post` may be -1 to set "file start" and "file end", cancelled by next fade
|
||||
* `time-pre/post` may be -1 to set "file start" and "file end", canceled by next fade
|
||||
|
||||
Considering:
|
||||
- `N` and `M` are channels (*current* value after previous operators are applied)
|
||||
@ -664,7 +664,7 @@ Manually setting values gets old, so TXTP supports a bunch of simple macros. The
|
||||
- `crosslayer-v/b/e N`: crossfades Nch layers to the main track after every loop (loop count is adjusted as needed)
|
||||
- `downmix`: downmixes up to 8 channels (7.1, 5.1, etc) to stereo, using standard downmixing formulas.
|
||||
|
||||
`channels` can be multiple comma-separated channels or N~M ranges and may be ommited were applicable to mean "all channels" (channel order doesn't matter but it's internally fixed).
|
||||
`channels` can be multiple comma-separated channels or N~M ranges and may be omitted were applicable to mean "all channels" (channel order doesn't matter but it's internally fixed).
|
||||
|
||||
Examples:
|
||||
```
|
||||
@ -868,7 +868,7 @@ To simplify TXTP creation, if the .txtp doesn't set a name inside then its filen
|
||||
|
||||
|
||||
## MIXING
|
||||
Sometimes games use multiple channels in uncommon ways, for example as layered tracks for dynamic music (like main+vocals), or crossfading a stereo song to another stereo song. In those cases we normally would want a stereo track, but vgmstream can't guess how channels are used (since it's game-dependant). To solve this via TXTP you can set mixing output and volumes manually.
|
||||
Sometimes games use multiple channels in uncommon ways, for example as layered tracks for dynamic music (like main+vocals), or crossfading a stereo song to another stereo song. In those cases we normally would want a stereo track, but vgmstream can't guess how channels are used (since it's game-dependent). To solve this via TXTP you can set mixing output and volumes manually.
|
||||
|
||||
A song file is just data that can contain a (sometimes unlimited) number of channels, that must play in physical speakers. Standard audio formats define how to "map" known channels to speakers:
|
||||
- `1.0: FC`
|
||||
@ -1026,7 +1026,7 @@ song#m1d,0*0.5
|
||||
|
||||
|
||||
## UNDERSTANDING PLAY CONFIG AND FINAL TIME
|
||||
When handling a new file, vgmstream reads its loop points and total samples. Based on that and player/TXTP's config it decides actual "final time" that is used to play it. "internal file's samples" and "external play duration" are treated separatedly, so a non-looping 100s file could be forced to play for 200s (100s of audio then 100s of silence), or a looping 100s file could be set to play 310s (so 3 loops + 10s fade).
|
||||
When handling a new file, vgmstream reads its loop points and total samples. Based on that and player/TXTP's config it decides actual "final time" that is used to play it. "internal file's samples" and "external play duration" are treated separately, so a non-looping 100s file could be forced to play for 200s (100s of audio then 100s of silence), or a looping 100s file could be set to play 310s (so 3 loops + 10s fade).
|
||||
|
||||
For example, with a 100s file that loops from 5..90s, `file.adx #p 5.0 #r 10.0 #l 2.0 #f 10.0 #P 2.0` means:
|
||||
- pad with 5s of silence first
|
||||
|
@ -1,170 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="getopt"
|
||||
ProjectGUID="{330B53AE-4FAE-46DA-8785-9016DB4E3E23}"
|
||||
RootNamespace="getopt"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\getopt.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\getopt.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@ -1,257 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="ext_libs"
|
||||
ProjectGUID="{10E6BFC6-1E5B-46E4-BA42-F04DFBD0ABFF}"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="10"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="10"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine=""
|
||||
AdditionalDependencies=""
|
||||
Outputs=""
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath=".\libmpg123-0.dll.def"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:libmpg123-0.def /machine:x86
"
|
||||
Outputs="libmpg123-0.lib libmpg123-0.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:libmpg123-0.def /machine:x86
"
|
||||
Outputs="libmpg123-0.lib libmpg123-0.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\libvorbis.def"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:libvorbis.def /machine:x86
"
|
||||
Outputs="libvorbis.lib libvorbis.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:libvorbis.def /machine:x86
"
|
||||
Outputs="libvorbis.lib libvorbis.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\libg719_decode.def"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:libg719_decode.def /machine:x86
"
|
||||
Outputs="libg719_decode.lib libg719_decode.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:libg719_decode.def /machine:x86
"
|
||||
Outputs="libg719_decode.lib libg719_decode.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\avcodec-vgmstream-58.def"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:avcodec-vgmstream-58.def /machine:x86 /out:avcodec.lib
"
|
||||
Outputs="avcodec.lib avcodec.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:avcodec-vgmstream-58.def /machine:x86 /out:avcodec.lib
"
|
||||
Outputs="avcodec.lib avcodec.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\avformat-vgmstream-58.def"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:avformat-vgmstream-58.def /machine:x86 /out:avformat.lib
"
|
||||
Outputs="avformat.lib avformat.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:avformat-vgmstream-58.def /machine:x86 /out:avformat.lib
"
|
||||
Outputs="avformat.lib avformat.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\avutil-vgmstream-56.def"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:avutil-vgmstream-56.def /machine:x86 /out:avutil.lib
"
|
||||
Outputs="avutil.lib avutil.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:avutil-vgmstream-56.def /machine:x86 /out:avutil.lib
"
|
||||
Outputs="avutil.lib avutil.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\swresample-vgmstream-3.def"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:swresample-vgmstream-3.def /machine:x86 /out:swresample.lib
"
|
||||
Outputs="swresample.lib swresample.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:swresample-vgmstream-3.def /machine:x86 /out:swresample.lib
"
|
||||
Outputs="swresample.lib swresample.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\libatrac9.def"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:libatrac9.def /machine:x86 /out:libatrac9.lib
"
|
||||
Outputs="libatrac9.lib libatrac9.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description="Building library stub"
|
||||
CommandLine="lib /def:libatrac9.def /machine:x86 /out:libatrac9.lib
"
|
||||
Outputs="libatrac9.lib libatrac9.exp"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@ -63,7 +63,7 @@ if(MSVC)
|
||||
add_dependencies(foo_input_vgmstream version_h)
|
||||
elseif(MINGW)
|
||||
if(VGMSTREAM_VERSION)
|
||||
target_compile_definitions(foo_input_vgmstream PRIVATE VERSION="${VGMSTREAM_VERSION}")
|
||||
target_compile_definitions(foo_input_vgmstream PRIVATE VGMSTREAM_VERSION="${VGMSTREAM_VERSION}")
|
||||
endif()
|
||||
|
||||
# Also, on MinGW when using GCC, these flags need to be included to prevent requiring MinGW's runtime DLLs from being included, which does unfortunately increase the size of the DLL
|
||||
|
@ -1,227 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="foo_input_vgmstream"
|
||||
ProjectGUID="{F3739CF2-F422-4A3D-BB0A-53C5D4C5ABA0}"
|
||||
RootNamespace="foo_input_vgmstream"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="0"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../ext_includes;../ext_includes/ffmpeg;"
|
||||
PreprocessorDefinitions="WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G719;VGM_USE_G7221;_DEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="shared.lib foobar2000_SDKd.lib foobar2000_component_clientd.lib pfcd.lib foobar2000_sdk_helpersd.lib ../ext_libs/libg719_decode.lib ../ext_libs/libvorbis.lib ../ext_libs/libmpg123-0.lib ../ext_libs/avcodec.lib ../ext_libs/avformat.lib ../ext_libs/avutil.lib ../ext_libs/swresample.lib"
|
||||
OutputFile="$(OutDir)\$(ProjectName).dll"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories=""
|
||||
DelayLoadDLLs=""
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
Description=""
|
||||
CommandLine=""
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="../ext_includes;../ext_includes/ffmpeg;"
|
||||
PreprocessorDefinitions="WIN32;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_FFMPEG;VGM_USE_G719;VGM_USE_G7221;NDEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="shared.lib foobar2000_SDK.lib foobar2000_sdk_helpers.lib foobar2000_component_client.lib pfc.lib ../ext_libs/libvorbis.lib ../ext_libs/libmpg123-0.lib ../ext_libs/libg719_decode.lib ../ext_libs/avcodec.lib ../ext_libs/avformat.lib ../ext_libs/avutil.lib ../ext_libs/swresample.lib"
|
||||
OutputFile="$(OutDir)\$(ProjectName).dll"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories=""
|
||||
IgnoreDefaultLibraryNames=""
|
||||
DelayLoadDLLs=""
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\foo_vgmstream.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\resource1.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\foo_input_vgmstream.rc"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\foo_prefs.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\foo_streamfile.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\foo_vgmstream.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
<Global
|
||||
Name="RESOURCE_FILE"
|
||||
Value="foo_input_vgmstream.rc"
|
||||
/>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@ -88,10 +88,10 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>"$(ProjectDir)..\version.bat" "$(ProjectDir)..\version.h" VERSION</Command>
|
||||
<Command>"$(ProjectDir)..\version-make.bat"</Command>
|
||||
</PreBuildEvent>
|
||||
<PreBuildEvent>
|
||||
<Message>Generating version.h</Message>
|
||||
<Message>Generating version</Message>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@ -118,10 +118,10 @@
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>"$(ProjectDir)..\version.bat" "$(ProjectDir)..\version.h" VERSION</Command>
|
||||
<Command>"$(ProjectDir)..\version-make.bat"</Command>
|
||||
</PreBuildEvent>
|
||||
<PreBuildEvent>
|
||||
<Message>Generating version.h</Message>
|
||||
<Message>Generating version</Message>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
@ -19,18 +19,17 @@ extern "C" {
|
||||
#include "foo_vgmstream.h"
|
||||
#include "foo_filetypes.h"
|
||||
|
||||
#ifndef VERSION
|
||||
#include "version.h"
|
||||
#ifndef VGMSTREAM_VERSION
|
||||
#include "../version.h"
|
||||
#endif
|
||||
|
||||
#ifndef VERSION
|
||||
#ifndef VGMSTREAM_VERSION
|
||||
#define PLUGIN_VERSION __DATE__
|
||||
#else
|
||||
#define PLUGIN_VERSION VERSION
|
||||
#define PLUGIN_VERSION VGMSTREAM_VERSION
|
||||
#endif
|
||||
|
||||
#define APP_NAME "vgmstream plugin"
|
||||
#define PLUGIN_DESCRIPTION "vgmstream plugin " VERSION " " __DATE__ "\n" \
|
||||
#define PLUGIN_DESCRIPTION "vgmstream plugin " VGMSTREAM_VERSION " " __DATE__ "\n" \
|
||||
"by hcs, FastElbja, manakoAT, bxaimc, snakemeat, soneek, kode54, bnnm and many others\n" \
|
||||
"\n" \
|
||||
"foobar2000 plugin by Josh W, kode54\n" \
|
||||
|
@ -1 +0,0 @@
|
||||
powershell -ExecutionPolicy Bypass -NoProfile -File .\build.ps1 Init
|
1
msvc-build-clean.bat
Normal file
1
msvc-build-clean.bat
Normal file
@ -0,0 +1 @@
|
||||
powershell -ExecutionPolicy Bypass -NoProfile -File .\msvc-build.ps1 Clean
|
1
msvc-build-init.bat
Normal file
1
msvc-build-init.bat
Normal file
@ -0,0 +1 @@
|
||||
powershell -ExecutionPolicy Bypass -NoProfile -File .\msvc-build.ps1 Init
|
1
msvc-build.bat
Normal file
1
msvc-build.bat
Normal file
@ -0,0 +1 @@
|
||||
powershell -ExecutionPolicy Bypass -NoProfile -File .\msvc-build.ps1 Build
|
170
msvc-build.ps1
Normal file
170
msvc-build.ps1
Normal file
@ -0,0 +1,170 @@
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[Parameter(Position=0, mandatory=$true)]
|
||||
[ValidateSet("Init", "Build", "Rebuild", "Clean")]
|
||||
[string]$Task
|
||||
)
|
||||
|
||||
###############################################################################
|
||||
# CONFIG
|
||||
# set these vars to override project defaults
|
||||
# can also create a mssvc-build.config.ps1 with those
|
||||
###############################################################################
|
||||
$config_file = ".\msvc-build.config.ps1"
|
||||
if((Test-Path $config_file)) { . $config_file }
|
||||
|
||||
# - toolsets: "" (default), "v140" (MSVC 2015), "v141" (MSVC 2017), "v141_xp" (XP support), "v142" (MSVC 2019), etc
|
||||
if (!$toolset) { $toolset = "" }
|
||||
# - sdks: "" (default), "7.0" (Win7 SDK), "8.1" (Win8 SDK), "10.0" (Win10 SDK), etc
|
||||
if (!$sdk) { $sdk = "" }
|
||||
# - platforms: "" (default), "Win32"
|
||||
if (!$platform) { $platform = "" }
|
||||
###############################################################################
|
||||
|
||||
$solution = "vgmstream_full.sln"
|
||||
$dependencies = "dependencies"
|
||||
$vswhere = "$dependencies/vswhere.exe"
|
||||
$config = "/p:Configuration=Release"
|
||||
# not used ATM
|
||||
$enable_aac = 0
|
||||
|
||||
if ($platform) { $platform = "/p:Platform=" + $platform }
|
||||
if ($toolset) { $toolset = "/p:PlatformToolset=" + $toolset }
|
||||
if ($sdk) { $sdk = "/p:WindowsTargetPlatformVersion=" + $sdk }
|
||||
|
||||
# https://stackoverflow.com/a/41618979/9919772
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
|
||||
# helper
|
||||
function Unzip
|
||||
{
|
||||
param([string]$zipfile, [string]$outpath)
|
||||
Write-Output "Extracting $zipfile"
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath)
|
||||
}
|
||||
|
||||
# helper
|
||||
function Download
|
||||
{
|
||||
param([string]$uri, [string]$outfile)
|
||||
Write-Output "Downloading $uri"
|
||||
$wc = New-Object net.webclient
|
||||
$wc.Downloadfile($uri, $outfile)
|
||||
}
|
||||
|
||||
# download and unzip dependencies
|
||||
function Init
|
||||
{
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
|
||||
Remove-Item -Path "$dependencies" -Recurse -ErrorAction Ignore
|
||||
New-Item "$dependencies" -Type directory -Force | out-null
|
||||
|
||||
# vswhere: MSBuild locator
|
||||
# may already be in %ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe
|
||||
# so could test that and skip this step
|
||||
Download "https://github.com/Microsoft/vswhere/releases/download/2.6.7/vswhere.exe" "$dependencies\vswhere.exe"
|
||||
|
||||
# foobar: wtl
|
||||
Download "https://www.nuget.org/api/v2/package/wtl/9.1.1" "$dependencies\wtl.zip"
|
||||
Unzip "$dependencies\wtl.zip" "$dependencies\wtl_tmp"
|
||||
Move-Item "$dependencies\wtl_tmp\lib\native" "$dependencies\wtl"
|
||||
Remove-Item -Path "$dependencies\wtl_tmp" -Recurse
|
||||
|
||||
# foobar: sdk anti-hotlink (random link) defeater
|
||||
#Download "https://www.foobar2000.org/SDK" "$dependencies\SDK"
|
||||
#$key = (Select-String -Path $dependencies\SDK -Pattern "\/([a-f0-9]+)\/SDK-2018-01-11\.zip").matches.groups[1]
|
||||
#Remove-Item -Path "$dependencies\SDK"
|
||||
#Download "https://www.foobar2000.org/files/$key/SDK-2018-01-11.zip" "$dependencies\foobar.zip"
|
||||
|
||||
# foobar: sdk direct link, but 2019< sdks gone ATM
|
||||
#Download "https://www.foobar2000.org/files/SDK-2018-01-11.zip" "$dependencies\foobar.zip"
|
||||
|
||||
# foobar: sdk static mirror
|
||||
Download "https://github.com/vgmstream/vgmstream-deps/raw/master/foobar2000/SDK-2018-02-05.zip" "$dependencies\foobar.zip"
|
||||
Unzip "$dependencies\foobar.zip" "$dependencies\foobar"
|
||||
|
||||
# foobar: aac (not used ATM)
|
||||
if ($enable_aac)
|
||||
{
|
||||
Download "https://github.com/kode54/fdk-aac/archive/master.zip" "$dependencies\fdk-aac.zip"
|
||||
Download "https://github.com/kode54/qaac/archive/master.zip" "$dependencies\qaac.zip"
|
||||
Unzip "$dependencies\fdk-aac.zip" "$dependencies\fdk-aac_tmp"
|
||||
Unzip "$dependencies\qaac.zip" "$dependencies\qaac_tmp"
|
||||
Move-Item "$dependencies\fdk-aac_tmp\fdk-aac-master" "$dependencies\fdk-aac"
|
||||
Move-Item "$dependencies\qaac_tmp\qaac-master" "$dependencies\qaac"
|
||||
Remove-Item -Path "$dependencies\fdk-aac_tmp" -Recurse
|
||||
Remove-Item -Path "$dependencies\qaac_tmp" -Recurse
|
||||
}
|
||||
|
||||
# open foobar sdk project and modify WTL path
|
||||
# (maybe should just pass include to CL envvar: set CL=/I"(path)\WTL\Include")
|
||||
[xml]$proj = Get-Content $dependencies\foobar\foobar2000\ATLHelpers\foobar2000_ATL_helpers.vcxproj
|
||||
$proj.project.ItemDefinitionGroup | ForEach-Object {
|
||||
$includes = $proj.CreateElement("AdditionalIncludeDirectories", $proj.project.NamespaceURI)
|
||||
$includes.InnerText = "../../../wtl/include"
|
||||
$_.ClCompile.AppendChild($includes)
|
||||
}
|
||||
$proj.Save("$dependencies\foobar\foobar2000\ATLHelpers\foobar2000_ATL_helpers.vcxproj")
|
||||
}
|
||||
|
||||
# main build
|
||||
function CallMsbuild
|
||||
{
|
||||
param([string]$target)
|
||||
if ($target) { $target = "/t:" + $target }
|
||||
|
||||
# download dependencies if needed
|
||||
if(!(Test-Path $vswhere)) { Init }
|
||||
|
||||
|
||||
# autolocate MSBuild path
|
||||
$msbuild = & $vswhere -latest -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe
|
||||
|
||||
if(!($msbuild -and $(Test-Path $msbuild))) {
|
||||
Write-Error "Unable to find MSBuild. Is Visual Studio installed?"
|
||||
}
|
||||
|
||||
# main build (pass config separate and not as a single string)
|
||||
& $msbuild $solution $config $platform $toolset $sdk $target /m
|
||||
}
|
||||
|
||||
function Build
|
||||
{
|
||||
CallMsbuild "Build"
|
||||
}
|
||||
|
||||
function Rebuild
|
||||
{
|
||||
CallMsbuild "Rebuild"
|
||||
}
|
||||
function Clean
|
||||
{
|
||||
CallMsbuild "Clean"
|
||||
# todo fix the above, for now:
|
||||
#Remove-Item -Path "$dependencies" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "cli/Debug" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "cli/Release" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "ext_libs/Debug" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "ext_libs/Release" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "ext_libs/Getopt/Release" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "ext_libs/Getopt/Release" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "fb2k/Debug" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "fb2k/Release" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "src/Debug" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "src/Release" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "winamp/Debug" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "winamp/Release" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "xmplay/Debug" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "xmplay/Release" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "Debug" -Recurse -ErrorAction Ignore
|
||||
Remove-Item -Path "Release" -Recurse -ErrorAction Ignore
|
||||
}
|
||||
|
||||
switch ($Task)
|
||||
{
|
||||
"Init" { Init }
|
||||
"Build" { Build }
|
||||
"Rebuild" { Rebuild }
|
||||
"Clean" { Clean }
|
||||
}
|
@ -29,6 +29,9 @@ OBJECTS += $(EXT_LIBS_OBJS)
|
||||
libvgmstream.a: $(OBJECTS)
|
||||
$(AR) crs libvgmstream.a $(OBJECTS)
|
||||
|
||||
libvgmstream.so: $(OBJECTS)
|
||||
$(LD) -shared -o libvgmstream.so $(OBJECTS)
|
||||
|
||||
#vgmstream-deps:
|
||||
# $(CC) $(CFLAGS) -M -o vgmstream-deps
|
||||
|
||||
|
@ -310,6 +310,7 @@ void decode_relic(VGMSTREAMCHANNEL* stream, relic_codec_data* data, sample_t* ou
|
||||
void reset_relic(relic_codec_data* data);
|
||||
void seek_relic(relic_codec_data* data, int32_t num_sample);
|
||||
void free_relic(relic_codec_data* data);
|
||||
int32_t relic_bytes_to_samples(size_t bytes, int channels, int bitrate);
|
||||
|
||||
|
||||
/* hca_decoder */
|
||||
|
@ -1,72 +1,57 @@
|
||||
#include <math.h>
|
||||
#include "coding.h"
|
||||
#include "relic_decoder_lib.h"
|
||||
|
||||
/* Relic Codec decoder, a fairly simple mono-interleave DCT-based codec.
|
||||
*
|
||||
* Decompiled from Relic's dec.exe with some info from Homeworld source code .h/lib
|
||||
* files (released around 2003 through Relic Dev Network), accurate with minor +-1
|
||||
* samples due to double<>float ops or maybe original compiler (Intel's) diffs.
|
||||
*
|
||||
* TODO: clean API, improve validations (can segfault on bad data) and naming
|
||||
*/
|
||||
|
||||
/* mixfft.c */
|
||||
extern void fft(int n, float *xRe, float *xIm, float *yRe, float *yIm);
|
||||
|
||||
static relic_codec_data* init_codec(int channels, int bitrate, int codec_rate);
|
||||
static int decode_frame_next(VGMSTREAMCHANNEL* stream, relic_codec_data* data);
|
||||
static void copy_samples(relic_codec_data* data, sample_t* outbuf, int32_t samples_to_get);
|
||||
static void reset_codec(relic_codec_data* data);
|
||||
|
||||
#define RELIC_MAX_CHANNELS 2
|
||||
#define RELIC_MAX_SCALES 6
|
||||
#define RELIC_BASE_SCALE 10.0f
|
||||
#define RELIC_FREQUENCY_MASKING_FACTOR 1.0f
|
||||
#define RELIC_CRITICAL_BAND_COUNT 27
|
||||
#define RELIC_PI 3.14159265358979323846f
|
||||
#define RELIC_SIZE_LOW 128
|
||||
#define RELIC_SIZE_MID 256
|
||||
#define RELIC_SIZE_HIGH 512
|
||||
#define RELIC_MAX_SIZE RELIC_SIZE_HIGH
|
||||
#define RELIC_MAX_FREQ (RELIC_MAX_SIZE / 2)
|
||||
#define RELIC_MAX_FFT (RELIC_MAX_SIZE / 4)
|
||||
#define RELIC_BITRATE_22 256
|
||||
#define RELIC_BITRATE_44 512
|
||||
#define RELIC_BITRATE_88 1024
|
||||
#define RELIC_BITRATE_176 2048
|
||||
#define RELIC_MAX_FRAME_SIZE ((RELIC_BITRATE_176 / 8) + 0x04) /* extra 0x04 for the bitreader */
|
||||
|
||||
//TODO: fix looping
|
||||
|
||||
struct relic_codec_data {
|
||||
/* decoder info */
|
||||
relic_handle_t* handle;
|
||||
int channels;
|
||||
int frame_size;
|
||||
int wave_size;
|
||||
int freq_size;
|
||||
int dct_mode;
|
||||
int samples_mode;
|
||||
/* decoder init state */
|
||||
float scales[RELIC_MAX_SCALES]; /* quantization scales */
|
||||
float dct[RELIC_MAX_SIZE];
|
||||
float window[RELIC_MAX_SIZE];
|
||||
/* decoder frame state */
|
||||
uint8_t exponents[RELIC_MAX_CHANNELS][RELIC_MAX_FREQ]; /* quantization/scale indexes */
|
||||
float freq1[RELIC_MAX_FREQ]; /* dequantized spectrum */
|
||||
float freq2[RELIC_MAX_FREQ];
|
||||
float wave_cur[RELIC_MAX_CHANNELS][RELIC_MAX_SIZE]; /* current frame samples */
|
||||
float wave_prv[RELIC_MAX_CHANNELS][RELIC_MAX_SIZE]; /* previous frame samples */
|
||||
|
||||
/* sample state */
|
||||
int32_t samples_discard;
|
||||
int32_t samples_consumed;
|
||||
int32_t samples_filled;
|
||||
};
|
||||
|
||||
/* ************************************* */
|
||||
|
||||
|
||||
relic_codec_data* init_relic(int channels, int bitrate, int codec_rate) {
|
||||
return init_codec(channels, bitrate, codec_rate);
|
||||
relic_codec_data* data = NULL;
|
||||
|
||||
data = calloc(1, sizeof(relic_codec_data));
|
||||
if (!data) goto fail;
|
||||
|
||||
data->handle = relic_init(channels, bitrate, codec_rate);
|
||||
if (!data->handle) goto fail;
|
||||
|
||||
data->channels = channels;
|
||||
data->frame_size = relic_get_frame_size(data->handle);
|
||||
|
||||
return data;
|
||||
fail:
|
||||
free_relic(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int decode_frame_next(VGMSTREAMCHANNEL* stream, relic_codec_data* data) {
|
||||
int ch;
|
||||
int bytes;
|
||||
int ok;
|
||||
uint8_t buf[RELIC_BUFFER_SIZE];
|
||||
|
||||
for (ch = 0; ch < data->channels; ch++) {
|
||||
bytes = read_streamfile(buf, stream->offset, data->frame_size, stream->streamfile);
|
||||
if (bytes != data->frame_size) goto fail;
|
||||
stream->offset += data->frame_size;
|
||||
|
||||
ok = relic_decode_frame(data->handle, buf, ch);
|
||||
if (!ok) goto fail;
|
||||
}
|
||||
|
||||
data->samples_consumed = 0;
|
||||
data->samples_filled = RELIC_SAMPLES_PER_FRAME;
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void decode_relic(VGMSTREAMCHANNEL* stream, relic_codec_data* data, sample_t* outbuf, int32_t samples_to_do) {
|
||||
@ -88,7 +73,7 @@ void decode_relic(VGMSTREAMCHANNEL* stream, relic_codec_data* data, sample_t* ou
|
||||
if (samples_to_get > samples_to_do)
|
||||
samples_to_get = samples_to_do;
|
||||
|
||||
copy_samples(data, outbuf, samples_to_get);
|
||||
relic_get_pcm16(data->handle, outbuf, samples_to_get, data->samples_consumed);
|
||||
|
||||
samples_to_do -= samples_to_get;
|
||||
outbuf += samples_to_get * data->channels;
|
||||
@ -113,7 +98,7 @@ decode_fail:
|
||||
void reset_relic(relic_codec_data* data) {
|
||||
if (!data) return;
|
||||
|
||||
reset_codec(data);
|
||||
relic_reset(data->handle);
|
||||
data->samples_filled = 0;
|
||||
data->samples_consumed = 0;
|
||||
data->samples_discard = 0;
|
||||
@ -129,378 +114,10 @@ void seek_relic(relic_codec_data* data, int32_t num_sample) {
|
||||
void free_relic(relic_codec_data* data) {
|
||||
if (!data) return;
|
||||
|
||||
relic_free(data->handle);
|
||||
free(data);
|
||||
}
|
||||
|
||||
/* ***************************************** */
|
||||
|
||||
static const int16_t critical_band_data[RELIC_CRITICAL_BAND_COUNT] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
9, 11, 13, 15, 17, 20, 23, 27,
|
||||
31, 37, 43, 51, 62, 74, 89, 110,
|
||||
139, 180, 256
|
||||
};
|
||||
|
||||
static void init_dct(float *dct, int dct_size) {
|
||||
int i;
|
||||
int dct_quarter = dct_size >> 2;
|
||||
|
||||
for (i = 0; i < dct_quarter; i++) {
|
||||
double temp = ((float)i + 0.125f) * (RELIC_PI * 2.0f) * (1.0f / (float)dct_size);
|
||||
dct[i] = sin(temp);
|
||||
dct[dct_quarter + i] = cos(temp);
|
||||
}
|
||||
}
|
||||
|
||||
static int apply_idct(const float *freq, float *wave, const float *dct, int dct_size) {
|
||||
int i;
|
||||
float factor;
|
||||
float out_re[RELIC_MAX_FFT];
|
||||
float out_im[RELIC_MAX_FFT];
|
||||
float in_re[RELIC_MAX_FFT];
|
||||
float in_im[RELIC_MAX_FFT];
|
||||
float wave_tmp[RELIC_MAX_SIZE];
|
||||
int dct_half = dct_size >> 1;
|
||||
int dct_quarter = dct_size >> 2;
|
||||
int dct_3quarter = 3 * (dct_size >> 2);
|
||||
|
||||
/* prerotation? */
|
||||
for (i = 0; i < dct_quarter; i++) {
|
||||
float coef1 = freq[2 * i] * 0.5f;
|
||||
float coef2 = freq[dct_half - 1 - 2 * i] * 0.5f;
|
||||
in_re[i] = coef1 * dct[dct_quarter + i] + coef2 * dct[i];
|
||||
in_im[i] = -coef1 * dct[i] + coef2 * dct[dct_quarter + i];
|
||||
}
|
||||
|
||||
/* main FFT */
|
||||
fft(dct_quarter, in_re, in_im, out_re, out_im);
|
||||
|
||||
/* postrotation, window and reorder? */
|
||||
factor = 8.0 / sqrt(dct_size);
|
||||
for (i = 0; i < dct_quarter; i++) {
|
||||
float out_re_i = out_re[i];
|
||||
out_re[i] = (out_re[i] * dct[dct_quarter + i] + out_im[i] * dct[i]) * factor;
|
||||
out_im[i] = (-out_re_i * dct[i] + out_im[i] * dct[dct_quarter + i]) * factor;
|
||||
wave_tmp[i * 2] = out_re[i];
|
||||
wave_tmp[i * 2 + dct_half] = out_im[i];
|
||||
}
|
||||
for (i = 1; i < dct_size; i += 2) {
|
||||
wave_tmp[i] = -wave_tmp[dct_size - 1 - i];
|
||||
}
|
||||
|
||||
/* wave mix thing? */
|
||||
for (i = 0; i < dct_3quarter; i++) {
|
||||
wave[i] = wave_tmp[dct_quarter + i];
|
||||
}
|
||||
for (i = dct_3quarter; i < dct_size; i++) {
|
||||
wave[i] = -wave_tmp[i - dct_3quarter];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void decode_frame(const float *freq1, const float *freq2, float *wave_cur, float *wave_prv, const float *dct, const float *window, int dct_size) {
|
||||
int i;
|
||||
float wave_tmp[RELIC_MAX_SIZE];
|
||||
int dct_half = dct_size >> 1;
|
||||
|
||||
/* copy for first half(?) */
|
||||
memcpy(wave_cur, wave_prv, RELIC_MAX_SIZE * sizeof(float));
|
||||
|
||||
/* transform frequency domain to time domain with DCT/FFT */
|
||||
apply_idct(freq1, wave_tmp, dct, dct_size);
|
||||
apply_idct(freq2, wave_prv, dct, dct_size);
|
||||
|
||||
/* overlap and apply window function to filter this block's beginning */
|
||||
for (i = 0; i < dct_half; i++) {
|
||||
wave_cur[dct_half + i] = wave_tmp[i] * window[i] + wave_cur[dct_half + i] * window[dct_half + i];
|
||||
wave_prv[i] = wave_prv[i] * window[i] + wave_tmp[dct_half + i] * window[dct_half + i];
|
||||
}
|
||||
}
|
||||
|
||||
static void init_window(float *window, int dct_size) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dct_size; i++) {
|
||||
window[i] = sin((float)i * (RELIC_PI / dct_size));
|
||||
}
|
||||
}
|
||||
|
||||
static void decode_frame_base(const float *freq1, const float *freq2, float *wave_cur, float *wave_prv, const float *dct, const float *window, int dct_mode, int samples_mode) {
|
||||
int i;
|
||||
float wave_tmp[RELIC_MAX_SIZE];
|
||||
|
||||
/* dec_relic only uses 512/512 mode, source references 256/256 (effects only?) too */
|
||||
|
||||
if (samples_mode == RELIC_SIZE_LOW) {
|
||||
{
|
||||
/* 128 DCT to 128 samples */
|
||||
decode_frame(freq1, freq2, wave_cur, wave_prv, dct, window, RELIC_SIZE_LOW);
|
||||
}
|
||||
}
|
||||
else if (samples_mode == RELIC_SIZE_MID) {
|
||||
if (dct_mode == RELIC_SIZE_LOW) {
|
||||
/* 128 DCT to 256 samples (repeat sample x2) */
|
||||
decode_frame(freq1, freq2, wave_tmp, wave_prv, dct, window, RELIC_SIZE_LOW);
|
||||
for (i = 0; i < 256 - 1; i += 2) {
|
||||
wave_cur[i + 0] = wave_tmp[i >> 1];
|
||||
wave_cur[i + 1] = wave_tmp[i >> 1];
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* 256 DCT to 256 samples */
|
||||
decode_frame(freq1, freq2, wave_cur, wave_prv, dct, window, RELIC_SIZE_MID);
|
||||
}
|
||||
}
|
||||
else if (samples_mode == RELIC_SIZE_HIGH) {
|
||||
if (dct_mode == RELIC_SIZE_LOW) {
|
||||
/* 128 DCT to 512 samples (repeat sample x4) */
|
||||
decode_frame(freq1, freq2, wave_tmp, wave_prv, dct, window, RELIC_SIZE_LOW);
|
||||
for (i = 0; i < 512 - 1; i += 4) {
|
||||
wave_cur[i + 0] = wave_tmp[i >> 2];
|
||||
wave_cur[i + 1] = wave_tmp[i >> 2];
|
||||
wave_cur[i + 2] = wave_tmp[i >> 2];
|
||||
wave_cur[i + 3] = wave_tmp[i >> 2];
|
||||
}
|
||||
}
|
||||
else if (dct_mode == RELIC_SIZE_MID) {
|
||||
/* 256 DCT to 512 samples (repeat sample x2) */
|
||||
decode_frame(freq1, freq2, wave_tmp, wave_prv, dct, window, RELIC_SIZE_MID);
|
||||
for (i = 0; i < 512 - 1; i += 2) {
|
||||
wave_cur[i + 0] = wave_tmp[i >> 1];
|
||||
wave_cur[i + 1] = wave_tmp[i >> 1];
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* 512 DCT to 512 samples */
|
||||
decode_frame(freq1, freq2, wave_cur, wave_prv, dct, window, RELIC_SIZE_HIGH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* reads 32b max, packed in LSB order per byte (like Vorbis), ex.
|
||||
* with 0x45 6A=01000101 01101010 could read 4b=0101, 6b=100100, 3b=010 ...
|
||||
* assumes buf has enough extra bits to read 32b (size +0x04) */
|
||||
static uint32_t read_ubits(uint8_t bits, uint32_t offset, uint8_t *buf) {
|
||||
uint32_t shift, mask, pos, val;
|
||||
|
||||
shift = offset - 8 * (offset / 8);
|
||||
mask = (1 << bits) - 1;
|
||||
pos = offset / 8;
|
||||
val = (buf[pos+0]) | (buf[pos+1]<<8) | (buf[pos+2]<<16) | (buf[pos+3]<<24);
|
||||
return (val >> shift) & mask;
|
||||
}
|
||||
static int read_sbits(uint8_t bits, uint32_t offset, uint8_t *buf) {
|
||||
uint32_t val = read_ubits(bits, offset, buf);
|
||||
int outval;
|
||||
if (val >> (bits - 1) == 1) { /* upper bit = sign */
|
||||
uint32_t mask = (1 << (bits - 1)) - 1;
|
||||
outval = (int)(val & mask);
|
||||
outval = -outval;
|
||||
}
|
||||
else {
|
||||
outval = (int)val;
|
||||
}
|
||||
return outval;
|
||||
}
|
||||
|
||||
static void init_dequantization(float* scales) {
|
||||
int i;
|
||||
|
||||
scales[0] = RELIC_BASE_SCALE;
|
||||
for (i = 1; i < RELIC_MAX_SCALES; i++) {
|
||||
scales[i] = scales[i - 1] * scales[0];
|
||||
}
|
||||
for (i = 0; i < RELIC_MAX_SCALES; i++) {
|
||||
scales[i] = RELIC_FREQUENCY_MASKING_FACTOR / (double) ((1 << (i + 1)) - 1) * scales[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void unpack_frame(uint8_t *buf, int buf_size, float *freq1, float *freq2, const float* scales, uint8_t *exponents, int freq_size) {
|
||||
uint8_t flags, cb_bits, ev_bits, ei_bits, qv_bits;
|
||||
int qv;
|
||||
uint8_t ev;
|
||||
uint8_t move, pos;
|
||||
uint32_t bit_offset;
|
||||
int i, j;
|
||||
int freq_half = freq_size >> 1;
|
||||
|
||||
|
||||
memset(freq1, 0, RELIC_MAX_FREQ * sizeof(float));
|
||||
memset(freq2, 0, RELIC_MAX_FREQ * sizeof(float));
|
||||
|
||||
flags = read_ubits(2u, 0u, buf);
|
||||
cb_bits = read_ubits(3u, 2u, buf);
|
||||
ev_bits = read_ubits(2u, 5u, buf);
|
||||
ei_bits = read_ubits(4u, 7u, buf);
|
||||
bit_offset = 11;
|
||||
|
||||
/* reset exponents indexes */
|
||||
if ((flags & 1) == 1) {
|
||||
memset(exponents, 0, RELIC_MAX_FREQ);
|
||||
}
|
||||
|
||||
/* read packed exponents indexes for all bands */
|
||||
if (cb_bits > 0 && ev_bits > 0) {
|
||||
pos = 0;
|
||||
for (i = 0; i < RELIC_CRITICAL_BAND_COUNT - 1; i++) {
|
||||
if (bit_offset >= 8u*buf_size)
|
||||
break;
|
||||
|
||||
move = read_ubits(cb_bits, bit_offset, buf);
|
||||
bit_offset += cb_bits;
|
||||
if (i > 0 && move == 0)
|
||||
break;
|
||||
pos += move;
|
||||
|
||||
ev = read_ubits(ev_bits, bit_offset, buf);
|
||||
bit_offset += ev_bits;
|
||||
for (j = critical_band_data[pos]; j < critical_band_data[pos + 1]; j++)
|
||||
exponents[j] = ev;
|
||||
}
|
||||
}
|
||||
|
||||
/* read quantized values */
|
||||
if (freq_half > 0 && ei_bits > 0) {
|
||||
|
||||
/* read first part */
|
||||
pos = 0;
|
||||
for (i = 0; i < RELIC_MAX_FREQ; i++) {
|
||||
if (bit_offset >= 8u*buf_size)
|
||||
break;
|
||||
|
||||
move = read_ubits(ei_bits, bit_offset, buf);
|
||||
bit_offset += ei_bits;
|
||||
if (i > 0 && move == 0)
|
||||
break;
|
||||
pos += move;
|
||||
|
||||
qv_bits = exponents[pos];
|
||||
qv = read_sbits(qv_bits + 2u, bit_offset, buf);
|
||||
bit_offset += qv_bits + 2u;
|
||||
|
||||
if (qv != 0 && pos < freq_half && qv_bits < 6)
|
||||
freq1[pos] = (float)qv * scales[qv_bits];
|
||||
}
|
||||
|
||||
/* read second part, or clone it */
|
||||
if ((flags & 2) == 2) {
|
||||
memcpy(freq2, freq1, RELIC_MAX_FREQ * sizeof(float));
|
||||
}
|
||||
else {
|
||||
pos = 0;
|
||||
for (i = 0; i < RELIC_MAX_FREQ; i++) {
|
||||
if (bit_offset >= 8u*buf_size)
|
||||
break;
|
||||
|
||||
move = read_ubits(ei_bits, bit_offset, buf);
|
||||
bit_offset += ei_bits;
|
||||
if (i > 0 && move == 0)
|
||||
break;
|
||||
pos += move;
|
||||
|
||||
qv_bits = exponents[pos];
|
||||
qv = read_sbits(qv_bits + 2u, bit_offset, buf);
|
||||
bit_offset += qv_bits + 2u;
|
||||
|
||||
if (qv != 0 && pos < freq_half && qv_bits < 6)
|
||||
freq2[pos] = (float)qv * scales[qv_bits];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int decode_frame_next(VGMSTREAMCHANNEL* stream, relic_codec_data* data) {
|
||||
int ch;
|
||||
int bytes;
|
||||
uint8_t buf[RELIC_MAX_FRAME_SIZE];
|
||||
|
||||
for (ch = 0; ch < data->channels; ch++) {
|
||||
/* clean extra bytes for bitreader */
|
||||
memset(buf + data->frame_size, 0, RELIC_MAX_FRAME_SIZE - data->frame_size);
|
||||
|
||||
bytes = read_streamfile(buf, stream->offset, data->frame_size, stream->streamfile);
|
||||
if (bytes != data->frame_size) goto fail;
|
||||
stream->offset += data->frame_size;
|
||||
|
||||
unpack_frame(buf, sizeof(buf), data->freq1, data->freq2, data->scales, data->exponents[ch], data->freq_size);
|
||||
|
||||
decode_frame_base(data->freq1, data->freq2, data->wave_cur[ch], data->wave_prv[ch], data->dct, data->window, data->dct_mode, data->samples_mode);
|
||||
}
|
||||
|
||||
data->samples_consumed = 0;
|
||||
data->samples_filled = data->wave_size;
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void copy_samples(relic_codec_data* data, sample_t* outbuf, int32_t samples) {
|
||||
int s, ch;
|
||||
int ichs = data->channels;
|
||||
int skip = data->samples_consumed;
|
||||
for (ch = 0; ch < ichs; ch++) {
|
||||
for (s = 0; s < samples; s++) {
|
||||
double d64_sample = data->wave_cur[ch][skip + s];
|
||||
int pcm_sample = clamp16((int32_t)d64_sample);
|
||||
|
||||
/* f32 in PCM 32767.0 .. -32768.0 format, original code
|
||||
* does some custom double-to-int rint() though */
|
||||
//FQ_BNUM ((float)(1<<26)*(1<<26)*1.5)
|
||||
//rint(x) ((d64 = (double)(x)+FQ_BNUM), *(int*)(&d64))
|
||||
|
||||
outbuf[s*ichs + ch] = pcm_sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static relic_codec_data* init_codec(int channels, int bitrate, int codec_rate) {
|
||||
relic_codec_data *data = NULL;
|
||||
|
||||
if (channels > RELIC_MAX_CHANNELS)
|
||||
goto fail;
|
||||
|
||||
data = calloc(1, sizeof(relic_codec_data));
|
||||
if (!data) goto fail;
|
||||
|
||||
data->channels = channels;
|
||||
|
||||
/* dequantized freq1+2 size (separate from DCT) */
|
||||
if (codec_rate < 22050) /* probably 11025 only */
|
||||
data->freq_size = RELIC_SIZE_LOW;
|
||||
if (codec_rate == 22050)
|
||||
data->freq_size = RELIC_SIZE_MID;
|
||||
if (codec_rate > 22050) /* probably 44100 only */
|
||||
data->freq_size = RELIC_SIZE_HIGH;
|
||||
|
||||
/* default for streams (only a few mode combos are valid, see decode) */
|
||||
data->wave_size = RELIC_SIZE_HIGH;
|
||||
data->dct_mode = RELIC_SIZE_HIGH;
|
||||
data->samples_mode = RELIC_SIZE_HIGH;
|
||||
|
||||
init_dct(data->dct, RELIC_SIZE_HIGH);
|
||||
init_window(data->window, RELIC_SIZE_HIGH);
|
||||
init_dequantization(data->scales);
|
||||
memset(data->wave_prv, 0, RELIC_MAX_CHANNELS * RELIC_MAX_SIZE * sizeof(float));
|
||||
|
||||
switch(bitrate) {
|
||||
case RELIC_BITRATE_22:
|
||||
case RELIC_BITRATE_44:
|
||||
case RELIC_BITRATE_88:
|
||||
case RELIC_BITRATE_176:
|
||||
data->frame_size = (bitrate / 8); /* 0x100 and 0x80 are common */
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
return data;
|
||||
fail:
|
||||
free_relic(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void reset_codec(relic_codec_data* data) {
|
||||
memset(data->wave_prv, 0, RELIC_MAX_CHANNELS * RELIC_MAX_SIZE * sizeof(float));
|
||||
int32_t relic_bytes_to_samples(size_t bytes, int channels, int bitrate) {
|
||||
return bytes / channels / (bitrate / 8) * RELIC_SAMPLES_PER_FRAME;
|
||||
}
|
||||
|
452
src/coding/relic_decoder_lib.c
Normal file
452
src/coding/relic_decoder_lib.c
Normal file
@ -0,0 +1,452 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "relic_decoder_lib.h"
|
||||
|
||||
/* Relic Codec decoder, a fairly simple mono-interleave DCT-based codec.
|
||||
*
|
||||
* Decompiled from Relic's dec.exe with some info from Homeworld source code .h/lib
|
||||
* files (released around 2003 through Relic Dev Network), accurate with minor +-1
|
||||
* samples due to double<>float ops or maybe original compiler (Intel's) diffs.
|
||||
*/
|
||||
|
||||
/* mixfft.c */
|
||||
extern void fft(int n, float* xRe, float* xIm, float* yRe, float* yIm);
|
||||
|
||||
|
||||
#define RELIC_MAX_CHANNELS 2
|
||||
#define RELIC_MAX_SCALES 6
|
||||
#define RELIC_BASE_SCALE 10.0f
|
||||
#define RELIC_FREQUENCY_MASKING_FACTOR 1.0f
|
||||
#define RELIC_CRITICAL_BAND_COUNT 27
|
||||
#define RELIC_PI 3.14159265358979323846f
|
||||
#define RELIC_SIZE_LOW 128
|
||||
#define RELIC_SIZE_MID 256
|
||||
#define RELIC_SIZE_HIGH 512
|
||||
#define RELIC_MAX_SIZE RELIC_SIZE_HIGH
|
||||
#define RELIC_MAX_FREQ (RELIC_MAX_SIZE / 2)
|
||||
#define RELIC_MAX_FFT (RELIC_MAX_SIZE / 4)
|
||||
#define RELIC_MIN_BITRATE 256
|
||||
#define RELIC_MAX_BITRATE 2048
|
||||
//#define RELIC_MAX_FRAME_SIZE ((RELIC_MAX_BITRATE / 8) + 0x04) /* extra 0x04 for the bitreader */
|
||||
|
||||
|
||||
struct relic_handle_t {
|
||||
/* decoder info */
|
||||
int channels;
|
||||
int frame_size;
|
||||
int wave_size;
|
||||
int freq_size;
|
||||
int dct_mode;
|
||||
int samples_mode;
|
||||
/* decoder init state */
|
||||
float scales[RELIC_MAX_SCALES]; /* quantization scales */
|
||||
float dct[RELIC_MAX_SIZE];
|
||||
float window[RELIC_MAX_SIZE];
|
||||
/* decoder frame state */
|
||||
uint8_t exponents[RELIC_MAX_CHANNELS][RELIC_MAX_FREQ]; /* quantization/scale indexes */
|
||||
float freq1[RELIC_MAX_FREQ]; /* dequantized spectrum */
|
||||
float freq2[RELIC_MAX_FREQ];
|
||||
float wave_cur[RELIC_MAX_CHANNELS][RELIC_MAX_SIZE]; /* current frame samples */
|
||||
float wave_prv[RELIC_MAX_CHANNELS][RELIC_MAX_SIZE]; /* previous frame samples */
|
||||
};
|
||||
|
||||
/* ************************************* */
|
||||
|
||||
static const int16_t critical_band_data[RELIC_CRITICAL_BAND_COUNT] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
9, 11, 13, 15, 17, 20, 23, 27,
|
||||
31, 37, 43, 51, 62, 74, 89, 110,
|
||||
139, 180, 256
|
||||
};
|
||||
|
||||
static void init_dct(float* dct, int dct_size) {
|
||||
int i;
|
||||
int dct_quarter = dct_size >> 2;
|
||||
|
||||
for (i = 0; i < dct_quarter; i++) {
|
||||
double temp = ((float)i + 0.125f) * (RELIC_PI * 2.0f) * (1.0f / (float)dct_size);
|
||||
dct[i] = sin(temp);
|
||||
dct[dct_quarter + i] = cos(temp);
|
||||
}
|
||||
}
|
||||
|
||||
static int apply_idct(const float* freq, float* wave, const float* dct, int dct_size) {
|
||||
int i;
|
||||
float factor;
|
||||
float out_re[RELIC_MAX_FFT];
|
||||
float out_im[RELIC_MAX_FFT];
|
||||
float in_re[RELIC_MAX_FFT];
|
||||
float in_im[RELIC_MAX_FFT];
|
||||
float wave_tmp[RELIC_MAX_SIZE];
|
||||
int dct_half = dct_size >> 1;
|
||||
int dct_quarter = dct_size >> 2;
|
||||
int dct_3quarter = 3 * (dct_size >> 2);
|
||||
|
||||
/* prerotation? */
|
||||
for (i = 0; i < dct_quarter; i++) {
|
||||
float coef1 = freq[2 * i] * 0.5f;
|
||||
float coef2 = freq[dct_half - 1 - 2 * i] * 0.5f;
|
||||
in_re[i] = coef1 * dct[dct_quarter + i] + coef2 * dct[i];
|
||||
in_im[i] = -coef1 * dct[i] + coef2 * dct[dct_quarter + i];
|
||||
}
|
||||
|
||||
/* main FFT */
|
||||
fft(dct_quarter, in_re, in_im, out_re, out_im);
|
||||
|
||||
/* postrotation, window and reorder? */
|
||||
factor = 8.0 / sqrt(dct_size);
|
||||
for (i = 0; i < dct_quarter; i++) {
|
||||
float out_re_i = out_re[i];
|
||||
out_re[i] = (out_re[i] * dct[dct_quarter + i] + out_im[i] * dct[i]) * factor;
|
||||
out_im[i] = (-out_re_i * dct[i] + out_im[i] * dct[dct_quarter + i]) * factor;
|
||||
wave_tmp[i * 2] = out_re[i];
|
||||
wave_tmp[i * 2 + dct_half] = out_im[i];
|
||||
}
|
||||
for (i = 1; i < dct_size; i += 2) {
|
||||
wave_tmp[i] = -wave_tmp[dct_size - 1 - i];
|
||||
}
|
||||
|
||||
/* wave mix thing? */
|
||||
for (i = 0; i < dct_3quarter; i++) {
|
||||
wave[i] = wave_tmp[dct_quarter + i];
|
||||
}
|
||||
for (i = dct_3quarter; i < dct_size; i++) {
|
||||
wave[i] = -wave_tmp[i - dct_3quarter];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void decode_frame(const float* freq1, const float* freq2, float* wave_cur, float* wave_prv, const float* dct, const float* window, int dct_size) {
|
||||
int i;
|
||||
float wave_tmp[RELIC_MAX_SIZE];
|
||||
int dct_half = dct_size >> 1;
|
||||
|
||||
/* copy for first half(?) */
|
||||
memcpy(wave_cur, wave_prv, RELIC_MAX_SIZE * sizeof(float));
|
||||
|
||||
/* transform frequency domain to time domain with DCT/FFT */
|
||||
apply_idct(freq1, wave_tmp, dct, dct_size);
|
||||
apply_idct(freq2, wave_prv, dct, dct_size);
|
||||
|
||||
/* overlap and apply window function to filter this block's beginning */
|
||||
for (i = 0; i < dct_half; i++) {
|
||||
wave_cur[dct_half + i] = wave_tmp[i] * window[i] + wave_cur[dct_half + i] * window[dct_half + i];
|
||||
wave_prv[i] = wave_prv[i] * window[i] + wave_tmp[dct_half + i] * window[dct_half + i];
|
||||
}
|
||||
}
|
||||
|
||||
static void init_window(float *window, int dct_size) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dct_size; i++) {
|
||||
window[i] = sin((float)i * (RELIC_PI / dct_size));
|
||||
}
|
||||
}
|
||||
|
||||
static void decode_frame_base(const float* freq1, const float* freq2, float* wave_cur, float* wave_prv, const float* dct, const float* window, int dct_mode, int samples_mode) {
|
||||
int i;
|
||||
float wave_tmp[RELIC_MAX_SIZE];
|
||||
|
||||
/* dec_relic only uses 512/512 mode, source references 256/256 (effects only?) too */
|
||||
|
||||
if (samples_mode == RELIC_SIZE_LOW) {
|
||||
{
|
||||
/* 128 DCT to 128 samples */
|
||||
decode_frame(freq1, freq2, wave_cur, wave_prv, dct, window, RELIC_SIZE_LOW);
|
||||
}
|
||||
}
|
||||
else if (samples_mode == RELIC_SIZE_MID) {
|
||||
if (dct_mode == RELIC_SIZE_LOW) {
|
||||
/* 128 DCT to 256 samples (repeat sample x2) */
|
||||
decode_frame(freq1, freq2, wave_tmp, wave_prv, dct, window, RELIC_SIZE_LOW);
|
||||
for (i = 0; i < 256 - 1; i += 2) {
|
||||
wave_cur[i + 0] = wave_tmp[i >> 1];
|
||||
wave_cur[i + 1] = wave_tmp[i >> 1];
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* 256 DCT to 256 samples */
|
||||
decode_frame(freq1, freq2, wave_cur, wave_prv, dct, window, RELIC_SIZE_MID);
|
||||
}
|
||||
}
|
||||
else if (samples_mode == RELIC_SIZE_HIGH) {
|
||||
if (dct_mode == RELIC_SIZE_LOW) {
|
||||
/* 128 DCT to 512 samples (repeat sample x4) */
|
||||
decode_frame(freq1, freq2, wave_tmp, wave_prv, dct, window, RELIC_SIZE_LOW);
|
||||
for (i = 0; i < 512 - 1; i += 4) {
|
||||
wave_cur[i + 0] = wave_tmp[i >> 2];
|
||||
wave_cur[i + 1] = wave_tmp[i >> 2];
|
||||
wave_cur[i + 2] = wave_tmp[i >> 2];
|
||||
wave_cur[i + 3] = wave_tmp[i >> 2];
|
||||
}
|
||||
}
|
||||
else if (dct_mode == RELIC_SIZE_MID) {
|
||||
/* 256 DCT to 512 samples (repeat sample x2) */
|
||||
decode_frame(freq1, freq2, wave_tmp, wave_prv, dct, window, RELIC_SIZE_MID);
|
||||
for (i = 0; i < 512 - 1; i += 2) {
|
||||
wave_cur[i + 0] = wave_tmp[i >> 1];
|
||||
wave_cur[i + 1] = wave_tmp[i >> 1];
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* 512 DCT to 512 samples */
|
||||
decode_frame(freq1, freq2, wave_cur, wave_prv, dct, window, RELIC_SIZE_HIGH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* reads 32b max, packed in LSB order per byte (like Vorbis), ex.
|
||||
* with 0x45 6A=01000101 01101010 could read 4b=0101, 6b=100100, 3b=010 ...
|
||||
* assumes buf has enough extra bits to read 32b (size +0x04) */
|
||||
static uint32_t read_ubits(uint8_t bits, uint32_t offset, uint8_t* buf) {
|
||||
uint32_t shift, mask, pos, val;
|
||||
|
||||
shift = offset - 8 * (offset / 8);
|
||||
mask = (1 << bits) - 1;
|
||||
pos = offset / 8;
|
||||
val = (buf[pos+0]) | (buf[pos+1]<<8) | (buf[pos+2]<<16) | (buf[pos+3]<<24);
|
||||
return (val >> shift) & mask;
|
||||
}
|
||||
|
||||
static int read_sbits(uint8_t bits, uint32_t offset, uint8_t* buf) {
|
||||
uint32_t val = read_ubits(bits, offset, buf);
|
||||
int outval;
|
||||
if (val >> (bits - 1) == 1) { /* upper bit = sign */
|
||||
uint32_t mask = (1 << (bits - 1)) - 1;
|
||||
outval = (int)(val & mask);
|
||||
outval = -outval;
|
||||
}
|
||||
else {
|
||||
outval = (int)val;
|
||||
}
|
||||
return outval;
|
||||
}
|
||||
|
||||
static void init_dequantization(float* scales) {
|
||||
int i;
|
||||
|
||||
scales[0] = RELIC_BASE_SCALE;
|
||||
for (i = 1; i < RELIC_MAX_SCALES; i++) {
|
||||
scales[i] = scales[i - 1] * scales[0];
|
||||
}
|
||||
for (i = 0; i < RELIC_MAX_SCALES; i++) {
|
||||
scales[i] = RELIC_FREQUENCY_MASKING_FACTOR / (double) ((1 << (i + 1)) - 1) * scales[i];
|
||||
}
|
||||
}
|
||||
|
||||
static int unpack_frame(uint8_t* buf, int buf_size, float* freq1, float* freq2, const float* scales, uint8_t* exponents, int freq_size) {
|
||||
uint8_t flags, cb_bits, ev_bits, ei_bits, qv_bits;
|
||||
int qv;
|
||||
uint8_t ev;
|
||||
uint8_t move, pos;
|
||||
uint32_t bit_offset, max_offset;
|
||||
int i, j;
|
||||
int freq_half = freq_size >> 1;
|
||||
|
||||
|
||||
memset(freq1, 0, RELIC_MAX_FREQ * sizeof(float));
|
||||
memset(freq2, 0, RELIC_MAX_FREQ * sizeof(float));
|
||||
|
||||
flags = read_ubits(2u, 0u, buf);
|
||||
cb_bits = read_ubits(3u, 2u, buf);
|
||||
ev_bits = read_ubits(2u, 5u, buf);
|
||||
ei_bits = read_ubits(4u, 7u, buf);
|
||||
bit_offset = 11;
|
||||
max_offset = buf_size * 8u;
|
||||
|
||||
/* reset exponents indexes */
|
||||
if ((flags & 1) == 1) {
|
||||
memset(exponents, 0, RELIC_MAX_FREQ);
|
||||
}
|
||||
|
||||
/* read packed exponents indexes for all bands */
|
||||
if (cb_bits > 0 && ev_bits > 0) {
|
||||
pos = 0;
|
||||
for (i = 0; i < RELIC_CRITICAL_BAND_COUNT - 1; i++) {
|
||||
if (bit_offset + cb_bits > max_offset)
|
||||
goto fail;
|
||||
move = read_ubits(cb_bits, bit_offset, buf);
|
||||
bit_offset += cb_bits;
|
||||
|
||||
if (i > 0 && move == 0)
|
||||
break;
|
||||
pos += move;
|
||||
|
||||
if (bit_offset + ev_bits > max_offset)
|
||||
goto fail;
|
||||
ev = read_ubits(ev_bits, bit_offset, buf);
|
||||
bit_offset += ev_bits;
|
||||
|
||||
if (pos + 1 >= sizeof(critical_band_data))
|
||||
goto fail;
|
||||
for (j = critical_band_data[pos]; j < critical_band_data[pos + 1]; j++) {
|
||||
exponents[j] = ev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* read quantized values */
|
||||
if (freq_half > 0 && ei_bits > 0) {
|
||||
|
||||
/* read first part */
|
||||
pos = 0;
|
||||
for (i = 0; i < RELIC_MAX_FREQ; i++) {
|
||||
if (bit_offset + ei_bits > max_offset)
|
||||
goto fail;
|
||||
move = read_ubits(ei_bits, bit_offset, buf);
|
||||
bit_offset += ei_bits;
|
||||
|
||||
if (i > 0 && move == 0)
|
||||
break;
|
||||
pos += move;
|
||||
|
||||
if (pos >= RELIC_MAX_FREQ)
|
||||
goto fail;
|
||||
qv_bits = exponents[pos];
|
||||
|
||||
if (bit_offset + qv_bits + 2u > max_offset)
|
||||
goto fail;
|
||||
qv = read_sbits(qv_bits + 2u, bit_offset, buf);
|
||||
bit_offset += qv_bits + 2u;
|
||||
|
||||
if (qv != 0 && pos < freq_half && qv_bits < 6) {
|
||||
freq1[pos] = (float)qv * scales[qv_bits];
|
||||
}
|
||||
}
|
||||
|
||||
/* read second part, or clone it */
|
||||
if ((flags & 2) == 2) {
|
||||
memcpy(freq2, freq1, RELIC_MAX_FREQ * sizeof(float));
|
||||
}
|
||||
else {
|
||||
pos = 0;
|
||||
for (i = 0; i < RELIC_MAX_FREQ; i++) {
|
||||
if (bit_offset + ei_bits > max_offset)
|
||||
goto fail;
|
||||
move = read_ubits(ei_bits, bit_offset, buf);
|
||||
bit_offset += ei_bits;
|
||||
|
||||
if (i > 0 && move == 0)
|
||||
break;
|
||||
pos += move;
|
||||
|
||||
if (pos >= RELIC_MAX_FREQ)
|
||||
goto fail;
|
||||
qv_bits = exponents[pos];
|
||||
|
||||
if (bit_offset + qv_bits + 2u > max_offset)
|
||||
goto fail;
|
||||
qv = read_sbits(qv_bits + 2u, bit_offset, buf);
|
||||
bit_offset += qv_bits + 2u;
|
||||
|
||||
if (qv != 0 && pos < freq_half && qv_bits < 6) {
|
||||
freq2[pos] = (float)qv * scales[qv_bits];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0; /* original code doesn't check bad sizes so no return errcode */
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
relic_handle_t* relic_init(int channels, int bitrate, int codec_rate) {
|
||||
relic_handle_t* handle = NULL;
|
||||
|
||||
if (channels < 0 || channels > RELIC_MAX_CHANNELS)
|
||||
goto fail;
|
||||
|
||||
handle = calloc(1, sizeof(relic_handle_t));
|
||||
if (!handle) goto fail;
|
||||
|
||||
handle->channels = channels;
|
||||
|
||||
/* dequantized freq1+2 size (separate from DCT) */
|
||||
if (codec_rate < 22050) /* probably 11025 only */
|
||||
handle->freq_size = RELIC_SIZE_LOW;
|
||||
else if (codec_rate == 22050)
|
||||
handle->freq_size = RELIC_SIZE_MID;
|
||||
else if (codec_rate > 22050) /* probably 44100 only */
|
||||
handle->freq_size = RELIC_SIZE_HIGH;
|
||||
|
||||
/* default for streams (only a few mode combos are valid, see decode) */
|
||||
handle->wave_size = RELIC_SIZE_HIGH;
|
||||
handle->dct_mode = RELIC_SIZE_HIGH;
|
||||
handle->samples_mode = RELIC_SIZE_HIGH;
|
||||
|
||||
init_dct(handle->dct, RELIC_SIZE_HIGH);
|
||||
init_window(handle->window, RELIC_SIZE_HIGH);
|
||||
init_dequantization(handle->scales);
|
||||
memset(handle->wave_prv, 0, RELIC_MAX_CHANNELS * RELIC_MAX_SIZE * sizeof(float));
|
||||
|
||||
/* known bitrates: 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400, 0x800
|
||||
* dec.exe doesn't validate this, so there may be more */
|
||||
if (bitrate < RELIC_MIN_BITRATE || bitrate > RELIC_MAX_BITRATE)
|
||||
goto fail;
|
||||
handle->frame_size = (bitrate / 8); /* 0x100 and 0x80 are common */
|
||||
|
||||
|
||||
return handle;
|
||||
fail:
|
||||
relic_free(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void relic_free(relic_handle_t* handle) {
|
||||
if (!handle) return;
|
||||
free(handle);
|
||||
}
|
||||
|
||||
void relic_reset(relic_handle_t* handle) {
|
||||
if (!handle) return;
|
||||
memset(handle->wave_prv, 0, RELIC_MAX_CHANNELS * RELIC_MAX_SIZE * sizeof(float));
|
||||
}
|
||||
|
||||
int relic_get_frame_size(relic_handle_t* handle) {
|
||||
if (!handle) return 0;
|
||||
return handle->frame_size;
|
||||
}
|
||||
|
||||
int relic_decode_frame(relic_handle_t* handle, uint8_t* buf, int channel) {
|
||||
int ok;
|
||||
|
||||
/* clean extra bytes for bitreader (due to a quirk in the original code it may read outside max frame size) */
|
||||
memset(buf + handle->frame_size, 0, RELIC_BUFFER_SIZE - handle->frame_size);
|
||||
|
||||
ok = unpack_frame(buf, RELIC_BUFFER_SIZE, handle->freq1, handle->freq2, handle->scales, handle->exponents[channel], handle->freq_size);
|
||||
if (!ok) return ok;
|
||||
|
||||
decode_frame_base(handle->freq1, handle->freq2, handle->wave_cur[channel], handle->wave_prv[channel], handle->dct, handle->window, handle->dct_mode, handle->samples_mode);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int clamp16(int32_t val) {
|
||||
if (val > 32767) return 32767;
|
||||
else if (val < -32768) return -32768;
|
||||
else return val;
|
||||
}
|
||||
|
||||
void relic_get_pcm16(relic_handle_t* handle, int16_t* outbuf, int32_t samples, int32_t skip) {
|
||||
int s, ch;
|
||||
int ichs = handle->channels;
|
||||
|
||||
for (ch = 0; ch < ichs; ch++) {
|
||||
for (s = 0; s < samples; s++) {
|
||||
double d64_sample = handle->wave_cur[ch][skip + s];
|
||||
int pcm_sample = clamp16((int32_t)d64_sample);
|
||||
|
||||
/* f32 in PCM 32767.0 .. -32768.0 format, original code
|
||||
* does some custom double-to-int rint() though */
|
||||
//FQ_BNUM ((float)(1<<26)*(1<<26)*1.5)
|
||||
//rint(x) ((d64 = (double)(x)+FQ_BNUM), *(int*)(&d64))
|
||||
|
||||
outbuf[s*ichs + ch] = pcm_sample;
|
||||
}
|
||||
}
|
||||
}
|
23
src/coding/relic_decoder_lib.h
Normal file
23
src/coding/relic_decoder_lib.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef _RELIC_DECODER_LIB_H_
|
||||
#define _RELIC_DECODER_LIB_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define RELIC_BUFFER_SIZE 0x104
|
||||
#define RELIC_SAMPLES_PER_FRAME 512
|
||||
|
||||
typedef struct relic_handle_t relic_handle_t;
|
||||
|
||||
relic_handle_t* relic_init(int channels, int bitrate, int codec_rate);
|
||||
|
||||
void relic_free(relic_handle_t* handle);
|
||||
|
||||
void relic_reset(relic_handle_t* handle);
|
||||
|
||||
int relic_get_frame_size(relic_handle_t* handle);
|
||||
|
||||
int relic_decode_frame(relic_handle_t* handle, uint8_t* buf, int channel);
|
||||
|
||||
void relic_get_pcm16(relic_handle_t* handle, int16_t* outbuf, int32_t samples, int32_t skip);
|
||||
|
||||
#endif/*_RELIC_DECODER_LIB_H_ */
|
@ -395,7 +395,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) {
|
||||
case coding_IMA:
|
||||
case coding_DVI_IMA:
|
||||
case coding_SNDS_IMA:
|
||||
case coding_OTNS_IMA:
|
||||
case coding_QD_IMA:
|
||||
case coding_UBI_IMA:
|
||||
case coding_UBI_SCE_IMA:
|
||||
case coding_OKI16:
|
||||
@ -631,7 +631,7 @@ int get_vgmstream_frame_size(VGMSTREAM* vgmstream) {
|
||||
case coding_RAD_IMA_mono:
|
||||
return 0x14;
|
||||
case coding_SNDS_IMA:
|
||||
case coding_OTNS_IMA:
|
||||
case coding_QD_IMA:
|
||||
return 0; //todo: 0x01?
|
||||
case coding_UBI_IMA: /* variable (PCM then IMA) */
|
||||
return 0;
|
||||
@ -1173,7 +1173,7 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
|
||||
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch);
|
||||
}
|
||||
break;
|
||||
case coding_OTNS_IMA:
|
||||
case coding_QD_IMA:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_otns_ima(vgmstream, &vgmstream->ch[ch], buffer+ch,
|
||||
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch);
|
||||
|
@ -594,6 +594,7 @@ static const char* extension_list[] = {
|
||||
"wve",
|
||||
"wvs",
|
||||
"wvx",
|
||||
"wxd",
|
||||
|
||||
"x",
|
||||
"x360audio", //fake extension for Unreal Engine 3 XMA (real extension unknown)
|
||||
@ -746,7 +747,7 @@ static const coding_info coding_info_list[] = {
|
||||
{coding_DVI_IMA_int, "Intel DVI 4-bit IMA ADPCM (mono/interleave)"},
|
||||
{coding_3DS_IMA, "3DS IMA 4-bit ADPCM"},
|
||||
{coding_SNDS_IMA, "Heavy Iron .snds 4-bit IMA ADPCM"},
|
||||
{coding_OTNS_IMA, "Omikron: The Nomad Soul 4-bit IMA ADPCM"},
|
||||
{coding_QD_IMA, "Quantic Dream 4-bit IMA ADPCM"},
|
||||
{coding_WV6_IMA, "Gorilla Systems WV6 4-bit IMA ADPCM"},
|
||||
{coding_ALP_IMA, "High Voltage ALP 4-bit IMA ADPCM"},
|
||||
{coding_FFTA2_IMA, "Final Fantasy Tactics A2 4-bit IMA ADPCM"},
|
||||
@ -1068,7 +1069,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_SMP, "Infernal Engine .smp header"},
|
||||
{meta_MUL, "Crystal Dynamics .MUL header"},
|
||||
{meta_THP, "Nintendo THP header"},
|
||||
{meta_STS_WII, "Shikigami no Shiro (WII) Header"},
|
||||
{meta_STS, "Alfa System .STS header"},
|
||||
{meta_PS2_P2BT, "Pop'n'Music 7 Header"},
|
||||
{meta_PS2_GBTS, "Pop'n'Music 9 Header"},
|
||||
{meta_NGC_DSP_IADP, "IADP Header"},
|
||||
@ -1166,7 +1167,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_HYPERSCAN_KVAG, "Mattel Hyperscan KVAG"},
|
||||
{meta_IOS_PSND, "PSND Header"},
|
||||
{meta_BOS_ADP, "ADP! header"},
|
||||
{meta_OTNS_ADP, "Omikron: The Nomad Soul ADP header"},
|
||||
{meta_QD_ADP, "Quantic Dream .ADP header"},
|
||||
{meta_EB_SFX, "Excitebots .sfx header"},
|
||||
{meta_EB_SF0, "assumed Excitebots .sf0 by extension"},
|
||||
{meta_MTAF, "Konami MTAF header"},
|
||||
@ -1353,6 +1354,8 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_DSP_KWA, "Kuju London .KWA header"},
|
||||
{meta_OGV_3RDEYE, "3rdEye .OGV header"},
|
||||
{meta_PIFF_TPCM, "Tantalus PIFF TPCM header"},
|
||||
{meta_WXD_WXH, "Relic WXD+WXH header"},
|
||||
{meta_BNK_RELIC, "Relic BNK header"},
|
||||
};
|
||||
|
||||
void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -163,6 +163,7 @@
|
||||
<ClInclude Include="coding\fsb_vorbis_data.h" />
|
||||
<ClInclude Include="coding\g72x_state.h" />
|
||||
<ClInclude Include="coding\nwa_decoder.h" />
|
||||
<ClInclude Include="coding\relic_decoder_lib.h" />
|
||||
<ClInclude Include="coding\tac_decoder_lib.h" />
|
||||
<ClInclude Include="coding\tac_decoder_lib_data.h" />
|
||||
<ClInclude Include="coding\tac_decoder_lib_ops.h" />
|
||||
@ -218,13 +219,14 @@
|
||||
<ClCompile Include="meta\mn_str.c" />
|
||||
<ClCompile Include="meta\mogg.c" />
|
||||
<ClCompile Include="meta\mp4.c" />
|
||||
<ClCompile Include="meta\mp4_faac.c" />
|
||||
<ClCompile Include="meta\msb_msh.c" />
|
||||
<ClCompile Include="meta\msf_banpresto.c" />
|
||||
<ClCompile Include="meta\msf_konami.c" />
|
||||
<ClCompile Include="meta\msf_tamasoft.c" />
|
||||
<ClCompile Include="meta\opus.c" />
|
||||
<ClCompile Include="meta\pc_adp.c" />
|
||||
<ClCompile Include="meta\pc_adp_otns.c" />
|
||||
<ClCompile Include="meta\adp_bos.c" />
|
||||
<ClCompile Include="meta\adp_qd.c" />
|
||||
<ClCompile Include="meta\pc_ast.c" />
|
||||
<ClCompile Include="meta\raw_snds.c" />
|
||||
<ClCompile Include="meta\ps2_2pfs.c" />
|
||||
@ -309,6 +311,7 @@
|
||||
<ClCompile Include="meta\bik.c" />
|
||||
<ClCompile Include="meta\bkhd.c" />
|
||||
<ClCompile Include="meta\bmp_konami.c" />
|
||||
<ClCompile Include="meta\bnk_relic.c" />
|
||||
<ClCompile Include="meta\bnk_sony.c" />
|
||||
<ClCompile Include="meta\bnsf.c" />
|
||||
<ClCompile Include="meta\brstm.c" />
|
||||
@ -565,11 +568,12 @@
|
||||
<ClCompile Include="meta\wii_bns.c" />
|
||||
<ClCompile Include="meta\wii_mus.c" />
|
||||
<ClCompile Include="meta\wii_sng.c" />
|
||||
<ClCompile Include="meta\wii_sts.c" />
|
||||
<ClCompile Include="meta\sts.c" />
|
||||
<ClCompile Include="meta\ws_aud.c" />
|
||||
<ClCompile Include="meta\wsi.c" />
|
||||
<ClCompile Include="meta\wv6.c" />
|
||||
<ClCompile Include="meta\wvs.c" />
|
||||
<ClCompile Include="meta\wxd_wxh.c" />
|
||||
<ClCompile Include="meta\wwise.c" />
|
||||
<ClCompile Include="meta\xau.c" />
|
||||
<ClCompile Include="meta\xavs.c" />
|
||||
@ -641,6 +645,7 @@
|
||||
<ClCompile Include="coding\psx_decoder.c" />
|
||||
<ClCompile Include="coding\ptadpcm_decoder.c" />
|
||||
<ClCompile Include="coding\relic_decoder.c" />
|
||||
<ClCompile Include="coding\relic_decoder_lib.c" />
|
||||
<ClCompile Include="coding\relic_decoder_mixfft.c" />
|
||||
<ClCompile Include="coding\sassc_decoder.c" />
|
||||
<ClCompile Include="coding\sdx2_decoder.c" />
|
||||
|
@ -251,6 +251,9 @@
|
||||
<ClInclude Include="coding\nwa_decoder.h">
|
||||
<Filter>coding\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="coding\relic_decoder_lib.h">
|
||||
<Filter>coding\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="coding\tac_decoder_lib.h">
|
||||
<Filter>coding\Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -1192,7 +1195,7 @@
|
||||
<ClCompile Include="meta\wii_sng.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\wii_sts.c">
|
||||
<ClCompile Include="meta\sts.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\ws_aud.c">
|
||||
@ -1207,6 +1210,9 @@
|
||||
<ClCompile Include="meta\wvs.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\wxd_wxh.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\wwise.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -1396,6 +1402,9 @@
|
||||
<ClCompile Include="coding\relic_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\relic_decoder_lib.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\relic_decoder_mixfft.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -1672,10 +1681,10 @@
|
||||
<ClCompile Include="meta\imuse.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\pc_adp.c">
|
||||
<ClCompile Include="meta\adp_bos.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\pc_adp_otns.c">
|
||||
<ClCompile Include="meta\adp_qd.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\excitebots.c">
|
||||
@ -1726,6 +1735,9 @@
|
||||
<ClCompile Include="meta\mp4.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\mp4_faac.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\msb_msh.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -1831,6 +1843,9 @@
|
||||
<ClCompile Include="meta\bmp_konami.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\bnk_relic.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\bnk_sony.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
47
src/meta/adp_bos.c
Normal file
47
src/meta/adp_bos.c
Normal file
@ -0,0 +1,47 @@
|
||||
#include "meta.h"
|
||||
|
||||
/* ADP - from Balls of Steel */
|
||||
VGMSTREAM* init_vgmstream_adp_bos(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag = 0;
|
||||
int channels;
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf,"adp"))
|
||||
goto fail;
|
||||
|
||||
if (!is_id32be(0x00,sf, "ADP!"))
|
||||
goto fail;
|
||||
|
||||
loop_flag = (-1 != read_s32le(0x08,sf));
|
||||
channels = 1;
|
||||
start_offset = 0x18;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_s32le(0x0C,sf);
|
||||
vgmstream->num_samples = read_s32le(0x04,sf);
|
||||
vgmstream->loop_start_sample = read_s32le(0x08,sf);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_DVI_IMA_int;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_BOS_ADP;
|
||||
|
||||
// 0x10, 0x12 - both initial history?
|
||||
//vgmstream->ch[0].adpcm_history1_32 = read_16bitLE(0x10,sf);
|
||||
// 0x14 - initial step index?
|
||||
//vgmstream->ch[0].adpcm_step_index = read_32bitLE(0x14,sf);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
46
src/meta/adp_qd.c
Normal file
46
src/meta/adp_qd.c
Normal file
@ -0,0 +1,46 @@
|
||||
#include "meta.h"
|
||||
|
||||
/* ADP - from Omikron: The Nomad Soul (PC/DC) */
|
||||
VGMSTREAM* init_vgmstream_adp_qd(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset, data_size;
|
||||
int loop_flag = 0, channels, stereo_flag;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf,"adp"))
|
||||
goto fail;
|
||||
|
||||
/* no ID, only a basic 0x10 header with filesize and nulls; do some extra checks */
|
||||
data_size = read_u32le(0x00,sf) & 0x00FFFFFF; /*24 bit*/
|
||||
if (data_size + 0x10 != sf->get_size(sf)
|
||||
|| read_u32le(0x04,sf) != 0
|
||||
|| read_u32le(0x08,sf) != 0
|
||||
|| read_u32le(0x0c,sf) != 0)
|
||||
goto fail;
|
||||
|
||||
stereo_flag = read_u8(0x03, sf);
|
||||
if (stereo_flag > 1 || stereo_flag < 0) goto fail;
|
||||
channels = stereo_flag ? 2 : 1;
|
||||
start_offset = 0x10;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_QD_ADP;
|
||||
vgmstream->sample_rate = 22050;
|
||||
vgmstream->num_samples = data_size * 2 / channels;
|
||||
|
||||
vgmstream->coding_type = coding_QD_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -43,8 +43,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *sf) {
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .akb.bytes is the usual extension in later games */
|
||||
if ( !check_extensions(sf, "akb,bytes") )
|
||||
if ( !check_extensions(sf, "akb") )
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,sf) != 0x414B4220) /* "AKB " */
|
||||
goto fail;
|
||||
@ -188,8 +187,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *sf) {
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
|
||||
/* check extensions */
|
||||
/* .akb.bytes is the usual extension in later games */
|
||||
if ( !check_extensions(sf, "akb,bytes") )
|
||||
if ( !check_extensions(sf, "akb") )
|
||||
goto fail;
|
||||
|
||||
/* checks */
|
||||
|
80
src/meta/bnk_relic.c
Normal file
80
src/meta/bnk_relic.c
Normal file
@ -0,0 +1,80 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* BNK - sfx container from Relic's earlier games [Homeworld (PC), Homeworld Cataclysm (PC)] */
|
||||
VGMSTREAM* init_vgmstream_bnk_relic(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
uint32_t start_offset, offset, data_size, loop_start, loop_end;
|
||||
int loop_flag, channels, bitrate, internal_rate, sample_rate;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "bnk"))
|
||||
goto fail;
|
||||
if (!is_id32be(0x00,sf, "BNK0"))
|
||||
goto fail;
|
||||
/* 0x04: flags? */
|
||||
|
||||
total_subsongs = read_u32le(0x08,sf);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
offset = 0x0c + (target_subsong-1) * 0x38;
|
||||
if (!is_id32be(offset + 0x00,sf, "PCH0"))
|
||||
goto fail;
|
||||
/* 0x04: null */
|
||||
/* 0x08: 0/+-number? */
|
||||
start_offset = read_u32le(offset + 0x0c,sf);
|
||||
data_size = read_u32le(offset + 0x10,sf);
|
||||
loop_start = read_u32le(offset + 0x14,sf); /* 0x14: 0/offset? */
|
||||
loop_end = read_u32le(offset + 0x18,sf); /* 0x18: 0/offset? */
|
||||
bitrate = read_u16le(offset + 0x1c,sf);
|
||||
loop_flag = read_u16le(offset + 0x1e,sf);
|
||||
/* 0x20: volume? */
|
||||
/* 0x22: -1 */
|
||||
/* 0x24: fmt pcm codec 1 */
|
||||
channels = read_u16le(offset + 0x26,sf);
|
||||
sample_rate = read_u32le(offset + 0x28,sf);
|
||||
/* 0x2c: bitrate */
|
||||
/* 0x30: pcm block size */
|
||||
/* 0x32: pcm bps */
|
||||
/* 0x34: 0 */
|
||||
/* 0x36: -1 */
|
||||
|
||||
internal_rate = 44100;
|
||||
|
||||
loop_flag = 0; //todo clicks on loop, wrong calcs?
|
||||
|
||||
/* stream info */
|
||||
if (!is_id32be(start_offset - 0x04,sf, "DATA"))
|
||||
goto fail;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_BNK_RELIC;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
vgmstream->num_samples = relic_bytes_to_samples(data_size, channels, bitrate);
|
||||
vgmstream->loop_start_sample = relic_bytes_to_samples(loop_start, channels, bitrate);
|
||||
vgmstream->loop_end_sample = relic_bytes_to_samples(loop_end, channels, bitrate);
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = data_size;
|
||||
|
||||
vgmstream->codec_data = init_relic(channels, bitrate, internal_rate);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_RELIC;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -1,354 +1,354 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
|
||||
#define EA_CODEC_PCM 0x00
|
||||
#define EA_CODEC_ULAW 0x01
|
||||
#define EA_CODEC_IMA 0x02
|
||||
#define EA_CODEC_PSX 0xFF //fake value
|
||||
|
||||
typedef struct {
|
||||
int32_t sample_rate;
|
||||
uint8_t bits;
|
||||
uint8_t channels;
|
||||
uint8_t codec;
|
||||
uint8_t type;
|
||||
int32_t num_samples;
|
||||
int32_t loop_start;
|
||||
int32_t loop_end;
|
||||
int32_t loop_start_offset;
|
||||
int32_t data_offset;
|
||||
|
||||
int big_endian;
|
||||
int loop_flag;
|
||||
int is_sead;
|
||||
int codec_config;
|
||||
int is_bank;
|
||||
int total_subsongs;
|
||||
} eacs_header;
|
||||
|
||||
static int parse_header(STREAMFILE* streamFile, eacs_header* ea, off_t begin_offset);
|
||||
static VGMSTREAM * init_vgmstream_main(STREAMFILE *streamFile, eacs_header* ea);
|
||||
|
||||
static void set_ea_1snh_num_samples(VGMSTREAM *vgmstream, STREAMFILE *streamFile, eacs_header *ea, int find_loop);
|
||||
static int get_ea_1snh_ima_version(STREAMFILE* streamFile, off_t start_offset, const eacs_header* ea);
|
||||
|
||||
/* EA 1SNh - from early EA games, stream (~1996, ex. Need for Speed) */
|
||||
VGMSTREAM * init_vgmstream_ea_1snh(STREAMFILE *streamFile) {
|
||||
eacs_header ea = { 0 };
|
||||
off_t offset, eacs_offset;
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .asf/as4: common,
|
||||
* .lasf: fake for plugins
|
||||
* .cnk: some PS1 games
|
||||
* .sng: fake for plugins (to mimic EA SCHl's common extension)
|
||||
* .uv/tgq: some SAT games (video only?)
|
||||
* .tgv: videos
|
||||
* (extensionless): Need for Speed (SAT) (videos) */
|
||||
if (!check_extensions(streamFile, "asf,lasf,as4,cnk,sng,uv,tgq,tgv,"))
|
||||
goto fail;
|
||||
|
||||
offset = 0x00;
|
||||
|
||||
/* in TGV videos, either TGVk or 1SNh block comes first */
|
||||
if (read_32bitBE(0x00, streamFile) == 0x5447566B) { /* "TGVk" */
|
||||
offset = read_32bitBE(0x04, streamFile);
|
||||
} else if (read_32bitLE(0x00, streamFile) == 0x5447566B) { /* "kVGT" */
|
||||
offset = read_32bitLE(0x04, streamFile);
|
||||
}
|
||||
|
||||
if (read_32bitBE(offset + 0x00, streamFile) != 0x31534E68 && /* "1SNh" */
|
||||
read_32bitBE(offset + 0x00, streamFile) != 0x53454144) /* "SEAD" */
|
||||
goto fail;
|
||||
|
||||
/* stream is divided into blocks/chunks: 1SNh=audio header, 1SNd=data xN, 1SNl=loop end, 1SNe=end.
|
||||
* Video uses various blocks (TGVk/TGVf/MUVf/etc) and sometimes alt audio blocks (SEAD/SNDC/SEND). */
|
||||
ea.is_sead = read_32bitBE(offset + 0x00, streamFile) == 0x53454144;
|
||||
|
||||
eacs_offset = offset + 0x08; /* after 1SNh block id+size */
|
||||
|
||||
if (!parse_header(streamFile, &ea, eacs_offset))
|
||||
goto fail;
|
||||
vgmstream = init_vgmstream_main(streamFile, &ea);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
if (ea.num_samples == 0) {
|
||||
/* header does not specify number of samples, need to calculate it manually */
|
||||
/* HACK: we need vgmstream object to use blocked layout so we're doing this calc after creating it */
|
||||
set_ea_1snh_num_samples(vgmstream, streamFile, &ea, 0);
|
||||
|
||||
/* update samples and loop state */
|
||||
vgmstream->num_samples = ea.num_samples;
|
||||
vgmstream_force_loop(vgmstream, ea.loop_flag, ea.loop_start, ea.loop_end);
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* EA EACS - from early EA games, bank (~1996, ex. Need for Speed) */
|
||||
VGMSTREAM * init_vgmstream_ea_eacs(STREAMFILE *streamFile) {
|
||||
eacs_header ea = {0};
|
||||
off_t eacs_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .eas: single bank [Need for Speed (PC)]
|
||||
* .bnk: multi bank [Need for Speed (PC)] */
|
||||
if (!check_extensions(streamFile,"eas,bnk"))
|
||||
goto fail;
|
||||
|
||||
/* plain data without blocks, can contain N*(EACS header) + N*(data), or N (EACS header + data) */
|
||||
ea.is_bank = 1;
|
||||
|
||||
/* use ??? as endian marker (Saturn = BE) */
|
||||
//ea.big_endian = guess_endianness32bit(0x04,streamFile);
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) == 0x45414353) { /* "EACS" */
|
||||
/* single bank variant */
|
||||
eacs_offset = 0x00;
|
||||
}
|
||||
else if (read_32bitBE(0x00,streamFile) == 0x00) {
|
||||
/* multi bank variant */
|
||||
int i;
|
||||
int target_subsong = streamFile->stream_index;
|
||||
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0) goto fail;
|
||||
|
||||
/* offsets to EACSs are scattered in the first 0x200
|
||||
* this looks dumb but seems like the only way */
|
||||
eacs_offset = 0;
|
||||
for (i = 0x00; i < 0x200; i += 0x04) {
|
||||
off_t bank_offset = read_32bitLE(i, streamFile);
|
||||
if (bank_offset == 0)
|
||||
continue;
|
||||
|
||||
ea.total_subsongs++;
|
||||
|
||||
/* parse mini bank header */
|
||||
if (ea.total_subsongs == target_subsong) {
|
||||
/* 0x00: some id or flags? */
|
||||
eacs_offset = read_32bitLE(bank_offset + 0x04, streamFile);
|
||||
if (read_32bitBE(eacs_offset, streamFile) != 0x45414353)
|
||||
goto fail;
|
||||
/* rest: not sure if part of this header */
|
||||
}
|
||||
}
|
||||
|
||||
if (eacs_offset == 0)
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!parse_header(streamFile,&ea, eacs_offset))
|
||||
goto fail;
|
||||
return init_vgmstream_main(streamFile, &ea);
|
||||
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static VGMSTREAM * init_vgmstream_main(STREAMFILE *streamFile, eacs_header* ea) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(ea->channels, ea->loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = ea->sample_rate;
|
||||
vgmstream->num_samples = ea->num_samples;
|
||||
vgmstream->loop_start_sample = ea->loop_start;
|
||||
vgmstream->loop_end_sample = ea->loop_end;
|
||||
|
||||
vgmstream->codec_endian = ea->big_endian;
|
||||
vgmstream->layout_type = ea->is_bank ? layout_none : layout_blocked_ea_1snh;
|
||||
vgmstream->meta_type = ea->is_bank ? meta_EA_EACS : meta_EA_1SNH;
|
||||
vgmstream->num_streams = ea->total_subsongs;
|
||||
|
||||
switch (ea->codec) {
|
||||
case EA_CODEC_PCM: /* Need for Speed (PC) */
|
||||
vgmstream->coding_type = ea->bits==1 ? coding_PCM8_int : coding_PCM16_int;
|
||||
break;
|
||||
|
||||
case EA_CODEC_ULAW: /* Crusader: No Remorse movies (SAT), FIFA 96 movies (SAT) */
|
||||
if (ea->bits && ea->bits != 2) goto fail; /* only set in EACS */
|
||||
vgmstream->coding_type = coding_ULAW_int;
|
||||
break;
|
||||
|
||||
case EA_CODEC_IMA: /* Need for Speed (PC) */
|
||||
if (ea->bits && ea->bits != 2) goto fail; /* only in EACS */
|
||||
vgmstream->coding_type = coding_DVI_IMA; /* stereo/mono, high nibble first */
|
||||
vgmstream->codec_config = ea->codec_config;
|
||||
break;
|
||||
|
||||
case EA_CODEC_PSX: /* Need for Speed (PS1) */
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("EA EACS: unknown codec 0x%02x\n", ea->codec);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,ea->data_offset))
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int parse_header(STREAMFILE* streamFile, eacs_header* ea, off_t offset) {
|
||||
/* audio header endianness doesn't always match block headers, use sample rate to detect */
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*);
|
||||
|
||||
if (read_32bitBE(offset+0x00, streamFile) == 0x45414353) { /* "EACS" */
|
||||
/* EACS subheader (PC, SAT) */
|
||||
ea->big_endian = guess_endianness32bit(offset + 0x04, streamFile);
|
||||
read_32bit = ea->big_endian ? read_32bitBE : read_32bitLE;
|
||||
|
||||
ea->sample_rate = read_32bit(offset+0x04, streamFile);
|
||||
ea->bits = read_8bit(offset+0x08, streamFile);
|
||||
ea->channels = read_8bit(offset+0x09, streamFile);
|
||||
ea->codec = read_8bit(offset+0x0a, streamFile);
|
||||
ea->type = read_8bit(offset+0x0b, streamFile); /* block type? 0=1SNh, -1=bank */
|
||||
ea->num_samples = read_32bit(offset+0x0c, streamFile);
|
||||
ea->loop_start = read_32bit(offset+0x10, streamFile);
|
||||
ea->loop_end = read_32bit(offset+0x14, streamFile) + ea->loop_start; /* loop length */
|
||||
ea->data_offset = read_32bit(offset+0x18, streamFile); /* 0 when blocked */
|
||||
/* 0x1c: pan/volume/etc? (0x7F)
|
||||
* rest may be padding/garbage */
|
||||
//VGM_ASSERT(ea->type != 0, "EA EACS: unknown type %i\n", ea->type);
|
||||
|
||||
if (ea->codec == EA_CODEC_IMA)
|
||||
ea->codec_config = get_ea_1snh_ima_version(streamFile, 0x00, ea);
|
||||
/* EACS banks with empty values exist but will be rejected later */
|
||||
}
|
||||
else if (read_32bitBE(offset + 0x00, streamFile) == 0x00) {
|
||||
/* found in early videos, similar to EACS */
|
||||
ea->big_endian = guess_endianness32bit(offset + 0x04, streamFile);
|
||||
read_32bit = ea->big_endian ? read_32bitBE : read_32bitLE;
|
||||
|
||||
ea->sample_rate = read_32bit(offset + 0x04, streamFile);
|
||||
ea->bits = read_8bit(offset + 0x08, streamFile);
|
||||
ea->channels = read_8bit(offset + 0x09, streamFile);
|
||||
ea->codec = read_8bit(offset + 0x0a, streamFile);
|
||||
ea->type = read_8bit(offset + 0x0b, streamFile); /* block type? 0=1SNh, -1=bank */
|
||||
|
||||
if (ea->codec == EA_CODEC_IMA)
|
||||
ea->codec_config = get_ea_1snh_ima_version(streamFile, 0x00, ea);
|
||||
}
|
||||
else if (ea->is_sead) {
|
||||
/* alt subheader (found in some PC videos) */
|
||||
ea->big_endian = guess_endianness32bit(offset + 0x00, streamFile);
|
||||
read_32bit = ea->big_endian ? read_32bitBE : read_32bitLE;
|
||||
|
||||
ea->sample_rate = read_32bit(offset+0x00, streamFile);
|
||||
ea->channels = read_32bit(offset+0x04, streamFile);
|
||||
ea->codec = read_32bit(offset+0x08, streamFile);
|
||||
|
||||
if (ea->codec == EA_CODEC_IMA)
|
||||
ea->codec_config = get_ea_1snh_ima_version(streamFile, 0x00, ea);
|
||||
}
|
||||
else {
|
||||
/* alt subheader (PS1) */
|
||||
ea->big_endian = guess_endianness32bit(offset + 0x00, streamFile);
|
||||
read_32bit = ea->big_endian ? read_32bitBE : read_32bitLE;
|
||||
|
||||
ea->sample_rate = read_32bit(offset+0x00, streamFile);
|
||||
ea->channels = read_8bit(offset+0x18, streamFile);
|
||||
ea->codec = EA_CODEC_PSX;
|
||||
}
|
||||
|
||||
ea->loop_flag = (ea->loop_end > 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* get total samples by parsing block headers, needed when EACS isn't present */
|
||||
static void set_ea_1snh_num_samples(VGMSTREAM *vgmstream, STREAMFILE *streamFile, eacs_header *ea, int find_loop) {
|
||||
int32_t num_samples = 0, block_id;
|
||||
size_t file_size;
|
||||
int32_t(*read_32bit)(off_t, STREAMFILE *) = ea->big_endian ? read_32bitBE : read_32bitLE;
|
||||
int loop_end_found = 0;
|
||||
|
||||
file_size = get_streamfile_size(streamFile);
|
||||
vgmstream->next_block_offset = ea->data_offset;
|
||||
|
||||
while (vgmstream->next_block_offset < file_size) {
|
||||
block_update_ea_1snh(vgmstream->next_block_offset, vgmstream);
|
||||
if (vgmstream->current_block_samples < 0)
|
||||
break;
|
||||
|
||||
block_id = read_32bitBE(vgmstream->current_block_offset, streamFile);
|
||||
if (find_loop) {
|
||||
if (vgmstream->current_block_offset == ea->loop_start_offset) {
|
||||
ea->loop_start = num_samples;
|
||||
ea->loop_flag = 1;
|
||||
block_update_ea_1snh(ea->data_offset, vgmstream);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (block_id == 0x31534E6C) { /* "1SNl" loop point found */
|
||||
ea->loop_start_offset = read_32bit(vgmstream->current_block_offset + 0x08, streamFile);
|
||||
ea->loop_end = num_samples;
|
||||
loop_end_found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
num_samples += vgmstream->current_block_samples;
|
||||
}
|
||||
|
||||
ea->num_samples = num_samples;
|
||||
|
||||
/* reset once we're done */
|
||||
block_update_ea_1snh(ea->data_offset, vgmstream);
|
||||
|
||||
if (loop_end_found) {
|
||||
/* recurse to find loop start sample */
|
||||
set_ea_1snh_num_samples(vgmstream, streamFile, ea, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* find codec version used, with or without ADPCM hist per block */
|
||||
static int get_ea_1snh_ima_version(STREAMFILE* streamFile, off_t start_offset, const eacs_header* ea) {
|
||||
off_t block_offset = start_offset;
|
||||
size_t file_size = get_streamfile_size(streamFile);
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE;
|
||||
|
||||
while (block_offset < file_size) {
|
||||
uint32_t id = read_32bitBE(block_offset+0x00,streamFile);
|
||||
size_t block_size;
|
||||
|
||||
/* BE in SAT, but one file may have both BE and LE chunks */
|
||||
if (guess_endianness32bit(block_offset + 0x04, streamFile))
|
||||
block_size = read_32bitBE(block_offset + 0x04, streamFile);
|
||||
else
|
||||
block_size = read_32bitLE(block_offset + 0x04, streamFile);
|
||||
|
||||
if (id == 0x31534E64 || id == 0x534E4443) { /* "1SNd" "SNDC" audio data */
|
||||
size_t ima_samples = read_32bit(block_offset + 0x08, streamFile);
|
||||
size_t expected_samples = (block_size - 0x08 - 0x04 - 0x08*ea->channels) * 2 / ea->channels;
|
||||
|
||||
if (ima_samples == expected_samples) {
|
||||
return 1; /* has ADPCM hist (hopefully) */
|
||||
}
|
||||
}
|
||||
|
||||
block_offset += block_size;
|
||||
}
|
||||
|
||||
return 0; /* no ADPCM hist */
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
|
||||
#define EA_CODEC_PCM 0x00
|
||||
#define EA_CODEC_ULAW 0x01
|
||||
#define EA_CODEC_IMA 0x02
|
||||
#define EA_CODEC_PSX 0xFF //fake value
|
||||
|
||||
typedef struct {
|
||||
int32_t sample_rate;
|
||||
uint8_t bits;
|
||||
uint8_t channels;
|
||||
uint8_t codec;
|
||||
uint8_t type;
|
||||
int32_t num_samples;
|
||||
int32_t loop_start;
|
||||
int32_t loop_end;
|
||||
int32_t loop_start_offset;
|
||||
int32_t data_offset;
|
||||
|
||||
int big_endian;
|
||||
int loop_flag;
|
||||
int is_sead;
|
||||
int codec_config;
|
||||
int is_bank;
|
||||
int total_subsongs;
|
||||
} eacs_header;
|
||||
|
||||
static int parse_header(STREAMFILE* sf, eacs_header* ea, off_t begin_offset);
|
||||
static VGMSTREAM* init_vgmstream_main(STREAMFILE* sf, eacs_header* ea);
|
||||
|
||||
static void set_ea_1snh_num_samples(VGMSTREAM* vgmstream, STREAMFILE* sf, eacs_header* ea, int find_loop);
|
||||
static int get_ea_1snh_ima_version(STREAMFILE* sf, off_t start_offset, const eacs_header* ea);
|
||||
|
||||
/* EA 1SNh - from early EA games, stream (~1996, ex. Need for Speed) */
|
||||
VGMSTREAM* init_vgmstream_ea_1snh(STREAMFILE* sf) {
|
||||
eacs_header ea = { 0 };
|
||||
off_t offset, eacs_offset;
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .asf/as4: common,
|
||||
* .lasf: fake for plugins
|
||||
* .sng: fake for plugins (for .asf issues)
|
||||
* .cnk: some PS1 games
|
||||
* .uv/tgq: some SAT videos
|
||||
* .tgv: videos
|
||||
* (extensionless): Need for Speed (SAT) videos */
|
||||
if (!check_extensions(sf, "asf,lasf,sng,as4,cnk,uv,tgq,tgv,"))
|
||||
goto fail;
|
||||
|
||||
offset = 0x00;
|
||||
|
||||
/* in TGV videos, either TGVk or 1SNh block comes first */
|
||||
if (is_id32be(0x00, sf, "TGVk")) {
|
||||
offset = read_u32be(0x04, sf);
|
||||
} else if (is_id32be(0x00, sf, "kVGT")) {
|
||||
offset = read_u32le(0x04, sf);
|
||||
}
|
||||
|
||||
if (!is_id32be(offset + 0x00, sf, "1SNh") &&
|
||||
!is_id32be(offset + 0x00, sf, "SEAD"))
|
||||
goto fail;
|
||||
|
||||
/* stream is divided into blocks/chunks: 1SNh=audio header, 1SNd=data xN, 1SNl=loop end, 1SNe=end.
|
||||
* Video uses various blocks (TGVk/TGVf/MUVf/etc) and sometimes alt audio blocks (SEAD/SNDC/SEND). */
|
||||
ea.is_sead = is_id32be(offset + 0x00, sf, "SEAD");
|
||||
|
||||
eacs_offset = offset + 0x08; /* after 1SNh block id+size */
|
||||
|
||||
if (!parse_header(sf, &ea, eacs_offset))
|
||||
goto fail;
|
||||
vgmstream = init_vgmstream_main(sf, &ea);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
if (ea.num_samples == 0) {
|
||||
/* header does not specify number of samples, need to calculate it manually */
|
||||
/* HACK: we need vgmstream object to use blocked layout so we're doing this calc after creating it */
|
||||
set_ea_1snh_num_samples(vgmstream, sf, &ea, 0);
|
||||
|
||||
/* update samples and loop state */
|
||||
vgmstream->num_samples = ea.num_samples;
|
||||
vgmstream_force_loop(vgmstream, ea.loop_flag, ea.loop_start, ea.loop_end);
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* EA EACS - from early EA games, bank (~1996, ex. Need for Speed) */
|
||||
VGMSTREAM* init_vgmstream_ea_eacs(STREAMFILE* sf) {
|
||||
eacs_header ea = {0};
|
||||
off_t eacs_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .eas: single bank [Need for Speed (PC)]
|
||||
* .bnk: multi bank [Need for Speed (PC)] */
|
||||
if (!check_extensions(sf,"eas,bnk"))
|
||||
goto fail;
|
||||
|
||||
/* plain data without blocks, can contain N*(EACS header) + N*(data), or N (EACS header + data) */
|
||||
ea.is_bank = 1;
|
||||
|
||||
/* use ??? as endian marker (Saturn = BE) */
|
||||
//ea.big_endian = guess_endianness32bit(0x04,sf);
|
||||
|
||||
if (is_id32be(0x00,sf, "EACS")) {
|
||||
/* single bank variant */
|
||||
eacs_offset = 0x00;
|
||||
}
|
||||
else if (read_u32be(0x00,sf) == 0x00) {
|
||||
/* multi bank variant */
|
||||
int i;
|
||||
int target_subsong = sf->stream_index;
|
||||
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0) goto fail;
|
||||
|
||||
/* offsets to EACSs are scattered in the first 0x200
|
||||
* this looks dumb but seems like the only way */
|
||||
eacs_offset = 0;
|
||||
for (i = 0x00; i < 0x200; i += 0x04) {
|
||||
off_t bank_offset = read_u32le(i, sf);
|
||||
if (bank_offset == 0)
|
||||
continue;
|
||||
|
||||
ea.total_subsongs++;
|
||||
|
||||
/* parse mini bank header */
|
||||
if (ea.total_subsongs == target_subsong) {
|
||||
/* 0x00: some id or flags? */
|
||||
eacs_offset = read_u32le(bank_offset + 0x04, sf);
|
||||
if (!is_id32be(eacs_offset, sf, "EACS"))
|
||||
goto fail;
|
||||
/* rest: not sure if part of this header */
|
||||
}
|
||||
}
|
||||
|
||||
if (eacs_offset == 0)
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!parse_header(sf,&ea, eacs_offset))
|
||||
goto fail;
|
||||
return init_vgmstream_main(sf, &ea);
|
||||
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static VGMSTREAM* init_vgmstream_main(STREAMFILE* sf, eacs_header* ea) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(ea->channels, ea->loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = ea->sample_rate;
|
||||
vgmstream->num_samples = ea->num_samples;
|
||||
vgmstream->loop_start_sample = ea->loop_start;
|
||||
vgmstream->loop_end_sample = ea->loop_end;
|
||||
|
||||
vgmstream->codec_endian = ea->big_endian;
|
||||
vgmstream->layout_type = ea->is_bank ? layout_none : layout_blocked_ea_1snh;
|
||||
vgmstream->meta_type = ea->is_bank ? meta_EA_EACS : meta_EA_1SNH;
|
||||
vgmstream->num_streams = ea->total_subsongs;
|
||||
|
||||
switch (ea->codec) {
|
||||
case EA_CODEC_PCM: /* Need for Speed (PC) */
|
||||
vgmstream->coding_type = ea->bits==1 ? coding_PCM8_int : coding_PCM16_int;
|
||||
break;
|
||||
|
||||
case EA_CODEC_ULAW: /* Crusader: No Remorse movies (SAT), FIFA 96 movies (SAT) */
|
||||
if (ea->bits && ea->bits != 2) goto fail; /* only set in EACS */
|
||||
vgmstream->coding_type = coding_ULAW_int;
|
||||
break;
|
||||
|
||||
case EA_CODEC_IMA: /* Need for Speed (PC) */
|
||||
if (ea->bits && ea->bits != 2) goto fail; /* only in EACS */
|
||||
vgmstream->coding_type = coding_DVI_IMA; /* stereo/mono, high nibble first */
|
||||
vgmstream->codec_config = ea->codec_config;
|
||||
break;
|
||||
|
||||
case EA_CODEC_PSX: /* Need for Speed (PS1) */
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("EA EACS: unknown codec 0x%02x\n", ea->codec);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, ea->data_offset))
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int parse_header(STREAMFILE* sf, eacs_header* ea, off_t offset) {
|
||||
/* audio header endianness doesn't always match block headers, use sample rate to detect */
|
||||
int32_t (*read_s32)(off_t,STREAMFILE*);
|
||||
|
||||
if (is_id32be(offset+0x00,sf, "EACS")) {
|
||||
/* EACS subheader (PC, SAT) */
|
||||
ea->big_endian = guess_endianness32bit(offset + 0x04, sf);
|
||||
read_s32 = ea->big_endian ? read_s32be : read_s32le;
|
||||
|
||||
ea->sample_rate = read_s32(offset+0x04, sf);
|
||||
ea->bits = read_u8(offset+0x08, sf);
|
||||
ea->channels = read_u8(offset+0x09, sf);
|
||||
ea->codec = read_u8(offset+0x0a, sf);
|
||||
ea->type = read_u8(offset+0x0b, sf); /* block type? 0=1SNh, -1=bank */
|
||||
ea->num_samples = read_s32(offset+0x0c, sf);
|
||||
ea->loop_start = read_s32(offset+0x10, sf);
|
||||
ea->loop_end = read_s32(offset+0x14, sf) + ea->loop_start; /* loop length */
|
||||
ea->data_offset = read_s32(offset+0x18, sf); /* 0 when blocked */
|
||||
/* 0x1c: pan/volume/etc? (0x7F)
|
||||
* rest may be padding/garbage */
|
||||
//VGM_ASSERT(ea->type != 0, "EA EACS: unknown type %i\n", ea->type);
|
||||
|
||||
if (ea->codec == EA_CODEC_IMA)
|
||||
ea->codec_config = get_ea_1snh_ima_version(sf, 0x00, ea);
|
||||
/* EACS banks with empty values exist but will be rejected later */
|
||||
}
|
||||
else if (read_u32be(offset + 0x00, sf) == 0x00) {
|
||||
/* found in early videos, similar to EACS */
|
||||
ea->big_endian = guess_endianness32bit(offset + 0x04, sf);
|
||||
read_s32 = ea->big_endian ? read_s32be : read_s32le;
|
||||
|
||||
ea->sample_rate = read_s32(offset + 0x04, sf);
|
||||
ea->bits = read_u8(offset + 0x08, sf);
|
||||
ea->channels = read_u8(offset + 0x09, sf);
|
||||
ea->codec = read_u8(offset + 0x0a, sf);
|
||||
ea->type = read_u8(offset + 0x0b, sf); /* block type? 0=1SNh, -1=bank */
|
||||
|
||||
if (ea->codec == EA_CODEC_IMA)
|
||||
ea->codec_config = get_ea_1snh_ima_version(sf, 0x00, ea);
|
||||
}
|
||||
else if (ea->is_sead) {
|
||||
/* alt subheader (found in some PC videos) */
|
||||
ea->big_endian = guess_endianness32bit(offset + 0x00, sf);
|
||||
read_s32 = ea->big_endian ? read_s32be : read_s32le;
|
||||
|
||||
ea->sample_rate = read_s32(offset+0x00, sf);
|
||||
ea->channels = read_s32(offset+0x04, sf);
|
||||
ea->codec = read_s32(offset+0x08, sf);
|
||||
|
||||
if (ea->codec == EA_CODEC_IMA)
|
||||
ea->codec_config = get_ea_1snh_ima_version(sf, 0x00, ea);
|
||||
}
|
||||
else {
|
||||
/* alt subheader (PS1) */
|
||||
ea->big_endian = guess_endianness32bit(offset + 0x00, sf);
|
||||
read_s32 = ea->big_endian ? read_s32be : read_s32le;
|
||||
|
||||
ea->sample_rate = read_s32(offset+0x00, sf);
|
||||
ea->channels = read_u8(offset+0x18, sf);
|
||||
ea->codec = EA_CODEC_PSX;
|
||||
}
|
||||
|
||||
ea->loop_flag = (ea->loop_end > 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* get total samples by parsing block headers, needed when EACS isn't present */
|
||||
static void set_ea_1snh_num_samples(VGMSTREAM *vgmstream, STREAMFILE* sf, eacs_header* ea, int find_loop) {
|
||||
int32_t num_samples = 0, block_id;
|
||||
size_t file_size;
|
||||
int32_t(*read_s32)(off_t, STREAMFILE *) = ea->big_endian ? read_s32be : read_s32le;
|
||||
int loop_end_found = 0;
|
||||
|
||||
file_size = get_streamfile_size(sf);
|
||||
vgmstream->next_block_offset = ea->data_offset;
|
||||
|
||||
while (vgmstream->next_block_offset < file_size) {
|
||||
block_update_ea_1snh(vgmstream->next_block_offset, vgmstream);
|
||||
if (vgmstream->current_block_samples < 0)
|
||||
break;
|
||||
|
||||
block_id = read_u32be(vgmstream->current_block_offset, sf);
|
||||
if (find_loop) {
|
||||
if (vgmstream->current_block_offset == ea->loop_start_offset) {
|
||||
ea->loop_start = num_samples;
|
||||
ea->loop_flag = 1;
|
||||
block_update_ea_1snh(ea->data_offset, vgmstream);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (block_id == get_id32be("1SNl") ) { /* loop point found */
|
||||
ea->loop_start_offset = read_s32(vgmstream->current_block_offset + 0x08, sf);
|
||||
ea->loop_end = num_samples;
|
||||
loop_end_found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
num_samples += vgmstream->current_block_samples;
|
||||
}
|
||||
|
||||
ea->num_samples = num_samples;
|
||||
|
||||
/* reset once we're done */
|
||||
block_update_ea_1snh(ea->data_offset, vgmstream);
|
||||
|
||||
if (loop_end_found) {
|
||||
/* recurse to find loop start sample */
|
||||
set_ea_1snh_num_samples(vgmstream, sf, ea, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* find codec version used, with or without ADPCM hist per block */
|
||||
static int get_ea_1snh_ima_version(STREAMFILE* sf, off_t start_offset, const eacs_header* ea) {
|
||||
off_t block_offset = start_offset;
|
||||
size_t file_size = get_streamfile_size(sf);
|
||||
int32_t (*read_s32)(off_t,STREAMFILE*) = ea->big_endian ? read_s32be : read_s32le;
|
||||
|
||||
while (block_offset < file_size) {
|
||||
uint32_t id = read_u32be(block_offset+0x00,sf);
|
||||
size_t block_size;
|
||||
|
||||
/* BE in SAT, but one file may have both BE and LE chunks */
|
||||
if (guess_endianness32bit(block_offset + 0x04, sf))
|
||||
block_size = read_u32be(block_offset + 0x04, sf);
|
||||
else
|
||||
block_size = read_u32le(block_offset + 0x04, sf);
|
||||
|
||||
if (id == 0x31534E64 || id == 0x534E4443) { /* "1SNd" "SNDC" audio data */
|
||||
size_t ima_samples = read_s32(block_offset + 0x08, sf);
|
||||
size_t expected_samples = (block_size - 0x08 - 0x04 - 0x08*ea->channels) * 2 / ea->channels;
|
||||
|
||||
if (ima_samples == expected_samples) {
|
||||
return 1; /* has ADPCM hist (hopefully) */
|
||||
}
|
||||
}
|
||||
|
||||
block_offset += block_size;
|
||||
}
|
||||
|
||||
return 0; /* no ADPCM hist */
|
||||
}
|
||||
|
@ -1,22 +1,19 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* FDA - from Relic Entertainment games [Warhammer 4000: Dawn of War (PC)] */
|
||||
VGMSTREAM * init_vgmstream_fda(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
VGMSTREAM* init_vgmstream_fda(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count, bitrate, sample_rate, num_samples;
|
||||
int loop_flag, channels, bitrate, sample_rate, num_samples;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "fda"))
|
||||
goto fail;
|
||||
|
||||
if (read_u32be(0x00, sf) != 0x52656C69 || /* "Reli" */
|
||||
read_u32be(0x04, sf) != 0x63204368 || /* "c Ch" */
|
||||
read_u32be(0x08, sf) != 0x756E6B79 || /* "unky" */
|
||||
read_u32be(0x0c, sf) != 0x0D0A1A00) /* "\r\n\1a\00"*/
|
||||
if (!is_id64be(0x00, sf, "Relic Ch") ||
|
||||
!is_id64be(0x08, sf, "unky\r\n\x1a\x00"))
|
||||
goto fail;
|
||||
|
||||
/* version? (later .fda change this) */
|
||||
@ -38,18 +35,18 @@ VGMSTREAM * init_vgmstream_fda(STREAMFILE *sf) {
|
||||
offset += 0x14 + name_size + chunk_size;
|
||||
|
||||
/* FOLD-FDA (folder of chunks) */
|
||||
if (read_u32be(offset + 0x04, sf) != 0x46444120) /* "FDA " */
|
||||
if (!is_id32be(offset + 0x04, sf, "FDA "))
|
||||
goto fail;
|
||||
offset += 0x14;
|
||||
|
||||
/* DATA-INFO (header) */
|
||||
if (read_u32be(offset + 0x04, sf) != 0x494E464F) /* "INFO" */
|
||||
if (!is_id32be(offset + 0x04, sf, "INFO"))
|
||||
goto fail;
|
||||
chunk_size = read_u32le(offset + 0x0c, sf);
|
||||
name_size = read_u32le(offset + 0x10, sf);
|
||||
offset += 0x14 + name_size;
|
||||
|
||||
channel_count = read_s32le(offset + 0x00, sf);
|
||||
channels = read_s32le(offset + 0x00, sf);
|
||||
/* 0x04: bps */
|
||||
bitrate = read_s32le(offset + 0x08, sf);
|
||||
sample_rate = read_s32le(offset + 0x0c, sf);
|
||||
@ -60,28 +57,28 @@ VGMSTREAM * init_vgmstream_fda(STREAMFILE *sf) {
|
||||
offset += chunk_size;
|
||||
|
||||
/* DATA-DATA (data) */
|
||||
if (read_u32be(offset + 0x04, sf) != 0x44415441) /* "DATA" */
|
||||
if (!is_id32be(offset + 0x04, sf, "DATA"))
|
||||
goto fail;
|
||||
chunk_size = read_u32le(offset + 0x0c, sf);
|
||||
name_size = read_u32le(offset + 0x10, sf);
|
||||
offset += 0x14 + name_size;
|
||||
|
||||
data_size = read_s32le(offset + 0x00, sf);
|
||||
data_size = read_u32le(offset + 0x00, sf);
|
||||
|
||||
start_offset = offset + 0x04;
|
||||
num_samples = data_size / channel_count / (bitrate / 8) * 512;
|
||||
num_samples = relic_bytes_to_samples(data_size, channels, bitrate);
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_FDA;
|
||||
vgmstream->sample_rate = 44100; /* fixed output */
|
||||
vgmstream->num_samples = num_samples;
|
||||
|
||||
vgmstream->codec_data = init_relic(channel_count, bitrate, sample_rate);
|
||||
vgmstream->codec_data = init_relic(channels, bitrate, sample_rate);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_RELIC;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
103
src/meta/hca.c
103
src/meta/hca.c
@ -5,7 +5,7 @@
|
||||
|
||||
//#define HCA_BRUTEFORCE
|
||||
#ifdef HCA_BRUTEFORCE
|
||||
static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* out_keycode, uint16_t subkey);
|
||||
static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey);
|
||||
#endif
|
||||
static void find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t subkey);
|
||||
|
||||
@ -191,7 +191,7 @@ done:
|
||||
/* Bruteforce binary keys in executables and similar files, mainly for some mobile games.
|
||||
* Kinda slow but acceptable for ~20MB exes, not very optimized. Unity usually has keys
|
||||
* in plaintext (inside levelX or other base files) instead though. */
|
||||
static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* out_keycode, uint16_t subkey) {
|
||||
static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
|
||||
STREAMFILE* sf_keys = NULL;
|
||||
uint8_t* buf = NULL;
|
||||
int best_score = 0xFFFFFF, cur_score;
|
||||
@ -200,9 +200,9 @@ static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigne
|
||||
uint64_t old_key = 0;
|
||||
|
||||
|
||||
VGM_LOG("HCA: test keys\n");
|
||||
VGM_LOG("HCA: test keys.bin\n");
|
||||
|
||||
*out_keycode = 0;
|
||||
*p_keycode = 0;
|
||||
|
||||
/* load whole file in memory for performance (exes with keys shouldn't be too big) */
|
||||
sf_keys = open_streamfile_by_filename(sf, "keys.bin");
|
||||
@ -232,14 +232,15 @@ static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigne
|
||||
//key = ((uint64_t)get_u32be(buf + pos + 0x00) << 0 ) | 0; /* upper bytes not set, ex. P5 */
|
||||
|
||||
/* observed files have aligned keys, change if needed */
|
||||
pos += 0x04; //pos++;
|
||||
pos += 0x04;
|
||||
//pos++;
|
||||
|
||||
if (key == 0 || key == old_key)
|
||||
continue;
|
||||
old_key = key;
|
||||
|
||||
cur_score = 0;
|
||||
test_key(hca_data, key, subkey, &cur_score, out_keycode);
|
||||
test_key(hca_data, key, subkey, &cur_score, p_keycode);
|
||||
if (cur_score == 1)
|
||||
goto done;
|
||||
|
||||
@ -253,10 +254,98 @@ static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigne
|
||||
|
||||
done:
|
||||
VGM_ASSERT(best_score > 0, "HCA: best key=%08x%08x (score=%i)\n",
|
||||
(uint32_t)((*out_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*out_keycode & 0xFFFFFFFF), best_score);
|
||||
(uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), best_score);
|
||||
VGM_ASSERT(best_score < 0, "HCA: key not found\n");
|
||||
if (best_score < 0 || best_score > 10000)
|
||||
*p_keycode = 0;
|
||||
|
||||
close_streamfile(sf_keys);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
#include <inttypes.h>
|
||||
//#include <stdio.h>
|
||||
|
||||
/* same as the above but for txt lines. */
|
||||
static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
|
||||
STREAMFILE* sf_keys = NULL;
|
||||
uint8_t* buf = NULL;
|
||||
int best_score = 0xFFFFFF, cur_score;
|
||||
off_t keys_size, bytes;
|
||||
int i = 0, pos;
|
||||
char line[1024];
|
||||
|
||||
|
||||
VGM_LOG("HCA: test keys.txt\n");
|
||||
|
||||
*p_keycode = 0;
|
||||
|
||||
/* load whole file in memory for performance (exes with keys shouldn't be too big) */
|
||||
sf_keys = open_streamfile_by_filename(sf, "keys.txt");
|
||||
if (!sf_keys) goto done;
|
||||
|
||||
keys_size = get_streamfile_size(sf_keys);
|
||||
|
||||
buf = malloc(keys_size);
|
||||
if (!buf) goto done;
|
||||
|
||||
bytes = read_streamfile(buf, 0, keys_size, sf_keys);
|
||||
if (bytes != keys_size) goto done;
|
||||
|
||||
VGM_LOG("HCA: start\n");
|
||||
|
||||
pos = 0;
|
||||
while (pos < keys_size) {
|
||||
int bytes_read, line_ok, count;
|
||||
uint64_t key = 0;
|
||||
|
||||
bytes_read = read_line(line, sizeof(line), pos, sf_keys, &line_ok);
|
||||
if (!line_ok) continue; //???
|
||||
|
||||
pos += bytes_read;
|
||||
|
||||
count = sscanf(line, "%" SCNd64, &key);
|
||||
if (count != 1) continue;
|
||||
|
||||
VGM_ASSERT(pos % 100000 == 0, "HCA: count %i...\n", i);
|
||||
|
||||
if (key == 0)
|
||||
continue;
|
||||
i++;
|
||||
|
||||
cur_score = 0;
|
||||
test_key(hca_data, key, subkey, &cur_score, p_keycode);
|
||||
if (cur_score == 1)
|
||||
goto done;
|
||||
|
||||
if (cur_score > 0 && cur_score <= 500) {
|
||||
VGM_LOG("HCA: possible key=%08x%08x (score=%i) at %x\n",
|
||||
(uint32_t)((key >> 32) & 0xFFFFFFFF), (uint32_t)(key & 0xFFFFFFFF), cur_score, pos-0x04);
|
||||
if (best_score > cur_score)
|
||||
best_score = cur_score;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
VGM_LOG("HCA: done %i keys.txt\n", i);
|
||||
VGM_ASSERT(best_score > 0, "HCA: best key=%08x%08x (score=%i)\n",
|
||||
(uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), best_score);
|
||||
VGM_ASSERT(best_score < 0, "HCA: key not found\n");
|
||||
if (best_score < 0 || best_score > 10000)
|
||||
*p_keycode = 0;
|
||||
|
||||
close_streamfile(sf_keys);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
|
||||
bruteforce_hca_key_bin(sf, hca_data, p_keycode, subkey);
|
||||
if (*p_keycode != 0)
|
||||
return;
|
||||
|
||||
bruteforce_hca_key_txt(sf, hca_data, p_keycode, subkey);
|
||||
if (*p_keycode != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -359,7 +359,7 @@ VGMSTREAM * init_vgmstream_mul(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_thp(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_wii_sts(STREAMFILE *streamFile);
|
||||
VGMSTREAM* init_vgmstream_sts(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_p2bt(STREAMFILE *streamFile);
|
||||
|
||||
@ -533,9 +533,9 @@ VGMSTREAM * init_vgmstream_hyperscan_kvag(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ios_psnd(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_pc_adp_bos(STREAMFILE* streamFile);
|
||||
VGMSTREAM* init_vgmstream_adp_bos(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM * init_vgmstream_pc_adp_otns(STREAMFILE* streamFile);
|
||||
VGMSTREAM* init_vgmstream_adp_qd(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM * init_vgmstream_eb_sfx(STREAMFILE* streamFile);
|
||||
VGMSTREAM * init_vgmstream_eb_sf0(STREAMFILE* streamFile);
|
||||
@ -955,4 +955,8 @@ VGMSTREAM* init_vgmstream_sspr(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_piff_tpcm(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_wxd_wxh(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_bnk_relic(STREAMFILE* sf);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
160
src/meta/mp4.c
160
src/meta/mp4.c
@ -1,167 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
#ifdef VGM_USE_MP4V2
|
||||
void* mp4_file_open( const char* name, MP4FileMode mode )
|
||||
{
|
||||
char * endptr;
|
||||
#ifdef _MSC_VER
|
||||
unsigned __int64 ptr = _strtoui64( name, &endptr, 16 );
|
||||
#else
|
||||
unsigned long ptr = strtoul( name, &endptr, 16 );
|
||||
#endif
|
||||
return (void*) ptr;
|
||||
}
|
||||
|
||||
int mp4_file_seek( void* handle, int64_t pos )
|
||||
{
|
||||
mp4_streamfile * file = ( mp4_streamfile * ) handle;
|
||||
if ( pos > file->size ) pos = file->size;
|
||||
pos += file->start;
|
||||
file->offset = pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mp4_file_get_size( void* handle, int64_t* size )
|
||||
{
|
||||
mp4_streamfile * file = ( mp4_streamfile * ) handle;
|
||||
*size = file->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mp4_file_read( void* handle, void* buffer, int64_t size, int64_t* nin, int64_t maxChunkSize )
|
||||
{
|
||||
mp4_streamfile * file = ( mp4_streamfile * ) handle;
|
||||
int64_t max_size = file->size - file->offset - file->start;
|
||||
if ( size > max_size ) size = max_size;
|
||||
if ( size > 0 )
|
||||
{
|
||||
*nin = read_streamfile( (uint8_t *) buffer, file->offset, size, file->streamfile );
|
||||
file->offset += *nin;
|
||||
}
|
||||
else
|
||||
{
|
||||
*nin = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mp4_file_write( void* handle, const void* buffer, int64_t size, int64_t* nout, int64_t maxChunkSize )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mp4_file_close( void* handle )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
MP4FileProvider mp4_file_provider = { mp4_file_open, mp4_file_seek, mp4_file_read, mp4_file_write, mp4_file_close, mp4_file_get_size };
|
||||
|
||||
#ifdef VGM_USE_FDKAAC
|
||||
VGMSTREAM * init_vgmstream_mp4_aac_offset(STREAMFILE *sf, uint64_t start, uint64_t size);
|
||||
|
||||
VGMSTREAM * init_vgmstream_mp4_aac(STREAMFILE *sf) {
|
||||
return init_vgmstream_mp4_aac_offset( sf, 0, sf->get_size(sf) );
|
||||
}
|
||||
|
||||
VGMSTREAM * init_vgmstream_mp4_aac_offset(STREAMFILE *sf, uint64_t start, uint64_t size) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
mp4_aac_codec_data * aac_file = ( mp4_aac_codec_data * ) calloc(1, sizeof(mp4_aac_codec_data));
|
||||
|
||||
CStreamInfo * stream_info;
|
||||
|
||||
uint8_t * buffer = NULL;
|
||||
uint32_t buffer_size;
|
||||
UINT ubuffer_size, bytes_valid;
|
||||
|
||||
if ( !aac_file ) goto fail;
|
||||
|
||||
aac_file->if_file.streamfile = sf;
|
||||
aac_file->if_file.start = start;
|
||||
aac_file->if_file.offset = start;
|
||||
aac_file->if_file.size = size;
|
||||
|
||||
/* Big ol' kludge! */
|
||||
sprintf( filename, "%p", &aac_file->if_file );
|
||||
aac_file->h_mp4file = MP4ReadProvider( filename, &mp4_file_provider );
|
||||
if ( !aac_file->h_mp4file ) goto fail;
|
||||
|
||||
if ( MP4GetNumberOfTracks(aac_file->h_mp4file, MP4_AUDIO_TRACK_TYPE, '\000') != 1 ) goto fail;
|
||||
|
||||
aac_file->track_id = MP4FindTrackId( aac_file->h_mp4file, 0, MP4_AUDIO_TRACK_TYPE, '\000' );
|
||||
|
||||
aac_file->h_aacdecoder = aacDecoder_Open( TT_MP4_RAW, 1 );
|
||||
if ( !aac_file->h_aacdecoder ) goto fail;
|
||||
|
||||
MP4GetTrackESConfiguration( aac_file->h_mp4file, aac_file->track_id, (uint8_t**)(&buffer), (uint32_t*)(&buffer_size));
|
||||
|
||||
ubuffer_size = buffer_size;
|
||||
if ( aacDecoder_ConfigRaw( aac_file->h_aacdecoder, &buffer, &ubuffer_size ) ) goto fail;
|
||||
|
||||
free( buffer ); buffer = NULL;
|
||||
|
||||
aac_file->sampleId = 1;
|
||||
aac_file->numSamples = MP4GetTrackNumberOfSamples( aac_file->h_mp4file, aac_file->track_id );
|
||||
|
||||
if (!MP4ReadSample(aac_file->h_mp4file, aac_file->track_id, aac_file->sampleId, (uint8_t**)(&buffer), (uint32_t*)(&buffer_size), 0, 0, 0, 0)) goto fail;
|
||||
|
||||
ubuffer_size = buffer_size;
|
||||
bytes_valid = buffer_size;
|
||||
if ( aacDecoder_Fill( aac_file->h_aacdecoder, &buffer, &ubuffer_size, &bytes_valid ) || bytes_valid ) goto fail;
|
||||
if ( aacDecoder_DecodeFrame( aac_file->h_aacdecoder, aac_file->sample_buffer, ( (6) * (2048)*4 ), 0 ) ) goto fail;
|
||||
|
||||
free( buffer ); buffer = NULL;
|
||||
|
||||
aac_file->sample_ptr = 0;
|
||||
|
||||
stream_info = aacDecoder_GetStreamInfo( aac_file->h_aacdecoder );
|
||||
|
||||
aac_file->samples_per_frame = stream_info->frameSize;
|
||||
aac_file->samples_discard = 0;
|
||||
|
||||
sf->get_name( sf, filename, sizeof(filename) );
|
||||
|
||||
aac_file->if_file.streamfile = sf->open(sf, filename, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!aac_file->if_file.streamfile) goto fail;
|
||||
|
||||
vgmstream = allocate_vgmstream( stream_info->numChannels, 1 );
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->loop_flag = 0;
|
||||
|
||||
vgmstream->codec_data = aac_file;
|
||||
|
||||
vgmstream->channels = stream_info->numChannels;
|
||||
vgmstream->sample_rate = stream_info->sampleRate;
|
||||
|
||||
vgmstream->num_samples = stream_info->frameSize * aac_file->numSamples;
|
||||
|
||||
vgmstream->coding_type = coding_MP4_AAC;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_MP4;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
if ( buffer ) free( buffer );
|
||||
if ( aac_file ) {
|
||||
if ( aac_file->h_aacdecoder ) aacDecoder_Close( aac_file->h_aacdecoder );
|
||||
if ( aac_file->h_mp4file ) MP4Close( aac_file->h_mp4file, 0 );
|
||||
free( aac_file );
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
|
||||
typedef struct {
|
||||
int channels;
|
||||
int sample_rate;
|
||||
|
160
src/meta/mp4_faac.c
Normal file
160
src/meta/mp4_faac.c
Normal file
@ -0,0 +1,160 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
|
||||
// VGM_USE_MP4V2
|
||||
void* mp4_file_open( const char* name, MP4FileMode mode )
|
||||
{
|
||||
char * endptr;
|
||||
#ifdef _MSC_VER
|
||||
unsigned __int64 ptr = _strtoui64( name, &endptr, 16 );
|
||||
#else
|
||||
unsigned long ptr = strtoul( name, &endptr, 16 );
|
||||
#endif
|
||||
return (void*) ptr;
|
||||
}
|
||||
|
||||
int mp4_file_seek( void* handle, int64_t pos )
|
||||
{
|
||||
mp4_streamfile * file = ( mp4_streamfile * ) handle;
|
||||
if ( pos > file->size ) pos = file->size;
|
||||
pos += file->start;
|
||||
file->offset = pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mp4_file_get_size( void* handle, int64_t* size )
|
||||
{
|
||||
mp4_streamfile * file = ( mp4_streamfile * ) handle;
|
||||
*size = file->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mp4_file_read( void* handle, void* buffer, int64_t size, int64_t* nin, int64_t maxChunkSize )
|
||||
{
|
||||
mp4_streamfile * file = ( mp4_streamfile * ) handle;
|
||||
int64_t max_size = file->size - file->offset - file->start;
|
||||
if ( size > max_size ) size = max_size;
|
||||
if ( size > 0 )
|
||||
{
|
||||
*nin = read_streamfile( (uint8_t *) buffer, file->offset, size, file->streamfile );
|
||||
file->offset += *nin;
|
||||
}
|
||||
else
|
||||
{
|
||||
*nin = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mp4_file_write( void* handle, const void* buffer, int64_t size, int64_t* nout, int64_t maxChunkSize )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mp4_file_close( void* handle )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
MP4FileProvider mp4_file_provider = { mp4_file_open, mp4_file_seek, mp4_file_read, mp4_file_write, mp4_file_close, mp4_file_get_size };
|
||||
|
||||
// VGM_USE_FDKAAC
|
||||
VGMSTREAM * init_vgmstream_mp4_aac_offset(STREAMFILE *sf, uint64_t start, uint64_t size);
|
||||
|
||||
VGMSTREAM * init_vgmstream_mp4_aac(STREAMFILE *sf) {
|
||||
return init_vgmstream_mp4_aac_offset( sf, 0, sf->get_size(sf) );
|
||||
}
|
||||
|
||||
VGMSTREAM * init_vgmstream_mp4_aac_offset(STREAMFILE *sf, uint64_t start, uint64_t size) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
mp4_aac_codec_data * aac_file = ( mp4_aac_codec_data * ) calloc(1, sizeof(mp4_aac_codec_data));
|
||||
|
||||
CStreamInfo * stream_info;
|
||||
|
||||
uint8_t * buffer = NULL;
|
||||
uint32_t buffer_size;
|
||||
UINT ubuffer_size, bytes_valid;
|
||||
|
||||
if ( !aac_file ) goto fail;
|
||||
|
||||
aac_file->if_file.streamfile = sf;
|
||||
aac_file->if_file.start = start;
|
||||
aac_file->if_file.offset = start;
|
||||
aac_file->if_file.size = size;
|
||||
|
||||
/* Big ol' kludge! */
|
||||
sprintf( filename, "%p", &aac_file->if_file );
|
||||
aac_file->h_mp4file = MP4ReadProvider( filename, &mp4_file_provider );
|
||||
if ( !aac_file->h_mp4file ) goto fail;
|
||||
|
||||
if ( MP4GetNumberOfTracks(aac_file->h_mp4file, MP4_AUDIO_TRACK_TYPE, '\000') != 1 ) goto fail;
|
||||
|
||||
aac_file->track_id = MP4FindTrackId( aac_file->h_mp4file, 0, MP4_AUDIO_TRACK_TYPE, '\000' );
|
||||
|
||||
aac_file->h_aacdecoder = aacDecoder_Open( TT_MP4_RAW, 1 );
|
||||
if ( !aac_file->h_aacdecoder ) goto fail;
|
||||
|
||||
MP4GetTrackESConfiguration( aac_file->h_mp4file, aac_file->track_id, (uint8_t**)(&buffer), (uint32_t*)(&buffer_size));
|
||||
|
||||
ubuffer_size = buffer_size;
|
||||
if ( aacDecoder_ConfigRaw( aac_file->h_aacdecoder, &buffer, &ubuffer_size ) ) goto fail;
|
||||
|
||||
free( buffer ); buffer = NULL;
|
||||
|
||||
aac_file->sampleId = 1;
|
||||
aac_file->numSamples = MP4GetTrackNumberOfSamples( aac_file->h_mp4file, aac_file->track_id );
|
||||
|
||||
if (!MP4ReadSample(aac_file->h_mp4file, aac_file->track_id, aac_file->sampleId, (uint8_t**)(&buffer), (uint32_t*)(&buffer_size), 0, 0, 0, 0)) goto fail;
|
||||
|
||||
ubuffer_size = buffer_size;
|
||||
bytes_valid = buffer_size;
|
||||
if ( aacDecoder_Fill( aac_file->h_aacdecoder, &buffer, &ubuffer_size, &bytes_valid ) || bytes_valid ) goto fail;
|
||||
if ( aacDecoder_DecodeFrame( aac_file->h_aacdecoder, aac_file->sample_buffer, ( (6) * (2048)*4 ), 0 ) ) goto fail;
|
||||
|
||||
free( buffer ); buffer = NULL;
|
||||
|
||||
aac_file->sample_ptr = 0;
|
||||
|
||||
stream_info = aacDecoder_GetStreamInfo( aac_file->h_aacdecoder );
|
||||
|
||||
aac_file->samples_per_frame = stream_info->frameSize;
|
||||
aac_file->samples_discard = 0;
|
||||
|
||||
sf->get_name( sf, filename, sizeof(filename) );
|
||||
|
||||
aac_file->if_file.streamfile = sf->open(sf, filename, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!aac_file->if_file.streamfile) goto fail;
|
||||
|
||||
vgmstream = allocate_vgmstream( stream_info->numChannels, 1 );
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->loop_flag = 0;
|
||||
|
||||
vgmstream->codec_data = aac_file;
|
||||
|
||||
vgmstream->channels = stream_info->numChannels;
|
||||
vgmstream->sample_rate = stream_info->sampleRate;
|
||||
|
||||
vgmstream->num_samples = stream_info->frameSize * aac_file->numSamples;
|
||||
|
||||
vgmstream->coding_type = coding_MP4_AAC;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_MP4;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
if ( buffer ) free( buffer );
|
||||
if ( aac_file ) {
|
||||
if ( aac_file->h_aacdecoder ) aacDecoder_Close( aac_file->h_aacdecoder );
|
||||
if ( aac_file->h_mp4file ) MP4Close( aac_file->h_mp4file, 0 );
|
||||
free( aac_file );
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
@ -1,49 +0,0 @@
|
||||
#include "meta.h"
|
||||
|
||||
/* ADP - from Balls of Steel */
|
||||
VGMSTREAM * init_vgmstream_pc_adp_bos(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
|
||||
if (!check_extensions(streamFile,"adp")) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x41445021) /* "ADP!" */
|
||||
goto fail;
|
||||
|
||||
loop_flag = (-1 != read_32bitLE(0x08,streamFile));
|
||||
channel_count = 1;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x18;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x0C,streamFile);
|
||||
vgmstream->num_samples = read_32bitLE(0x04,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_DVI_IMA_int;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_BOS_ADP;
|
||||
|
||||
// 0x10, 0x12 - both initial history?
|
||||
//vgmstream->ch[0].adpcm_history1_32 = read_16bitLE(0x10,streamFile);
|
||||
// 0x14 - initial step index?
|
||||
//vgmstream->ch[0].adpcm_step_index = read_32bitLE(0x14,streamFile);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
#include "meta.h"
|
||||
|
||||
/* ADP - from Omikron: The Nomad Soul (PC/DC) */
|
||||
VGMSTREAM * init_vgmstream_pc_adp_otns(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, datasize;
|
||||
int loop_flag = 0, channel_count, stereo_flag;
|
||||
|
||||
if (!check_extensions(streamFile,"adp")) goto fail;
|
||||
|
||||
/* no ID, only a basic 0x10 header with filesize and nulls; do some extra checks */
|
||||
datasize = read_32bitLE(0x00,streamFile) & 0x00FFFFFF; /*24 bit*/
|
||||
if (datasize + 0x10 != streamFile->get_size(streamFile)
|
||||
|| read_32bitLE(0x04,streamFile) != 0
|
||||
|| read_32bitLE(0x08,streamFile) != 0
|
||||
|| read_32bitLE(0x0c,streamFile) != 0)
|
||||
goto fail;
|
||||
|
||||
stereo_flag = read_8bit(0x03, streamFile);
|
||||
if (stereo_flag > 1 || stereo_flag < 0) goto fail;
|
||||
channel_count = stereo_flag ? 2 : 1;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
start_offset = 0x10;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = 22050;
|
||||
vgmstream->num_samples = channel_count== 1 ? datasize*2 : datasize;
|
||||
|
||||
vgmstream->coding_type = coding_OTNS_IMA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_OTNS_ADP;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
55
src/meta/sts.c
Normal file
55
src/meta/sts.c
Normal file
@ -0,0 +1,55 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* .STS - from Alfa System games [Shikigami no Shiro 3 (Wii)] */
|
||||
VGMSTREAM* init_vgmstream_sts(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
uint32_t start_offset, data_size, channel_size;
|
||||
int loop_flag, channels, sample_rate;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "sts"))
|
||||
goto fail;
|
||||
|
||||
data_size = read_u32be(0x00,sf);
|
||||
if (data_size + 0x04 != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
|
||||
channels = read_u8(0x08,sf) + 1;
|
||||
sample_rate = read_u16be(0x0c,sf);
|
||||
/* 0x10: dsp related? */
|
||||
/* 0x16: usable size */
|
||||
channel_size = read_u32be(0x1a,sf);
|
||||
|
||||
loop_flag = 0; //(read_s32be(0x4C,sf) != -1); /* not seen */
|
||||
|
||||
start_offset = (channels == 1) ? 0x70 : 0x50;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_STS;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(channel_size, 1);
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = channel_size + 0x2e;
|
||||
|
||||
dsp_read_coefs_be(vgmstream, sf, 0x1e, start_offset - 0x1e + channel_size);
|
||||
dsp_read_hist_be(vgmstream, sf, 0x1e + 0x24, start_offset - 0x1e + channel_size);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* STS
|
||||
|
||||
STS (found in Shikigami No Shiro 3)
|
||||
Don't confuse with ps2 .STS (EXST) format, this one is for WII
|
||||
*/
|
||||
|
||||
VGMSTREAM * init_vgmstream_wii_sts(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
int loop_flag=0;
|
||||
int channel_count;
|
||||
int i,j;
|
||||
off_t start_offset;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("sts",filename_extension(filename))) goto fail;
|
||||
|
||||
/* First bytes contain the size of the file (-4) */
|
||||
if(read_32bitBE(0x0,streamFile)!=get_streamfile_size(streamFile)-4)
|
||||
goto fail;
|
||||
|
||||
loop_flag = (read_32bitLE(0x4C,streamFile)!=0xFFFFFFFF);
|
||||
channel_count=read_8bit(0x8,streamFile)+1;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitBE(0x0A,streamFile);
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
|
||||
if(vgmstream->channels==1)
|
||||
vgmstream->num_samples = (read_32bitBE(0x0,streamFile)+4-0x70)/8*14;
|
||||
else
|
||||
vgmstream->num_samples = (read_32bitBE(0x0,streamFile)+4-0x50-0x26)/8*14/2;
|
||||
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_STS_WII;
|
||||
|
||||
if(loop_flag) {
|
||||
vgmstream->loop_start_sample=read_32bitLE(0x24,streamFile);
|
||||
vgmstream->loop_end_sample=vgmstream->num_samples;
|
||||
}
|
||||
|
||||
/* setting coef tables */
|
||||
if(vgmstream->channels==1)
|
||||
start_offset = 0x70;
|
||||
else
|
||||
start_offset = 0x50;
|
||||
|
||||
// First channel
|
||||
for(j=0;j<16;j++) {
|
||||
vgmstream->ch[0].adpcm_coef[j]=read_16bitBE(0x1E + (j*2),streamFile);
|
||||
}
|
||||
|
||||
// Second channel ?
|
||||
if(vgmstream->channels==2) {
|
||||
start_offset+=read_32bitBE(0x1a,streamFile);
|
||||
for(j=0;j<16;j++) {
|
||||
vgmstream->ch[1].adpcm_coef[j]=read_16bitBE(start_offset+(j*2),streamFile);
|
||||
}
|
||||
}
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
vgmstream->ch[i].offset = 0x50+(i*(start_offset+0x26-0x50));
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
76
src/meta/wxd_wxh.c
Normal file
76
src/meta/wxd_wxh.c
Normal file
@ -0,0 +1,76 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* WXD+WXH - stream container from Relic's earlier games [Homeworld (PC), Homeworld Cataclysm (PC)] */
|
||||
VGMSTREAM* init_vgmstream_wxd_wxh(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* sh = NULL;
|
||||
uint32_t start_offset, offset, data_size;
|
||||
int loop_flag, channels, bitrate, internal_rate;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "wxd"))
|
||||
goto fail;
|
||||
if (!is_id32be(0x00,sf, "WXD1"))
|
||||
goto fail;
|
||||
/* 0x04: crc? */
|
||||
|
||||
/* companion .wxh found in .big bigfiles, must extract and put together */
|
||||
sh = open_streamfile_by_ext(sf,"wxh");
|
||||
if (!sh) goto fail;
|
||||
|
||||
if (!is_id32be(0x00,sh, "WXH1"))
|
||||
goto fail;
|
||||
/* 0x04: crc? */
|
||||
|
||||
total_subsongs = read_u32le(0x08,sh);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
offset = 0x0c + (target_subsong-1) * 0x0c;
|
||||
start_offset = read_u32le(offset + 0x00,sh);
|
||||
loop_flag = read_u16le(offset + 0x04,sh);
|
||||
bitrate = read_u16le(offset + 0x06,sh);
|
||||
/* 0x08: volume (255=max) */
|
||||
channels = read_u8 (offset + 0x09,sh);
|
||||
/* 0x0a: unused (-1) */
|
||||
internal_rate = 44100;
|
||||
|
||||
/* stream info */
|
||||
if (!is_id32be(start_offset + 0x00,sf, "DATA"))
|
||||
goto fail;
|
||||
data_size = read_u32le(start_offset + 0x04,sf);
|
||||
start_offset += 0x08;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_WXD_WXH;
|
||||
vgmstream->sample_rate = 44100;
|
||||
|
||||
vgmstream->num_samples = relic_bytes_to_samples(data_size, channels, bitrate);
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = data_size;
|
||||
|
||||
vgmstream->codec_data = init_relic(channels, bitrate, internal_rate);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_RELIC;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
close_streamfile(sh);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(sh);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -179,7 +179,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||
init_vgmstream_dcs_wav,
|
||||
init_vgmstream_mul,
|
||||
init_vgmstream_thp,
|
||||
init_vgmstream_wii_sts,
|
||||
init_vgmstream_sts,
|
||||
init_vgmstream_ps2_p2bt,
|
||||
init_vgmstream_ps2_gbts,
|
||||
init_vgmstream_wii_sng,
|
||||
@ -275,8 +275,8 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||
init_vgmstream_ps2_wmus,
|
||||
init_vgmstream_hyperscan_kvag,
|
||||
init_vgmstream_ios_psnd,
|
||||
init_vgmstream_pc_adp_bos,
|
||||
init_vgmstream_pc_adp_otns,
|
||||
init_vgmstream_adp_bos,
|
||||
init_vgmstream_adp_qd,
|
||||
init_vgmstream_eb_sfx,
|
||||
init_vgmstream_eb_sf0,
|
||||
init_vgmstream_mtaf,
|
||||
@ -526,6 +526,8 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||
init_vgmstream_ogv_3rdeye,
|
||||
init_vgmstream_sspr,
|
||||
init_vgmstream_piff_tpcm,
|
||||
init_vgmstream_wxd_wxh,
|
||||
init_vgmstream_bnk_relic,
|
||||
|
||||
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
|
||||
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
|
||||
|
@ -6,13 +6,15 @@
|
||||
#define _VGMSTREAM_H
|
||||
|
||||
/* reasonable limits */
|
||||
enum { PATH_LIMIT = 32768 };
|
||||
enum { STREAM_NAME_SIZE = 255 };
|
||||
enum { VGMSTREAM_MAX_CHANNELS = 64 };
|
||||
enum { VGMSTREAM_MIN_SAMPLE_RATE = 300 }; /* 300 is Wwise min */
|
||||
enum { VGMSTREAM_MAX_SAMPLE_RATE = 192000 }; /* found in some FSB5 */
|
||||
enum { VGMSTREAM_MAX_SUBSONGS = 65535 };
|
||||
enum { VGMSTREAM_MAX_NUM_SAMPLES = 1000000000 }; /* no ~5h vgm hopefully */
|
||||
enum {
|
||||
PATH_LIMIT = 32768,
|
||||
STREAM_NAME_SIZE = 255,
|
||||
VGMSTREAM_MAX_CHANNELS = 64,
|
||||
VGMSTREAM_MIN_SAMPLE_RATE = 300, /* 300 is Wwise min */
|
||||
VGMSTREAM_MAX_SAMPLE_RATE = 192000, /* found in some FSB5 */
|
||||
VGMSTREAM_MAX_SUBSONGS = 65535, /* +20000 isn't that uncommon */
|
||||
VGMSTREAM_MAX_NUM_SAMPLES = 1000000000, /* no ~5h vgm hopefully */
|
||||
};
|
||||
|
||||
#include "streamfile.h"
|
||||
|
||||
@ -104,7 +106,7 @@ typedef enum {
|
||||
coding_DVI_IMA_int, /* DVI IMA ADPCM (mono/interleave, high nibble first) */
|
||||
coding_3DS_IMA, /* 3DS IMA ADPCM */
|
||||
coding_SNDS_IMA, /* Heavy Iron Studios .snds IMA ADPCM */
|
||||
coding_OTNS_IMA, /* Omikron The Nomad Soul IMA ADPCM */
|
||||
coding_QD_IMA,
|
||||
coding_WV6_IMA, /* Gorilla Systems WV6 4-bit IMA ADPCM */
|
||||
coding_ALP_IMA, /* High Voltage ALP 4-bit IMA ADPCM */
|
||||
coding_FFTA2_IMA, /* Final Fantasy Tactics A2 4-bit IMA ADPCM */
|
||||
@ -481,7 +483,7 @@ typedef enum {
|
||||
meta_VS, /* Men in Black .vs */
|
||||
meta_FFXI_BGW, /* FFXI (PC) BGW */
|
||||
meta_FFXI_SPW, /* FFXI (PC) SPW */
|
||||
meta_STS_WII, /* Shikigami No Shiro 3 STS Audio File */
|
||||
meta_STS,
|
||||
meta_PS2_P2BT, /* Pop'n'Music 7 Audio File */
|
||||
meta_PS2_GBTS, /* Pop'n'Music 9 Audio File */
|
||||
meta_NGC_DSP_IADP, /* Gamecube Interleave DSP */
|
||||
@ -556,8 +558,8 @@ typedef enum {
|
||||
meta_PS2_WMUS, /* The Warriors (PS2) */
|
||||
meta_HYPERSCAN_KVAG, /* Hyperscan KVAG/BVG */
|
||||
meta_IOS_PSND, /* Crash Bandicoot Nitro Kart 2 (iOS) */
|
||||
meta_BOS_ADP, /* ADP! (Balls of Steel, PC) */
|
||||
meta_OTNS_ADP, /* Omikron: The Nomad Soul .adp (PC/DC) */
|
||||
meta_BOS_ADP,
|
||||
meta_QD_ADP,
|
||||
meta_EB_SFX, /* Excitebots .sfx */
|
||||
meta_EB_SF0, /* Excitebots .sf0 */
|
||||
meta_MTAF,
|
||||
@ -741,6 +743,8 @@ typedef enum {
|
||||
meta_DSP_KWA,
|
||||
meta_OGV_3RDEYE,
|
||||
meta_PIFF_TPCM,
|
||||
meta_WXD_WXH,
|
||||
meta_BNK_RELIC,
|
||||
} meta_t;
|
||||
|
||||
/* standard WAVEFORMATEXTENSIBLE speaker positions */
|
||||
@ -1025,7 +1029,7 @@ typedef struct {
|
||||
} acm_codec_data;
|
||||
|
||||
|
||||
#ifdef VGM_USE_MP4V2
|
||||
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
|
||||
typedef struct {
|
||||
STREAMFILE* streamfile;
|
||||
uint64_t start;
|
||||
@ -1033,7 +1037,6 @@ typedef struct {
|
||||
uint64_t size;
|
||||
} mp4_streamfile;
|
||||
|
||||
#ifdef VGM_USE_FDKAAC
|
||||
typedef struct {
|
||||
mp4_streamfile if_file;
|
||||
MP4FileHandle h_mp4file;
|
||||
@ -1045,7 +1048,6 @@ typedef struct {
|
||||
INT_PCM sample_buffer[( (6) * (2048)*4 )];
|
||||
} mp4_aac_codec_data;
|
||||
#endif
|
||||
#endif //VGM_USE_MP4V2
|
||||
|
||||
// VGMStream description in structure format
|
||||
typedef struct {
|
||||
|
18
version-get.sh
Normal file
18
version-get.sh
Normal file
@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
# echo current git version (doesn't make version.h)
|
||||
|
||||
# test if git exists
|
||||
if ! command -v git > /dev/null
|
||||
then
|
||||
VERSION="unknown"
|
||||
else
|
||||
VERSION=$(git describe --always 2>&1 | tr : _ )
|
||||
fi
|
||||
|
||||
# ignore git stderr "fatal:
|
||||
if case $VERSION in fatal*) ;; *) false;; esac; then
|
||||
echo "unknown"
|
||||
else
|
||||
echo "$VERSION"
|
||||
fi;
|
38
version-make.bat
Normal file
38
version-make.bat
Normal file
@ -0,0 +1,38 @@
|
||||
@echo off
|
||||
setlocal enableextensions enabledelayedexpansion
|
||||
|
||||
REM creates or updates version.h
|
||||
REM params: $1=filename (usually version.h), $2=VARNAME (usually VGMSTREAM_VERSION)
|
||||
|
||||
|
||||
REM defaults
|
||||
set VERSION_DEFAULT=unknown
|
||||
set VERSION_FILE=%1
|
||||
set VERSION_NAME=%2
|
||||
if "%~1" == "" set VERSION_FILE=version.h
|
||||
if "%~2" == "" set VERSION_NAME=VGMSTREAM_VERSION
|
||||
|
||||
if not "%version%"=="" set version=!version:^:=_!
|
||||
|
||||
cd /d "%~dp0"
|
||||
|
||||
|
||||
REM try get version from Git, leave original version.h untouched if not possible
|
||||
for /f %%v in ('git describe --always') do set version=%%v
|
||||
|
||||
if not "%version%"=="" set version=!version:^:=_!
|
||||
if not "%version%"=="" goto :got_version
|
||||
|
||||
echo Git version not found, can't autogenerate version.h
|
||||
goto :exit
|
||||
|
||||
|
||||
REM overwrite version.h
|
||||
:got_version
|
||||
if %version%==%VERSION_DEFAULT% goto :exit
|
||||
|
||||
echo #define %VERSION_NAME% "%version%" /* autogenerated */ > %VERSION_FILE%
|
||||
|
||||
|
||||
REM done
|
||||
:exit
|
21
version-make.sh
Normal file
21
version-make.sh
Normal file
@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
# make current git version (overwrites version.h)
|
||||
VERSION_NAME=VGMSTREAM_VERSION
|
||||
VERSION_FILE=version.h
|
||||
|
||||
|
||||
# test if git exists
|
||||
if ! command -v git > /dev/null ; then
|
||||
VERSION=""
|
||||
else
|
||||
VERSION=$(git describe --always 2>&1 | tr : _ )
|
||||
fi
|
||||
|
||||
|
||||
# ignore git stderr "fatal:*" or blank
|
||||
if [[ $VERSION != fatal* ]] && [ ! -z "$VERSION" ] ; then
|
||||
echo "#define $VERSION_NAME \"$VERSION\" /* autogenerated */" > $VERSION_FILE
|
||||
else
|
||||
echo "Git version not found, can't autogenerate version.h"
|
||||
fi;
|
53
version.bat
53
version.bat
@ -1,53 +0,0 @@
|
||||
@echo off
|
||||
|
||||
REM creates or updates version.h
|
||||
REM params: $1=filename (usually version.h), $2=VARNAME (usually VERSION)
|
||||
|
||||
setlocal enableextensions enabledelayedexpansion
|
||||
|
||||
cd /d "%~dp0"
|
||||
|
||||
for /f %%v in ('git describe --always') do set version=%%v
|
||||
|
||||
if not "%version%"=="" set version=!version:^:=_!
|
||||
|
||||
if not "%version%"=="" goto :gotversion
|
||||
|
||||
if exist "version.mk" goto :getversion
|
||||
|
||||
echo Git cannot be found, nor can version.mk. Generating unknown version.
|
||||
|
||||
set version=unknown
|
||||
|
||||
goto :gotversion
|
||||
|
||||
:getversion
|
||||
|
||||
for /f "delims== tokens=2" %%v in (version.mk) do set version=%%v
|
||||
|
||||
set version=!version:^"=!
|
||||
set version=!version: =!
|
||||
|
||||
:gotversion
|
||||
|
||||
set version_out=#define %2 "%version%"
|
||||
set version_mk=%2 = "%version%"
|
||||
|
||||
echo %version_out%> %1_temp
|
||||
|
||||
if %version%==unknown goto :skipgenerate
|
||||
|
||||
echo # static version string; update manually before and after every release.> "version.mk"
|
||||
echo %version_mk%>> "version.mk"
|
||||
|
||||
:skipgenerate
|
||||
|
||||
echo n | comp %1_temp %1 > NUL 2> NUL
|
||||
|
||||
if not errorlevel 1 goto exit
|
||||
|
||||
copy /y %1_temp %1 > NUL 2> NUL
|
||||
|
||||
:exit
|
||||
|
||||
del %1_temp
|
4
version.h
Normal file
4
version.h
Normal file
@ -0,0 +1,4 @@
|
||||
/* Static/fallback version.
|
||||
* Version is autogenerated from Git (passed via compiler args, or updated with scripts), but this file is
|
||||
* for Git-less builds (not installed or downloaded master) and builds that don't do the above should still work. */
|
||||
#define VGMSTREAM_VERSION "unknown"
|
11
version.sh
11
version.sh
@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# get current git version, redirect stderr to stdin, change : to _
|
||||
VERSION=$(git describe --always 2>&1 | tr : _ )
|
||||
|
||||
# ignore git stderr "fatal:
|
||||
if case $VERSION in fatal*) ;; *) false;; esac; then
|
||||
echo ""
|
||||
else
|
||||
echo "$VERSION"
|
||||
fi;
|
@ -1,54 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual Studio 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libvgmstream", "src\libvgmstream.vcproj", "{54A6AD11-5369-4895-A06F-E255ABB99B11}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "in_vgmstream", "winamp\in_vgmstream.vcproj", "{42D86561-8CE4-40F5-86CE-58C986B77502}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{54A6AD11-5369-4895-A06F-E255ABB99B11} = {54A6AD11-5369-4895-A06F-E255ABB99B11}
|
||||
{10E6BFC6-1E5B-46E4-BA42-F04DFBD0ABFF} = {10E6BFC6-1E5B-46E4-BA42-F04DFBD0ABFF}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ext_libs", "ext_libs\ext_libs.vcproj", "{10E6BFC6-1E5B-46E4-BA42-F04DFBD0ABFF}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vgmstream_cli", "cli\vgmstream_cli.vcproj", "{AF7D88A0-3CB1-4CD8-BAD1-0305EB996D69}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{54A6AD11-5369-4895-A06F-E255ABB99B11} = {54A6AD11-5369-4895-A06F-E255ABB99B11}
|
||||
{42D86561-8CE4-40F5-86CE-58C986B77502} = {42D86561-8CE4-40F5-86CE-58C986B77502}
|
||||
{330B53AE-4FAE-46DA-8785-9016DB4E3E23} = {330B53AE-4FAE-46DA-8785-9016DB4E3E23}
|
||||
{10E6BFC6-1E5B-46E4-BA42-F04DFBD0ABFF} = {10E6BFC6-1E5B-46E4-BA42-F04DFBD0ABFF}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt", "ext_libs\Getopt\getopt.vcproj", "{330B53AE-4FAE-46DA-8785-9016DB4E3E23}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{54A6AD11-5369-4895-A06F-E255ABB99B11}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{54A6AD11-5369-4895-A06F-E255ABB99B11}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{54A6AD11-5369-4895-A06F-E255ABB99B11}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{54A6AD11-5369-4895-A06F-E255ABB99B11}.Release|Win32.Build.0 = Release|Win32
|
||||
{42D86561-8CE4-40F5-86CE-58C986B77502}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{42D86561-8CE4-40F5-86CE-58C986B77502}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{42D86561-8CE4-40F5-86CE-58C986B77502}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{42D86561-8CE4-40F5-86CE-58C986B77502}.Release|Win32.Build.0 = Release|Win32
|
||||
{10E6BFC6-1E5B-46E4-BA42-F04DFBD0ABFF}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{10E6BFC6-1E5B-46E4-BA42-F04DFBD0ABFF}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{10E6BFC6-1E5B-46E4-BA42-F04DFBD0ABFF}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{10E6BFC6-1E5B-46E4-BA42-F04DFBD0ABFF}.Release|Win32.Build.0 = Release|Win32
|
||||
{AF7D88A0-3CB1-4CD8-BAD1-0305EB996D69}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{AF7D88A0-3CB1-4CD8-BAD1-0305EB996D69}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{AF7D88A0-3CB1-4CD8-BAD1-0305EB996D69}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{AF7D88A0-3CB1-4CD8-BAD1-0305EB996D69}.Release|Win32.Build.0 = Release|Win32
|
||||
{330B53AE-4FAE-46DA-8785-9016DB4E3E23}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{330B53AE-4FAE-46DA-8785-9016DB4E3E23}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{330B53AE-4FAE-46DA-8785-9016DB4E3E23}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{330B53AE-4FAE-46DA-8785-9016DB4E3E23}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -38,7 +38,7 @@ if(MSVC)
|
||||
add_dependencies(in_vgmstream version_h)
|
||||
elseif(MINGW)
|
||||
if(VGMSTREAM_VERSION)
|
||||
target_compile_definitions(in_vgmstream PRIVATE VERSION="${VGMSTREAM_VERSION}")
|
||||
target_compile_definitions(in_vgmstream PRIVATE VGMSTREAM_VERSION="${VGMSTREAM_VERSION}")
|
||||
endif()
|
||||
|
||||
# Also, on MinGW when using GCC, these flags need to be included to prevent requiring MinGW's runtime DLLs from being included, which does unfortunately increase the size of the DLL
|
||||
|
@ -21,7 +21,7 @@ ifeq ($(TARGET_OS),Windows_NT)
|
||||
endif
|
||||
|
||||
CFLAGS += $(DEF_CFLAGS) -I../ext_includes $(EXTRA_CFLAGS)
|
||||
LDFLAGS += -L../src -L../ext_libs -lm -lvgmstream $(EXTRA_LDFLAGS)
|
||||
LDFLAGS += -L../src -L../ext_libs -lvgmstream -lm $(EXTRA_LDFLAGS)
|
||||
TARGET_EXT_LIBS =
|
||||
|
||||
CFLAGS += $(LIBS_CFLAGS)
|
||||
@ -38,7 +38,7 @@ SRC_SRCS = in_vgmstream.c in_streamfile.c in_config.c
|
||||
### targets
|
||||
|
||||
in_vgmstream: libvgmstream.a $(TARGET_EXT_LIBS) resource.o
|
||||
$(CC) -shared -static-libgcc $(CFLAGS) "-DVERSION=\"`../version.sh`\"" $(SRC_SRCS) resource.o $(LDFLAGS) -o $(OUTPUT_WINAMP)
|
||||
$(CC) -shared -static-libgcc $(CFLAGS) "-DVGMSTREAM_VERSION=\"$(VGMSTREAM_VERSION_PREV)\"" $(SRC_SRCS) resource.o $(LDFLAGS) -o $(OUTPUT_WINAMP)
|
||||
$(STRIP) $(OUTPUT_WINAMP)
|
||||
|
||||
resource.o: resource.rc resource.h
|
||||
|
@ -3,14 +3,14 @@
|
||||
*/
|
||||
#include "in_vgmstream.h"
|
||||
|
||||
#ifndef VERSION
|
||||
#include "version.h"
|
||||
#ifndef VGMSTREAM_VERSION
|
||||
#include "../version.h"
|
||||
#endif
|
||||
#ifndef VERSION
|
||||
#define VERSION "(unknown version)"
|
||||
#ifndef VGMSTREAM_VERSION
|
||||
#define VGMSTREAM_VERSION "(unknown version)"
|
||||
#endif
|
||||
|
||||
#define PLUGIN_DESCRIPTION "vgmstream plugin " VERSION " " __DATE__
|
||||
#define PLUGIN_DESCRIPTION "vgmstream plugin " VGMSTREAM_VERSION " " __DATE__
|
||||
|
||||
|
||||
/* ***************************************** */
|
||||
|
@ -1,218 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="in_vgmstream"
|
||||
ProjectGUID="{42D86561-8CE4-40F5-86CE-58C986B77502}"
|
||||
RootNamespace="in_vgmstream"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../ext_includes"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="../ext_libs/libvorbis.lib ../ext_libs/libmpg123-0.lib ../ext_libs/libg719_decode.lib"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="../ext_includes"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;IN_VGMSTREAM_EXPORTS;VGM_USE_VORBIS;VGM_USE_MPEG;VGM_USE_G7221"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="../ext_libs/libvorbis.lib ../ext_libs/libmpg123-0.lib ../ext_libs/libg719_decode.lib"
|
||||
LinkIncremental="2"
|
||||
ModuleDefinitionFile=""
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\in_vgmstream.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\resource.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\resource.rc"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\in_config.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\in_streamfile.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\in_vgmstream.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@ -89,10 +89,10 @@
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>"$(ProjectDir)..\version.bat" "$(ProjectDir)..\version.h" VERSION</Command>
|
||||
<Command>"$(ProjectDir)..\version-make.bat"</Command>
|
||||
</PreBuildEvent>
|
||||
<PreBuildEvent>
|
||||
<Message>Generating version.h</Message>
|
||||
<Message>Generating version</Message>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@ -119,10 +119,10 @@
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>"$(ProjectDir)..\version.bat" "$(ProjectDir)..\version.h" VERSION</Command>
|
||||
<Command>"$(ProjectDir)..\version-make.bat"</Command>
|
||||
</PreBuildEvent>
|
||||
<PreBuildEvent>
|
||||
<Message>Generating version.h</Message>
|
||||
<Message>Generating version</Message>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
@ -22,7 +22,7 @@ if(MSVC)
|
||||
add_dependencies(xmp-vgmstream version_h)
|
||||
elseif(MINGW)
|
||||
if(VGMSTREAM_VERSION)
|
||||
target_compile_definitions(xmp-vgmstream PRIVATE VERSION="${VGMSTREAM_VERSION}")
|
||||
target_compile_definitions(xmp-vgmstream PRIVATE VGMSTREAM_VERSION="${VGMSTREAM_VERSION}")
|
||||
endif()
|
||||
|
||||
# Also, on MinGW when using GCC, these flags need to be included to prevent requiring MinGW's runtime DLLs from being included, which does unfortunately increase the size of the DLL
|
||||
|
@ -21,7 +21,7 @@ ifeq ($(TARGET_OS),Windows_NT)
|
||||
endif
|
||||
|
||||
CFLAGS += $(DEF_CFLAGS) -I../ext_includes $(EXTRA_CFLAGS)
|
||||
LDFLAGS += -L../src -L../ext_libs -lm -lvgmstream $(EXTRA_LDFLAGS)
|
||||
LDFLAGS += -L../src -L../ext_libs -lvgmstream -lm $(EXTRA_LDFLAGS)
|
||||
TARGET_EXT_LIBS =
|
||||
|
||||
CFLAGS += $(LIBS_CFLAGS)
|
||||
@ -36,7 +36,7 @@ export CFLAGS LDFLAGS
|
||||
### targets
|
||||
|
||||
xmp_vgmstream: libvgmstream.a $(TARGET_EXT_LIBS)
|
||||
$(CC) -shared -static-libgcc $(CFLAGS) "-DVERSION=\"`../version.sh`\"" xmp_vgmstream.c $(LDFLAGS) -o $(OUTPUT_XMPLAY) xmpin.def
|
||||
$(CC) -shared -static-libgcc $(CFLAGS) "-DVGMSTREAM_VERSION=\"$(VGMSTREAM_VERSION_PREV)\"" xmp_vgmstream.c $(LDFLAGS) -o $(OUTPUT_XMPLAY) xmpin.def
|
||||
$(STRIP) $(OUTPUT_XMPLAY)
|
||||
|
||||
libvgmstream.a:
|
||||
|
@ -77,10 +77,10 @@
|
||||
<ModuleDefinitionFile>xmpin.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>"$(ProjectDir)..\version.bat" "$(ProjectDir)..\version.h" VERSION</Command>
|
||||
<Command>"$(ProjectDir)..\version-make.bat"</Command>
|
||||
</PreBuildEvent>
|
||||
<PreBuildEvent>
|
||||
<Message>Generating version.h</Message>
|
||||
<Message>Generating version</Message>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@ -107,10 +107,10 @@
|
||||
<ModuleDefinitionFile>xmpin.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>"$(ProjectDir)..\version.bat" "$(ProjectDir)..\version.h" VERSION</Command>
|
||||
<Command>"$(ProjectDir)..\version-make.bat"</Command>
|
||||
</PreBuildEvent>
|
||||
<PreBuildEvent>
|
||||
<Message>Generating version.h</Message>
|
||||
<Message>Generating version</Message>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
@ -16,11 +16,11 @@
|
||||
#include "../src/plugins.h"
|
||||
|
||||
|
||||
#ifndef VERSION
|
||||
#include "version.h"
|
||||
#ifndef VGMSTREAM_VERSION
|
||||
#include "../version.h"
|
||||
#endif
|
||||
#ifndef VERSION
|
||||
#define VERSION "(unknown version)"
|
||||
#ifndef VGMSTREAM_VERSION
|
||||
#define VGMSTREAM_VERSION "(unknown version)"
|
||||
#endif
|
||||
|
||||
/* ************************************* */
|
||||
@ -435,7 +435,7 @@ static void build_extension_list() {
|
||||
/* info for the "about" button in plugin options */
|
||||
void WINAPI xmplay_About(HWND win) {
|
||||
MessageBox(win,
|
||||
"vgmstream plugin " VERSION " " __DATE__ "\n"
|
||||
"vgmstream plugin " VGMSTREAM_VERSION " " __DATE__ "\n"
|
||||
"by hcs, FastElbja, manakoAT, bxaimc, snakemeat, soneek, kode54, bnnm and many others\n"
|
||||
"\n"
|
||||
"XMPlay plugin by unknownfile, PSXGamerPro1, kode54\n"
|
||||
|
Loading…
Reference in New Issue
Block a user