From d98e1c854ff585fb530075501baf471e483d6251 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 27 Jul 2024 14:42:43 +0200 Subject: [PATCH] cleanup: api misc --- cli/api_example.c | 2 +- src/api.h | 55 --- src/api_decode.h | 202 ---------- src/api_helpers.h | 81 ---- src/api_tags.h | 45 --- src/api_version.h | 25 -- src/base/api_internal.h | 3 +- src/base/mixing.h | 1 + src/coding/coding.h | 1 + src/layout/layout.h | 1 + src/libvgmstream.h | 360 ++++++++++++++++++ src/libvgmstream.vcxproj | 7 +- src/libvgmstream.vcxproj.filters | 13 +- ...streamfile.h => libvgmstream_streamfile.h} | 29 +- src/meta/meta.h | 1 + src/vgmstream.h | 35 +- 16 files changed, 400 insertions(+), 461 deletions(-) delete mode 100644 src/api_decode.h delete mode 100644 src/api_helpers.h delete mode 100644 src/api_tags.h delete mode 100644 src/api_version.h create mode 100644 src/libvgmstream.h rename src/{api_streamfile.h => libvgmstream_streamfile.h} (51%) diff --git a/cli/api_example.c b/cli/api_example.c index deae0ca4..36a0f4d4 100644 --- a/cli/api_example.c +++ b/cli/api_example.c @@ -1,4 +1,4 @@ -#include "../src/api.h" +#include "../src/libvgmstream.h" #if LIBVGMSTREAM_ENABLE #include #include diff --git a/src/api.h b/src/api.h index 50b08394..85ee8144 100644 --- a/src/api.h +++ b/src/api.h @@ -1,59 +1,4 @@ #ifndef _API_H_ #define _API_H_ #include "base/plugins.h" //TODO: to be removed - -//#define LIBVGMSTREAM_ENABLE 1 -#if LIBVGMSTREAM_ENABLE - -/* vgmstream's public API - * - * By default vgmstream behaves like a simple decoder (extract samples until stream end), but you can configure it - * to loop N times or even downmix. In other words, it also behaves a bit like a player. - * - * It exposes multiple options and convenience functions beyond simple decoding mainly for various plugins, - * since it was faster moving shared behavior to core rather than reimplementing every time. - * - * All this may make the API a bit twisted and coupled (sorry, tried my best), probably will improve later. Probably. - * - * Notes: - * - vgmstream may dynamically allocate stuff as needed (not too much beyond some setup buffers, but varies per format) - * - previously the only way to use vgmstream was accesing its internals. Now there is an API internals may change in the future - * - some details described in the API may not happen at the moment (they are defined for future internal changes) - * - main reason it uses the slighly long-winded libvgmstream_* names is that internals use the vgmstream_* 'namespace' - * - c-strings should be in UTF-8 - * - the API is still WIP and may be slightly buggy overall due to lack of time, to be improved later - * - vgmstream's features are mostly stable, but this API may be tweaked from time to time (check API_VERSION) - * - * Basic usage (also see api_example.c): - * - libvgmstream_init(...) // base context - * - libvgmstream_setup(...) // config if needed - * - libvgmstream_open(...) // setup format - * - libvgmstream_play(...) // main decode - * - output samples + repeat libvgmstream_play until stream is done - * - libvgmstream_free(...) // cleanup - */ - -#include -#include - -/* standard C param call and name mangling (to avoid __stdcall / .defs) */ -//#define LIBVGMSTREAM_CALL __cdecl //needed? -//LIBVGMSTREAM_API (type) LIBVGMSTREAM_CALL libvgmstream_function(...); - -/* define external function behavior (during compilation) */ -#if defined(LIBVGMSTREAM_EXPORT) - #define LIBVGMSTREAM_API __declspec(dllexport) /* when exporting/creating vgmstream DLL */ -#elif defined(LIBVGMSTREAM_IMPORT) - #define LIBVGMSTREAM_API __declspec(dllimport) /* when importing/linking vgmstream DLL */ -#else - #define LIBVGMSTREAM_API /* nothing, internal/default */ -#endif - -#include "api_version.h" -#include "api_decode.h" -#include "api_helpers.h" -#include "api_streamfile.h" -#include "api_tags.h" - -#endif #endif diff --git a/src/api_decode.h b/src/api_decode.h deleted file mode 100644 index 3d0d6f11..00000000 --- a/src/api_decode.h +++ /dev/null @@ -1,202 +0,0 @@ -#ifndef _API_DECODE_H_ -#define _API_DECODE_H_ -#include "api.h" -#if LIBVGMSTREAM_ENABLE -#include "api_streamfile.h" - - -/* vgmstream's main (decode) API. - */ - - -/* interleaved samples: buf[0]=ch0, buf[1]=ch1, buf[2]=ch0, buf[3]=ch0, ... */ -typedef enum { - LIBVGMSTREAM_SAMPLE_PCM16 = 0x01, - LIBVGMSTREAM_SAMPLE_PCM24 = 0x02, - LIBVGMSTREAM_SAMPLE_PCM32 = 0x03, - LIBVGMSTREAM_SAMPLE_FLOAT = 0x04, -} libvgmstream_sample_t; - -/* current song info, may be copied around (values are info-only) */ -typedef struct { - /* main (always set) */ - libvgmstream_sample_t sample_type; // output buffer's sample type - int channels; // output channels - int sample_rate; // output sample rate - - int sample_size; // derived from sample_type (pcm16=2, float=4, etc) - - /* extra info (may be 0 if not known or not relevant) */ - uint32_t channel_layout; // standard WAVE bitflags - - int subsong_index; // 0 = none, N = loaded subsong N - int subsong_count; // 0 = format has no concept of subsongs, N = has N subsongs (1 = format has subsongs, and only 1) - - int input_channels; // original file's channels before downmixing (if any) - //int interleave; // when file is interleaved - //int interleave_first; // when file is interleaved - //int interleave_last; // when file is interleaved - //int frame_size; // when file has some configurable frame size - - /* sample info (may not be used depending on config) */ - int64_t sample_count; // file's max samples (not final play duration) - int64_t loop_start; // loop start sample - int64_t loop_end; // loop end sample - bool loop_flag; // if file loops; note that false + defined loops means looping was forcefully disabled - - bool play_forever; // if file loops forever based on current config (meaning _play never stops) - int64_t play_samples; // totals after all calculations (after applying loop/fade/etc config) - // ** may not be 100% accurate in some cases (must check decoder's 'done' flag rather than this count) - // ** if play_forever is set this is still provided for reference based on non-forever config - - int stream_bitrate; // average bitrate of the subsong (slightly bloated vs codec_bitrate; incorrect in rare cases) - //int codec_bitrate; // average bitrate of the codec data - // ** not possible / slow to calculate in most cases - - /* descriptions */ - char codec_name[128]; // - char layout_name[128]; // - char meta_name[128]; // (not internal "tag" metadata) - char stream_name[256]; // some internal name or representation, not always useful - // ** these are a bit big for a struct, but the typical use case of vgsmtream is opening a file > immediately - // query description and since libvgmstream returns its own copy it shouldn't be too much of a problem - // ** (may be separated later) - - /* misc */ - //bool rough_samples; // signal cases where loop points or sample count can't exactly reflect actual behavior (do not use to export) - - 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 - -} 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 */ - const 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 disable_config_override; // ignore forced (TXTP) config - 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_time; // fade period after target loops - double fade_delay; // fade delay after target loops - - int auto_downmix_channels; // downmixing if vgmstream's channels are higher than value - // ** for players that can only handle N channels, but this type of downmixing is very simplistic and not recommended - - bool force_pcm16; // forces output buffer to be remixed into PCM16 - -} 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* libsf; // 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 = default/first - // ** to check if a file has subsongs, _open first + check format->total_subsongs (then _open 2nd, 3rd, etc) - - int format_internal_id; // force a format (for example when loading new subsong of the same archive) - - 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); - -#if 0 -/* 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 - * - in many cases the only way for vgmstream to get a file's format info is making 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* options, libvgmstream_format_t* format); -#endif - -/* closes current song; may still use libvgmstream to open other songs - */ -LIBVGMSTREAM_API void libvgmstream_close(libvgmstream_t* lib); - - -/* decodes next batch of samples - * - vgmstream supplies its own buffer, updated on lib->decoder->* values (may change between calls) - * - returns < 0 on error - */ -LIBVGMSTREAM_API int libvgmstream_play(libvgmstream_t* lib); - -/* Same as _play, but fills some external buffer (also updates lib->decoder->* values) - * - returns < 0 on error, or N = number of filled samples. - * - buf must be at least as big as channels * sample_size * buf_samples - * - needs copying around from internal bufs so may be slightly slower; mainly for cases when you have buf constraints - */ -LIBVGMSTREAM_API int libvgmstream_fill(libvgmstream_t* lib, void* buf, int buf_samples); - -/* Gets current position within the song. - * - return < 0 on error (file not ready) - */ -LIBVGMSTREAM_API int64_t libvgmstream_get_play_position(libvgmstream_t* lib); - -/* Seeks to absolute position. Will clamp incorrect values such as seeking before/past playable length. - * - on play_forever may seek to any position - */ -LIBVGMSTREAM_API void libvgmstream_seek(libvgmstream_t* lib, int64_t sample); - -/* Reset current song - */ -LIBVGMSTREAM_API void libvgmstream_reset(libvgmstream_t* lib); - -#endif -#endif diff --git a/src/api_helpers.h b/src/api_helpers.h deleted file mode 100644 index 9d070ba1..00000000 --- a/src/api_helpers.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef _API_HELPERS_H_ -#define _API_HELPERS_H_ -#include "api.h" -#if LIBVGMSTREAM_ENABLE - - -/* vgmstream's helper stuff, for plugins. - */ - - -typedef enum { - LIBVGMSTREAM_LOG_LEVEL_ALL = 0, - LIBVGMSTREAM_LOG_LEVEL_DEBUG = 20, - LIBVGMSTREAM_LOG_LEVEL_INFO = 30, - LIBVGMSTREAM_LOG_LEVEL_NONE = 100, -} libvgmstream_loglevel_t; - -typedef struct { - libvgmstream_loglevel_t level; // log level - void (*callback)(int level, const char* str); // log callback - bool stdout_callback; // use default log callback rather than user supplied -} 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* cfg); - - -/* Returns a list of supported extensions (WARNING: it's pretty big), such as "adx", "dsp", etc. - * Mainly for plugins that want to know which extensions are supported. - * - returns NULL if no size is provided - */ -LIBVGMSTREAM_API const char** libvgmstream_get_extensions(size_t* size); - - -/* Same as above, buf returns a list what vgmstream considers "common" formats (such as "wav", "ogg"), - * which usually one doesn't want to associate to vgmstream. - * - returns NULL if no size is provided - */ -LIBVGMSTREAM_API const char** libvgmstream_get_common_extensions(size_t* 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); - - -typedef struct { - bool force_title; // TODO: what was this for? - bool subsong_range; // print a range of possible subsongs after title 'filename#1~N' - bool remove_extension; // remove extension from passed filename - bool remove_archive; // remove '(archive)|(subfile)' format of some plugins - const char* filename; // base file's filename - // ** note that sometimes vgmstream doesn't have/know the original name, so it's needed again here -} libvgmstream_title_t; - -/* get a simple title for plugins, derived from internal stream name if available - * - valid after _open - */ -LIBVGMSTREAM_API int libvgmstream_get_title(libvgmstream_t* lib, libvgmstream_title_t* cfg, char* buf, int buf_len); - - -/* Writes a description of the current song into dst. Will always be null-terminated. - * - returns < 0 if file was truncated, though will still succeed. - */ -LIBVGMSTREAM_API int libvgmstream_format_describe(libvgmstream_t* lib, char* dst, int dst_size); - -#endif -#endif diff --git a/src/api_tags.h b/src/api_tags.h deleted file mode 100644 index e0c00699..00000000 --- a/src/api_tags.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _API_TAGS_H_ -#define _API_TAGS_H_ -#include "api.h" -#if LIBVGMSTREAM_ENABLE - -/* vgmstream's !tags.m3u API. - * Doesn't need a main libvgmstream as tags aren't tied to loaded songs. - * - * Meant to be a simple implementation; feel free to ignore and roll your own - * (or use another external tags plugin). - */ - - -/* tag state */ -typedef struct { - void* priv; // internal data - - const char* key; // current key - const char* val; // current value -} libvgmstream_tags_t; - -/* Initializes tags. - * - libsf should point to a !tags.m3u file - * - unlike libvgmstream_open, sf tagfile must be valid during the tag extraction process. - */ -LIBVGMSTREAM_API libvgmstream_tags_t* libvgmstream_tags_init(libvgmstream_streamfile_t* libsf); - - -/* Finds tags for a new filename. Must be called first before extracting tags. - */ -LIBVGMSTREAM_API void libvgmstream_tags_find(libvgmstream_tags_t* tags, const char* target_filename); - - -/* Extracts next valid tag in tagfile to key/val. - * - returns false if no more tags are found (meant to be called repeatedly until false) - * - key/values are trimmed of beginning/end whitespaces and values are in UTF-8 - */ -LIBVGMSTREAM_API bool libvgmstream_tags_next_tag(libvgmstream_tags_t* tags); - - -/* Closes tags. */ -LIBVGMSTREAM_API void libvgmstream_tags_free(libvgmstream_tags_t* tags); - -#endif -#endif diff --git a/src/api_version.h b/src/api_version.h deleted file mode 100644 index 91771ca7..00000000 --- a/src/api_version.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _API_VERSION_H_ -#define _API_VERSION_H_ -#include "api.h" -#if LIBVGMSTREAM_ENABLE - -/* Current API version. - * - only refers to the API itself, as changes related to formats/etc don't alter this (since they are usually additive) - * - vgmstream's features are mostly stable, but this API may be tweaked from time to time - */ -#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 - -/* 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); - -/* CHANGELOG: - * - * - 1.0.0: initial version - */ - -#endif -#endif diff --git a/src/base/api_internal.h b/src/base/api_internal.h index 573b1a95..fec1035f 100644 --- a/src/base/api_internal.h +++ b/src/base/api_internal.h @@ -1,6 +1,7 @@ #ifndef _API_INTERNAL_H_ #define _API_INTERNAL_H_ -#include "../api.h" +#include "../libvgmstream.h" +#include "../util/log.h" #include "../vgmstream.h" #include "plugins.h" diff --git a/src/base/mixing.h b/src/base/mixing.h index 4d8705bb..53d2ab8f 100644 --- a/src/base/mixing.h +++ b/src/base/mixing.h @@ -2,6 +2,7 @@ #define _MIXING_H_ #include "../vgmstream.h" +#include "../util/log.h" /* Applies mixing commands to the sample buffer. Mixing must be externally enabled and * outbuf must big enough to hold output_channels*samples_to_do */ diff --git a/src/coding/coding.h b/src/coding/coding.h index c98a1a63..43a3357d 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -4,6 +4,7 @@ #include "../vgmstream.h" #include "../util/reader_sf.h" #include "../util/reader_get_nibbles.h" +#include "../util/log.h" //todo remove #include "libs/clhca.h" diff --git a/src/layout/layout.h b/src/layout/layout.h index 4b3c8a4f..3423e2d8 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -4,6 +4,7 @@ #include "../streamtypes.h" #include "../vgmstream.h" #include "../util/reader_sf.h" +#include "../util/log.h" /* blocked layouts */ void render_vgmstream_blocked(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream); diff --git a/src/libvgmstream.h b/src/libvgmstream.h new file mode 100644 index 00000000..3287dcb1 --- /dev/null +++ b/src/libvgmstream.h @@ -0,0 +1,360 @@ +/* libvgmstream: vgmstream's public API */ + +#ifndef _LIBVGMSTREAM_H_ +#define _LIBVGMSTREAM_H_ + +//#define LIBVGMSTREAM_ENABLE 1 +#if LIBVGMSTREAM_ENABLE + +/* By default vgmstream behaves like a decoder (decode samples until stream end), but you can configure + * it to loop N times or even downmix. In other words, it also behaves a bit like a player. + * It exposes multiple convenience stuff mainly for various plugins that mostly repeat the same features. + * All this may make the API still WIP and a bit twisted, probably will improve later. Probably. + * + * Notes: + * - now there is an API internals (vgmstream.h) may change in the future + * - may dynamically allocate stuff as needed (mainly some buffers, but varies per format) + * - some details described in the API may not happen at the moment (defined for future changes) + * - uses long-winded libvgmstream_* names since internals alredy use the vgmstream_* 'namespace', #define as needed + * - c-strings should be in UTF-8 + * + * Basic usage (also see api_example.c): + * - libvgmstream_init(...) // base context + * - libvgmstream_setup(...) // config if needed + * - libvgmstream_open(...) // setup format + * - libvgmstream_play(...) // main decode + * - output samples + repeat libvgmstream_play until stream is done + * - libvgmstream_free(...) // cleanup + */ + + +/*****************************************************************************/ +/* DEFINES */ + +///* standard C param call and name mangling (to avoid __stdcall / .defs) */ +//#define LIBVGMSTREAM_CALL __cdecl //needed? +//LIBVGMSTREAM_API (type) LIBVGMSTREAM_CALL libvgmstream_function(...); + +/* external function behavior (for compile time) */ +#if defined(LIBVGMSTREAM_EXPORT) + #define LIBVGMSTREAM_API __declspec(dllexport) /* when exporting/creating vgmstream DLL */ +#elif defined(LIBVGMSTREAM_IMPORT) + #define LIBVGMSTREAM_API __declspec(dllimport) /* when importing/linking vgmstream DLL */ +#else + #define LIBVGMSTREAM_API /* nothing, internal/default */ +#endif + +#include +#include +#include "libvgmstream_streamfile.h" + + +/*****************************************************************************/ +/* VERSION */ + +/* Current API version, for static checks. + * - only refers to the API itself, changes related to formats/etc don't alter this + * - vgmstream's features are mostly stable, but this API may be tweaked from time to time + */ +#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 + +/* Current API version, for dynamic checks. returns hex value: 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); + +/* CHANGELOG: + * - 1.0.0: initial version + */ + + +/*****************************************************************************/ +/* DECODE */ + +/* interleaved samples: buf[0]=ch0, buf[1]=ch1, buf[2]=ch0, buf[3]=ch0, ... */ +typedef enum { + LIBVGMSTREAM_SAMPLE_PCM16 = 0x01, + LIBVGMSTREAM_SAMPLE_PCM24 = 0x02, + LIBVGMSTREAM_SAMPLE_PCM32 = 0x03, + LIBVGMSTREAM_SAMPLE_FLOAT = 0x04, +} libvgmstream_sample_t; + +/* current song info, may be copied around (values are info-only) */ +typedef struct { + /* main (always set) */ + int channels; // output channels + int sample_rate; // output sample rate + + libvgmstream_sample_t sample_type; // output buffer's sample type + int sample_size; // derived from sample_type (pcm16=0x02, float=0x04, etc) + + /* extra info (may be 0 if not known or not relevant) */ + uint32_t channel_layout; // standard WAVE bitflags + + int subsong_index; // 0 = none, N = loaded subsong N (1=first) + int subsong_count; // 0 = format has no concept of subsongs, N = has N subsongs + // ** 1 = format has subsongs, and only 1 for current file + + int input_channels; // original file's channels before downmixing (if any) + //int interleave; // when file is interleaved + //int interleave_first; // when file is interleaved + //int interleave_last; // when file is interleaved + //int frame_size; // when file has some configurable frame size + + /* sample info (may not be used depending on config) */ + int64_t sample_count; // file's max samples (not final play duration) + int64_t loop_start; // loop start sample + int64_t loop_end; // loop end sample + bool loop_flag; // if file loops (false + defined loops means looping was forcefully disabled) + + bool play_forever; // if file loops forever based on current config (meaning _play never stops) + int64_t play_samples; // totals after all calculations (after applying loop/fade/etc config) + // ** may not be 100% accurate in some cases (check decoder's 'done' flag to stop) + // ** if play_forever is set this is still provided for reference based on non-forever config + + int stream_bitrate; // average bitrate of the subsong (slightly bloated vs codec_bitrate; incorrect in rare cases) + //int codec_bitrate; // average bitrate of the codec data + // ** not possible / slow to calculate in most cases + + /* descriptions */ + char codec_name[128]; // + char layout_name[128]; // + char meta_name[128]; // (not internal "tag" metadata) + char stream_name[256]; // some internal name or representation, not always useful + // ** these are a bit big for a struct, but the typical use case of vgsmtream is opening a file > immediately + // query description and since libvgmstream returns its own copy it shouldn't be too much of a problem + // ** (may be separated later) + + /* misc */ + //bool rough_samples; // signal cases where loop points or sample count can't exactly reflect actual behavior + + int format_internal_id; // when reopening subfiles or similar formats without checking other all possible formats + // ** this value WILL change without warning between vgmstream versions/commits + +} 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) + int buf_bytes; // current buffer bytes (channels * sample_size * samples) + + bool done; // when stream is done based on config + // ** 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 */ + const 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 + */ +LIBVGMSTREAM_API libvgmstream_t* libvgmstream_init(void); + +/* Frees the vgmstream context and any other internal stuff. + */ +LIBVGMSTREAM_API void libvgmstream_free(libvgmstream_t* lib); + + +/* configures how vgmstream behaves internally when playing a file */ +typedef struct { + bool disable_config_override; // ignore forced (TXTP) config + bool allow_play_forever; // must allow manually as some cases a TXTP may set loop forever but client may not handle it + + 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_time; // fade period after target loops + double fade_delay; // fade delay after target loops + + int auto_downmix_channels; // downmixing if vgmstream's channels are higher than value + // ** for players that can only handle N channels + // ** this type of downmixing is very simplistic and not recommended + + bool force_pcm16; // forces output buffer to be remixed into PCM16 + +} 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* libsf; // 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 = default/first + // ** to check if a file has subsongs, _open first + check format->total_subsongs (then _open 2nd, 3rd, etc) + + int format_internal_id; // force a format (for example when loading new subsong of the same archive) + + 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); + +/* Closes current song; may still use libvgmstream to open other songs + */ +LIBVGMSTREAM_API void libvgmstream_close(libvgmstream_t* lib); + + +/* Decodes next batch of samples + * - vgmstream supplies its own buffer, updated on lib->decoder->* values (may change between calls) + * - returns < 0 on error + */ +LIBVGMSTREAM_API int libvgmstream_play(libvgmstream_t* lib); + +/* Same as _play, but fills some external buffer (also updates lib->decoder->* values) + * - returns < 0 on error, or N = number of filled samples. + * - buf must be at least as big as channels * sample_size * buf_samples + * - needs copying around from internal bufs so may be slightly slower; mainly for cases when you have buf constraints + */ +LIBVGMSTREAM_API int libvgmstream_fill(libvgmstream_t* lib, void* buf, int buf_samples); + +/* Gets current position within the song. + * - return < 0 on error + */ +LIBVGMSTREAM_API int64_t libvgmstream_get_play_position(libvgmstream_t* lib); + +/* Seeks to absolute position. Will clamp incorrect values such as seeking before/past playable length. + */ +LIBVGMSTREAM_API void libvgmstream_seek(libvgmstream_t* lib, int64_t sample); + +/* Reset current song + */ +LIBVGMSTREAM_API void libvgmstream_reset(libvgmstream_t* lib); + + + +/*****************************************************************************/ +/* HELPERS */ + +typedef enum { + LIBVGMSTREAM_LOG_LEVEL_ALL = 0, + LIBVGMSTREAM_LOG_LEVEL_DEBUG = 20, + LIBVGMSTREAM_LOG_LEVEL_INFO = 30, + LIBVGMSTREAM_LOG_LEVEL_NONE = 100, +} libvgmstream_loglevel_t; + +typedef struct { + libvgmstream_loglevel_t level; // log level + void (*callback)(int level, const char* str); // log callback + bool stdout_callback; // use default log callback rather than user supplied +} 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* cfg); + + +/* Returns a list of supported extensions (WARNING: it's pretty big), such as "adx", "dsp", etc. + * Mainly for plugins that want to know which extensions are supported. + * - returns NULL if no size is provided + */ +LIBVGMSTREAM_API const char** libvgmstream_get_extensions(size_t* size); + +/* Same as above, buf returns a list what vgmstream considers "common" formats (such as "wav", "ogg"), + * which usually one doesn't want to associate to vgmstream. + * - returns NULL if no size is provided + */ +LIBVGMSTREAM_API const char** libvgmstream_get_common_extensions(size_t* 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); + + +typedef struct { + bool force_title; // TODO: what was this for? + bool subsong_range; // print a range of possible subsongs after title 'filename#1~N' + bool remove_extension; // remove extension from passed filename + bool remove_archive; // remove '(archive)|(subfile)' format of some plugins + const char* filename; // base file's filename + // ** note that sometimes vgmstream doesn't have/know the original name, so it's needed again here +} libvgmstream_title_t; + +/* Get a simple title for plugins, derived from internal stream name if available + * - valid after _open + */ +LIBVGMSTREAM_API int libvgmstream_get_title(libvgmstream_t* lib, libvgmstream_title_t* cfg, char* buf, int buf_len); + +/* Writes a description of the current song into dst. Will always be null-terminated. + * - returns < 0 if file was truncated, though will still succeed. + */ +LIBVGMSTREAM_API int libvgmstream_format_describe(libvgmstream_t* lib, char* dst, int dst_size); + + + +/*****************************************************************************/ +/* TAGS */ + +/* Meant to be a simple implementation; feel free to ignore and roll your own (or use another tags plugin). + * Doesn't need a main libvgmstream 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. + * - libsf should point to a !tags.m3u file + * - unlike libvgmstream_open, sf tagfile must be valid during the tag extraction process. + */ +LIBVGMSTREAM_API libvgmstream_tags_t* libvgmstream_tags_init(libvgmstream_streamfile_t* libsf); + +/* Finds tags for a new filename. Must be called first before extracting tags. + */ +LIBVGMSTREAM_API void libvgmstream_tags_find(libvgmstream_tags_t* tags, const char* target_filename); + +/* Extracts next valid tag in tagfile to key/val. + * - returns false if no more tags are found (meant to be called repeatedly until false) + * - key/values are trimmed of beginning/end whitespaces and values are in UTF-8 + */ +LIBVGMSTREAM_API bool libvgmstream_tags_next_tag(libvgmstream_tags_t* tags); + +/* Closes tags. */ +LIBVGMSTREAM_API void libvgmstream_tags_free(libvgmstream_tags_t* tags); + + +#endif +#endif diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index f739fb71..203a5643 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -81,11 +81,8 @@ - - - - - + + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 4ee205eb..d0cbc775 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -77,19 +77,10 @@ Header Files - + Header Files - - Header Files - - - Header Files - - - Header Files - - + Header Files diff --git a/src/api_streamfile.h b/src/libvgmstream_streamfile.h similarity index 51% rename from src/api_streamfile.h rename to src/libvgmstream_streamfile.h index ee830f60..19fdc497 100644 --- a/src/api_streamfile.h +++ b/src/libvgmstream_streamfile.h @@ -1,18 +1,13 @@ -#ifndef _API_STREAMFILE_H_ -#define _API_STREAMFILE_H_ -#include "api.h" +#ifndef _LIBVGMSTREAM_STREAMFILE_H_ +#define _LIBVGMSTREAM_STREAMFILE_H_ +#include "libvgmstream.h" #if LIBVGMSTREAM_ENABLE /* vgmstream's IO API, defined as a "streamfile" (SF). * - * Compared to typical IO, vgmstream has some extra needs that roughly assume there is an underlying filesystem (as usual in games): - * - seeking + reading from arbitrary offsets: header not in the beginning of a stream, rewinding back when looping, etc - * - opening other streamfiles: reopening a copy of the current SF, formats with split header + data, decryption files, etc - * - extracting the filename: opening similarly named companion files, basic extension sanity checks, heuristics for odd cases, etc - * - * If your IO can't fully satisfy those constraints, it may still be possible to create a streamfile that just simulates part of it. - * For example, returning a fake filename, and only handling "open" that reopens itself (same filename), while returning default/incorrect - * values for non-handled operations. Simpler formats will probably work just fine. + * vgmstream roughly assumes there is an underlying filesystem (as usual in games): seeking + reading from arbitrary offsets, + * opening companion files, filename tests, etc. If your case is too different you may still create a partial streamfile: returning + * a fake filename, only handling "open" that reopens itself (same filename), etc. Simpler formats will probably work just fine. */ @@ -28,26 +23,26 @@ typedef struct libvgmstream_streamfile_t { //uint32_t flags; // info flags for vgmstream void* user_data; // any internal structure - /* read 'length' data at internal offset to 'dst' (implicit seek if needed) - * - assumes 0 = failure/EOF + /* read 'length' data at internal offset to 'dst' + * - assumes 0 = failure/EOF */ int (*read)(void* user_data, uint8_t* dst, int dst_size); /* seek to offset - * - note that due to how vgmstream works this is a fairly common operation (to be optimized later) + * - note that vgmstream needs to seek + read fairly often (to be optimized later) */ int64_t (*seek)(void* user_data, int64_t offset, int whence); - /* get max offset + /* get max offset (typically for checks or calculations) */ int64_t (*get_size)(void* user_data); - /* get current filename + /* get current filename (used to open same or other streamfiles and heuristics; no need to be a real path) */ const char* (*get_name)(void* user_data); /* open another streamfile from filename (may be some path/protocol, or same as current get_name = reopen) - * - vgmstream mainly opens stuff based on current get_name (relative), so there shouldn't be need to transform this path + * - vgmstream opens stuff based on current get_name (relative), so there shouldn't be need to transform this path */ struct libvgmstream_streamfile_t* (*open)(void* user_data, const char* filename); diff --git a/src/meta/meta.h b/src/meta/meta.h index 702092ef..192488df 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -5,6 +5,7 @@ #include "../util/reader_sf.h" #include "../util/reader_text.h" #include "../util/sf_utils.h" +#include "../util/log.h" typedef VGMSTREAM* (*init_vgmstream_t)(STREAMFILE* sf); diff --git a/src/vgmstream.h b/src/vgmstream.h index 4e86fc2c..064db43b 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -23,7 +23,6 @@ #include "streamfile.h" #include "vgmstream_types.h" -#include "util/log.h" #ifdef VGM_USE_MP4V2 #define MP4V2_NO_STDINT_DEFS @@ -38,14 +37,14 @@ typedef struct { - int config_set; /* some of the mods below are set */ + bool config_set; /* some of the mods below are set */ /* modifiers */ - int play_forever; - int ignore_loop; - int force_loop; - int really_force_loop; - int ignore_fade; + bool play_forever; + bool ignore_loop; + bool force_loop; + bool really_force_loop; + bool ignore_fade; /* processing */ double loop_count; @@ -66,18 +65,18 @@ typedef struct { double pad_end_s; /* internal flags */ - int pad_begin_set; - int trim_begin_set; - int body_time_set; - int loop_count_set; - int trim_end_set; - int fade_delay_set; - int fade_time_set; - int pad_end_set; + bool pad_begin_set; + bool trim_begin_set; + bool body_time_set; + bool loop_count_set; + bool trim_end_set; + bool fade_delay_set; + bool fade_time_set; + bool pad_end_set; /* for lack of a better place... */ - int is_txtp; - int is_mini_txtp; + bool is_txtp; + bool is_mini_txtp; } play_config_t; @@ -165,7 +164,7 @@ typedef struct { meta_t meta_type; /* type of metadata */ /* loop config */ - int loop_flag; /* is this stream looped? */ + bool loop_flag; /* is this stream looped? */ int32_t loop_start_sample; /* first sample of the loop (included in the loop) */ int32_t loop_end_sample; /* last sample of the loop (not included in the loop) */