Move plugin parts to internal vgmstream code to simplify plugin code

This commit is contained in:
bnnm 2020-07-21 19:18:53 +02:00
parent 48cfd96bcc
commit 479e6b8889
5 changed files with 351 additions and 21 deletions

View File

@ -185,6 +185,10 @@
RelativePath=".\mixing.c" RelativePath=".\mixing.c"
> >
</File> </File>
<File
RelativePath=".\player.c"
>
</File>
<File <File
RelativePath=".\plugins.c" RelativePath=".\plugins.c"
> >

View File

@ -247,6 +247,7 @@
<ClCompile Include="formats.c" /> <ClCompile Include="formats.c" />
<ClCompile Include="meta\xmv_valve.c" /> <ClCompile Include="meta\xmv_valve.c" />
<ClCompile Include="mixing.c" /> <ClCompile Include="mixing.c" />
<ClCompile Include="player.c" />
<ClCompile Include="plugins.c" /> <ClCompile Include="plugins.c" />
<ClCompile Include="meta\ps2_va3.c" /> <ClCompile Include="meta\ps2_va3.c" />
<ClCompile Include="streamfile.c" /> <ClCompile Include="streamfile.c" />

View File

@ -271,6 +271,9 @@
<ClCompile Include="mixing.c"> <ClCompile Include="mixing.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="player.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="plugins.c"> <ClCompile Include="plugins.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>

216
src/player.c Normal file
View 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;
}
}
}
}

View File

@ -5,6 +5,25 @@
#define _PLUGINS_H_ #define _PLUGINS_H_
#include "streamfile.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 */ /* CONTEXT: simplifies plugin code */
@ -21,42 +40,129 @@ typedef struct {
/* returns if vgmstream can parse file by extension */ /* returns if vgmstream can parse file by extension */
int vgmstream_ctx_is_valid(const char* filename, vgmstream_ctx_valid_cfg *cfg); 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 { typedef struct {
//... int allow_play_forever;
} VGMSTREAM_CTX_INFO; 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(...); /* song processing */
VGMSTREAM_CTX* vgmstream_ctx_set_format_whilelist(...); double loop_times; /* target loops */
VGMSTREAM_CTX* vgmstream_ctx_set_format_blacklist(...); 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 #endif