Minor layout cleanup + doc

This commit is contained in:
bnnm 2018-08-25 20:46:54 +02:00
parent 3765831dbe
commit 3130eebf0c
6 changed files with 119 additions and 86 deletions

View File

@ -1,16 +1,20 @@
#include "layout.h"
#include "../vgmstream.h"
static void block_update(VGMSTREAM * vgmstream);
/* Decodes samples for blocked streams.
* Data is divided into headered blocks with a bunch of data. The layout calls external helper functions
* when a block is decoded, and those must parse the new block and move offsets accordingly. */
void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written=0;
int samples_written = 0;
int frame_size, samples_per_frame, samples_this_block;
int frame_size = get_vgmstream_frame_size(vgmstream);
int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
int samples_this_block;
frame_size = get_vgmstream_frame_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
samples_this_block = 0;
/* get samples in the current block */
if (vgmstream->current_block_samples) {
samples_this_block = vgmstream->current_block_samples;
} else if (frame_size == 0) { /* assume 4 bit */ //TODO: get_vgmstream_frame_size() really should return bits... */
@ -19,12 +23,13 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame;
}
/* decode all samples */
while (samples_written < sample_count) {
int samples_to_do;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
/* on loop those values are changed */
/* handle looping, readjust back to loop start values */
if (vgmstream->current_block_samples) {
samples_this_block = vgmstream->current_block_samples;
} else if (frame_size == 0) { /* assume 4 bit */ //TODO: get_vgmstream_frame_size() really should return bits... */
@ -35,26 +40,26 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
continue;
}
/* probably block bug or EOF, next calcs would give wrong values and buffer segfaults */
if (samples_this_block < 0) {
/* probably block bug or EOF, next calcs would give wrong values/segfaults/infinite loop */
VGM_LOG("layout_blocked: wrong block samples at 0x%lx\n", vgmstream->current_block_offset);
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample));
break; /* probable infinite loop otherwise */
break;
}
/* probably block bug or EOF, block functions won't be able to read anything useful */
if (vgmstream->current_block_offset < 0 || vgmstream->current_block_offset == 0xFFFFFFFF) {
/* probably block bug or EOF, block functions won't be able to read anything useful/infinite loop */
VGM_LOG("layout_blocked: wrong block offset found\n");
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample));
break; /* probable infinite loop otherwise */
break;
}
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
if (samples_written + samples_to_do > sample_count)
if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written;
/* samples_this_block = 0 is allowed (empty block, do nothing then move to next block) */
if (samples_to_do > 0) {
/* samples_this_block = 0 is allowed (empty block, do nothing then move to next block) */
decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer);
}
@ -64,15 +69,13 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
/* move to next block when all samples are consumed */
if (vgmstream->samples_into_block==samples_this_block
/*&& vgmstream->current_sample < vgmstream->num_samples*/) { /* don't go past last block */
if (vgmstream->samples_into_block == samples_this_block
/*&& vgmstream->current_sample < vgmstream->num_samples*/) { /* don't go past last block */ //todo
block_update(vgmstream);
/* for VBR these may change */
/* update since these may change each block */
frame_size = get_vgmstream_frame_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
/* get samples in the current block */
if (vgmstream->current_block_samples) {
samples_this_block = vgmstream->current_block_samples;
} else if (frame_size == 0) { /* assume 4 bit */ //TODO: get_vgmstream_frame_size() really should return bits... */
@ -87,7 +90,7 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
}
}
/* helper functions to parse new block */
static void block_update(VGMSTREAM * vgmstream) {
switch (vgmstream->layout_type) {
case layout_blocked_ast:

View File

@ -1,33 +1,39 @@
#include "layout.h"
#include "../vgmstream.h"
/* Decodes samples for flat streams.
* Data forms a single stream, and the decoder may internally skip chunks and move offsets as needed. */
void render_vgmstream_flat(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written=0;
int samples_written = 0;
int samples_per_frame, samples_this_block;
const int samples_this_block = vgmstream->num_samples;
int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
samples_this_block = vgmstream->num_samples; /* do all samples if possible */
while (samples_written<sample_count) {
while (samples_written < sample_count) {
int samples_to_do;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
/* handle looping */
continue;
}
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
if (samples_written+samples_to_do > sample_count)
samples_to_do=sample_count-samples_written;
if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written;
if (!samples_to_do) {
memset(buffer + samples_written * vgmstream->channels, 0, sizeof(sample) * vgmstream->channels * (sample_count - samples_written));
return;
if (samples_to_do == 0) {
VGM_LOG("layout_flat: wrong samples_to_do found\n");
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample));
break;
}
decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer);
samples_written += samples_to_do;
vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block+=samples_to_do;
vgmstream->samples_into_block += samples_to_do;
}
}

View File

@ -1,29 +1,35 @@
#include "layout.h"
#include "../vgmstream.h"
/* Decodes samples for interleaved streams.
* Data has interleaved chunks per channel, and once one is decoded the layout moves offsets,
* skipping other chunks (essentially a simplified variety of blocked layout).
* Incompatible with decoders that move offsets. */
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written=0;
int frame_size = get_vgmstream_frame_size(vgmstream);
int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
int samples_this_block;
int samples_written = 0;
int frame_size, samples_per_frame, samples_this_block;
int has_interleave_last = vgmstream->interleave_last_block_size && vgmstream->channels > 1;
frame_size = get_vgmstream_frame_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame;
if (vgmstream->interleave_last_block_size && vgmstream->channels > 1 &&
vgmstream->current_sample - vgmstream->samples_into_block + samples_this_block> vgmstream->num_samples) {
if (has_interleave_last &&
vgmstream->current_sample - vgmstream->samples_into_block + samples_this_block > vgmstream->num_samples) {
/* adjust values again if inside last interleave */
frame_size = get_vgmstream_shortframe_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream);
samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame;
}
while (samples_written<sample_count) {
while (samples_written < sample_count) {
int samples_to_do;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
/* we assume that the loop is not back into a short block */
if (vgmstream->interleave_last_block_size && vgmstream->channels > 1) {
/* handle looping, restore standard interleave sizes */
if (has_interleave_last) { /* assumes that won't loop back into a interleave_last */
frame_size = get_vgmstream_frame_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
samples_this_block = vgmstream->interleave_block_size / frame_size * samples_per_frame;
@ -32,33 +38,43 @@ void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREA
}
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
/*printf("vgmstream_samples_to_do(samples_this_block=%d,samples_per_frame=%d,vgmstream) returns %d\n",samples_this_block,samples_per_frame,samples_to_do);*/
if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written;
if (samples_written+samples_to_do > sample_count)
samples_to_do=sample_count-samples_written;
//todo test if (samples to do == 0)
decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer);
samples_written += samples_to_do;
vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block+=samples_to_do;
vgmstream->samples_into_block += samples_to_do;
if (vgmstream->samples_into_block==samples_this_block) {
int chan;
if (vgmstream->interleave_last_block_size && vgmstream->channels > 1 &&
vgmstream->current_sample + samples_this_block > vgmstream->num_samples) {
/* move to next interleaved block when all samples are consumed */
if (vgmstream->samples_into_block == samples_this_block) {
int ch;
if (has_interleave_last &&
vgmstream->current_sample + samples_this_block > vgmstream->num_samples) {
/* adjust values again if inside last interleave */
frame_size = get_vgmstream_shortframe_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_shortframe(vgmstream);
samples_this_block = vgmstream->interleave_last_block_size / frame_size * samples_per_frame;
for (chan=0;chan<vgmstream->channels;chan++)
vgmstream->ch[chan].offset+=vgmstream->interleave_block_size*(vgmstream->channels-chan)+vgmstream->interleave_last_block_size*chan;
} else {
for (chan=0;chan<vgmstream->channels;chan++)
vgmstream->ch[chan].offset+=vgmstream->interleave_block_size*vgmstream->channels;
for (ch = 0; ch < vgmstream->channels; ch++) {
off_t skip = vgmstream->interleave_block_size*(vgmstream->channels-ch) +
vgmstream->interleave_last_block_size*ch;;
vgmstream->ch[ch].offset += skip;
}
}
vgmstream->samples_into_block=0;
else {
for (ch = 0; ch < vgmstream->channels; ch++) {
off_t skip = vgmstream->interleave_block_size*vgmstream->channels;
vgmstream->ch[ch].offset += skip;
}
}
vgmstream->samples_into_block = 0;
}
}

View File

@ -1,37 +1,41 @@
#include "layout.h"
#include "../vgmstream.h"
/* TODO: there must be a reasonable way to respect the loop settings, as
the substreams are in their own little world.
Currently the VGMSTREAMs layers loop internally and the external/base VGMSTREAM
doesn't actually loop, and would ignore any altered values/loop_flag. */
/* NOTE: if loop settings change the layered vgmstreams must be notified (preferably using vgmstream_force_loop) */
#define LAYER_BUF_SIZE 512
#define LAYER_MAX_CHANNELS 6 /* at least 2, but let's be generous */
/* Decodes samples for layered streams.
* Similar to interleave layout, but decodec samples are mixed from complete vgmstreams, each
* with custom codecs and different number of channels, creating a single super-vgmstream.
* Usually combined with custom streamfiles to handle data interleaved in weird ways. */
void render_vgmstream_layered(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
sample interleave_buf[LAYER_BUF_SIZE*LAYER_MAX_CHANNELS];
int32_t samples_done = 0;
int samples_written = 0;
layered_layout_data *data = vgmstream->layout_data;
sample interleave_buf[LAYER_BUF_SIZE*LAYER_MAX_CHANNELS];
while (samples_done < sample_count) {
int32_t samples_to_do = LAYER_BUF_SIZE;
while (samples_written < sample_count) {
int samples_to_do = LAYER_BUF_SIZE;
int layer, ch = 0;
if (samples_to_do > sample_count - samples_done)
samples_to_do = sample_count - samples_done;
if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written;
for (layer = 0; layer < data->layer_count; layer++) {
int s,l_ch;
int s, layer_ch;
int layer_channels = data->layers[layer]->channels;
/* each layer will handle its own looping internally */
render_vgmstream(interleave_buf, samples_to_do, data->layers[layer]);
for (l_ch = 0; l_ch < layer_channels; l_ch++) {
/* mix layer samples to main samples */
for (layer_ch = 0; layer_ch < layer_channels; layer_ch++) {
for (s = 0; s < samples_to_do; s++) {
size_t layer_sample = s*layer_channels + l_ch;
size_t buffer_sample = (samples_done+s)*vgmstream->channels + ch;
size_t layer_sample = s*layer_channels + layer_ch;
size_t buffer_sample = (samples_written+s)*vgmstream->channels + ch;
buffer[buffer_sample] = interleave_buf[layer_sample];
}
@ -39,8 +43,9 @@ void render_vgmstream_layered(sample * buffer, int32_t sample_count, VGMSTREAM *
}
}
samples_done += samples_to_do;
samples_written += samples_to_do;
vgmstream->current_sample = data->layers[0]->current_sample; /* just in case it's used for info */
//vgmstream->samples_into_block = 0; /* handled in each layer */
}
}

View File

@ -2,35 +2,38 @@
#include "../vgmstream.h"
/* Decodes samples for segmented streams.
* 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;
segmented_layout_data *data = vgmstream->layout_data;
//int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
while (samples_written<sample_count) {
while (samples_written < sample_count) {
int samples_to_do;
int samples_this_block = data->segments[data->current_segment]->num_samples;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
/* handle looping, moving to loop segment */
//todo can only loop in a segment start
// (for arbitrary values find loop segment from loop_start_sample, and skip N samples until loop start)
data->current_segment = data->loop_segment;
reset_vgmstream(data->segments[data->current_segment]);
vgmstream->samples_into_block = 0;
continue;
}
samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream);
if (samples_written+samples_to_do > sample_count)
samples_to_do=sample_count-samples_written;
/* decode samples */
samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream); //todo should use a buffer
if (samples_to_do > sample_count - samples_written)
samples_to_do = sample_count - samples_written;
/* detect segment change and restart */
if (samples_to_do == 0) {
data->current_segment++;
reset_vgmstream(data->segments[data->current_segment]);
vgmstream->samples_into_block = 0;
continue;
}
@ -40,7 +43,7 @@ void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM
samples_written += samples_to_do;
vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block+=samples_to_do;
vgmstream->samples_into_block += samples_to_do;
}
}

View File

@ -779,8 +779,8 @@ typedef struct {
/* layout/block state */
size_t full_block_size; /* actual data size of an entire block (ie. may be fixed, include padding/headers, etc) */
int32_t current_sample; /* number of samples we've passed */
int32_t samples_into_block; /* number of samples into the current block */
int32_t current_sample; /* number of samples we've passed (for loop detection) */
int32_t samples_into_block; /* number of samples into the current block/interleave/segment/etc */
off_t current_block_offset; /* start of this block (offset of block header) */
size_t current_block_size; /* size in usable bytes of the block we're in now (used to calculate num_samples per block) */
size_t current_block_samples; /* size in samples of the block we're in now (used over current_block_size if possible) */