From 9e9495168cef4fd74b7bf0c6f0e373feaacdafa2 Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 15 Feb 2019 18:36:12 +0100 Subject: [PATCH] Add TXTP "loop_mode=keep" for intro+main songs that also loop normally --- src/layout/segmented.c | 48 +++++++++++++++++++++++++++++------------- src/meta/txtp.c | 20 ++++++++++++++++-- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/src/layout/segmented.c b/src/layout/segmented.c index ff87c68e..4350e717 100644 --- a/src/layout/segmented.c +++ b/src/layout/segmented.c @@ -6,7 +6,7 @@ * Chains together sequential vgmstreams, for data divided into separate sections or files * (like one part for intro and other for loop segments, which may even use different codecs). */ void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { - int samples_written = 0; + int samples_written = 0, loop_samples_skip = 0; segmented_layout_data *data = vgmstream->layout_data; @@ -16,28 +16,34 @@ void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { - /* handle looping, finding loop segment */ - int loop_segment = 0, samples = 0, loop_samples_skip = 0; - while (samples < vgmstream->num_samples) { + int segment, loop_segment, total_samples; + + /* handle looping by finding loop segment and loop_start inside that segment */ + loop_segment = 0; + total_samples = 0; + while (total_samples < vgmstream->num_samples) { int32_t segment_samples = data->segments[loop_segment]->num_samples; - if (vgmstream->loop_start_sample >= samples && vgmstream->loop_start_sample < samples + segment_samples) { - loop_samples_skip = vgmstream->loop_start_sample - samples; + + if (vgmstream->loop_start_sample >= total_samples && vgmstream->loop_start_sample < total_samples + segment_samples) { + loop_samples_skip = vgmstream->loop_start_sample - total_samples; break; /* loop_start falls within loop_segment's samples */ } - samples += segment_samples; + total_samples += segment_samples; loop_segment++; } + if (loop_segment == data->segment_count) { VGM_LOG("segmented_layout: can't find loop segment\n"); loop_segment = 0; } - if (loop_samples_skip > 0) { - VGM_LOG("segmented_layout: loop starts after %i samples\n", loop_samples_skip); - //todo skip/fix, but probably won't happen - } data->current_segment = loop_segment; - reset_vgmstream(data->segments[data->current_segment]); + + /* loops can span multiple segments */ + for (segment = loop_segment; segment < data->segment_count; segment++) { + reset_vgmstream(data->segments[segment]); + } + vgmstream->samples_into_block = 0; continue; } @@ -46,6 +52,12 @@ void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM if (samples_to_do > sample_count - samples_written) samples_to_do = sample_count - samples_written; + /* segment looping: discard until actual start */ + if (loop_samples_skip > 0) { + if (samples_to_do > loop_samples_skip) + samples_to_do = loop_samples_skip; + } + /* detect segment change and restart */ if (samples_to_do == 0) { data->current_segment++; @@ -57,9 +69,15 @@ void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM render_vgmstream(&buffer[samples_written*data->segments[data->current_segment]->channels], samples_to_do,data->segments[data->current_segment]); - samples_written += samples_to_do; - vgmstream->current_sample += samples_to_do; - vgmstream->samples_into_block += samples_to_do; + if (loop_samples_skip > 0) { + loop_samples_skip -= samples_to_do; + vgmstream->samples_into_block += samples_to_do; + } + else { + samples_written += samples_to_do; + vgmstream->current_sample += samples_to_do; + vgmstream->samples_into_block += samples_to_do; + } } } diff --git a/src/meta/txtp.c b/src/meta/txtp.c index faa6c496..a54fa6d5 100644 --- a/src/meta/txtp.c +++ b/src/meta/txtp.c @@ -32,6 +32,7 @@ typedef struct { int default_entry_set; size_t is_layered; + int is_loop_keep; } txtp_header; static txtp_header* parse_txtp(STREAMFILE* streamFile); @@ -148,17 +149,24 @@ VGMSTREAM * init_vgmstream_txtp(STREAMFILE *streamFile) { if (txtp->loop_start_segment && !txtp->loop_end_segment) txtp->loop_end_segment = txtp->entry_count; loop_flag = (txtp->loop_start_segment > 0 && txtp->loop_start_segment <= txtp->entry_count); + num_samples = 0; for (i = 0; i < data_s->segment_count; i++) { if (loop_flag && txtp->loop_start_segment == i+1) { - loop_start_sample = num_samples; + if (txtp->is_loop_keep /*&& data_s->segments[i]->loop_start_sample*/) + loop_start_sample = num_samples + data_s->segments[i]->loop_start_sample; + else + loop_start_sample = num_samples; } num_samples += data_s->segments[i]->num_samples; if (loop_flag && txtp->loop_end_segment == i+1) { - loop_end_sample = num_samples; + if (txtp->is_loop_keep && data_s->segments[i]->loop_end_sample) + loop_end_sample = num_samples - data_s->segments[i]->num_samples + data_s->segments[i]->loop_end_sample; + else + loop_end_sample = num_samples; } } @@ -475,6 +483,14 @@ static int parse_keyval(txtp_header * txtp, const char * key, const char * val) goto fail; } } + else if (0==strcmp(key,"loop_mode")) { + if (0==strcmp(val,"keep")) { + txtp->is_loop_keep = 1; + } + else { + goto fail; + } + } else if (0==strcmp(key,"commands")) { char val2[TXT_LINE_MAX]; strcpy(val2, val); /* copy since val is modified here but probably not important */