mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-31 12:23:44 +01:00
Merge pull request #1555 from bnnm/fsb-etc
- Fix .fsb with XMA + basic headers [Forza 3 (X360)] - Add FSB key - cleanup
This commit is contained in:
commit
34d8e84411
3
Makefile
3
Makefile
@ -280,6 +280,9 @@ vgmstream_cli: version
|
|||||||
vgmstream123: version
|
vgmstream123: version
|
||||||
$(MAKE) -C cli vgmstream123
|
$(MAKE) -C cli vgmstream123
|
||||||
|
|
||||||
|
api_example: version
|
||||||
|
$(MAKE) -C cli api_example
|
||||||
|
|
||||||
winamp: version
|
winamp: version
|
||||||
$(MAKE) -C winamp in_vgmstream
|
$(MAKE) -C winamp in_vgmstream
|
||||||
|
|
||||||
|
16
cli/Makefile
16
cli/Makefile
@ -12,19 +12,17 @@ CFLAGS += $(DEF_CFLAGS) -DVAR_ARRAYS $(EXTRA_CFLAGS)
|
|||||||
LDFLAGS += -L../src -lvgmstream -lm $(EXTRA_LDFLAGS)
|
LDFLAGS += -L../src -lvgmstream -lm $(EXTRA_LDFLAGS)
|
||||||
TARGET_EXT_LIBS =
|
TARGET_EXT_LIBS =
|
||||||
|
|
||||||
ifeq ($(TARGET_OS),Windows_NT)
|
OUTPUT_CLI = vgmstream-cli
|
||||||
OUTPUT_CLI = vgmstream-cli.exe
|
OUTPUT_123 = vgmstream123
|
||||||
OUTPUT_123 = vgmstream123.exe
|
OUTPUT_API = api_example
|
||||||
|
|
||||||
|
ifeq ($(TARGET_OS),Windows_NT)
|
||||||
CFLAGS += -DWIN32 -I../ext_includes -I../ext_libs/Getopt
|
CFLAGS += -DWIN32 -I../ext_includes -I../ext_libs/Getopt
|
||||||
LDFLAGS += -L../ext_libs/$(DLL_DIR)
|
LDFLAGS += -L../ext_libs/$(DLL_DIR)
|
||||||
|
|
||||||
LIBAO_INC = -I$(LIBAO_IPATH)
|
LIBAO_INC = -I$(LIBAO_IPATH)
|
||||||
LIBAO_LIB = -L$(LIBAO_LPATH) -lao
|
LIBAO_LIB = -L$(LIBAO_LPATH) -lao
|
||||||
else
|
else
|
||||||
OUTPUT_CLI = vgmstream-cli
|
|
||||||
OUTPUT_123 = vgmstream123
|
|
||||||
|
|
||||||
#todo move to subfolders and remove
|
#todo move to subfolders and remove
|
||||||
CFLAGS += -I../ext_includes
|
CFLAGS += -I../ext_includes
|
||||||
|
|
||||||
@ -50,6 +48,10 @@ vgmstream123: libvgmstream.a $(TARGET_EXT_LIBS)
|
|||||||
$(CC) $(CFLAGS) $(LIBAO_INC) vgmstream123.c $(LDFLAGS) $(LIBAO_LIB) -o $(OUTPUT_123)
|
$(CC) $(CFLAGS) $(LIBAO_INC) vgmstream123.c $(LDFLAGS) $(LIBAO_LIB) -o $(OUTPUT_123)
|
||||||
$(STRIP) $(OUTPUT_123)
|
$(STRIP) $(OUTPUT_123)
|
||||||
|
|
||||||
|
api_example: libvgmstream.a $(TARGET_EXT_LIBS)
|
||||||
|
$(CC) $(CFLAGS) api_example.c $(LDFLAGS) -o $(OUTPUT_API)
|
||||||
|
$(STRIP) api_example
|
||||||
|
|
||||||
libvgmstream.a:
|
libvgmstream.a:
|
||||||
$(MAKE) -C ../src $@
|
$(MAKE) -C ../src $@
|
||||||
|
|
||||||
@ -57,6 +59,6 @@ $(TARGET_EXT_LIBS):
|
|||||||
$(MAKE) -C ../ext_libs $@
|
$(MAKE) -C ../ext_libs $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RMF) $(OUTPUT_CLI) $(OUTPUT_123)
|
$(RMF) $(OUTPUT_CLI) $(OUTPUT_123) $(OUTPUT_123)
|
||||||
|
|
||||||
.PHONY: clean vgmstream_cli libvgmstream.a $(TARGET_EXT_LIBS)
|
.PHONY: clean vgmstream_cli libvgmstream.a $(TARGET_EXT_LIBS)
|
||||||
|
112
cli/api_example.c
Normal file
112
cli/api_example.c
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#if 0
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../src/api.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void usage(const char* progname) {
|
||||||
|
fprintf(stderr, "API test v%08x\n"
|
||||||
|
"Usage: %s <infile>\n"
|
||||||
|
, libvgmstream_get_version()
|
||||||
|
, progname
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FILE* get_output_file(const char* filename) {
|
||||||
|
char out_filename[0x7FFF];
|
||||||
|
snprintf(out_filename, sizeof(out_filename), "%s.pcm", filename);
|
||||||
|
|
||||||
|
FILE* outfile = fopen(out_filename, "wb");
|
||||||
|
if (!outfile) {
|
||||||
|
fprintf(stderr, "failed to open %s for output\n", out_filename);
|
||||||
|
}
|
||||||
|
return outfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
static libvgmstream_streamfile_t* get_streamfile(const char* filename) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* simplistic example of vgmstream's API
|
||||||
|
* for something a bit more featured see vgmstream-cli
|
||||||
|
*/
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
int err;
|
||||||
|
FILE* outfile = NULL;
|
||||||
|
const char* infile;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
usage(argv[0]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
infile = argv[1];
|
||||||
|
|
||||||
|
|
||||||
|
// main init
|
||||||
|
libvgmstream_t* lib = libvgmstream_init();
|
||||||
|
if (!lib) return EXIT_FAILURE;
|
||||||
|
|
||||||
|
|
||||||
|
// set default config
|
||||||
|
libvgmstream_config_t cfg = {
|
||||||
|
.loop_count = 2.0,
|
||||||
|
.fade_time = 10.0,
|
||||||
|
};
|
||||||
|
libvgmstream_setup(lib, &cfg);
|
||||||
|
|
||||||
|
|
||||||
|
// open target file
|
||||||
|
libvgmstream_options_t options = {
|
||||||
|
.sf = get_streamfile(infile)
|
||||||
|
};
|
||||||
|
err = libvgmstream_open(lib, &options);
|
||||||
|
if (err < 0) goto fail;
|
||||||
|
|
||||||
|
|
||||||
|
// external SF is not needed after _open
|
||||||
|
libvgmstream_streamfile_close(options.sf);
|
||||||
|
|
||||||
|
|
||||||
|
// output file
|
||||||
|
outfile = get_output_file(infile);
|
||||||
|
if (!outfile) goto fail;
|
||||||
|
|
||||||
|
|
||||||
|
// play file and do something with decoded samples
|
||||||
|
while (true) {
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
if (lib->decoder->done)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// get current samples
|
||||||
|
err = libvgmstream_play(lib);
|
||||||
|
if (err < 0) goto fail;
|
||||||
|
|
||||||
|
fwrite(lib->decoder->buf, sizeof(uint8_t), lib->decoder->buf_bytes, outfile);
|
||||||
|
|
||||||
|
pos = (int)libvgmstream_play_position(lib);
|
||||||
|
printf("\rpos: %d", pos);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// close current streamfile before opening new ones, optional
|
||||||
|
//libvgmstream_close(lib);
|
||||||
|
|
||||||
|
// process done
|
||||||
|
libvgmstream_free(lib);
|
||||||
|
fclose(outfile);
|
||||||
|
|
||||||
|
printf("done\n");
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
fail:
|
||||||
|
// process failed
|
||||||
|
libvgmstream_free(lib);
|
||||||
|
fclose(outfile);
|
||||||
|
|
||||||
|
printf("failed!\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
#endif
|
@ -902,7 +902,7 @@ static int write_file(VGMSTREAM* vgmstream, cli_config* cfg) {
|
|||||||
render_vgmstream(buf, to_get, vgmstream);
|
render_vgmstream(buf, to_get, vgmstream);
|
||||||
|
|
||||||
swap_samples_le(buf, channels * to_get); /* write PC endian */
|
swap_samples_le(buf, channels * to_get); /* write PC endian */
|
||||||
fwrite(buf, sizeof(sample_t) * channels, to_get, outfile);
|
fwrite(buf, sizeof(sample_t), to_get * channels, outfile);
|
||||||
/* should write infinitely until program kill */
|
/* should write infinitely until program kill */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -930,7 +930,7 @@ static int write_file(VGMSTREAM* vgmstream, cli_config* cfg) {
|
|||||||
|
|
||||||
if (!cfg->decode_only) {
|
if (!cfg->decode_only) {
|
||||||
swap_samples_le(buf, channels * to_get); /* write PC endian */
|
swap_samples_le(buf, channels * to_get); /* write PC endian */
|
||||||
fwrite(buf, sizeof(sample_t) * channels, to_get, outfile);
|
fwrite(buf, sizeof(sample_t), to_get * channels, outfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
# vgmstream lib build help
|
# vgmstream lib build help
|
||||||
This document explains how to build various external dependencies used in vgmstream. Like *vgmstream*, most external libs use C and need to be compiled as such.
|
This document explains how to build various external dependencies used in vgmstream. Like *vgmstream*, most external libs use C and need to be compiled as such.
|
||||||
|
|
||||||
|
The main purpose this doc is to have a reference of what each lib is doing, and to rebuild Windows DLLs. Linux libs are handled automatically using CMake, though you can use these steps too.
|
||||||
|
|
||||||
See [BUILD](BUILD.md#external-libraries) for a description of each lib first.
|
See [BUILD](BUILD.md#external-libraries) for a description of each lib first.
|
||||||
|
|
||||||
## Intro
|
## Intro
|
||||||
@ -60,7 +62,7 @@ On Linux `install` is used to actually *install* libs on system dirs (so `--pref
|
|||||||
You can call multiple *targets* in a single line `make clean install-strip` is the same as `make clean` and `make install` (which in turn calls plain `make` / default). That's the theory, but at some libs don't properly handle this.
|
You can call multiple *targets* in a single line `make clean install-strip` is the same as `make clean` and `make install` (which in turn calls plain `make` / default). That's the theory, but at some libs don't properly handle this.
|
||||||
|
|
||||||
### autotools config
|
### autotools config
|
||||||
*autotools* are **very** fragile and picky, beware when changing stuff.Check other flags by calling `sh ./configure --help`, but changing some of the steps will likely cause odd issues, *autotools are not consistent between libs*.
|
*autotools* are **very** fragile and picky, beware when changing stuff. Check other flags by calling `sh ./configure --help`, but changing some of the steps will likely cause odd issues. *autotools are not consistent between libs*.
|
||||||
|
|
||||||
Common *configure*/Makefile params:
|
Common *configure*/Makefile params:
|
||||||
- `--build=...`: current compilation environment (autodetected, but may fail in outdated libs)
|
- `--build=...`: current compilation environment (autodetected, but may fail in outdated libs)
|
||||||
@ -98,7 +100,7 @@ Roughly, a `.dll` is a Windows "shared library"; Linux equivalent would be a `.s
|
|||||||
DLL must *export symbols* (functions), which on a Windows's DLL is done with:
|
DLL must *export symbols* (functions), which on a Windows's DLL is done with:
|
||||||
- adding `__declspec(dllexport)` to a function (usually done with `#define EXPORT ...` and similar ways)
|
- adding `__declspec(dllexport)` to a function (usually done with `#define EXPORT ...` and similar ways)
|
||||||
- using a `.def` module definition file
|
- using a `.def` module definition file
|
||||||
- if neither of the above is used, GCC exports every function by default (not great=
|
- if neither of the above is used, GCC exports every function by default (not great)
|
||||||
|
|
||||||
Then, to *link* (refer to) a DLL compiler usually needs helper files (`.dll.a` in GCC, `.lib` in MSVC). DLL's are copied to vgmstream's source, while helper files are created on compile time from `.dll`+`.def` (see *ext_libs/Makefile* for GCC and `ext_libs.vcxproj` for MSVC).
|
Then, to *link* (refer to) a DLL compiler usually needs helper files (`.dll.a` in GCC, `.lib` in MSVC). DLL's are copied to vgmstream's source, while helper files are created on compile time from `.dll`+`.def` (see *ext_libs/Makefile* for GCC and `ext_libs.vcxproj` for MSVC).
|
||||||
|
|
||||||
|
136
src/api.h
136
src/api.h
@ -1,26 +1,29 @@
|
|||||||
#ifndef _API_H_
|
#ifndef _API_H_
|
||||||
#define _API_H_
|
#define _API_H_
|
||||||
|
#include "base/plugins.h" //TODO: to be removed
|
||||||
|
|
||||||
#include "base/plugins.h"
|
|
||||||
|
|
||||||
|
|
||||||
//possible future public/opaque API
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
||||||
|
/* vgmstream's public API
|
||||||
|
* basic usage (also see api_example.c):
|
||||||
|
* - libvgmstream_get_version() // if needed
|
||||||
|
* - libvgmstream_init(...) // base context
|
||||||
|
* - libvgmstream_setup(...) // standard config
|
||||||
|
* - libvgmstream_open(...) // check detected format
|
||||||
|
* - libvgmstream_play(...) // main decode
|
||||||
|
* - output samples + repeat libvgmstream_play until stream is done
|
||||||
|
* - libvgmstream_free(...) // cleanup
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "api_streamfile.h"
|
#include <stdbool.h>
|
||||||
|
|
||||||
/* Current API version (major=breaking API/ABI changes, minor=compatible ABI changes).
|
/* standard C param call and name mangling (to avoid __stdcall / .defs) */
|
||||||
* Internal bug fixes or added formats don't change these (see commit revision).
|
|
||||||
* Regular vgmstream features or formats are stable and are rarely removed, while this API may change from time to time */
|
|
||||||
#define LIBVGMSTREAM_API_VERSION_MAJOR 0
|
|
||||||
#define LIBVGMSTREAM_API_VERSION_MINOR 0
|
|
||||||
|
|
||||||
/* define standard C param call and name mangling (to avoid __stdcall / .defs) */
|
|
||||||
//#define LIBVGMSTREAM_CALL __cdecl //needed?
|
//#define LIBVGMSTREAM_CALL __cdecl //needed?
|
||||||
|
//LIBVGMSTREAM_API (type) LIBVGMSTREAM_CALL libvgmstream_function(...);
|
||||||
|
|
||||||
/* define external function types (during compilation) */
|
|
||||||
//LIBVGMSTREAM_API void LIBVGMSTREAM_CALL vgmstream_function(void);
|
/* define external function behavior (during compilation) */
|
||||||
#if defined(LIBVGMSTREAM_EXPORT)
|
#if defined(LIBVGMSTREAM_EXPORT)
|
||||||
#define LIBVGMSTREAM_API __declspec(dllexport) /* when exporting/creating vgmstream DLL */
|
#define LIBVGMSTREAM_API __declspec(dllexport) /* when exporting/creating vgmstream DLL */
|
||||||
#elif defined(LIBVGMSTREAM_IMPORT)
|
#elif defined(LIBVGMSTREAM_IMPORT)
|
||||||
@ -29,104 +32,17 @@
|
|||||||
#define LIBVGMSTREAM_API /* nothing, internal/default */
|
#define LIBVGMSTREAM_API /* nothing, internal/default */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* opaque vgmstream context/handle */
|
|
||||||
typedef struct libvgmstream_t libvgmstream_t;
|
|
||||||
|
|
||||||
/* init base vgmstream context */
|
|
||||||
libvgmstream_t* libvgmstream_init(void);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int downmix_max_channels; // max number of channels
|
|
||||||
//int upmix_min_channels; // adds channels until min
|
|
||||||
} libvgmstream_config_t;
|
|
||||||
|
|
||||||
/* pass default config, that will be applied to song on open (some formats like TXTP may override
|
|
||||||
* these settings).
|
|
||||||
* May only be called without song loaded (before _open or after _close), otherwise ignored. */
|
|
||||||
void libvgmstream_setup(libvgmstream_t* vctx, libvgmstream_config_t* vcfg);
|
|
||||||
|
|
||||||
//void libvgmstream_buffer(libvgmstream_t* vctx, int samples, int max_samples);
|
|
||||||
|
|
||||||
/* Opens a new STREAMFILE to play. Returns < 0 on error when the file isn't recogniced.
|
|
||||||
* If file has subsongs, first open usually loads first subsong. get_info then can be used to check
|
|
||||||
* whether file has more subsongs (total_subsongs > 1), and call others.
|
|
||||||
* */
|
|
||||||
int libvgmstream_open(libvgmstream_t* vctx, STREAMFILE* sf);
|
|
||||||
int libvgmstream_open_subsong(libvgmstream_t* vctx, STREAMFILE* sf, int subsong);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const int channels;
|
|
||||||
const int sample_rate;
|
|
||||||
|
|
||||||
const int sample_count; /* file's samples (not final duration) */
|
|
||||||
const int loop_start_sample;
|
|
||||||
const int loop_end_sample;
|
|
||||||
const int loop_flag;
|
|
||||||
|
|
||||||
const int current_subsong; /* 0=not set, N=loaded subsong N */
|
|
||||||
const int total_subsongs; /* 0=format has no subsongs, N=has N subsongs */
|
|
||||||
const int file_bitrate; /* file's average bitrate */
|
|
||||||
//const int codec_bitrate; /* codec's average bitrate */
|
|
||||||
|
|
||||||
/* descriptions */
|
|
||||||
//const char* codec;
|
|
||||||
//const char* layout;
|
|
||||||
//const char* metadata;
|
|
||||||
|
|
||||||
//int type; /* 0=pcm16, 1=float32, always interleaved: [0]=ch0, [1]=ch1 ... */
|
|
||||||
} libvgmstream_into_t;
|
|
||||||
|
|
||||||
/* Get info from current song. */
|
|
||||||
void libvgmstream_t_get_info(libvgmstream_t* vctx, libvgmstream_into_t* vinfo);
|
|
||||||
|
|
||||||
|
|
||||||
libvgmstream_sbuf_t* libgstream_get_sbuf(libvgmstream_t* vctx);
|
|
||||||
|
|
||||||
/* Converts samples. returns number of rendered samples, or <=0 if no more
|
|
||||||
* samples left (will fill buffer with silence) */
|
|
||||||
int libvgmstream_play(libvgmstream_t* vctx);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Gets final time based on config and current song. If config is set to "play forever"
|
|
||||||
* this still returns final time based on config as a reference. Returns > 0 on success. */
|
|
||||||
int32_t libvgmstream_get_total_time(libvgmstream_t* vctx);
|
|
||||||
double libvgmstream_get_total_samples(libvgmstream_t* vctx);
|
|
||||||
|
|
||||||
|
|
||||||
/* Gets current position within song. When "play forever" is set, it'll clamp results to total_time. */
|
|
||||||
int32_t libvgmstream_get_current_time(libvgmstream_t* vctx);
|
|
||||||
double libvgmstream_get_current_samples(libvgmstream_t* vctx);
|
|
||||||
|
|
||||||
|
|
||||||
/* Seeks to position */
|
|
||||||
libvgmstream_t* libvgmstream_seek_absolute_sample(libvgmstream_t* vctx, int32_t sample);
|
|
||||||
libvgmstream_t* libvgmstream_seek_absolute_time(libvgmstream_t* vctx, double time);
|
|
||||||
libvgmstream_t* libvgmstream_seek_current_sample(libvgmstream_t* vctx, int32_t sample);
|
|
||||||
libvgmstream_t* libvgmstream_seek_current_time(libvgmstream_t* vctx, double time);
|
|
||||||
|
|
||||||
|
|
||||||
/* Closes current song. */
|
|
||||||
void libvgmstream_close(libvgmstream_t* vctx);
|
|
||||||
|
|
||||||
/* Frees vgmstream context. */
|
|
||||||
void libvgmstream_free(libvgmstream_t* vctx);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
void vgmstream_get_buffer(...);
|
|
||||||
|
|
||||||
void vgmstream_format_check(...);
|
|
||||||
void vgmstream_set_format_whilelist(...);
|
|
||||||
void vgmstream_set_format_blacklist(...);
|
|
||||||
|
|
||||||
const char* vgmstream_describe(...);
|
|
||||||
|
|
||||||
const char* vgmstream_get_title(...);
|
|
||||||
|
|
||||||
VGMSTREAM_TAGS* vgmstream_get_tagfile(...);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
/* Current API version. Only refers to the API itself, as changes related to formats/etc don't alter it.
|
||||||
|
* vgmstream's features are mostly stable, while this API may change from time to time.
|
||||||
|
* May change as well when related (such as api_streamfile.h) are changed. */
|
||||||
|
#define LIBVGMSTREAM_API_VERSION_MAJOR 1 // breaking API/ABI changes
|
||||||
|
#define LIBVGMSTREAM_API_VERSION_MINOR 0 // compatible API/ABI changes
|
||||||
|
#define LIBVGMSTREAM_API_VERSION_PATCH 0 // fixes
|
||||||
|
|
||||||
|
#include "api_main.h"
|
||||||
|
#include "api_streamfile.h"
|
||||||
|
#include "api_tags.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
156
src/api_main.c
Normal file
156
src/api_main.c
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
#if 0
|
||||||
|
#include "api.h"
|
||||||
|
#include "vgmstream.h"
|
||||||
|
|
||||||
|
#define LIBVGMSTREAM_ERROR_GENERIC -1
|
||||||
|
#define LIBVGMSTREAM_OK 0
|
||||||
|
|
||||||
|
|
||||||
|
LIBVGMSTREAM_API uint32_t libvgmstream_get_version(void) {
|
||||||
|
return (LIBVGMSTREAM_API_VERSION_MAJOR << 24) | (LIBVGMSTREAM_API_VERSION_MINOR << 16) | (LIBVGMSTREAM_API_VERSION_PATCH << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* vgmstream context/handle */
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
libvgmstream_config_t cfg; // current config
|
||||||
|
libvgmstream_format_t fmt; // format config
|
||||||
|
libvgmstream_decoder_t dec; // decoder config
|
||||||
|
} libvgmstream_internal_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* base init */
|
||||||
|
LIBVGMSTREAM_API libvgmstream_t* libvgmstream_init(void) {
|
||||||
|
libvgmstream_t* lib = NULL;
|
||||||
|
libvgmstream_internal_t* priv = NULL;
|
||||||
|
|
||||||
|
lib = calloc(1, sizeof(libvgmstream_t));
|
||||||
|
if (!lib) goto fail;
|
||||||
|
|
||||||
|
lib->priv = calloc(1, sizeof(libvgmstream_internal_t));
|
||||||
|
if (!lib->priv) goto fail;
|
||||||
|
|
||||||
|
priv = lib->priv;
|
||||||
|
|
||||||
|
//TODO only setup on decode? (but may less error prone if set)
|
||||||
|
lib->format = &priv->fmt;
|
||||||
|
lib->decoder = &priv->dec;
|
||||||
|
|
||||||
|
return lib;
|
||||||
|
fail:
|
||||||
|
libvgmstream_free(lib);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* base free */
|
||||||
|
LIBVGMSTREAM_API void libvgmstream_free(libvgmstream_t* lib) {
|
||||||
|
if (!lib)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//TODO close stuff in priv
|
||||||
|
//if (lib->priv) {
|
||||||
|
// libvgmstream_internal_t* priv = lib->priv;
|
||||||
|
//}
|
||||||
|
|
||||||
|
free(lib->priv);
|
||||||
|
free(lib);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* current play config */
|
||||||
|
LIBVGMSTREAM_API void libvgmstream_setup(libvgmstream_t* lib, libvgmstream_config_t* cfg) {
|
||||||
|
if (!lib)
|
||||||
|
return;
|
||||||
|
if (!cfg)
|
||||||
|
return;
|
||||||
|
libvgmstream_internal_t* priv = lib->priv;
|
||||||
|
|
||||||
|
priv->cfg = *cfg;
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open new file */
|
||||||
|
LIBVGMSTREAM_API int libvgmstream_open(libvgmstream_t* lib, libvgmstream_options_t* opt) {
|
||||||
|
if (!lib)
|
||||||
|
return LIBVGMSTREAM_ERROR_GENERIC;
|
||||||
|
//if (!opt || !opt->sf || opt->subsong < 0)
|
||||||
|
// return LIBVGMSTREAM_ERROR_GENERIC;
|
||||||
|
|
||||||
|
// close loaded song if any
|
||||||
|
libvgmstream_close(lib);
|
||||||
|
|
||||||
|
//format_internal_id
|
||||||
|
|
||||||
|
// TODO open new vgmstream, save in priv
|
||||||
|
|
||||||
|
return LIBVGMSTREAM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* query new vgmstream, without closing current one */
|
||||||
|
LIBVGMSTREAM_API int libvgmstream_open_info(libvgmstream_t* lib, libvgmstream_options_t* opt, libvgmstream_format_t* fmt) {
|
||||||
|
//TODO
|
||||||
|
return LIBVGMSTREAM_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* close current vgmstream */
|
||||||
|
LIBVGMSTREAM_API void libvgmstream_close(libvgmstream_t* lib) {
|
||||||
|
//TODO close current vgmstream
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* decodes samples */
|
||||||
|
LIBVGMSTREAM_API int libvgmstream_play(libvgmstream_t* lib) {
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
//if (!lib->decoder)
|
||||||
|
// ...
|
||||||
|
|
||||||
|
lib->decoder->done = true;
|
||||||
|
|
||||||
|
return LIBVGMSTREAM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vgmstream current decode position */
|
||||||
|
LIBVGMSTREAM_API int64_t libvgmstream_play_position(libvgmstream_t* lib) {
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vgmstream seek */
|
||||||
|
LIBVGMSTREAM_API int libvgmstream_seek(libvgmstream_t* lib, int64_t sample) {
|
||||||
|
return LIBVGMSTREAM_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LIBVGMSTREAM_API int libvgmstream_format_describe(libvgmstream_format_t* format, char* dst, int dst_size) {
|
||||||
|
return LIBVGMSTREAM_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBVGMSTREAM_API bool libvgmstream_is_valid(const char* filename, libvgmstream_valid_t* cfg) {
|
||||||
|
//TODO
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LIBVGMSTREAM_API void libvgmstream_get_title(libvgmstream_t* lib, libvgmstream_title_t* cfg, char* buf, int buf_len) {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LIBVGMSTREAM_API void libvgmstream_set_log(libvgmstream_log_t* log) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
LIBVGMSTREAM_API libvgmstream_streamfile_t* libvgmstream_streamfile_get_file(const char* filename) {
|
||||||
|
STREAMFILE* sf = open_stdio_streamfile(filename);
|
||||||
|
//TODO make STREAMFILE compatible with libvgmstream_streamfile_t
|
||||||
|
// would need bridge functions (since defs aren't compatible), not ideal since we are calling functions over functions
|
||||||
|
// but basically not noticeable performance-wise
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif
|
235
src/api_main.h
Normal file
235
src/api_main.h
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
#if 0
|
||||||
|
#ifndef _API_MAIN_H_
|
||||||
|
#define _API_MAIN_H_
|
||||||
|
#include "api.h"
|
||||||
|
#include "api_streamfile.h"
|
||||||
|
|
||||||
|
/* vgmstream's main (decode) API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* returns API version in hex format: 0xMMmmpppp = MM-major, mm-minor, pppp-patch
|
||||||
|
* - use when loading vgmstream as a dynamic library to ensure API/ABI compatibility */
|
||||||
|
LIBVGMSTREAM_API uint32_t libvgmstream_get_version(void);
|
||||||
|
|
||||||
|
// interleaved: buf[0]=ch0, buf[1]=ch1, buf[2]=ch0, buf[3]=ch0, ...
|
||||||
|
enum {
|
||||||
|
LIBVGMSTREAM_SAMPLE_PCM16 = 0x01,
|
||||||
|
LIBVGMSTREAM_SAMPLE_FLOAT = 0x02,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* main (always set) */
|
||||||
|
const int channels; // output channels
|
||||||
|
const int sample_rate; // output sample rate
|
||||||
|
const int sample_type; // size of resulting samples
|
||||||
|
|
||||||
|
/* extra info (may be 0 if not known or not relevant) */
|
||||||
|
const uint32_t channel_layout; // standard bitflags
|
||||||
|
const int input_channels; // original file's channels before downmixing (if any)
|
||||||
|
|
||||||
|
const int interleave; // when file is interleaved
|
||||||
|
const int frame_size; // when file has some configurable frame size
|
||||||
|
|
||||||
|
const int subsong_index; // 0 = none, N = loaded subsong N
|
||||||
|
const int subsong_count; // 0 = format has no subsongs, N = has N subsongs (1 = format has subsongs and only 1)
|
||||||
|
|
||||||
|
/* sample info (may not be used depending on config) */
|
||||||
|
const int64_t sample_count; // file's max samples (not final play duration)
|
||||||
|
const int64_t loop_start; // loop start sample
|
||||||
|
const int64_t loop_end; // loop end sample
|
||||||
|
const bool loop_flag; // if file loops; note that false + defined loops means looping was forcefully disabled
|
||||||
|
|
||||||
|
const int64_t play_time; // samples after all calculations (after applying loop/fade/etc config)
|
||||||
|
// ** may not be 100% accurate in some cases (must check decoder's 'done' flag)
|
||||||
|
// ** if loop_forever is set this value is provided for reference based on non-forever config
|
||||||
|
|
||||||
|
const bool rough_samples; // signal cases where loop points or sample count can't exactly reflect actual behavior (do not use to export)
|
||||||
|
|
||||||
|
const int stream_bitrate; // average bitrate of the subsong (slightly bloated vs codec_bitrate: incorrect in rare cases)
|
||||||
|
//const int codec_bitrate; // average bitrate of the codec data (not possible/slow to calculate in most cases)
|
||||||
|
|
||||||
|
const int format_internal_id; // may be used when reopening subfiles or similar formats without checking other possible formats first
|
||||||
|
// ** this value WILL change without warning between vgmstream versions/commits, do not store
|
||||||
|
|
||||||
|
/* descriptions */
|
||||||
|
const char codec[256];
|
||||||
|
const char layout[256];
|
||||||
|
const char metadata[256];
|
||||||
|
|
||||||
|
} libvgmstream_format_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void* buf; // current decoded buf (valid after _decode until next call; may change between calls)
|
||||||
|
int buf_samples; // current buffer samples (0 is possible in some cases, meaning current _decode can't generate samples)
|
||||||
|
int buf_bytes; // current buffer bytes (channels * sample-size * samples)
|
||||||
|
|
||||||
|
bool done; // flag when stream is done playing based on config; will still allow _play calls returning blank samples
|
||||||
|
// ** note that with play_forever this flag is never set
|
||||||
|
} libvgmstream_decoder_t;
|
||||||
|
|
||||||
|
|
||||||
|
/* vgmstream context/handle */
|
||||||
|
typedef struct {
|
||||||
|
void* priv; // internal data
|
||||||
|
|
||||||
|
/* pointers for easier ABI compatibility */
|
||||||
|
libvgmstream_format_t* format; // current song info, updated on _open
|
||||||
|
libvgmstream_decoder_t* decoder; // updated on each _decode call
|
||||||
|
|
||||||
|
} libvgmstream_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* inits the vgmstream context
|
||||||
|
* - returns NULL on error
|
||||||
|
* - call libvgmstream_free when done.
|
||||||
|
*/
|
||||||
|
LIBVGMSTREAM_API libvgmstream_t* libvgmstream_init(void);
|
||||||
|
|
||||||
|
/* frees vgmstream context and any other internal stuff that may not be closed
|
||||||
|
*/
|
||||||
|
LIBVGMSTREAM_API void libvgmstream_free(libvgmstream_t* lib);
|
||||||
|
|
||||||
|
|
||||||
|
/* configures how vgmstream behaves internally when playing a file */
|
||||||
|
typedef struct {
|
||||||
|
bool allow_play_forever; // must allow manually as some cases a TXTP may set loop forever but client may not handle it (ex. wave dumpers)
|
||||||
|
|
||||||
|
bool play_forever; // keeps looping forever (file must have loop_flag set)
|
||||||
|
bool ignore_loop; // ignores loops points
|
||||||
|
bool force_loop; // enables full loops (0..samples) if file doesn't have loop points
|
||||||
|
bool really_force_loop; // forces full loops (0..samples) even if file has loop points
|
||||||
|
bool ignore_fade; // don't fade after N loops and play remaning stream (for files with outros)
|
||||||
|
|
||||||
|
double loop_count; // target loops (values like 1.5 are ok)
|
||||||
|
double fade_delay; // fade delay after target loops
|
||||||
|
double fade_time; // fade period after target loops
|
||||||
|
|
||||||
|
int max_channels; // automatic downmixing if vgmstream's channels are higher than max_channels
|
||||||
|
// ** for players that can only handle N channels, but this type of downmixing is very simplistic and not recommended
|
||||||
|
|
||||||
|
int force_format; // forces output buffer to be remixed into some LIBVGMSTREAM_SAMPLE_x format
|
||||||
|
|
||||||
|
//bool disable_config_override; // ignore forced (TXTP) config
|
||||||
|
|
||||||
|
} libvgmstream_config_t;
|
||||||
|
|
||||||
|
/* pass default config, that will be applied to song on open
|
||||||
|
* - invalid config or complex cases (ex. some TXTP) may ignore these settings.
|
||||||
|
* - called without a song loaded (before _open or after _close), otherwise ignored.
|
||||||
|
* - without config vgmstream will decode the current stream once
|
||||||
|
*/
|
||||||
|
LIBVGMSTREAM_API void libvgmstream_setup(libvgmstream_t* lib, libvgmstream_config_t* cfg);
|
||||||
|
|
||||||
|
|
||||||
|
/* configures how vgmstream opens the format */
|
||||||
|
typedef struct {
|
||||||
|
libvgmstream_streamfile_t* sf; // custom IO streamfile that provides reader info for vgmstream
|
||||||
|
// ** not needed after _open and should be closed, as vgmstream re-opens its own SFs internally as needed
|
||||||
|
|
||||||
|
int subsong; // target subsong (1..N) or 0 = unknown/first
|
||||||
|
// ** to check if a file has subsongs, _open first + check total_subsongs (then _open 2nd, 3rd, etc)
|
||||||
|
|
||||||
|
void* external_buf; // set a custom-sized sample buf instead of the default provided buf
|
||||||
|
// ** must be at least as big as channels * sample-size * buf_samples
|
||||||
|
// ** libvgmstream decoder->buf will set this buf
|
||||||
|
// ** slower than using the provided buf (needs copying around), mainly if you have fixed sample constraints
|
||||||
|
int external_buf_samples; // max samples the custom buffer may hold
|
||||||
|
|
||||||
|
int format_internal_id; // force a format (for example when loading new subsong)
|
||||||
|
|
||||||
|
int stereo_track; // forces vgmstream to decode one 2ch+2ch+2ch... 'track' and discard other channels, where 0 = disabled, 1..N = Nth track
|
||||||
|
|
||||||
|
} libvgmstream_options_t;
|
||||||
|
|
||||||
|
/* opens file based on config and prepares it to play if supported.
|
||||||
|
* - returns < 0 on error (file not recognised, invalid subsong index, etc)
|
||||||
|
* - will close currently loaded song if needed
|
||||||
|
*/
|
||||||
|
LIBVGMSTREAM_API int libvgmstream_open(libvgmstream_t* lib, libvgmstream_options_t* open_options);
|
||||||
|
|
||||||
|
/* opens file based on config and returns its file info
|
||||||
|
* - returns < 0 on error (file not recognised, invalid subsong index, etc)
|
||||||
|
* - equivalent to _open, but doesn't update the current loaded song / format and copies to passed struct
|
||||||
|
* - may be used while current song is loaded/playing but you need to query next song with current config
|
||||||
|
* - to play a new song don't call _open_info to check the format first, just call _open + check format afterwards
|
||||||
|
* - the only way for vgmstream to know a file's metadata is getting it almost ready to play,
|
||||||
|
* so this isn't any faster than _open
|
||||||
|
*/
|
||||||
|
LIBVGMSTREAM_API int libvgmstream_open_info(libvgmstream_t* lib, libvgmstream_options_t* open_options, libvgmstream_format_t* format);
|
||||||
|
|
||||||
|
/* closes current song; may still use libvgmstream to open other songs
|
||||||
|
*/
|
||||||
|
LIBVGMSTREAM_API void libvgmstream_close(libvgmstream_t* lib);
|
||||||
|
|
||||||
|
|
||||||
|
/* decodes next batch of samples (lib->decoder->* will be updated)
|
||||||
|
* - returns < 0 on error
|
||||||
|
*/
|
||||||
|
LIBVGMSTREAM_API int libvgmstream_play(libvgmstream_t* lib);
|
||||||
|
|
||||||
|
/* Gets current position within the song.
|
||||||
|
* - return < 0 on error (file not ready) */
|
||||||
|
LIBVGMSTREAM_API int64_t libvgmstream_play_position(libvgmstream_t* lib);
|
||||||
|
|
||||||
|
/* Seeks to absolute position. Will clamp incorrect values.
|
||||||
|
* - return < 0 on error (ignores seek attempt)
|
||||||
|
* - on play_forever one may locally seek to any position, but there is an internal limit */
|
||||||
|
LIBVGMSTREAM_API int libvgmstream_seek(libvgmstream_t* lib, int64_t sample);
|
||||||
|
|
||||||
|
|
||||||
|
/* Writes a description of the format into dst. Will always be null-terminated.
|
||||||
|
* - returns < 0 if file was truncated, though will still succeed. */
|
||||||
|
LIBVGMSTREAM_API int libvgmstream_format_describe(libvgmstream_format_t* format, char* dst, int dst_size);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool is_extension; /* set if filename is just an extension */
|
||||||
|
bool skip_default; /* set if shouldn't check default formats */
|
||||||
|
bool reject_extensionless; /* set if player can't play extensionless files */
|
||||||
|
bool accept_unknown; /* set to allow any extension (for txth) */
|
||||||
|
bool accept_common; /* set to allow known-but-common extension (when player has plugin priority) */
|
||||||
|
} libvgmstream_valid_t;
|
||||||
|
|
||||||
|
/* returns if vgmstream can parse a filename by extension, to reject some files earlier
|
||||||
|
* - doesn't check file contents (that's only done on _open)
|
||||||
|
* - config may be NULL
|
||||||
|
* - mainly for plugins that fail early; libvgmstream doesn't use this
|
||||||
|
*/
|
||||||
|
LIBVGMSTREAM_API bool libvgmstream_is_valid(const char* filename, libvgmstream_valid_t* cfg);
|
||||||
|
|
||||||
|
|
||||||
|
//TODO are all these options necessary?
|
||||||
|
typedef struct {
|
||||||
|
bool force_title;
|
||||||
|
bool subsong_range;
|
||||||
|
bool remove_extension;
|
||||||
|
bool remove_archive;
|
||||||
|
const char* filename;
|
||||||
|
} libvgmstream_title_t;
|
||||||
|
|
||||||
|
/* get a simple title for plugins, derived from internal stream name if available
|
||||||
|
* - valid after _open */
|
||||||
|
LIBVGMSTREAM_API void libvgmstream_get_title(libvgmstream_t* lib, libvgmstream_title_t* cfg, char* buf, int buf_len);
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LIBVGMSTREAM_LOG_LEVEL_ALL = 0,
|
||||||
|
LIBVGMSTREAM_LOG_LEVEL_DEBUG = 20,
|
||||||
|
LIBVGMSTREAM_LOG_LEVEL_INFO = 30,
|
||||||
|
LIBVGMSTREAM_LOG_LEVEL_NONE = 100,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int level; // log level
|
||||||
|
void (*callback)(int level, const char* str); // log callback
|
||||||
|
bool stdout_callback; // use log callback
|
||||||
|
} libvgmstream_log_t;
|
||||||
|
|
||||||
|
/* defines a global log callback, as vgmstream sometimes communicates format issues to the user.
|
||||||
|
* - note that log is currently set globally rather than per libvgmstream_t
|
||||||
|
*/
|
||||||
|
LIBVGMSTREAM_API void libvgmstream_set_log(libvgmstream_log_t* log);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
51
src/api_streamfile.h
Normal file
51
src/api_streamfile.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#if 0
|
||||||
|
#ifndef _API_STREAMFILE_H_
|
||||||
|
#define _API_STREAMFILE_H_
|
||||||
|
|
||||||
|
/* vgmstream's IO API, defined as a "streamfile" (SF).
|
||||||
|
*
|
||||||
|
* Unlike more typical IO, vgmstream has particular needs that roughly assume there is some underlying filesystem (as typical of games):
|
||||||
|
* - reading from arbitrary offsets: header not found in the beginning of a stream, rewinding during looping, etc
|
||||||
|
* - opening other streamfiles: reopening a copy of current SF, formats with split header + data, decryption files, etc
|
||||||
|
* - filename: opening similarly named companion files, heuristics when file's data is not enough, etc
|
||||||
|
*
|
||||||
|
* If your use case can't satisfy those constraints, it may still be possible to create a streamfile that just simulates part of it.
|
||||||
|
* For example, loading data into memory, returning a fake filename, and only handling "open" that reopens itself (same filename),
|
||||||
|
* while returning default/incorrect values on non-handled operations. Simpler, non-looped formats probably work fine just being read linearly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "api.h"
|
||||||
|
|
||||||
|
// TODO: pass opaque instead?
|
||||||
|
typedef struct libvgmstream_streamfile_t {
|
||||||
|
/* user data */
|
||||||
|
void* opaque;
|
||||||
|
|
||||||
|
/* read 'length' data at 'offset' to 'dst' (implicit seek) */
|
||||||
|
size_t (*read)(struct libvgmstream_streamfile_t* sf, uint8_t* dst, int64_t offset, size_t length);
|
||||||
|
|
||||||
|
/* get max offset */
|
||||||
|
size_t (*get_size)(struct libvgmstream_streamfile_t* sf); //TODO return int64_t?
|
||||||
|
|
||||||
|
/* copy current filename to name buf */
|
||||||
|
void (*get_name)(struct libvgmstream_streamfile_t* sf, char* name, size_t name_size);
|
||||||
|
|
||||||
|
/* open another streamfile from filename (which may be some internal path/protocol) */
|
||||||
|
struct libvgmstream_streamfile_t* (*open)(struct libvgmstream_streamfile_t* sf, const char* const filename, size_t buf_size);
|
||||||
|
|
||||||
|
/* free current STREAMFILE */
|
||||||
|
void (*close)(struct libvgmstream_streamfile_t* sf);
|
||||||
|
|
||||||
|
} libvgmstream_streamfile_t;
|
||||||
|
|
||||||
|
/* helper */
|
||||||
|
static inline void libvgmstream_streamfile_close(libvgmstream_streamfile_t* sf) {
|
||||||
|
if (!sf)
|
||||||
|
return;
|
||||||
|
sf->close(sf);
|
||||||
|
}
|
||||||
|
|
||||||
|
//LIBVGMSTREAM_API libvgmstream_streamfile_t* libvgmstream_streamfile_get_file(const char* filename);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
40
src/api_tags.h
Normal file
40
src/api_tags.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#if 0
|
||||||
|
#ifndef _API_TAGS_H_
|
||||||
|
#define _API_TAGS_H_
|
||||||
|
#include "api.h"
|
||||||
|
#include "api_streamfile.h"
|
||||||
|
|
||||||
|
/* vgmstream's !tags.m3u API.
|
||||||
|
* Doesn't need a main libvgmstream lib as tags aren't tied to loaded songs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tag state */
|
||||||
|
typedef struct {
|
||||||
|
void* priv; // internal data
|
||||||
|
|
||||||
|
const char* key; // current key
|
||||||
|
const char* val; // current value
|
||||||
|
|
||||||
|
} libvgmstream_tags_t;
|
||||||
|
|
||||||
|
/* Initializes tags.
|
||||||
|
* - may be reused for different files for cache purposed
|
||||||
|
*/
|
||||||
|
LIBVGMSTREAM_API libvgmstream_tags_t* libvgmstream_tags_init();
|
||||||
|
|
||||||
|
/* Restarts tagfile for a new filename. Must be called first before extracting tags.
|
||||||
|
* - unlike libvgmstream_open, sf tagfile must be valid during the tag extraction process.
|
||||||
|
*/
|
||||||
|
LIBVGMSTREAM_API void libvgmstream_tags_reset(libvgmstream_tags_t* tags, libvgmstream_streamfile_t* sf, const char* target_filename);
|
||||||
|
|
||||||
|
/* Extracts next valid tag in tagfile to key/val.
|
||||||
|
* - returns 0 if no more tags are found (meant to be called repeatedly until 0)
|
||||||
|
* - key/values are trimmed of beginning/end whitespaces and values are in UTF-8
|
||||||
|
*/
|
||||||
|
LIBVGMSTREAM_API int libvgmstream_tags_next_tag(libvgmstream_tags_t* tags);
|
||||||
|
|
||||||
|
/* Closes tags. */
|
||||||
|
LIBVGMSTREAM_API void libvgmstream_tags_free(libvgmstream_tags_t* tags);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
@ -430,10 +430,26 @@ fail:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FFmpeg internals (roughly) for reference:
|
||||||
|
*
|
||||||
|
* AVFormatContext // base info extracted from input file
|
||||||
|
* AVStream // substreams
|
||||||
|
* AVCodecParameters // codec id, channels, format, ...
|
||||||
|
*
|
||||||
|
* AVCodecContext // sample rate and general info
|
||||||
|
*
|
||||||
|
* - open avformat to get all possible format info (needs file or custom IO)
|
||||||
|
* - open avcodec based on target stream + codec info from avformat
|
||||||
|
* - decode chunks of data (feed style)
|
||||||
|
* - read next frame into packet via avformat
|
||||||
|
* - decode packet via avcodec
|
||||||
|
* - handle samples
|
||||||
|
*/
|
||||||
|
|
||||||
static int init_ffmpeg_config(ffmpeg_codec_data* data, int target_subsong, int reset) {
|
static int init_ffmpeg_config(ffmpeg_codec_data* data, int target_subsong, int reset) {
|
||||||
int errcode = 0;
|
int errcode = 0;
|
||||||
|
|
||||||
/* basic IO/format setup */
|
/* custom IO/format setup */
|
||||||
data->buffer = av_malloc(FFMPEG_DEFAULT_IO_BUFFER_SIZE);
|
data->buffer = av_malloc(FFMPEG_DEFAULT_IO_BUFFER_SIZE);
|
||||||
if (!data->buffer) goto fail;
|
if (!data->buffer) goto fail;
|
||||||
|
|
||||||
@ -448,13 +464,14 @@ static int init_ffmpeg_config(ffmpeg_codec_data* data, int target_subsong, int r
|
|||||||
//data->inputFormatCtx = av_find_input_format("h264"); /* set directly? */
|
//data->inputFormatCtx = av_find_input_format("h264"); /* set directly? */
|
||||||
/* on reset could use AVFormatContext.iformat to reload old format too */
|
/* on reset could use AVFormatContext.iformat to reload old format too */
|
||||||
|
|
||||||
|
/* format detection */
|
||||||
errcode = avformat_open_input(&data->formatCtx, NULL /*""*/, NULL, NULL);
|
errcode = avformat_open_input(&data->formatCtx, NULL /*""*/, NULL, NULL);
|
||||||
if (errcode < 0) goto fail;
|
if (errcode < 0) goto fail;
|
||||||
|
|
||||||
errcode = avformat_find_stream_info(data->formatCtx, NULL);
|
errcode = avformat_find_stream_info(data->formatCtx, NULL);
|
||||||
if (errcode < 0) goto fail;
|
if (errcode < 0) goto fail;
|
||||||
|
|
||||||
/* find valid audio stream and set other streams to discard */
|
/* find valid audio stream and set other streams to be discarded */
|
||||||
{
|
{
|
||||||
int i, stream_index, stream_count;
|
int i, stream_index, stream_count;
|
||||||
|
|
||||||
@ -485,24 +502,22 @@ static int init_ffmpeg_config(ffmpeg_codec_data* data, int target_subsong, int r
|
|||||||
data->stream_count = stream_count;
|
data->stream_count = stream_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup codec with stream info */
|
/* setup codec from stream info */
|
||||||
data->codecCtx = avcodec_alloc_context3(NULL);
|
data->codecCtx = avcodec_alloc_context3(NULL);
|
||||||
if (!data->codecCtx) goto fail;
|
if (!data->codecCtx) goto fail;
|
||||||
|
|
||||||
errcode = avcodec_parameters_to_context(data->codecCtx, data->formatCtx->streams[data->stream_index]->codecpar);
|
errcode = avcodec_parameters_to_context(data->codecCtx, data->formatCtx->streams[data->stream_index]->codecpar);
|
||||||
if (errcode < 0) goto fail;
|
if (errcode < 0) goto fail;
|
||||||
|
|
||||||
/* deprecated and seemingly not needed */
|
//av_codec_set_pkt_timebase(data->codecCtx, stream->time_base); /* deprecated and seemingly not needed */
|
||||||
//av_codec_set_pkt_timebase(data->codecCtx, stream->time_base);
|
|
||||||
|
|
||||||
/* not useddeprecated and seemingly not needed */
|
|
||||||
data->codec = avcodec_find_decoder(data->codecCtx->codec_id);
|
data->codec = avcodec_find_decoder(data->codecCtx->codec_id);
|
||||||
if (!data->codec) goto fail;
|
if (!data->codec) goto fail;
|
||||||
|
|
||||||
errcode = avcodec_open2(data->codecCtx, data->codec, NULL);
|
errcode = avcodec_open2(data->codecCtx, data->codec, NULL);
|
||||||
if (errcode < 0) goto fail;
|
if (errcode < 0) goto fail;
|
||||||
|
|
||||||
/* prepare codec and frame/packet buffers */
|
/* prepare frame/packet buffers */
|
||||||
data->packet = av_malloc(sizeof(AVPacket)); /* av_packet_alloc? */
|
data->packet = av_malloc(sizeof(AVPacket)); /* av_packet_alloc? */
|
||||||
if (!data->packet) goto fail;
|
if (!data->packet) goto fail;
|
||||||
av_new_packet(data->packet, 0);
|
av_new_packet(data->packet, 0);
|
||||||
|
@ -641,7 +641,6 @@ static const char* extension_list[] = {
|
|||||||
"wbk",
|
"wbk",
|
||||||
"wd",
|
"wd",
|
||||||
"wem",
|
"wem",
|
||||||
"wii",
|
|
||||||
"wiive", //txth/semi [Rubik World (Wii)]
|
"wiive", //txth/semi [Rubik World (Wii)]
|
||||||
"wic", //txth/reserved [Road Rash (SAT)-videos]
|
"wic", //txth/reserved [Road Rash (SAT)-videos]
|
||||||
"wip", //txth/reserved [Colin McRae DiRT (PC)]
|
"wip", //txth/reserved [Colin McRae DiRT (PC)]
|
||||||
|
947
src/meta/fsb.c
947
src/meta/fsb.c
File diff suppressed because it is too large
Load Diff
@ -12,14 +12,14 @@ VGMSTREAM* init_vgmstream_fsb_encrypted(STREAMFILE* sf) {
|
|||||||
|
|
||||||
/* ignore non-encrypted FSB */
|
/* ignore non-encrypted FSB */
|
||||||
if ((read_u32be(0x00,sf) & 0xFFFFFF00) == get_id32be("FSB\0"))
|
if ((read_u32be(0x00,sf) & 0xFFFFFF00) == get_id32be("FSB\0"))
|
||||||
goto fail;
|
return NULL;
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
/* .fsb: standard
|
/* .fsb: standard
|
||||||
* .fsb.ps3: various Guitar Hero (PS3)
|
* .fsb.ps3: various Guitar Hero (PS3)
|
||||||
* .fsb.xen: various Guitar Hero (X360/PC) */
|
* .fsb.xen: various Guitar Hero (X360/PC) */
|
||||||
if (!check_extensions(sf, "fsb,ps3,xen"))
|
if (!check_extensions(sf, "fsb,ps3,xen"))
|
||||||
goto fail;
|
return NULL;
|
||||||
|
|
||||||
/* try fsbkey + all combinations of FSB4/5 and decryption algorithms */
|
/* try fsbkey + all combinations of FSB4/5 and decryption algorithms */
|
||||||
{
|
{
|
||||||
@ -27,7 +27,7 @@ VGMSTREAM* init_vgmstream_fsb_encrypted(STREAMFILE* sf) {
|
|||||||
size_t key_size = read_key_file(key, FSB_KEY_MAX, sf);
|
size_t key_size = read_key_file(key, FSB_KEY_MAX, sf);
|
||||||
|
|
||||||
if (key_size) {
|
if (key_size) {
|
||||||
vgmstream = test_fsbkey(sf, key, key_size, MODE_FSBS_ALL);
|
vgmstream = test_fsbkey(sf, key, key_size, MODE_FSBS);
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,10 +60,10 @@ static VGMSTREAM* test_fsbkey(STREAMFILE* sf, const uint8_t* key, size_t key_siz
|
|||||||
if (!key_size)
|
if (!key_size)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
int test_fsb4 = flags & FLAG_FSB4;
|
bool test_fsb4 = flags & FLAG_FSB4;
|
||||||
int test_fsb5 = flags & FLAG_FSB5;
|
bool test_fsb5 = flags & FLAG_FSB5;
|
||||||
int test_std = flags & FLAG_STD;
|
bool test_alt = flags & FLAG_ALT;
|
||||||
int test_alt = flags & FLAG_ALT;
|
bool test_std = flags & FLAG_STD;
|
||||||
|
|
||||||
if (!vc && test_std && test_fsb_streamfile(sf, key, key_size, 0)) {
|
if (!vc && test_std && test_fsb_streamfile(sf, key, key_size, 0)) {
|
||||||
temp_sf = setup_fsb_streamfile(sf, key, key_size, 0);
|
temp_sf = setup_fsb_streamfile(sf, key, key_size, 0);
|
||||||
|
@ -3,85 +3,77 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List of known keys, found in aluigi's site (http://aluigi.altervista.org), forums, guessfsb.exe or manually.
|
* List of known keys, some found in aluigi's site (http://aluigi.altervista.org), forums, guessfsb.exe or manually.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Unknown:
|
|
||||||
// - Battle: Los Angeles
|
|
||||||
// - Guitar Hero: Warriors of Rock, DJ hero FSB
|
|
||||||
// - Longmenkezhan
|
|
||||||
// - Gas Guzzlers: Combat Carnage (PC?) "C5FA83EA64B34EC2BFE" hex or text? [FSB5]
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
const char* key;
|
const char* key;
|
||||||
size_t key_size; /* precalc'd for speed */
|
size_t key_size; /* precalc'd for speed */
|
||||||
} fsbkey_info;
|
} fsbkey_info;
|
||||||
|
|
||||||
#define FLAG_FSB4 (1 << 0) /* key is valid for FSB4/3 */
|
#define FLAG_FSB4 (1 << 0) /* key is valid for FSB3/4 */
|
||||||
#define FLAG_FSB5 (1 << 1) /* key is valid for FSB5 */
|
#define FLAG_FSB5 (1 << 1) /* key is valid for FSB5 */
|
||||||
#define FLAG_STD (1 << 2) /* regular XOR mode */
|
#define FLAG_STD (1 << 2) /* regular XOR mode */
|
||||||
#define FLAG_ALT (1 << 3) /* alt XOR mode (seemingly older files or possibly FSB3 only) */
|
#define FLAG_ALT (1 << 3) /* alt XOR mode (seemingly older files or possibly FSB3 only) */
|
||||||
|
|
||||||
#define MODE_FSB4_STD (FLAG_FSB4 | FLAG_STD)
|
#define MODE_FSB3 (FLAG_FSB4 | FLAG_ALT)
|
||||||
#define MODE_FSB4_ALT (FLAG_FSB4 | FLAG_ALT)
|
#define MODE_FSB4 (FLAG_FSB4 | FLAG_STD)
|
||||||
#define MODE_FSB4_ALL (FLAG_FSB4 | FLAG_STD | FLAG_ALT)
|
#define MODE_FSB5 (FLAG_FSB5 | FLAG_STD)
|
||||||
#define MODE_FSB5_STD (FLAG_FSB5 | FLAG_STD)
|
#define MODE_FSBS (FLAG_FSB4 | FLAG_FSB5 | FLAG_STD | FLAG_ALT)
|
||||||
#define MODE_FSB5_ALT (FLAG_FSB5 | FLAG_STD)
|
|
||||||
#define MODE_FSB5_ALL (FLAG_FSB5 | FLAG_STD | FLAG_ALT)
|
|
||||||
#define MODE_FSBS_STD (FLAG_FSB4 | FLAG_FSB5 | FLAG_STD)
|
|
||||||
#define MODE_FSBS_ALL (FLAG_FSB4 | FLAG_FSB5 | FLAG_STD | FLAG_ALT)
|
|
||||||
|
|
||||||
/* ugly macro for string + precomputed len (removing string's extra NULL)*/
|
/* ugly macro for string + precomputed len (removing string's extra NULL)*/
|
||||||
#define FSBKEY_ADD(key) key, sizeof(key) - 1
|
#define FSBKEY_ADD(key) key, sizeof(key) - 1
|
||||||
|
|
||||||
static const fsbkey_info fsbkey_list[] = {
|
static const fsbkey_info fsbkey_list[] = {
|
||||||
{ MODE_FSBS_STD, FSBKEY_ADD("DFm3t4lFTW") }, // Double Fine Productions: Brutal Legend, Massive Chalice, etc (multi)
|
{ MODE_FSB4, FSBKEY_ADD("DFm3t4lFTW") }, // Double Fine Productions: Brutal Legend, Massive Chalice, etc (multi)
|
||||||
{ MODE_FSB4_STD, FSBKEY_ADD("nos71RiT") }, // DJ Hero 2 (X360)
|
{ MODE_FSB5, FSBKEY_ADD("DFm3t4lFTW") }, // Double Fine Productions
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("H$#FJa%7gRZZOlxLiN50&g5Q") }, // N++ (PC?)
|
{ MODE_FSB4, FSBKEY_ADD("nos71RiT") }, // DJ Hero 2 (X360)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("sTOoeJXI2LjK8jBMOk8h5IDRNZl3jq3I") }, // Slightly Mad Studios: Project CARS (PC?), World of Speed (PC)
|
{ MODE_FSB5, FSBKEY_ADD("H$#FJa%7gRZZOlxLiN50&g5Q") }, // N++ (PC?)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("%lAn2{Pi*Lhw3T}@7*!kV=?qS$@iNlJ") }, // Ghost in the Shell: First Assault (PC)
|
{ MODE_FSB5, FSBKEY_ADD("sTOoeJXI2LjK8jBMOk8h5IDRNZl3jq3I") }, // Slightly Mad Studios: Project CARS (PC?), World of Speed (PC)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("1^7%82#&5$~/8sz") }, // RevHeadz Engine Sounds (Mobile)
|
{ MODE_FSB5, FSBKEY_ADD("%lAn2{Pi*Lhw3T}@7*!kV=?qS$@iNlJ") }, // Ghost in the Shell: First Assault (PC)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("FDPrVuT4fAFvdHJYAgyMzRF4EcBAnKg") }, // Dark Souls 3 (PC)
|
{ MODE_FSB5, FSBKEY_ADD("1^7%82#&5$~/8sz") }, // RevHeadz Engine Sounds (Mobile)
|
||||||
{ MODE_FSB4_STD, FSBKEY_ADD("p&oACY^c4LK5C2v^x5nIO6kg5vNH$tlj") }, // Need for Speed Shift 2 Unleashed (PC)
|
{ MODE_FSB5, FSBKEY_ADD("FDPrVuT4fAFvdHJYAgyMzRF4EcBAnKg") }, // Dark Souls 3 (PC)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("996164B5FC0F402983F61F220BB51DC6") }, // Mortal Kombat X/XL (PC)
|
{ MODE_FSB4, FSBKEY_ADD("p&oACY^c4LK5C2v^x5nIO6kg5vNH$tlj") }, // Need for Speed Shift 2 Unleashed (PC)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("logicsounddesignmwsdev") }, // Mirror War: Reincarnation of Holiness (PC)
|
{ MODE_FSB5, FSBKEY_ADD("996164B5FC0F402983F61F220BB51DC6") }, // Mortal Kombat X/XL (PC)
|
||||||
{ MODE_FSBS_ALL, FSBKEY_ADD("gat@tcqs2010") }, // Xian Xia Chuan (PC) [untested]
|
{ MODE_FSB5, FSBKEY_ADD("logicsounddesignmwsdev") }, // Mirror War: Reincarnation of Holiness (PC)
|
||||||
{ MODE_FSBS_ALL, FSBKEY_ADD("j1$Mk0Libg3#apEr42mo") }, // Critter Crunch (PC), Superbrothers: Sword & Sworcery (PC) [untested]
|
{ MODE_FSBS, FSBKEY_ADD("gat@tcqs2010") }, // Xian Xia Chuan (PC) [untested]
|
||||||
{ MODE_FSBS_ALL, FSBKEY_ADD("@kdj43nKDN^k*kj3ndf02hd95nsl(NJG") }, // Cyphers [untested]
|
{ MODE_FSBS, FSBKEY_ADD("j1$Mk0Libg3#apEr42mo") }, // Critter Crunch (PC), Superbrothers: Sword & Sworcery (PC) [untested]
|
||||||
{ MODE_FSBS_ALL, FSBKEY_ADD("Xiayuwu69252.Sonicli81223#$*@*0") }, // Xuan Dou Zhi Wang / King of Combat [untested]
|
{ MODE_FSBS, FSBKEY_ADD("@kdj43nKDN^k*kj3ndf02hd95nsl(NJG") }, // Cyphers [untested]
|
||||||
{ MODE_FSBS_ALL, FSBKEY_ADD("kri_tika_5050_") }, // Ji Feng Zhi Ren / Kritika Online [untested]
|
{ MODE_FSBS, FSBKEY_ADD("Xiayuwu69252.Sonicli81223#$*@*0") }, // Xuan Dou Zhi Wang / King of Combat [untested]
|
||||||
{ MODE_FSBS_ALL, FSBKEY_ADD("mint78run52") }, // Invisible Inc. (PC?) [untested]
|
{ MODE_FSBS, FSBKEY_ADD("kri_tika_5050_") }, // Ji Feng Zhi Ren / Kritika Online [untested]
|
||||||
{ MODE_FSBS_ALL, FSBKEY_ADD("5atu6w4zaw") }, // Guitar Hero 3 [untested]
|
{ MODE_FSBS, FSBKEY_ADD("mint78run52") }, // Invisible Inc. (PC?) [untested]
|
||||||
{ MODE_FSBS_ALL, FSBKEY_ADD("B2A7BB00") }, // Supreme Commander 2 [untested]
|
{ MODE_FSBS, FSBKEY_ADD("5atu6w4zaw") }, // Guitar Hero 3 [untested]
|
||||||
{ MODE_FSB4_STD, FSBKEY_ADD("ghfxhslrghfxhslr") }, // Cookie Run: Ovenbreak
|
{ MODE_FSB4, FSBKEY_ADD("B2A7BB00") }, // Supreme Commander 2 (PC)
|
||||||
{ MODE_FSB4_ALT, FSBKEY_ADD("truck/impact/carbody") }, // Monster Jam (PS2) [FSB3]
|
{ MODE_FSB4, FSBKEY_ADD("ghfxhslrghfxhslr") }, // Cookie Run: Ovenbreak
|
||||||
{ MODE_FSB4_ALT, FSBKEY_ADD("\xFC\xF9\xE4\xB3\xF5\x57\x5C\xA5\xAC\x13\xEC\x4A\x43\x19\x58\xEB\x4E\xF3\x84\x0B\x8B\x78\xFA\xFD\xBB\x18\x46\x7E\x31\xFB\xD0") }, // Guitar Hero 5 (X360)
|
{ MODE_FSB3, FSBKEY_ADD("truck/impact/carbody") }, // Monster Jam (PS2) [FSB3]
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("G0KTrWjS9syqF7vVD6RaVXlFD91gMgkC") }, // Sekiro: Shadows Die Twice (PC)
|
{ MODE_FSB5, FSBKEY_ADD("G0KTrWjS9syqF7vVD6RaVXlFD91gMgkC") }, // Sekiro: Shadows Die Twice (PC)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("BasicEncryptionKey") }, // SCP: Unity (PC)
|
{ MODE_FSB5, FSBKEY_ADD("BasicEncryptionKey") }, // SCP: Unity (PC)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("FXnTffGJ9LS855Gc") }, // Worms Rumble Beta (PC)
|
{ MODE_FSB5, FSBKEY_ADD("FXnTffGJ9LS855Gc") }, // Worms Rumble Beta (PC)
|
||||||
{ MODE_FSB4_STD, FSBKEY_ADD("qjvkeoqkrdhkdckd") }, // Bubble Fighter (PC)
|
{ MODE_FSB4, FSBKEY_ADD("qjvkeoqkrdhkdckd") }, // Bubble Fighter (PC)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("p@4_ih*srN:UJk&8") }, // Fall Guys (PC) update ~2021-11
|
{ MODE_FSB5, FSBKEY_ADD("p@4_ih*srN:UJk&8") }, // Fall Guys (PC) update ~2021-11
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD(",&.XZ8]fLu%caPF+") }, // Fall Guys (PC) update ~2022-07
|
{ MODE_FSB5, FSBKEY_ADD(",&.XZ8]fLu%caPF+") }, // Fall Guys (PC) update ~2022-07
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("^*4[hE>K]x90Vj") }, // Fall Guys (PC) update ~2023-05
|
{ MODE_FSB5, FSBKEY_ADD("^*4[hE>K]x90Vj") }, // Fall Guys (PC) update ~2023-05
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("Achilles_0_15_DpG") }, // Achilles: Legends Untold (PC)
|
{ MODE_FSB5, FSBKEY_ADD("Achilles_0_15_DpG") }, // Achilles: Legends Untold (PC)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("4FB8CC894515617939F4E1B7D50972D27213B8E6") }, // Cult of the Lamb Demo (PC)
|
{ MODE_FSB5, FSBKEY_ADD("4FB8CC894515617939F4E1B7D50972D27213B8E6") }, // Cult of the Lamb Demo (PC)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("X3EK%Bbga-%Y9HZZ%gkc*C512*$$DhRxWTGgjUG@=rUD") }, // Signalis (PC)
|
{ MODE_FSB5, FSBKEY_ADD("X3EK%Bbga-%Y9HZZ%gkc*C512*$$DhRxWTGgjUG@=rUD") }, // Signalis (PC)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("281ad163160cfc16f9a22c6755a64fad") }, // Ash Echoes beta (Android)
|
{ MODE_FSB5, FSBKEY_ADD("281ad163160cfc16f9a22c6755a64fad") }, // Ash Echoes beta (Android)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("Aurogon666") }, // Afterimage demo (PC)
|
{ MODE_FSB5, FSBKEY_ADD("Aurogon666") }, // Afterimage demo (PC)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("IfYouLikeThosesSoundsWhyNotRenumerateTheir2Authors?") }, // Blanc (PC/Switch)
|
{ MODE_FSB5, FSBKEY_ADD("IfYouLikeThosesSoundsWhyNotRenumerateTheir2Authors?") }, // Blanc (PC/Switch)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("L36nshM520") }, // Nishuihan Mobile (Android)
|
{ MODE_FSB5, FSBKEY_ADD("L36nshM520") }, // Nishuihan Mobile (Android)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("Forza2!") }, // Forza Motorsport (PC)
|
{ MODE_FSB5, FSBKEY_ADD("Forza2!") }, // Forza Motorsport (PC)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("cbfjZTlUPaZI") }, // JDM: Japanese Drift Master (PC)
|
{ MODE_FSB5, FSBKEY_ADD("cbfjZTlUPaZI") }, // JDM: Japanese Drift Master (PC)
|
||||||
{ MODE_FSB4_ALT, FSBKEY_ADD("tkdnsem000") }, // Ys Online: The Call of Solum (PC) [FSB3] (alt key: 2ED62676CEA6B60C0C0C)
|
{ MODE_FSB3, FSBKEY_ADD("tkdnsem000") }, // Ys Online: The Call of Solum (PC) [FSB3] (alt key: 2ED62676CEA6B60C0C0C)
|
||||||
{ MODE_FSB4_STD, FSBKEY_ADD("4DxgpNV3pQLPD6GT7g9Gf6eWU7SXutGQ") }, // Test Drive: Ferrari Racing Legends (PC)
|
{ MODE_FSB4, FSBKEY_ADD("4DxgpNV3pQLPD6GT7g9Gf6eWU7SXutGQ") }, // Test Drive: Ferrari Racing Legends (PC)
|
||||||
{ MODE_FSB4_STD, FSBKEY_ADD("AjaxIsTheGoodestBoy") }, // Hello Kitty: Island Adventure (iOS)
|
{ MODE_FSB4, FSBKEY_ADD("AjaxIsTheGoodestBoy") }, // Hello Kitty: Island Adventure (iOS)
|
||||||
{ MODE_FSB5_STD, FSBKEY_ADD("resoforce") }, // Rivals of Aether 2 (PC)
|
{ MODE_FSB5, FSBKEY_ADD("resoforce") }, // Rivals of Aether 2 (PC)
|
||||||
|
{ MODE_FSB5, FSBKEY_ADD("3cfe772db5b55b806541d3faf894020e") }, // Final Fantasy XV: War for Eos (Android)
|
||||||
|
|
||||||
/* these games use a key per file, generated from the filename; could be possible to add them but there is a lot of songs,
|
/* some games use a key per file, generated from the filename
|
||||||
so external .fsbkey may be better (use guessfsb 3.1 with --write-key-file or ) */
|
* (could add all of them but there are a lot of songs, so external .fsbkey are probably better) */
|
||||||
//{ MODE_FSB4_STD, FSBKEY_ADD("...") }, // Guitar Hero: Metallica (PC/PS3/X360) [FSB4]
|
//{ MODE_FSB4_STD, FSBKEY_ADD("...") }, // Guitar Hero: Metallica (PC/PS3/X360) [FSB4]
|
||||||
//{ MODE_FSB4_STD, FSBKEY_ADD("...") }, // Guitar Hero: World Tour (PC/PS3/X360) [FSB4]
|
//{ MODE_FSB4_STD, FSBKEY_ADD("...") }, // Guitar Hero: World Tour (PC/PS3/X360) [FSB4]
|
||||||
|
//{ MODE_FSB4_STD, FSBKEY_ADD("...") }, // Guitar Hero 5 (PC/PS3/X360) [FSB4] (streams seem to use the same default key)
|
||||||
};
|
};
|
||||||
static const int fsbkey_list_count = sizeof(fsbkey_list) / sizeof(fsbkey_list[0]);
|
static const int fsbkey_list_count = sizeof(fsbkey_list) / sizeof(fsbkey_list[0]);
|
||||||
|
|
||||||
|
@ -1314,7 +1314,7 @@ static const hcakey_info hcakey_list[] = {
|
|||||||
// Sonic Rumble (Android)
|
// Sonic Rumble (Android)
|
||||||
{6834182874188563}, // 001847A7328BCB13
|
{6834182874188563}, // 001847A7328BCB13
|
||||||
|
|
||||||
// P A Certain Magical Index 2 (Android)
|
// P A Certain Magical Index 1/2 (Android)
|
||||||
{5963}, // 000000000000174B
|
{5963}, // 000000000000174B
|
||||||
|
|
||||||
// Reynatis (Switch)
|
// Reynatis (Switch)
|
||||||
|
@ -208,10 +208,9 @@ VGMSTREAM * init_vgmstream_aus(STREAMFILE * streamFile);
|
|||||||
|
|
||||||
VGMSTREAM * init_vgmstream_rws(STREAMFILE * streamFile);
|
VGMSTREAM * init_vgmstream_rws(STREAMFILE * streamFile);
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_fsb(STREAMFILE * streamFile);
|
VGMSTREAM* init_vgmstream_fsb(STREAMFILE* sf);
|
||||||
VGMSTREAM * init_vgmstream_fsb4_wav(STREAMFILE * streamFile);
|
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_fsb5(STREAMFILE * streamFile);
|
VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf);
|
||||||
|
|
||||||
VGMSTREAM* init_vgmstream_rwax(STREAMFILE* sf);
|
VGMSTREAM* init_vgmstream_rwax(STREAMFILE* sf);
|
||||||
|
|
||||||
|
@ -73,6 +73,8 @@ void vgm_log_set_callback(void* ctx_p, int level, int type, void* callback);
|
|||||||
printf("\n"); \
|
printf("\n"); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define VGM_STEP() do { printf("%s: %s:%i\n", __FILE__, __FUNCTION__, __LINE__); } while (0)
|
||||||
|
|
||||||
#else /* VGM_DEBUG_OUTPUT */
|
#else /* VGM_DEBUG_OUTPUT */
|
||||||
|
|
||||||
#define VGM_LOG_ONCE(...) /* nothing */
|
#define VGM_LOG_ONCE(...) /* nothing */
|
||||||
@ -83,6 +85,8 @@ void vgm_log_set_callback(void* ctx_p, int level, int type, void* callback);
|
|||||||
|
|
||||||
#define VGM_LOGB(buf, buf_size, bytes_per_line) /* nothing */
|
#define VGM_LOGB(buf, buf_size, bytes_per_line) /* nothing */
|
||||||
|
|
||||||
|
#define VGM_STEP() /* nothing */
|
||||||
|
|
||||||
#endif /*VGM_DEBUG_OUTPUT*/
|
#endif /*VGM_DEBUG_OUTPUT*/
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -79,7 +79,6 @@ init_vgmstream_t init_vgmstream_functions[] = {
|
|||||||
init_vgmstream_aus,
|
init_vgmstream_aus,
|
||||||
init_vgmstream_rws,
|
init_vgmstream_rws,
|
||||||
init_vgmstream_fsb,
|
init_vgmstream_fsb,
|
||||||
init_vgmstream_fsb4_wav,
|
|
||||||
init_vgmstream_fsb5,
|
init_vgmstream_fsb5,
|
||||||
init_vgmstream_rwax,
|
init_vgmstream_rwax,
|
||||||
init_vgmstream_xwb,
|
init_vgmstream_xwb,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user