mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-12 09:40:51 +01:00
Minor layout cleanup + doc
This commit is contained in:
parent
3765831dbe
commit
3130eebf0c
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) */
|
||||
|
Loading…
Reference in New Issue
Block a user