mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 08:20:54 +01:00
Move plugin parts to internal vgmstream code to simplify plugin code
This commit is contained in:
parent
48cfd96bcc
commit
479e6b8889
@ -185,6 +185,10 @@
|
||||
RelativePath=".\mixing.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\player.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\plugins.c"
|
||||
>
|
||||
|
@ -247,6 +247,7 @@
|
||||
<ClCompile Include="formats.c" />
|
||||
<ClCompile Include="meta\xmv_valve.c" />
|
||||
<ClCompile Include="mixing.c" />
|
||||
<ClCompile Include="player.c" />
|
||||
<ClCompile Include="plugins.c" />
|
||||
<ClCompile Include="meta\ps2_va3.c" />
|
||||
<ClCompile Include="streamfile.c" />
|
||||
|
@ -271,6 +271,9 @@
|
||||
<ClCompile Include="mixing.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="player.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="plugins.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
216
src/player.c
Normal file
216
src/player.c
Normal file
@ -0,0 +1,216 @@
|
||||
#include "vgmstream.h"
|
||||
#include "plugins.h"
|
||||
|
||||
|
||||
int vgmstream_get_play_forever(VGMSTREAM* vgmstream) {
|
||||
return vgmstream->config.play_forever;
|
||||
}
|
||||
int32_t vgmstream_get_samples(VGMSTREAM* vgmstream) {
|
||||
if (!vgmstream->config_set)
|
||||
return vgmstream->num_samples;
|
||||
return vgmstream->pstate.play_duration;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void setup_state_vgmstream(VGMSTREAM* vgmstream) {
|
||||
play_state_t* ps = &vgmstream->pstate;
|
||||
play_config_t* pc = &vgmstream->config;
|
||||
|
||||
|
||||
ps->pad_begin_duration = pc->pad_begin;
|
||||
ps->pad_begin_start = 0;
|
||||
ps->pad_begin_end = ps->pad_begin_start + ps->pad_begin_duration;
|
||||
|
||||
ps->trim_begin_duration = pc->trim_begin;
|
||||
ps->trim_begin_start = ps->pad_begin_end;
|
||||
ps->trim_begin_end = ps->trim_begin_start + ps->trim_begin_duration;
|
||||
|
||||
/* main samples part */
|
||||
ps->body_duration = 0;
|
||||
if (pc->target_time) {
|
||||
ps->body_duration += pc->target_time; /* wheter it loops or not */
|
||||
}
|
||||
else if (vgmstream->loop_flag) {
|
||||
ps->body_duration += vgmstream->loop_start_sample;
|
||||
if (pc->ignore_fade) {
|
||||
ps->body_duration += (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * (int)pc->loop_count;
|
||||
ps->body_duration += (vgmstream->num_samples - vgmstream->loop_end_sample);
|
||||
}
|
||||
else {
|
||||
ps->body_duration += (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * pc->loop_count;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ps->body_duration += vgmstream->num_samples;
|
||||
}
|
||||
|
||||
/* no need to apply in real time */
|
||||
if (pc->trim_end)
|
||||
ps->body_duration -= pc->trim_end;
|
||||
if (pc->fade_delay && vgmstream->loop_flag)
|
||||
ps->body_duration += pc->fade_delay * vgmstream->sample_rate;
|
||||
if (ps->body_duration < 0) /* ? */
|
||||
ps->body_duration = 0;
|
||||
ps->body_start = ps->trim_begin_end;
|
||||
ps->body_end = ps->body_start + ps->body_duration;
|
||||
|
||||
if (pc->fade_time && vgmstream->loop_flag)
|
||||
ps->fade_duration = pc->fade_time * vgmstream->sample_rate;
|
||||
ps->fade_start = ps->body_end;
|
||||
ps->fade_end = ps->fade_start + ps->fade_duration;
|
||||
|
||||
ps->pad_end_duration = pc->pad_end;
|
||||
ps->pad_end_start = ps->fade_end;
|
||||
ps->pad_end_end = ps->pad_end_start + ps->pad_end_duration;
|
||||
|
||||
/* final count */
|
||||
ps->play_duration = ps->pad_end_end;
|
||||
ps->play_position = 0;
|
||||
|
||||
/* other info */
|
||||
vgmstream_mixing_enable(vgmstream, 0, &ps->input_channels, &ps->output_channels);
|
||||
|
||||
VGM_LOG("**%i, %i, %i\n", ps->body_duration, ps->fade_duration, ps->play_duration);//todo
|
||||
}
|
||||
|
||||
static void load_player_config(VGMSTREAM* vgmstream, play_config_t* def, vgmstream_cfg_t* vcfg) {
|
||||
def->play_forever = vcfg->play_forever;
|
||||
def->ignore_loop = vcfg->ignore_loop;
|
||||
def->force_loop = vcfg->force_loop;
|
||||
def->really_force_loop = vcfg->really_force_loop;
|
||||
def->ignore_fade = vcfg->ignore_fade;
|
||||
def->loop_count = vcfg->loop_times; //todo loop times
|
||||
def->fade_delay = vcfg->fade_delay;
|
||||
def->fade_time = vcfg->fade_period; //todo loop period
|
||||
}
|
||||
|
||||
static void load_internal_config(VGMSTREAM* vgmstream, play_config_t* def, play_config_t* tcfg) {
|
||||
/* loop limit: txtp #L > txtp #l > player #L > player #l */
|
||||
if (tcfg->play_forever) {
|
||||
def->play_forever = 1;
|
||||
def->ignore_loop = 0;
|
||||
}
|
||||
if (tcfg->loop_count_set) {
|
||||
def->ignore_loop = 0;
|
||||
def->loop_count = tcfg->loop_count;
|
||||
if (!tcfg->play_forever)
|
||||
def->play_forever = 0;
|
||||
}
|
||||
|
||||
/* fade priority: #F > #f, #d */
|
||||
if (tcfg->ignore_fade) {
|
||||
def->ignore_fade = 1;
|
||||
}
|
||||
if (tcfg->fade_delay_set) {
|
||||
def->fade_delay = tcfg->fade_delay;
|
||||
}
|
||||
if (tcfg->fade_time_set) {
|
||||
def->fade_time = tcfg->fade_time;
|
||||
}
|
||||
|
||||
/* loop priority: #i > #e > #E */
|
||||
if (tcfg->really_force_loop) {
|
||||
def->ignore_loop = 0;
|
||||
def->force_loop = 0;
|
||||
def->really_force_loop = 1;
|
||||
}
|
||||
if (tcfg->force_loop) {
|
||||
def->ignore_loop = 0;
|
||||
def->force_loop = 1;
|
||||
def->really_force_loop = 0;
|
||||
}
|
||||
if (tcfg->ignore_loop) {
|
||||
def->ignore_loop = 1;
|
||||
def->force_loop = 0;
|
||||
def->really_force_loop = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void vgmstream_apply_config(VGMSTREAM* vgmstream, vgmstream_cfg_t* vcfg) {
|
||||
play_config_t defs = {0};
|
||||
play_config_t* def = &defs; /* for convenience... */
|
||||
play_config_t* tcfg = &vgmstream->config;
|
||||
|
||||
|
||||
load_player_config(vgmstream, def, vcfg);
|
||||
|
||||
if (!vcfg->disable_config_override)
|
||||
load_internal_config(vgmstream, def, tcfg);
|
||||
|
||||
|
||||
/* apply final config */
|
||||
if (def->really_force_loop) {
|
||||
vgmstream_force_loop(vgmstream, 1, 0,vgmstream->num_samples);
|
||||
}
|
||||
if (def->force_loop && !vgmstream->loop_flag) {
|
||||
vgmstream_force_loop(vgmstream, 1, 0,vgmstream->num_samples);
|
||||
}
|
||||
if (def->ignore_loop) {
|
||||
vgmstream_force_loop(vgmstream, 0, 0,0);
|
||||
}
|
||||
|
||||
/* remove non-compatible options */
|
||||
if (!vcfg->allow_play_forever)
|
||||
def->play_forever = 0;
|
||||
|
||||
if (!vgmstream->loop_flag) {
|
||||
def->play_forever = 0;
|
||||
}
|
||||
if (def->play_forever) {
|
||||
def->ignore_fade = 0;
|
||||
}
|
||||
|
||||
/* loop N times, but also play stream end instead of fading out */
|
||||
if (def->ignore_fade) {
|
||||
vgmstream_set_loop_target(vgmstream, (int)def->loop_count);
|
||||
def->fade_time = 0;
|
||||
def->fade_delay = 0;
|
||||
}
|
||||
|
||||
|
||||
/* copy final config back */
|
||||
*tcfg = *def;
|
||||
vgmstream->config_set = 1;
|
||||
|
||||
setup_state_vgmstream(vgmstream);
|
||||
setup_vgmstream(vgmstream); /* save current config for reset */
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void fade_vgmstream(VGMSTREAM* vgmstream, sample_t* buf, int samples_done) {
|
||||
play_state_t* ps = &vgmstream->pstate;
|
||||
play_config_t* pc = &vgmstream->config;
|
||||
|
||||
if (!ps->fade_duration || pc->play_forever)
|
||||
return;
|
||||
if (ps->play_position + samples_done < ps->fade_start)
|
||||
return;
|
||||
if (ps->play_position > ps->fade_end)
|
||||
return;
|
||||
|
||||
{
|
||||
int s, ch;
|
||||
int channels = ps->output_channels;
|
||||
int sample_start, fade_pos;
|
||||
|
||||
if (ps->play_position < ps->fade_start) {
|
||||
sample_start = samples_done - (ps->play_position + samples_done - ps->fade_start);
|
||||
fade_pos = 0;
|
||||
}
|
||||
else {
|
||||
sample_start = 0;
|
||||
fade_pos = ps->play_position - ps->fade_start;
|
||||
}
|
||||
|
||||
//TODO: use delta fadedness to improve performance?
|
||||
for (s = sample_start; s < samples_done; s++, fade_pos++) {
|
||||
double fadedness = (double)(ps->fade_duration - fade_pos) / ps->fade_duration;
|
||||
for (ch = 0; ch < channels; ch++) {
|
||||
buf[s*channels + ch] = (sample_t)buf[s*channels + ch] * fadedness;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
148
src/plugins.h
148
src/plugins.h
@ -5,6 +5,25 @@
|
||||
#define _PLUGINS_H_
|
||||
|
||||
#include "streamfile.h"
|
||||
//todo rename to api.h once public enough
|
||||
|
||||
|
||||
#if 0
|
||||
/* define standard C param call and name mangling (to avoid __stdcall / .defs) */
|
||||
//#define VGMSTREAM_CALL __cdecl //needed?
|
||||
|
||||
/* define external function types (during compilation) */
|
||||
#if defined(VGMSTREAM_EXPORT)
|
||||
#define VGMSTREAM_API __declspec(dllexport) /* when exporting/creating vgmstream DLL */
|
||||
#elif defined(VGMSTREAM_IMPORT)
|
||||
#define VGMSTREAM_API __declspec(dllimport) /* when importing/linking vgmstream DLL */
|
||||
#else
|
||||
#define VGMSTREAM_API /* nothing, internal/default */
|
||||
#endif
|
||||
|
||||
//VGMSTREAM_API void VGMSTREAM_CALL vgmstream_function(void);
|
||||
#endif
|
||||
|
||||
|
||||
/* ****************************************** */
|
||||
/* CONTEXT: simplifies plugin code */
|
||||
@ -21,42 +40,129 @@ typedef struct {
|
||||
/* returns if vgmstream can parse file by extension */
|
||||
int vgmstream_ctx_is_valid(const char* filename, vgmstream_ctx_valid_cfg *cfg);
|
||||
|
||||
#if 0
|
||||
|
||||
/* opaque player state */
|
||||
typedef struct VGMSTREAM_CTX VGMSTREAM_CTX;
|
||||
|
||||
typedef struct {
|
||||
//...
|
||||
} VGMSTREAM_CTX_INFO;
|
||||
int allow_play_forever;
|
||||
int disable_config_override;
|
||||
|
||||
VGMSTREAM_CTX* vgmstream_ctx_init(...);
|
||||
/* song mofidiers */
|
||||
int play_forever; /* keeps looping forever (needs loop points) */
|
||||
int ignore_loop; /* ignores loops points */
|
||||
int force_loop; /* enables full loops (0..samples) if file doesn't have loop points */
|
||||
int really_force_loop; /* forces full loops even if file has loop points */
|
||||
int ignore_fade; /* don't fade after N loops */
|
||||
|
||||
VGMSTREAM_CTX* vgmstream_ctx_format_check(...);
|
||||
VGMSTREAM_CTX* vgmstream_ctx_set_format_whilelist(...);
|
||||
VGMSTREAM_CTX* vgmstream_ctx_set_format_blacklist(...);
|
||||
/* song processing */
|
||||
double loop_times; /* target loops */
|
||||
double fade_delay; /* fade delay after target loops */
|
||||
double fade_period; /* fade time after target loops */
|
||||
|
||||
VGMSTREAM_CTX* vgmstream_ctx_set_file(...);
|
||||
//int downmix; /* max number of channels allowed (0=disable downmix) */
|
||||
|
||||
VGMSTREAM_CTX* vgmstream_ctx_get_config(...);
|
||||
} vgmstream_cfg_t;
|
||||
|
||||
VGMSTREAM_CTX* vgmstream_ctx_set_config(...);
|
||||
// WARNING: these are not stable and may change anytime without notice
|
||||
void vgmstream_apply_config(VGMSTREAM* vgmstream, vgmstream_cfg_t* pcfg);
|
||||
int32_t vgmstream_get_samples(VGMSTREAM* vgmstream);
|
||||
int vgmstream_get_play_forever(VGMSTREAM* vgmstream);
|
||||
|
||||
VGMSTREAM_CTX* vgmstream_ctx_get_buffer(...);
|
||||
|
||||
VGMSTREAM_CTX* vgmstream_ctx_get_info(...);
|
||||
|
||||
VGMSTREAM_CTX* vgmstream_ctx_describe(...);
|
||||
#if 0
|
||||
//possible future public/opaque API
|
||||
|
||||
VGMSTREAM_CTX* vgmstream_ctx_get_title(...);
|
||||
/* opaque player state */
|
||||
//#define VGMSTREAM_CTX_VERSION 1
|
||||
typedef struct VGMSTREAM_CTX VGMSTREAM_CTX;
|
||||
|
||||
VGMSTREAM_CTX* vgmstream_ctx_get_tagfile(...);
|
||||
|
||||
VGMSTREAM_CTX* vgmstream_ctx_play(...);
|
||||
/* Setups base vgmstream player context. */
|
||||
VGMSTREAM_CTX* vgmstream_init_ctx(void);
|
||||
|
||||
VGMSTREAM_CTX* vgmstream_ctx_seek(...);
|
||||
|
||||
VGMSTREAM_CTX* vgmstream_ctx_close(...);
|
||||
/* Sets 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 vgmstream_set_config(VGMSTREAM_CTX* vctx, VGMSTREAM_CFG* vcfg);
|
||||
|
||||
void vgmstream_set_buffer(VGMSTREAM_CTX* 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 vgmstream_open(STREAMFILE* sf);
|
||||
int vgmstream_open_subsong(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 ... */
|
||||
} VGMSTREAM_INFO;
|
||||
|
||||
/* Get info from current song. */
|
||||
void vgmstream_ctx_get_info(VGMSTREAM_CTX* vctx, VGMSTREAM_INFO* vinfo);
|
||||
|
||||
|
||||
/* 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 vgmstream_get_total_time(VGMSTREAM_CTX* vctx);
|
||||
double vgmstream_get_total_samples(VGMSTREAM_CTX* vctx);
|
||||
|
||||
|
||||
/* Gets current position within song. When "play forever" is set, it'll clamp results to total_time. */
|
||||
int32_t vgmstream_get_current_time(VGMSTREAM_CTX* vctx);
|
||||
double vgmstream_get_current_samples(VGMSTREAM_CTX* vctx);
|
||||
|
||||
|
||||
/* Seeks to position */
|
||||
VGMSTREAM_CTX* vgmstream_seek_absolute_sample(VGMSTREAM_CTX* vctx, int32_t sample);
|
||||
VGMSTREAM_CTX* vgmstream_seek_absolute_time(VGMSTREAM_CTX* vctx, double time);
|
||||
VGMSTREAM_CTX* vgmstream_seek_current_sample(VGMSTREAM_CTX* vctx, int32_t sample);
|
||||
VGMSTREAM_CTX* vgmstream_seek_current_time(VGMSTREAM_CTX* vctx, double time);
|
||||
|
||||
|
||||
/* Closes current song. */
|
||||
void vgmstream_close(VGMSTREAM_CTX* vctx);
|
||||
|
||||
/* Frees vgmstream context. */
|
||||
void vgmstream_free_ctx(VGMSTREAM_CTX* vctx);
|
||||
|
||||
|
||||
/* Converts samples. returns number of rendered samples, or <=0 if no more
|
||||
* samples left (will fill buffer with silence) */
|
||||
int vgmstream_play(VGMSTREAM_CTX* 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
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user