api: beta defs/tests

This commit is contained in:
bnnm 2024-07-07 21:25:59 +02:00
parent b1b218bea5
commit 316c0eecd6
8 changed files with 632 additions and 117 deletions

View File

@ -280,6 +280,9 @@ vgmstream_cli: version
vgmstream123: version
$(MAKE) -C cli vgmstream123
api_example: version
$(MAKE) -C cli api_example
winamp: version
$(MAKE) -C winamp in_vgmstream

View File

@ -12,19 +12,17 @@ CFLAGS += $(DEF_CFLAGS) -DVAR_ARRAYS $(EXTRA_CFLAGS)
LDFLAGS += -L../src -lvgmstream -lm $(EXTRA_LDFLAGS)
TARGET_EXT_LIBS =
ifeq ($(TARGET_OS),Windows_NT)
OUTPUT_CLI = vgmstream-cli.exe
OUTPUT_123 = vgmstream123.exe
OUTPUT_CLI = vgmstream-cli
OUTPUT_123 = vgmstream123
OUTPUT_API = api_example
ifeq ($(TARGET_OS),Windows_NT)
CFLAGS += -DWIN32 -I../ext_includes -I../ext_libs/Getopt
LDFLAGS += -L../ext_libs/$(DLL_DIR)
LIBAO_INC = -I$(LIBAO_IPATH)
LIBAO_LIB = -L$(LIBAO_LPATH) -lao
else
OUTPUT_CLI = vgmstream-cli
OUTPUT_123 = vgmstream123
#todo move to subfolders and remove
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)
$(STRIP) $(OUTPUT_123)
api_example: libvgmstream.a $(TARGET_EXT_LIBS)
$(CC) $(CFLAGS) api_example.c $(LDFLAGS) -o $(OUTPUT_API)
$(STRIP) api_example
libvgmstream.a:
$(MAKE) -C ../src $@
@ -57,6 +59,6 @@ $(TARGET_EXT_LIBS):
$(MAKE) -C ../ext_libs $@
clean:
$(RMF) $(OUTPUT_CLI) $(OUTPUT_123)
$(RMF) $(OUTPUT_CLI) $(OUTPUT_123) $(OUTPUT_123)
.PHONY: clean vgmstream_cli libvgmstream.a $(TARGET_EXT_LIBS)

112
cli/api_example.c Normal file
View 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

136
src/api.h
View File

@ -1,26 +1,29 @@
#ifndef _API_H_
#define _API_H_
#include "base/plugins.h" //TODO: to be removed
#include "base/plugins.h"
//possible future public/opaque API
#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 "api_streamfile.h"
#include <stdbool.h>
/* Current API version (major=breaking API/ABI changes, minor=compatible ABI changes).
* 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) */
/* 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 types (during compilation) */
//LIBVGMSTREAM_API void LIBVGMSTREAM_CALL vgmstream_function(void);
/* define external function behavior (during compilation) */
#if defined(LIBVGMSTREAM_EXPORT)
#define LIBVGMSTREAM_API __declspec(dllexport) /* when exporting/creating vgmstream DLL */
#elif defined(LIBVGMSTREAM_IMPORT)
@ -29,104 +32,17 @@
#define LIBVGMSTREAM_API /* nothing, internal/default */
#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

156
src/api_main.c Normal file
View 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
View 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
View 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
View 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