Fix seeking into the outro region when loop+outro is set

This commit is contained in:
bnnm 2024-03-31 16:22:17 +02:00
parent 8097e772f4
commit 843a0e83a4

View File

@ -34,10 +34,10 @@ static void seek_force_decode(VGMSTREAM* vgmstream, int samples) {
} }
static void seek_layout_standard(VGMSTREAM* vgmstream, int32_t seek_sample) { static void seek_body(VGMSTREAM* vgmstream, int32_t seek_sample) {
//;VGM_LOG("SEEK: body / seekr=%i, curr=%i\n", seek_sample, vgmstream->current_sample); //;VGM_LOG("SEEK: body / seekr=%i, curr=%i\n", seek_sample, vgmstream->current_sample);
int32_t decode_samples = 0; int32_t decode_samples;
play_state_t* ps = &vgmstream->pstate; play_state_t* ps = &vgmstream->pstate;
bool is_looped = vgmstream->loop_flag || vgmstream->loop_target > 0; /* loop target disabled loop flag during decode */ bool is_looped = vgmstream->loop_flag || vgmstream->loop_target > 0; /* loop target disabled loop flag during decode */
@ -45,13 +45,9 @@ static void seek_layout_standard(VGMSTREAM* vgmstream, int32_t seek_sample) {
int play_forever = vgmstream->config.play_forever; int play_forever = vgmstream->config.play_forever;
/* seek=10 would be seekr=10-5+3=8 inside decoder */ /* seek=10 would be seekr=10-5+3=8 inside decoder */
int32_t seek_relative = seek_sample; int32_t seek_relative = seek_sample - ps->pad_begin_duration + ps->trim_begin_duration;
if (is_config)
seek_relative = seek_relative - ps->pad_begin_duration + ps->trim_begin_duration;
//;VGM_LOG("SEEK: body / seekr=%i, curr=%i\n", seek_relative, vgmstream->current_sample);
/* seek can be in some part of the body, depending on looping/decoder's current position/etc */ /* seek can be in some part of the body, depending on looping/decoder's current position/etc */
if (!is_looped && seek_relative < vgmstream->current_sample) { if (!is_looped && seek_relative < vgmstream->current_sample) {
/* non-looped seek before decoder's position: restart + consume (seekr=50s, curr=95 > restart + decode=50s) */ /* non-looped seek before decoder's position: restart + consume (seekr=50s, curr=95 > restart + decode=50s) */
@ -92,9 +88,12 @@ static void seek_layout_standard(VGMSTREAM* vgmstream, int32_t seek_sample) {
} }
else { else {
/* looped seek after loop start: can be clamped between loop parts (relative to decoder's current_sample) to minimize decoding */ /* looped seek after loop start: can be clamped between loop parts (relative to decoder's current_sample) to minimize decoding */
int32_t loop_body = (vgmstream->loop_end_sample - vgmstream->loop_start_sample); //int32_t loop_outr = (vgmstream->num_samples - vgmstream->loop_end_sample);
int32_t loop_seek = (seek_relative - vgmstream->loop_start_sample) % loop_body; int32_t loop_part = (vgmstream->loop_end_sample - vgmstream->loop_start_sample); /* samples of 1 looped part */
int loop_count = loop_seek / loop_body; int32_t loop_seek = (seek_relative - vgmstream->loop_start_sample); /* samples within loop region */
int loop_count = loop_seek / loop_part; /* not accurate when loop_target is set */
loop_seek = loop_seek % loop_part; /* clamp within single loop after calcs */
/* current must have reached loop start at some point, otherwise force it (NOTE: some layouts don't actually set hit_loop) */ /* current must have reached loop start at some point, otherwise force it (NOTE: some layouts don't actually set hit_loop) */
if (!vgmstream->hit_loop) { if (!vgmstream->hit_loop) {
@ -104,40 +103,39 @@ static void seek_layout_standard(VGMSTREAM* vgmstream, int32_t seek_sample) {
} }
int32_t skip_samples = (vgmstream->loop_start_sample - vgmstream->current_sample); int32_t skip_samples = (vgmstream->loop_start_sample - vgmstream->current_sample);
//;VGM_LOG("SEEK: must loop / skip=%i, curr=%i\n", skip_samples, vgmstream->current_sample); //;VGM_LOG("SEEK: force loop region / skip=%i, curr=%i\n", skip_samples, vgmstream->current_sample);
seek_force_decode(vgmstream, skip_samples); seek_force_decode(vgmstream, skip_samples);
} }
/* current must be in loop area (may happen at start) */ /* current must be in loop area (may happen at start since it's smaller than loop_end) */
if (vgmstream->current_sample < vgmstream->loop_start_sample if (vgmstream->current_sample < vgmstream->loop_start_sample
|| vgmstream->current_sample < vgmstream->loop_end_sample) { || vgmstream->current_sample < vgmstream->loop_end_sample) {
;VGM_LOG("SEEK: outside loop area / curr=%i, ls=%i, le=%i\n", vgmstream->current_sample, vgmstream->current_sample, vgmstream->loop_end_sample); //;VGM_LOG("SEEK: outside loop region / curr=%i, ls=%i, le=%i\n", vgmstream->current_sample, vgmstream->current_sample, vgmstream->loop_end_sample);
seek_force_loop_end(vgmstream, 0); seek_force_loop_end(vgmstream, 0);
} }
int32_t loop_curr = vgmstream->current_sample - vgmstream->loop_start_sample; //;VGM_LOG("SEEK: in loop region / seekr=%i, seekl=%i, loops=%i, dec_curr=%i\n", seek_relative, loop_seek, loop_count, loop_curr);
//;VGM_LOG("SEEK: in loop / seekr=%i, seekl=%i, loops=%i, cur=%i, dec=%i\n", seek_relative, loop_seek, loop_count, loop_curr, decode_samples); /* when "ignore fade" is set and seek falls into the outro part (loop count if bigged than expected), adjust seek
* to do a whole part + outro samples (should probably calculate correct loop_count before but...) */
if (vgmstream->loop_target && loop_count >= vgmstream->loop_target) {
loop_seek = loop_part + (seek_relative - vgmstream->loop_start_sample) - vgmstream->loop_target * loop_part;
loop_count = vgmstream->loop_target - 1; /* so seek_force_loop_end detection kicks in and adds +1 */
/* when "ignore fade" is used and seek falls into non-fade part, this needs to seek right before it //;VGM_LOG("SEEK: outro outside / seek=%i, count=%i\n", decode_samples, loop_seek, loop_count);
so when calling seek_force_loop_end detection kicks in, and non-fade then decodes normally */
if (vgmstream->loop_target && vgmstream->loop_target == loop_count) {
loop_seek = loop_body;
//decode_samples += loop_seek;
//VGM_LOG("outside!: %i\n", loop_body);
} }
int32_t loop_curr = vgmstream->current_sample - vgmstream->loop_start_sample;
if (loop_seek < loop_curr) { if (loop_seek < loop_curr) {
decode_samples += loop_seek; decode_samples = loop_seek;
seek_force_loop_end(vgmstream, loop_count); seek_force_loop_end(vgmstream, loop_count);
//;VGM_LOG("SEEK: loop reset / dec=%i, loop=%i\n", decode_samples, loop_count); //;VGM_LOG("SEEK: loop reset / dec=%i, loop=%i\n", decode_samples, loop_count);
} }
else { else {
decode_samples += (loop_seek - loop_curr); decode_samples = (loop_seek - loop_curr);
//vgmstream->loop_count = loop_count - 1; //todo vgmstream->loop_count = loop_count;
//;VGM_LOG("SEEK: loop forward / dec=%i, loop=%i\n", decode_samples, loop_count); //;VGM_LOG("SEEK: loop forward / dec=%i, loop=%i\n", decode_samples, loop_count);
} }
@ -147,18 +145,13 @@ static void seek_layout_standard(VGMSTREAM* vgmstream, int32_t seek_sample) {
&& seek_sample >= ps->pad_begin_duration + ps->body_duration && seek_sample >= ps->pad_begin_duration + ps->body_duration
&& seek_sample < ps->pad_begin_duration + ps->body_duration + ps->fade_duration) { && seek_sample < ps->pad_begin_duration + ps->body_duration + ps->fade_duration) {
ps->fade_left = ps->pad_begin_duration + ps->body_duration + ps->fade_duration - seek_sample; ps->fade_left = ps->pad_begin_duration + ps->body_duration + ps->fade_duration - seek_sample;
//;VGM_LOG("SEEK: in fade / fade=%i, %i\n", ps->fade_left, ps->fade_duration); //;VGM_LOG("SEEK: in fade / fade=%i, %i\n", ps->fade_left, ps->fade_duration);
} }
} }
/* done at the end in case of reset */
if (is_config) {
ps->pad_begin_left = 0;
ps->trim_begin_left = 0;
}
seek_force_decode(vgmstream, decode_samples); seek_force_decode(vgmstream, decode_samples);
;VGM_LOG("SEEK: force=%i, current=%i\n", decode_samples, vgmstream->current_sample); //;VGM_LOG("SEEK: decode=%i, current=%i\n", decode_samples, vgmstream->current_sample);
} }
@ -220,7 +213,7 @@ void seek_vgmstream(VGMSTREAM* vgmstream, int32_t seek_sample) {
reset_vgmstream(vgmstream); reset_vgmstream(vgmstream);
ps->pad_begin_left = ps->pad_begin_duration - seek_sample; ps->pad_begin_left = ps->pad_begin_duration - seek_sample;
//;VGM_LOG("SEEK: pad start / dec=%i\n", decode_samples); //;VGM_LOG("SEEK: pad start / dec=%i\n", 0);
} }
/* pad end and beyond: ignored */ /* pad end and beyond: ignored */
@ -230,16 +223,15 @@ void seek_vgmstream(VGMSTREAM* vgmstream, int32_t seek_sample) {
if (!is_looped) if (!is_looped)
vgmstream->current_sample = vgmstream->num_samples + 1; vgmstream->current_sample = vgmstream->num_samples + 1;
//;VGM_LOG("SEEK: end silence / dec=%i\n", decode_samples); //;VGM_LOG("SEEK: end silence / dec=%i\n", 0);
/* looping decoder state isn't changed (seek backwards could use current sample) */ /* looping decoder state isn't changed (seek backwards could use current sample) */
} }
/* body: seek relative to decoder's current sample */ /* body: seek relative to decoder's current sample */
else { else {
#if 0 #if 0
//TODO issues: handles seek into loops number N correctly, and into fade region //TODO calculate samples into loop number N, and into fade region (segmented layout can only seek to loop start)
//- handle looping within
//- handle
/* optimize as layouts can seek faster internally */ /* optimize as layouts can seek faster internally */
if (vgmstream->layout_type == layout_segmented) { if (vgmstream->layout_type == layout_segmented) {
seek_layout_segmented(vgmstream, seek_sample); seek_layout_segmented(vgmstream, seek_sample);
@ -249,10 +241,15 @@ void seek_vgmstream(VGMSTREAM* vgmstream, int32_t seek_sample) {
} }
else else
#endif #endif
seek_layout_standard(vgmstream, seek_sample); seek_body(vgmstream, seek_sample);
/* done at the end in case of reset (that restores these values) */
if (is_config) {
ps->pad_begin_left = 0;
ps->trim_begin_left = 0;
}
} }
if (is_config)
vgmstream->pstate.play_position = seek_sample; vgmstream->pstate.play_position = seek_sample;
} }