mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-12 09:40:51 +01:00
Add TXTP "loop_mode=keep" for intro+main songs that also loop normally
This commit is contained in:
parent
a49d9851a1
commit
9e9495168c
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user