diff --git a/src/base/seek.c b/src/base/seek.c index aa5407d7..cfa80b0d 100644 --- a/src/base/seek.c +++ b/src/base/seek.c @@ -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); - int32_t decode_samples = 0; + int32_t decode_samples; play_state_t* ps = &vgmstream->pstate; 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; /* seek=10 would be seekr=10-5+3=8 inside decoder */ - int32_t seek_relative = seek_sample; - if (is_config) - seek_relative = seek_relative - ps->pad_begin_duration + ps->trim_begin_duration; + int32_t seek_relative = seek_sample - 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 */ if (!is_looped && seek_relative < vgmstream->current_sample) { /* 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 { /* 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_seek = (seek_relative - vgmstream->loop_start_sample) % loop_body; - int loop_count = loop_seek / loop_body; + //int32_t loop_outr = (vgmstream->num_samples - vgmstream->loop_end_sample); + int32_t loop_part = (vgmstream->loop_end_sample - vgmstream->loop_start_sample); /* samples of 1 looped part */ + 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) */ 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); - //;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); } - /* 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 || 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); } - 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 - 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); + //;VGM_LOG("SEEK: outro outside / seek=%i, count=%i\n", decode_samples, loop_seek, loop_count); } - + + int32_t loop_curr = vgmstream->current_sample - vgmstream->loop_start_sample; if (loop_seek < loop_curr) { - decode_samples += loop_seek; + decode_samples = loop_seek; seek_force_loop_end(vgmstream, loop_count); //;VGM_LOG("SEEK: loop reset / dec=%i, loop=%i\n", decode_samples, loop_count); } else { - decode_samples += (loop_seek - loop_curr); - //vgmstream->loop_count = loop_count - 1; //todo + decode_samples = (loop_seek - loop_curr); + vgmstream->loop_count = 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 + ps->fade_duration) { 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); } } - /* 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); - ;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); 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 */ @@ -230,16 +223,15 @@ void seek_vgmstream(VGMSTREAM* vgmstream, int32_t seek_sample) { if (!is_looped) 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) */ } /* body: seek relative to decoder's current sample */ else { #if 0 - //TODO issues: handles seek into loops number N correctly, and into fade region - //- handle looping within - //- handle + //TODO calculate samples into loop number N, and into fade region (segmented layout can only seek to loop start) + /* optimize as layouts can seek faster internally */ if (vgmstream->layout_type == layout_segmented) { seek_layout_segmented(vgmstream, seek_sample); @@ -249,10 +241,15 @@ void seek_vgmstream(VGMSTREAM* vgmstream, int32_t seek_sample) { } else #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; + } } - - vgmstream->pstate.play_position = seek_sample; + if (is_config) + vgmstream->pstate.play_position = seek_sample; }