mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-30 20:03:44 +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
|
* 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). */
|
* (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) {
|
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;
|
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)) {
|
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
|
||||||
/* handle looping, finding loop segment */
|
int segment, loop_segment, total_samples;
|
||||||
int loop_segment = 0, samples = 0, loop_samples_skip = 0;
|
|
||||||
while (samples < vgmstream->num_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;
|
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 */
|
break; /* loop_start falls within loop_segment's samples */
|
||||||
}
|
}
|
||||||
samples += segment_samples;
|
total_samples += segment_samples;
|
||||||
loop_segment++;
|
loop_segment++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loop_segment == data->segment_count) {
|
if (loop_segment == data->segment_count) {
|
||||||
VGM_LOG("segmented_layout: can't find loop segment\n");
|
VGM_LOG("segmented_layout: can't find loop segment\n");
|
||||||
loop_segment = 0;
|
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;
|
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;
|
vgmstream->samples_into_block = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -46,6 +52,12 @@ void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM
|
|||||||
if (samples_to_do > sample_count - samples_written)
|
if (samples_to_do > sample_count - samples_written)
|
||||||
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 */
|
/* detect segment change and restart */
|
||||||
if (samples_to_do == 0) {
|
if (samples_to_do == 0) {
|
||||||
data->current_segment++;
|
data->current_segment++;
|
||||||
@ -57,10 +69,16 @@ void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM
|
|||||||
render_vgmstream(&buffer[samples_written*data->segments[data->current_segment]->channels],
|
render_vgmstream(&buffer[samples_written*data->segments[data->current_segment]->channels],
|
||||||
samples_to_do,data->segments[data->current_segment]);
|
samples_to_do,data->segments[data->current_segment]);
|
||||||
|
|
||||||
|
if (loop_samples_skip > 0) {
|
||||||
|
loop_samples_skip -= samples_to_do;
|
||||||
|
vgmstream->samples_into_block += samples_to_do;
|
||||||
|
}
|
||||||
|
else {
|
||||||
samples_written += samples_to_do;
|
samples_written += samples_to_do;
|
||||||
vgmstream->current_sample += samples_to_do;
|
vgmstream->current_sample += samples_to_do;
|
||||||
vgmstream->samples_into_block += samples_to_do;
|
vgmstream->samples_into_block += samples_to_do;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ typedef struct {
|
|||||||
int default_entry_set;
|
int default_entry_set;
|
||||||
|
|
||||||
size_t is_layered;
|
size_t is_layered;
|
||||||
|
int is_loop_keep;
|
||||||
} txtp_header;
|
} txtp_header;
|
||||||
|
|
||||||
static txtp_header* parse_txtp(STREAMFILE* streamFile);
|
static txtp_header* parse_txtp(STREAMFILE* streamFile);
|
||||||
@ -148,16 +149,23 @@ VGMSTREAM * init_vgmstream_txtp(STREAMFILE *streamFile) {
|
|||||||
if (txtp->loop_start_segment && !txtp->loop_end_segment)
|
if (txtp->loop_start_segment && !txtp->loop_end_segment)
|
||||||
txtp->loop_end_segment = txtp->entry_count;
|
txtp->loop_end_segment = txtp->entry_count;
|
||||||
loop_flag = (txtp->loop_start_segment > 0 && txtp->loop_start_segment <= txtp->entry_count);
|
loop_flag = (txtp->loop_start_segment > 0 && txtp->loop_start_segment <= txtp->entry_count);
|
||||||
|
|
||||||
num_samples = 0;
|
num_samples = 0;
|
||||||
for (i = 0; i < data_s->segment_count; i++) {
|
for (i = 0; i < data_s->segment_count; i++) {
|
||||||
|
|
||||||
if (loop_flag && txtp->loop_start_segment == i+1) {
|
if (loop_flag && txtp->loop_start_segment == i+1) {
|
||||||
|
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;
|
loop_start_sample = num_samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
num_samples += data_s->segments[i]->num_samples;
|
num_samples += data_s->segments[i]->num_samples;
|
||||||
|
|
||||||
if (loop_flag && txtp->loop_end_segment == i+1) {
|
if (loop_flag && txtp->loop_end_segment == i+1) {
|
||||||
|
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;
|
loop_end_sample = num_samples;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -475,6 +483,14 @@ static int parse_keyval(txtp_header * txtp, const char * key, const char * val)
|
|||||||
goto fail;
|
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")) {
|
else if (0==strcmp(key,"commands")) {
|
||||||
char val2[TXT_LINE_MAX];
|
char val2[TXT_LINE_MAX];
|
||||||
strcpy(val2, val); /* copy since val is modified here but probably not important */
|
strcpy(val2, val); /* copy since val is modified here but probably not important */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user