mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-27 16:10:48 +01:00
cleanup: move code
This commit is contained in:
parent
06db5fca76
commit
1169b68b99
@ -1601,10 +1601,10 @@ int decode_get_samples_to_do(int samples_this_block, int samples_per_frame, VGMS
|
||||
return samples_to_do;
|
||||
}
|
||||
|
||||
/* Detect loop start and save values, or detect loop end and restore (loop back).
|
||||
* Returns 1 if loop was done. */
|
||||
int decode_do_loop(VGMSTREAM* vgmstream) {
|
||||
/*if (!vgmstream->loop_flag) return 0;*/
|
||||
|
||||
/* Detect loop start and save values, or detect loop end and restore (loop back). Returns true if loop was done. */
|
||||
bool decode_do_loop(VGMSTREAM* vgmstream) {
|
||||
//if (!vgmstream->loop_flag) return false;
|
||||
|
||||
/* is this the loop end? = new loop, continue from loop_start_sample */
|
||||
if (vgmstream->current_sample == vgmstream->loop_end_sample) {
|
||||
@ -1613,8 +1613,8 @@ int decode_do_loop(VGMSTREAM* vgmstream) {
|
||||
* (only needed with the "play stream end after looping N times" option enabled) */
|
||||
vgmstream->loop_count++;
|
||||
if (vgmstream->loop_target && vgmstream->loop_target == vgmstream->loop_count) {
|
||||
vgmstream->loop_flag = 0; /* could be improved but works ok, will be restored on resets */
|
||||
return 0;
|
||||
vgmstream->loop_flag = false; /* could be improved but works ok, will be restored on resets */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* against everything I hold sacred, preserve adpcm history before looping for certain types */
|
||||
@ -1623,8 +1623,7 @@ int decode_do_loop(VGMSTREAM* vgmstream) {
|
||||
vgmstream->meta_type == meta_DSP_CSTR ||
|
||||
vgmstream->coding_type == coding_PSX ||
|
||||
vgmstream->coding_type == coding_PSX_badflags) {
|
||||
int ch;
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
for (int ch = 0; ch < vgmstream->channels; ch++) {
|
||||
vgmstream->loop_ch[ch].adpcm_history1_16 = vgmstream->ch[ch].adpcm_history1_16;
|
||||
vgmstream->loop_ch[ch].adpcm_history2_16 = vgmstream->ch[ch].adpcm_history2_16;
|
||||
vgmstream->loop_ch[ch].adpcm_history1_32 = vgmstream->ch[ch].adpcm_history1_32;
|
||||
@ -1633,12 +1632,13 @@ int decode_do_loop(VGMSTREAM* vgmstream) {
|
||||
}
|
||||
|
||||
//TODO: improve
|
||||
/* loop codecs that need special handling, usually:
|
||||
* - on hit_loop, current offset is copied to loop_ch[].offset
|
||||
* - some codecs will overwrite loop_ch[].offset with a custom value
|
||||
* - loop_ch[] is copied to ch[] (with custom value)
|
||||
* - then codec will use ch[]'s offset
|
||||
* regular codecs may use copied loop_ch[] offset without issue */
|
||||
/* codecs with codec_data that decode_seek need special handling, usually:
|
||||
* - during decode, codec uses vgmstream->ch[].offset to handle current offset
|
||||
* - on hit_loop, current offset is auto-copied to vgmstream->loop_ch[].offset
|
||||
* - decode_seek codecs may overwrite vgmstream->loop_ch[].offset with a custom value (such as start_offset)
|
||||
* - vgmstream->loop_ch[] is copied below to vgmstream->ch[] (with the newly assigned custom value)
|
||||
* - then codec will use vgmstream->ch[].offset during decode
|
||||
* regular codecs will use copied vgmstream->loop_ch[].offset without issue */
|
||||
decode_seek(vgmstream);
|
||||
|
||||
/* restore! */
|
||||
@ -1649,7 +1649,7 @@ int decode_do_loop(VGMSTREAM* vgmstream) {
|
||||
vgmstream->current_block_samples = vgmstream->loop_block_samples;
|
||||
vgmstream->current_block_offset = vgmstream->loop_block_offset;
|
||||
vgmstream->next_block_offset = vgmstream->loop_next_block_offset;
|
||||
//vgmstream->pstate = vgmstream->lstate; /* play state is applied over loops */
|
||||
vgmstream->full_block_size = vgmstream->loop_full_block_size;
|
||||
|
||||
/* loop layouts (after restore, in case layout needs state manipulations) */
|
||||
switch(vgmstream->layout_type) {
|
||||
@ -1663,24 +1663,30 @@ int decode_do_loop(VGMSTREAM* vgmstream) {
|
||||
break;
|
||||
}
|
||||
|
||||
return 1; /* looped */
|
||||
/* play state is applied over loops and stream decoding, so it's not restored on loops */
|
||||
//vgmstream->pstate = vgmstream->lstate;
|
||||
|
||||
return true; /* has looped */
|
||||
}
|
||||
|
||||
|
||||
/* is this the loop start? save if we haven't saved yet (right when first loop starts) */
|
||||
if (!vgmstream->hit_loop && vgmstream->current_sample == vgmstream->loop_start_sample) {
|
||||
/* save! */
|
||||
memcpy(vgmstream->loop_ch, vgmstream->ch, sizeof(VGMSTREAMCHANNEL)*vgmstream->channels);
|
||||
memcpy(vgmstream->loop_ch, vgmstream->ch, sizeof(VGMSTREAMCHANNEL) * vgmstream->channels);
|
||||
vgmstream->loop_current_sample = vgmstream->current_sample;
|
||||
vgmstream->loop_samples_into_block = vgmstream->samples_into_block;
|
||||
vgmstream->loop_block_size = vgmstream->current_block_size;
|
||||
vgmstream->loop_block_samples = vgmstream->current_block_samples;
|
||||
vgmstream->loop_block_offset = vgmstream->current_block_offset;
|
||||
vgmstream->loop_next_block_offset = vgmstream->next_block_offset;
|
||||
//vgmstream->lstate = vgmstream->pstate; /* play state is applied over loops */
|
||||
vgmstream->loop_full_block_size = vgmstream->full_block_size;
|
||||
|
||||
/* play state is applied over loops and stream decoding, so it's not saved on loops */
|
||||
//vgmstream->lstate = vgmstream->pstate;
|
||||
|
||||
vgmstream->hit_loop = true; /* info that loop is now ready to use */
|
||||
}
|
||||
|
||||
return 0; /* not looped */
|
||||
return false; /* has not looped */
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ void decode_reset(VGMSTREAM* vgmstream);
|
||||
* buffer already, and we have samples_to_do consecutive samples ahead of us. */
|
||||
void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_do, sample_t* buffer);
|
||||
|
||||
/* Detect loop start and save values, or detect loop end and restore (loop back). Returns 1 if loop was done. */
|
||||
int decode_do_loop(VGMSTREAM* vgmstream);
|
||||
/* Detect loop start and save values, or detect loop end and restore (loop back). Returns true if loop was done. */
|
||||
bool decode_do_loop(VGMSTREAM* vgmstream);
|
||||
|
||||
/* Calculate number of consecutive samples to do (taking into account stopping for loop start and end) */
|
||||
int decode_get_samples_to_do(int samples_this_block, int samples_per_frame, VGMSTREAM* vgmstream);
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include "../util/channel_mappings.h"
|
||||
#include "../util/sf_utils.h"
|
||||
|
||||
#define TEMPSIZE (256+32)
|
||||
|
||||
/*******************************************************************************/
|
||||
/* TEXT */
|
||||
/*******************************************************************************/
|
||||
@ -21,7 +23,6 @@ static void describe_get_time(int32_t samples, int sample_rate, double* p_time_m
|
||||
/* Write a description of the stream into array pointed by desc, which must be length bytes long.
|
||||
* Will always be null-terminated if length > 0 */
|
||||
void describe_vgmstream(VGMSTREAM* vgmstream, char* desc, int length) {
|
||||
#define TEMPSIZE (256+32)
|
||||
char temp[TEMPSIZE];
|
||||
double time_mm, time_ss;
|
||||
|
||||
|
@ -13,50 +13,50 @@ static void copy_time(bool* dst_flag, int32_t* dst_time, double* dst_time_s, boo
|
||||
*dst_time_s = *src_time_s;
|
||||
}
|
||||
|
||||
//todo reuse in txtp?
|
||||
// config that has been set internally via TXTP
|
||||
static void load_default_config(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;
|
||||
def->play_forever = true;
|
||||
def->ignore_loop = false;
|
||||
}
|
||||
if (tcfg->loop_count_set) {
|
||||
def->loop_count = tcfg->loop_count;
|
||||
def->loop_count_set = 1;
|
||||
def->ignore_loop = 0;
|
||||
def->loop_count_set = true;
|
||||
def->ignore_loop = false;
|
||||
if (!tcfg->play_forever)
|
||||
def->play_forever = 0;
|
||||
def->play_forever = false;
|
||||
}
|
||||
|
||||
/* fade priority: #F > #f, #d */
|
||||
if (tcfg->ignore_fade) {
|
||||
def->ignore_fade = 1;
|
||||
def->ignore_fade = true;
|
||||
}
|
||||
if (tcfg->fade_delay_set) {
|
||||
def->fade_delay = tcfg->fade_delay;
|
||||
def->fade_delay_set = 1;
|
||||
def->fade_delay_set = true;
|
||||
}
|
||||
if (tcfg->fade_time_set) {
|
||||
def->fade_time = tcfg->fade_time;
|
||||
def->fade_time_set = 1;
|
||||
def->fade_time_set = true;
|
||||
}
|
||||
|
||||
/* loop priority: #i > #e > #E (respect player's ignore too) */
|
||||
if (tcfg->really_force_loop) {
|
||||
//def->ignore_loop = 0;
|
||||
def->force_loop = 0;
|
||||
def->really_force_loop = 1;
|
||||
//def->ignore_loop = false;
|
||||
def->force_loop = false;
|
||||
def->really_force_loop = true;
|
||||
}
|
||||
if (tcfg->force_loop) {
|
||||
//def->ignore_loop = 0;
|
||||
def->force_loop = 1;
|
||||
def->really_force_loop = 0;
|
||||
//def->ignore_loop = false;
|
||||
def->force_loop = true;
|
||||
def->really_force_loop = false;
|
||||
}
|
||||
if (tcfg->ignore_loop) {
|
||||
def->ignore_loop = 1;
|
||||
def->force_loop = 0;
|
||||
def->really_force_loop = 0;
|
||||
def->ignore_loop = true;
|
||||
def->force_loop = false;
|
||||
def->really_force_loop = false;
|
||||
}
|
||||
|
||||
copy_time(&def->pad_begin_set, &def->pad_begin, &def->pad_begin_s, &tcfg->pad_begin_set, &tcfg->pad_begin, &tcfg->pad_begin_s);
|
||||
@ -69,7 +69,8 @@ static void load_default_config(play_config_t* def, play_config_t* tcfg) {
|
||||
def->is_txtp = tcfg->is_txtp;
|
||||
}
|
||||
|
||||
static void load_player_config(play_config_t* def, vgmstream_cfg_t* vcfg) {
|
||||
/* config that has been set externally by plugins */
|
||||
static void load_external_config(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;
|
||||
@ -77,31 +78,32 @@ static void load_player_config(play_config_t* def, vgmstream_cfg_t* vcfg) {
|
||||
def->ignore_fade = vcfg->ignore_fade;
|
||||
|
||||
def->loop_count = vcfg->loop_count;
|
||||
def->loop_count_set = 1;
|
||||
def->loop_count_set = true;
|
||||
def->fade_delay = vcfg->fade_delay;
|
||||
def->fade_delay_set = 1;
|
||||
def->fade_delay_set = true;
|
||||
def->fade_time = vcfg->fade_time;
|
||||
def->fade_time_set = 1;
|
||||
def->fade_time_set = true;
|
||||
}
|
||||
|
||||
/* apply play config to vgmstream */
|
||||
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(def, vcfg);
|
||||
def->config_set = 1;
|
||||
load_external_config(def, vcfg);
|
||||
def->config_set = true;
|
||||
|
||||
if (!vcfg->disable_config_override)
|
||||
load_default_config(def, tcfg);
|
||||
|
||||
if (!vcfg->allow_play_forever)
|
||||
def->play_forever = 0;
|
||||
def->play_forever = false;
|
||||
|
||||
/* copy final config back */
|
||||
*tcfg = *def;
|
||||
|
||||
vgmstream->config_enabled = def->config_set;
|
||||
setup_state_vgmstream(vgmstream);
|
||||
setup_vgmstream_play_state(vgmstream);
|
||||
}
|
185
src/base/play_state.c
Normal file
185
src/base/play_state.c
Normal file
@ -0,0 +1,185 @@
|
||||
#include "../vgmstream.h"
|
||||
//#include "../layout/layout.h"
|
||||
//#include "render.h"
|
||||
//#include "decode.h"
|
||||
//#include "mixing.h"
|
||||
//#include "plugins.h"
|
||||
|
||||
|
||||
|
||||
int vgmstream_get_play_forever(VGMSTREAM* vgmstream) {
|
||||
return vgmstream->config.play_forever;
|
||||
}
|
||||
|
||||
void vgmstream_set_play_forever(VGMSTREAM* vgmstream, int enabled) {
|
||||
/* sometimes we need to enable/disable right before playback
|
||||
* (play config is left untouched, should mix ok as this flag is only used during
|
||||
* render, while config is always prepared as if play forever wasn't enabled) */
|
||||
vgmstream->config.play_forever = enabled;
|
||||
setup_vgmstream(vgmstream); /* update config */
|
||||
}
|
||||
|
||||
int32_t vgmstream_get_samples(VGMSTREAM* vgmstream) {
|
||||
if (!vgmstream->config_enabled || !vgmstream->config.config_set)
|
||||
return vgmstream->num_samples;
|
||||
return vgmstream->pstate.play_duration;
|
||||
}
|
||||
|
||||
/* calculate samples based on player's config */
|
||||
int32_t get_vgmstream_play_samples(double looptimes, double fadeseconds, double fadedelayseconds, VGMSTREAM* vgmstream) {
|
||||
if (vgmstream->loop_flag) {
|
||||
if (vgmstream->loop_target == (int)looptimes) { /* set externally, as this function is info-only */
|
||||
/* Continue playing the file normally after looping, instead of fading.
|
||||
* Most files cut abruply after the loop, but some do have proper endings.
|
||||
* With looptimes = 1 this option should give the same output vs loop disabled */
|
||||
int loop_count = (int)looptimes; /* no half loops allowed */
|
||||
return vgmstream->loop_start_sample
|
||||
+ (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * loop_count
|
||||
+ (vgmstream->num_samples - vgmstream->loop_end_sample);
|
||||
}
|
||||
else {
|
||||
return vgmstream->loop_start_sample
|
||||
+ (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * looptimes
|
||||
+ (fadedelayseconds + fadeseconds) * vgmstream->sample_rate;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return vgmstream->num_samples;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* apply config like forced loops */
|
||||
static void setup_state_modifiers(VGMSTREAM* vgmstream) {
|
||||
play_config_t* pc = &vgmstream->config;
|
||||
|
||||
/* apply final config */
|
||||
if (pc->really_force_loop) {
|
||||
vgmstream_force_loop(vgmstream, true, 0, vgmstream->num_samples);
|
||||
}
|
||||
if (pc->force_loop && !vgmstream->loop_flag) {
|
||||
vgmstream_force_loop(vgmstream, true, 0, vgmstream->num_samples);
|
||||
}
|
||||
if (pc->ignore_loop) {
|
||||
vgmstream_force_loop(vgmstream, false, 0, 0);
|
||||
}
|
||||
|
||||
if (!vgmstream->loop_flag) {
|
||||
pc->play_forever = false;
|
||||
}
|
||||
if (pc->play_forever) {
|
||||
pc->ignore_fade = false;
|
||||
}
|
||||
|
||||
|
||||
/* loop N times, but also play stream end instead of fading out */
|
||||
if (pc->ignore_fade) {
|
||||
vgmstream_set_loop_target(vgmstream, (int)pc->loop_count);
|
||||
pc->fade_time = 0;
|
||||
pc->fade_delay = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* apply config like trims */
|
||||
static void setup_state_processing(VGMSTREAM* vgmstream) {
|
||||
play_state_t* ps = &vgmstream->pstate;
|
||||
play_config_t* pc = &vgmstream->config;
|
||||
double sample_rate = vgmstream->sample_rate;
|
||||
|
||||
/* time to samples */
|
||||
if (pc->pad_begin_s)
|
||||
pc->pad_begin = pc->pad_begin_s * sample_rate;
|
||||
if (pc->pad_end_s)
|
||||
pc->pad_end = pc->pad_end_s * sample_rate;
|
||||
if (pc->trim_begin_s)
|
||||
pc->trim_begin = pc->trim_begin_s * sample_rate;
|
||||
if (pc->trim_end_s)
|
||||
pc->trim_end = pc->trim_end_s * sample_rate;
|
||||
if (pc->body_time_s)
|
||||
pc->body_time = pc->body_time_s * sample_rate;
|
||||
//todo fade time also set to samples
|
||||
|
||||
/* samples before all decode */
|
||||
ps->pad_begin_duration = pc->pad_begin;
|
||||
|
||||
/* removed samples from first decode */
|
||||
ps->trim_begin_duration = pc->trim_begin;
|
||||
|
||||
/* main samples part */
|
||||
ps->body_duration = 0;
|
||||
if (pc->body_time) {
|
||||
ps->body_duration += pc->body_time; /* whether it loops or not */
|
||||
}
|
||||
else if (vgmstream->loop_flag) {
|
||||
double loop_count = 1.0;
|
||||
if (pc->loop_count_set) /* may set 0.0 on purpose I guess */
|
||||
loop_count = pc->loop_count;
|
||||
|
||||
ps->body_duration += vgmstream->loop_start_sample;
|
||||
if (pc->ignore_fade) {
|
||||
ps->body_duration += (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * (int)loop_count;
|
||||
ps->body_duration += (vgmstream->num_samples - vgmstream->loop_end_sample);
|
||||
}
|
||||
else {
|
||||
ps->body_duration += (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * loop_count;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ps->body_duration += vgmstream->num_samples;
|
||||
}
|
||||
|
||||
/* samples from some modify body */
|
||||
if (pc->trim_begin)
|
||||
ps->body_duration -= pc->trim_begin;
|
||||
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;
|
||||
|
||||
/* samples from fade part */
|
||||
if (pc->fade_time && vgmstream->loop_flag)
|
||||
ps->fade_duration = pc->fade_time * vgmstream->sample_rate;
|
||||
|
||||
/* samples from last part (anything beyond this is empty, unless play forever is set) */
|
||||
ps->pad_end_duration = pc->pad_end;
|
||||
|
||||
/* final count */
|
||||
ps->play_duration = ps->pad_begin_duration + ps->body_duration + ps->fade_duration + ps->pad_end_duration;
|
||||
ps->play_position = 0;
|
||||
|
||||
/* values too big can overflow, just ignore */
|
||||
if (ps->pad_begin_duration < 0)
|
||||
ps->pad_begin_duration = 0;
|
||||
if (ps->body_duration < 0)
|
||||
ps->body_duration = 0;
|
||||
if (ps->fade_duration < 0)
|
||||
ps->fade_duration = 0;
|
||||
if (ps->pad_end_duration < 0)
|
||||
ps->pad_end_duration = 0;
|
||||
if (ps->play_duration < 0)
|
||||
ps->play_duration = 0;
|
||||
|
||||
ps->pad_begin_left = ps->pad_begin_duration;
|
||||
ps->trim_begin_left = ps->trim_begin_duration;
|
||||
ps->fade_left = ps->fade_duration;
|
||||
ps->fade_start = ps->pad_begin_duration + ps->body_duration;
|
||||
//ps->pad_end_left = ps->pad_end_duration;
|
||||
ps->pad_end_start = ps->fade_start + ps->fade_duration;
|
||||
|
||||
/* other info (updated once mixing is enabled) */
|
||||
ps->input_channels = vgmstream->channels;
|
||||
ps->output_channels = vgmstream->channels;
|
||||
}
|
||||
|
||||
/* apply play config to internal state */
|
||||
void setup_vgmstream_play_state(VGMSTREAM* vgmstream) {
|
||||
if (!vgmstream->config.config_set)
|
||||
return;
|
||||
|
||||
setup_state_modifiers(vgmstream);
|
||||
setup_state_processing(vgmstream);
|
||||
|
||||
/* save new config for resets */
|
||||
setup_vgmstream(vgmstream);
|
||||
}
|
@ -47,179 +47,6 @@
|
||||
* This mainly applies to TXTP, segments/layers in metas usually don't need to trigger config mode.
|
||||
*/
|
||||
|
||||
|
||||
int vgmstream_get_play_forever(VGMSTREAM* vgmstream) {
|
||||
return vgmstream->config.play_forever;
|
||||
}
|
||||
|
||||
void vgmstream_set_play_forever(VGMSTREAM* vgmstream, int enabled) {
|
||||
/* sometimes we need to enable/disable right before playback
|
||||
* (play config is left untouched, should mix ok as this flag is only used during
|
||||
* render, while config is always prepared as if play forever wasn't enabled) */
|
||||
vgmstream->config.play_forever = enabled;
|
||||
setup_vgmstream(vgmstream); /* update config */
|
||||
}
|
||||
|
||||
int32_t vgmstream_get_samples(VGMSTREAM* vgmstream) {
|
||||
if (!vgmstream->config_enabled || !vgmstream->config.config_set)
|
||||
return vgmstream->num_samples;
|
||||
return vgmstream->pstate.play_duration;
|
||||
}
|
||||
|
||||
/* calculate samples based on player's config */
|
||||
int32_t get_vgmstream_play_samples(double looptimes, double fadeseconds, double fadedelayseconds, VGMSTREAM* vgmstream) {
|
||||
if (vgmstream->loop_flag) {
|
||||
if (vgmstream->loop_target == (int)looptimes) { /* set externally, as this function is info-only */
|
||||
/* Continue playing the file normally after looping, instead of fading.
|
||||
* Most files cut abruply after the loop, but some do have proper endings.
|
||||
* With looptimes = 1 this option should give the same output vs loop disabled */
|
||||
int loop_count = (int)looptimes; /* no half loops allowed */
|
||||
return vgmstream->loop_start_sample
|
||||
+ (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * loop_count
|
||||
+ (vgmstream->num_samples - vgmstream->loop_end_sample);
|
||||
}
|
||||
else {
|
||||
return vgmstream->loop_start_sample
|
||||
+ (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * looptimes
|
||||
+ (fadedelayseconds + fadeseconds) * vgmstream->sample_rate;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return vgmstream->num_samples;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void setup_state_modifiers(VGMSTREAM* vgmstream) {
|
||||
play_config_t* pc = &vgmstream->config;
|
||||
|
||||
/* apply final config */
|
||||
if (pc->really_force_loop) {
|
||||
vgmstream_force_loop(vgmstream, 1, 0,vgmstream->num_samples);
|
||||
}
|
||||
if (pc->force_loop && !vgmstream->loop_flag) {
|
||||
vgmstream_force_loop(vgmstream, 1, 0,vgmstream->num_samples);
|
||||
}
|
||||
if (pc->ignore_loop) {
|
||||
vgmstream_force_loop(vgmstream, 0, 0,0);
|
||||
}
|
||||
|
||||
if (!vgmstream->loop_flag) {
|
||||
pc->play_forever = 0;
|
||||
}
|
||||
if (pc->play_forever) {
|
||||
pc->ignore_fade = 0;
|
||||
}
|
||||
|
||||
|
||||
/* loop N times, but also play stream end instead of fading out */
|
||||
if (pc->ignore_fade) {
|
||||
vgmstream_set_loop_target(vgmstream, (int)pc->loop_count);
|
||||
pc->fade_time = 0;
|
||||
pc->fade_delay = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_state_processing(VGMSTREAM* vgmstream) {
|
||||
play_state_t* ps = &vgmstream->pstate;
|
||||
play_config_t* pc = &vgmstream->config;
|
||||
double sample_rate = vgmstream->sample_rate;
|
||||
|
||||
/* time to samples */
|
||||
if (pc->pad_begin_s)
|
||||
pc->pad_begin = pc->pad_begin_s * sample_rate;
|
||||
if (pc->pad_end_s)
|
||||
pc->pad_end = pc->pad_end_s * sample_rate;
|
||||
if (pc->trim_begin_s)
|
||||
pc->trim_begin = pc->trim_begin_s * sample_rate;
|
||||
if (pc->trim_end_s)
|
||||
pc->trim_end = pc->trim_end_s * sample_rate;
|
||||
if (pc->body_time_s)
|
||||
pc->body_time = pc->body_time_s * sample_rate;
|
||||
//todo fade time also set to samples
|
||||
|
||||
/* samples before all decode */
|
||||
ps->pad_begin_duration = pc->pad_begin;
|
||||
|
||||
/* removed samples from first decode */
|
||||
ps->trim_begin_duration = pc->trim_begin;
|
||||
|
||||
/* main samples part */
|
||||
ps->body_duration = 0;
|
||||
if (pc->body_time) {
|
||||
ps->body_duration += pc->body_time; /* whether it loops or not */
|
||||
}
|
||||
else if (vgmstream->loop_flag) {
|
||||
double loop_count = 1.0;
|
||||
if (pc->loop_count_set) /* may set 0.0 on purpose I guess */
|
||||
loop_count = pc->loop_count;
|
||||
|
||||
ps->body_duration += vgmstream->loop_start_sample;
|
||||
if (pc->ignore_fade) {
|
||||
ps->body_duration += (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * (int)loop_count;
|
||||
ps->body_duration += (vgmstream->num_samples - vgmstream->loop_end_sample);
|
||||
}
|
||||
else {
|
||||
ps->body_duration += (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * loop_count;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ps->body_duration += vgmstream->num_samples;
|
||||
}
|
||||
|
||||
/* samples from some modify body */
|
||||
if (pc->trim_begin)
|
||||
ps->body_duration -= pc->trim_begin;
|
||||
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;
|
||||
|
||||
/* samples from fade part */
|
||||
if (pc->fade_time && vgmstream->loop_flag)
|
||||
ps->fade_duration = pc->fade_time * vgmstream->sample_rate;
|
||||
|
||||
/* samples from last part (anything beyond this is empty, unless play forever is set) */
|
||||
ps->pad_end_duration = pc->pad_end;
|
||||
|
||||
/* final count */
|
||||
ps->play_duration = ps->pad_begin_duration + ps->body_duration + ps->fade_duration + ps->pad_end_duration;
|
||||
ps->play_position = 0;
|
||||
|
||||
/* values too big can overflow, just ignore */
|
||||
if (ps->pad_begin_duration < 0)
|
||||
ps->pad_begin_duration = 0;
|
||||
if (ps->body_duration < 0)
|
||||
ps->body_duration = 0;
|
||||
if (ps->fade_duration < 0)
|
||||
ps->fade_duration = 0;
|
||||
if (ps->pad_end_duration < 0)
|
||||
ps->pad_end_duration = 0;
|
||||
if (ps->play_duration < 0)
|
||||
ps->play_duration = 0;
|
||||
|
||||
ps->pad_begin_left = ps->pad_begin_duration;
|
||||
ps->trim_begin_left = ps->trim_begin_duration;
|
||||
ps->fade_left = ps->fade_duration;
|
||||
ps->fade_start = ps->pad_begin_duration + ps->body_duration;
|
||||
//ps->pad_end_left = ps->pad_end_duration;
|
||||
ps->pad_end_start = ps->fade_start + ps->fade_duration;
|
||||
|
||||
/* other info (updated once mixing is enabled) */
|
||||
ps->input_channels = vgmstream->channels;
|
||||
ps->output_channels = vgmstream->channels;
|
||||
}
|
||||
|
||||
void setup_state_vgmstream(VGMSTREAM* vgmstream) {
|
||||
if (!vgmstream->config.config_set)
|
||||
return;
|
||||
|
||||
setup_state_modifiers(vgmstream);
|
||||
setup_state_processing(vgmstream);
|
||||
setup_vgmstream(vgmstream); /* save current config for reset */
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void render_free(VGMSTREAM* vgmstream) {
|
||||
@ -333,8 +160,9 @@ int render_layout(sample_t* buf, int32_t sample_count, VGMSTREAM* vgmstream) {
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void render_trim(VGMSTREAM* vgmstream) {
|
||||
static void render_op_trim(VGMSTREAM* vgmstream) {
|
||||
sample_t* tmpbuf = vgmstream->tmpbuf;
|
||||
size_t tmpbuf_size = vgmstream->tmpbuf_size;
|
||||
int32_t buf_samples = tmpbuf_size / vgmstream->channels; /* base channels, no need to apply mixing */
|
||||
@ -350,7 +178,7 @@ static void render_trim(VGMSTREAM* vgmstream) {
|
||||
}
|
||||
}
|
||||
|
||||
static int render_pad_begin(VGMSTREAM* vgmstream, sample_t* buf, int samples_to_do) {
|
||||
static int render_op_pad_begin(VGMSTREAM* vgmstream, sample_t* buf, int samples_to_do) {
|
||||
int channels = vgmstream->pstate.output_channels;
|
||||
int to_do = vgmstream->pstate.pad_begin_left;
|
||||
if (to_do > samples_to_do)
|
||||
@ -362,7 +190,7 @@ static int render_pad_begin(VGMSTREAM* vgmstream, sample_t* buf, int samples_to_
|
||||
return to_do;
|
||||
}
|
||||
|
||||
static int render_fade(VGMSTREAM* vgmstream, sample_t* buf, int samples_left) {
|
||||
static int render_op_fade(VGMSTREAM* vgmstream, sample_t* buf, int samples_left) {
|
||||
play_state_t* ps = &vgmstream->pstate;
|
||||
//play_config_t* pc = &vgmstream->config;
|
||||
|
||||
@ -404,7 +232,7 @@ static int render_fade(VGMSTREAM* vgmstream, sample_t* buf, int samples_left) {
|
||||
}
|
||||
}
|
||||
|
||||
static int render_pad_end(VGMSTREAM* vgmstream, sample_t* buf, int samples_left) {
|
||||
static int render_op_pad_end(VGMSTREAM* vgmstream, sample_t* buf, int samples_left) {
|
||||
play_state_t* ps = &vgmstream->pstate;
|
||||
int channels = vgmstream->pstate.output_channels;
|
||||
int skip = 0;
|
||||
@ -428,6 +256,7 @@ static int render_pad_end(VGMSTREAM* vgmstream, sample_t* buf, int samples_left)
|
||||
return skip + to_do;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Decode data into sample buffer. Controls the "external" part of the decoding,
|
||||
* while layout/decode control the "internal" part. */
|
||||
@ -449,12 +278,12 @@ int render_vgmstream(sample_t* buf, int32_t sample_count, VGMSTREAM* vgmstream)
|
||||
|
||||
/* trim may go first since it doesn't need output nor changes totals */
|
||||
if (ps->trim_begin_left) {
|
||||
render_trim(vgmstream);
|
||||
render_op_trim(vgmstream);
|
||||
}
|
||||
|
||||
/* adds empty samples to buf */
|
||||
if (ps->pad_begin_left) {
|
||||
done = render_pad_begin(vgmstream, tmpbuf, samples_to_do);
|
||||
done = render_op_pad_begin(vgmstream, tmpbuf, samples_to_do);
|
||||
samples_done += done;
|
||||
samples_to_do -= done;
|
||||
tmpbuf += done * vgmstream->pstate.output_channels; /* as if mixed */
|
||||
@ -464,7 +293,7 @@ int render_vgmstream(sample_t* buf, int32_t sample_count, VGMSTREAM* vgmstream)
|
||||
if (!vgmstream->config.play_forever
|
||||
&& ps->play_position /*+ samples_to_do*/ >= ps->pad_end_start
|
||||
&& samples_to_do) {
|
||||
done = render_pad_end(vgmstream, tmpbuf, samples_to_do);
|
||||
done = render_op_pad_end(vgmstream, tmpbuf, samples_to_do);
|
||||
samples_done += done;
|
||||
samples_to_do -= done;
|
||||
tmpbuf += done * vgmstream->pstate.output_channels; /* as if mixed */
|
||||
@ -481,12 +310,12 @@ int render_vgmstream(sample_t* buf, int32_t sample_count, VGMSTREAM* vgmstream)
|
||||
if (!vgmstream->config.play_forever) {
|
||||
/* simple fadeout */
|
||||
if (ps->fade_left && ps->play_position + done >= ps->fade_start) {
|
||||
render_fade(vgmstream, tmpbuf, done);
|
||||
render_op_fade(vgmstream, tmpbuf, done);
|
||||
}
|
||||
|
||||
/* silence leftover buf samples (rarely used when no fade is set) */
|
||||
if (ps->play_position + done >= ps->pad_end_start) {
|
||||
render_pad_end(vgmstream, tmpbuf, done);
|
||||
render_op_pad_end(vgmstream, tmpbuf, done);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,6 @@
|
||||
<ClCompile Include="base\api_helpers.c" />
|
||||
<ClCompile Include="base\api_libsf.c" />
|
||||
<ClCompile Include="base\api_tags.c" />
|
||||
<ClCompile Include="base\config.c" />
|
||||
<ClCompile Include="base\decode.c" />
|
||||
<ClCompile Include="base\info.c" />
|
||||
<ClCompile Include="base\mixer.c" />
|
||||
@ -228,6 +227,8 @@
|
||||
<ClCompile Include="base\mixing.c" />
|
||||
<ClCompile Include="base\mixing_commands.c" />
|
||||
<ClCompile Include="base\mixing_macros.c" />
|
||||
<ClCompile Include="base\play_config.c" />
|
||||
<ClCompile Include="base\play_state.c" />
|
||||
<ClCompile Include="base\plugins.c" />
|
||||
<ClCompile Include="base\render.c" />
|
||||
<ClCompile Include="base\seek.c" />
|
||||
@ -630,7 +631,6 @@
|
||||
<ClCompile Include="meta\ps2_vgv.c" />
|
||||
<ClCompile Include="meta\ps2_vms.c" />
|
||||
<ClCompile Include="meta\ps2_wmus.c" />
|
||||
<ClCompile Include="meta\ps2_xa30.c" />
|
||||
<ClCompile Include="meta\psb.c" />
|
||||
<ClCompile Include="meta\psf.c" />
|
||||
<ClCompile Include="meta\psnd.c" />
|
||||
|
@ -487,9 +487,6 @@
|
||||
<ClCompile Include="base\api_tags.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\config.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\decode.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -514,6 +511,12 @@
|
||||
<ClCompile Include="base\mixing_macros.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\play_config.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\play_state.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\plugins.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -1720,9 +1723,6 @@
|
||||
<ClCompile Include="meta\ps2_wmus.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\ps2_xa30.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\psb.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -131,7 +131,7 @@ static void apply_settings(VGMSTREAM* vgmstream, txtp_entry_t* current) {
|
||||
|
||||
/* default play config (last after sample rate mods/mixing/etc) */
|
||||
txtp_copy_config(&vgmstream->config, ¤t->config);
|
||||
setup_state_vgmstream(vgmstream);
|
||||
setup_vgmstream_play_state(vgmstream);
|
||||
/* config is enabled in layouts or externally (for compatibility, since we don't know yet if this
|
||||
* VGMSTREAM will part of a layout, or is enabled externally to not mess up plugins's calcs) */
|
||||
}
|
||||
|
@ -186,8 +186,15 @@ typedef struct {
|
||||
bool allow_dual_stereo; /* search for dual stereo (file_L.ext + file_R.ext = single stereo file) */
|
||||
int format_id; /* internal format ID */
|
||||
|
||||
|
||||
/* decoder config/state */
|
||||
int codec_endian; /* little/big endian marker; name is left vague but usually means big endian */
|
||||
int codec_config; /* flags for codecs or layouts with minor variations; meaning is up to them (may change during decode) */
|
||||
bool codec_internal_updates; /* temp(?) kludge (see vgmstream_open_stream/decode) */
|
||||
int32_t ws_output_size; /* WS ADPCM: output bytes for this block */
|
||||
|
||||
/* layout/block state */
|
||||
int32_t current_sample; /* sample point within the file (for loop detection) */
|
||||
int32_t current_sample; /* sample point within the stream (for loop detection) */
|
||||
int32_t samples_into_block; /* number of samples into the current block/interleave/segment/etc */
|
||||
off_t current_block_offset; /* start of this block (offset of block header) */
|
||||
size_t current_block_size; /* size in usable bytes of the block we're in now (used to calculate num_samples per block) */
|
||||
@ -195,28 +202,24 @@ typedef struct {
|
||||
off_t next_block_offset; /* offset of header of the next block */
|
||||
size_t full_block_size; /* actual data size of an entire block (ie. may be fixed, include padding/headers, etc) */
|
||||
|
||||
/* loop state (saved when loop is hit to restore later) */
|
||||
/* layout/block state copy for loops (saved on loop_start and restored later on loop_end) */
|
||||
int32_t loop_current_sample; /* saved from current_sample (same as loop_start_sample, but more state-like) */
|
||||
int32_t loop_samples_into_block;/* saved from samples_into_block */
|
||||
off_t loop_block_offset; /* saved from current_block_offset */
|
||||
size_t loop_block_size; /* saved from current_block_size */
|
||||
int32_t loop_block_samples; /* saved from current_block_samples */
|
||||
off_t loop_next_block_offset; /* saved from next_block_offset */
|
||||
size_t loop_full_block_size; /* saved from full_block_size (probably unnecessary) */
|
||||
|
||||
bool hit_loop; /* save config when loop is hit, but first time only */
|
||||
|
||||
|
||||
/* decoder config/state */
|
||||
int codec_endian; /* little/big endian marker; name is left vague but usually means big endian */
|
||||
int codec_config; /* flags for codecs or layouts with minor variations; meaning is up to them */
|
||||
bool codec_internal_updates; /* temp(?) kludge (see vgmstream_open_stream/decode) */
|
||||
int32_t ws_output_size; /* WS ADPCM: output bytes for this block */
|
||||
|
||||
|
||||
/* main state */
|
||||
VGMSTREAMCHANNEL* ch; /* array of channels */
|
||||
VGMSTREAMCHANNEL* start_ch; /* shallow copy of channels as they were at the beginning of the stream (for resets) */
|
||||
VGMSTREAMCHANNEL* ch; /* array of channels with current offset + per-channel codec config */
|
||||
|
||||
VGMSTREAMCHANNEL* loop_ch; /* shallow copy of channels as they were at the loop point (for loops) */
|
||||
|
||||
void* start_vgmstream; /* shallow copy of the VGMSTREAM as it was at the beginning of the stream (for resets) */
|
||||
VGMSTREAMCHANNEL* start_ch; /* shallow copy of channels as they were at the beginning of the stream (for resets) */
|
||||
|
||||
void* mixer; /* state for mixing effects */
|
||||
|
||||
@ -242,7 +245,6 @@ typedef struct {
|
||||
} VGMSTREAM;
|
||||
|
||||
|
||||
// VGMStream description in structure format
|
||||
typedef struct {
|
||||
int sample_rate;
|
||||
int channels;
|
||||
@ -326,11 +328,10 @@ void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t ou
|
||||
void get_vgmstream_layout_description(VGMSTREAM* vgmstream, char* out, size_t out_size);
|
||||
void get_vgmstream_meta_description(VGMSTREAM* vgmstream, char* out, size_t out_size);
|
||||
|
||||
//TODO: remove, unused internally
|
||||
/* calculate the number of samples to be played based on looping parameters */
|
||||
int32_t get_vgmstream_play_samples(double looptimes, double fadeseconds, double fadedelayseconds, VGMSTREAM* vgmstream);
|
||||
|
||||
void setup_state_vgmstream(VGMSTREAM* vgmstream);
|
||||
|
||||
/* Force enable/disable internal looping. Should be done before playing anything (or after reset),
|
||||
* and not all codecs support arbitrary loop values ATM. */
|
||||
void vgmstream_force_loop(VGMSTREAM* vgmstream, int loop_flag, int loop_start_sample, int loop_end_sample);
|
||||
@ -338,4 +339,6 @@ void vgmstream_force_loop(VGMSTREAM* vgmstream, int loop_flag, int loop_start_sa
|
||||
/* Set number of max loops to do, then play up to stream end (for songs with proper endings) */
|
||||
void vgmstream_set_loop_target(VGMSTREAM* vgmstream, int loop_target);
|
||||
|
||||
void setup_vgmstream_play_state(VGMSTREAM* vgmstream);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user