mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-12 01:30:49 +01:00
cleanup: layouts
This commit is contained in:
parent
1f97c2aeb7
commit
b5dffc9556
76
src/base/sbuf.c
Normal file
76
src/base/sbuf.c
Normal file
@ -0,0 +1,76 @@
|
||||
#include <string.h>
|
||||
#include "../util.h"
|
||||
#include "sbuf.h"
|
||||
|
||||
#if 0
|
||||
/* skips N samples from current sbuf */
|
||||
void sbuf_init16(sbuf_t* sbuf, int16_t* buf, int samples, int channels) {
|
||||
memset(sbuf, 0, sizeof(sbuf_t));
|
||||
sbuf->buf = buf;
|
||||
sbuf->samples = samples;
|
||||
sbuf->channels = channels;
|
||||
sbuf->fmt = SFMT_S16;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// TODO decide if using float 1.0 style or 32767 style (fuzzy PCM changes when doing that)
|
||||
void sbuf_copy_s16_to_f32(float* buf_f32, int16_t* buf_s16, int samples, int channels) {
|
||||
for (int s = 0; s < samples * channels; s++) {
|
||||
buf_f32[s] = (float)buf_s16[s]; // / 32767.0f
|
||||
}
|
||||
}
|
||||
|
||||
void sbuf_copy_f32_to_s16(int16_t* buf_s16, float* buf_f32, int samples, int channels) {
|
||||
/* when casting float to int, value is simply truncated:
|
||||
* - (int)1.7 = 1, (int)-1.7 = -1
|
||||
* alts for more accurate rounding could be:
|
||||
* - (int)floor(f)
|
||||
* - (int)(f < 0 ? f - 0.5f : f + 0.5f)
|
||||
* - (((int) (f1 + 32768.5)) - 32768)
|
||||
* - etc
|
||||
* but since +-1 isn't really audible we'll just cast, as it's the fastest
|
||||
*/
|
||||
for (int s = 0; s < samples * channels; s++) {
|
||||
buf_s16[s] = clamp16( buf_f32[s]); // * 32767.0f
|
||||
}
|
||||
}
|
||||
|
||||
void sbuf_copy_samples(sample_t* dst, int dst_channels, sample_t* src, int src_channels, int samples_to_do, int samples_filled) {
|
||||
int pos = samples_filled * dst_channels;
|
||||
|
||||
if (src_channels == dst_channels) { /* most common and probably faster */
|
||||
for (int s = 0; s < samples_to_do * dst_channels; s++) {
|
||||
dst[pos + s] = src[s];
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int s = 0; s < samples_to_do; s++) {
|
||||
for (int ch = 0; ch < src_channels; ch++) {
|
||||
dst[pos + s * dst_channels + ch] = src[s * src_channels + ch];
|
||||
}
|
||||
for (int ch = src_channels; ch < dst_channels; ch++) {
|
||||
dst[pos + s * dst_channels + ch] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* copy interleaving */
|
||||
void sbuf_copy_layers(sample_t* dst, int dst_channels, sample_t* src, int src_channels, int samples_to_do, int samples_filled, int dst_ch_start) {
|
||||
// dst_channels == src_channels isn't likely
|
||||
for (int src_ch = 0; src_ch < src_channels; src_ch++) {
|
||||
for (int s = 0; s < samples_to_do; s++) {
|
||||
int src_pos = s * src_channels + src_ch;
|
||||
int dst_pos = (samples_filled + s) * dst_channels + dst_ch_start;
|
||||
|
||||
dst[dst_pos] = src[src_pos];
|
||||
}
|
||||
|
||||
dst_ch_start++;
|
||||
}
|
||||
}
|
||||
|
||||
void sbuf_silence(sample_t* dst, int samples, int channels, int filled) {
|
||||
memset(dst + filled * channels, 0, (samples - filled) * channels * sizeof(sample_t));
|
||||
}
|
@ -3,26 +3,44 @@
|
||||
|
||||
#include "../streamtypes.h"
|
||||
|
||||
// TODO decide if using float 1.0 style or 32767 style (fuzzy PCM changes when doing that)
|
||||
static inline void sbuf_copy_s16_to_f32(float* buf_f32, int16_t* buf_s16, int samples, int channels) {
|
||||
for (int s = 0; s < samples * channels; s++) {
|
||||
buf_f32[s] = (float)buf_s16[s]; // / 32767.0f
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
/* interleaved: buffer for all channels = [ch*s] = (ch1 ch2 ch1 ch2 ch1 ch2 ch1 ch2 ...) */
|
||||
/* planar: buffer per channel = [ch][s] = (c1 c1 c1 c1 ...) (c2 c2 c2 c2 ...) */
|
||||
typedef enum {
|
||||
SFMT_NONE,
|
||||
SFMT_S16,
|
||||
SFMT_F32,
|
||||
//SFMT_S24,
|
||||
//SFMT_S32,
|
||||
//SFMT_S16P,
|
||||
//SFMT_F32P,
|
||||
} sfmt_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
void* buf; /* current sample buffer */
|
||||
int samples; /* max samples */
|
||||
int channels; /* interleaved step or planar buffers */
|
||||
sfmt_t fmt; /* buffer type */
|
||||
//int filled; /* samples in buffer */
|
||||
//int planar;
|
||||
} sbuf_t;
|
||||
|
||||
void sbuf_init16(sbuf_t* sbuf, int16_t* buf, int samples, int channels);
|
||||
#endif
|
||||
|
||||
/* it's probably slightly faster to make those inline'd, but aren't called that often to matter (given big enough total samples) */
|
||||
|
||||
// TODO decide if using float 1.0 style or 32767 style (fuzzy PCM changes when doing that)
|
||||
void sbuf_copy_s16_to_f32(float* buf_f32, int16_t* buf_s16, int samples, int channels);
|
||||
|
||||
void sbuf_copy_f32_to_s16(int16_t* buf_s16, float* buf_f32, int samples, int channels);
|
||||
|
||||
void sbuf_copy_samples(sample_t* dst, int dst_channels, sample_t* src, int src_channels, int samples_to_do, int samples_written);
|
||||
|
||||
void sbuf_copy_layers(sample_t* dst, int dst_channels, sample_t* src, int src_channels, int samples_to_do, int samples_filled, int dst_ch_start);
|
||||
|
||||
void sbuf_silence(sample_t* dst, int samples, int channels, int filled);
|
||||
|
||||
static inline void sbuf_copy_f32_to_s16(int16_t* buf_s16, float* buf_f32, int samples, int channels) {
|
||||
/* when casting float to int, value is simply truncated:
|
||||
* - (int)1.7 = 1, (int)-1.7 = -1
|
||||
* alts for more accurate rounding could be:
|
||||
* - (int)floor(f)
|
||||
* - (int)(f < 0 ? f - 0.5f : f + 0.5f)
|
||||
* - (((int) (f1 + 32768.5)) - 32768)
|
||||
* - etc
|
||||
* but since +-1 isn't really audible we'll just cast as it's the fastest
|
||||
*/
|
||||
for (int s = 0; s < samples * channels; s++) {
|
||||
buf_s16[s] = clamp16( buf_f32[s]); // * 32767.0f
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -3,36 +3,32 @@
|
||||
#include "../base/decode.h"
|
||||
#include "../base/mixing.h"
|
||||
#include "../base/plugins.h"
|
||||
#include "../base/sbuf.h"
|
||||
|
||||
#define VGMSTREAM_MAX_LAYERS 255
|
||||
#define VGMSTREAM_LAYER_SAMPLE_BUFFER 8192
|
||||
|
||||
|
||||
/* Decodes samples for layered streams.
|
||||
* Similar to flat layout, but decoded vgmstream are mixed into a final buffer, each vgmstream
|
||||
* may have different codecs and 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_t* outbuf, int32_t sample_count, VGMSTREAM* vgmstream) {
|
||||
int samples_written = 0;
|
||||
* Each decoded vgmstream 'layer' (which may have different codecs and number of channels)
|
||||
* is mixed into a final buffer, creating a single super-vgmstream. */
|
||||
void render_vgmstream_layered(sample_t* outbuf, int32_t sample_len, VGMSTREAM* vgmstream) {
|
||||
layered_layout_data* data = vgmstream->layout_data;
|
||||
int samples_per_frame, samples_this_block;
|
||||
|
||||
samples_per_frame = VGMSTREAM_LAYER_SAMPLE_BUFFER;
|
||||
samples_this_block = vgmstream->num_samples; /* do all samples if possible */
|
||||
|
||||
while (samples_written < sample_count) {
|
||||
int samples_to_do;
|
||||
int layer, ch;
|
||||
|
||||
int samples_per_frame = VGMSTREAM_LAYER_SAMPLE_BUFFER;
|
||||
int samples_this_block = vgmstream->num_samples; /* do all samples if possible */
|
||||
|
||||
int samples_filled = 0;
|
||||
while (samples_filled < sample_len) {
|
||||
if (vgmstream->loop_flag && decode_do_loop(vgmstream)) {
|
||||
/* handle looping (loop_layout has been called below) */
|
||||
continue;
|
||||
}
|
||||
|
||||
samples_to_do = decode_get_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
if (samples_to_do > sample_count - samples_written)
|
||||
samples_to_do = sample_count - samples_written;
|
||||
int ch;
|
||||
int samples_to_do = decode_get_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
if (samples_to_do > sample_len - samples_filled)
|
||||
samples_to_do = sample_len - samples_filled;
|
||||
|
||||
if (samples_to_do <= 0) { /* when decoding more than num_samples */
|
||||
VGM_LOG_ONCE("LAYERED: samples_to_do 0\n");
|
||||
@ -41,46 +37,34 @@ void render_vgmstream_layered(sample_t* outbuf, int32_t sample_count, VGMSTREAM*
|
||||
|
||||
/* decode all layers */
|
||||
ch = 0;
|
||||
for (layer = 0; layer < data->layer_count; layer++) {
|
||||
int s, layer_ch, layer_channels;
|
||||
for (int current_layer = 0; current_layer < data->layer_count; current_layer++) {
|
||||
|
||||
/* layers may have its own number of channels */
|
||||
mixing_info(data->layers[layer], NULL, &layer_channels);
|
||||
/* layers may have their own number of channels */
|
||||
int layer_channels;
|
||||
mixing_info(data->layers[current_layer], NULL, &layer_channels);
|
||||
|
||||
render_vgmstream(
|
||||
data->buffer,
|
||||
samples_to_do,
|
||||
data->layers[layer]);
|
||||
render_vgmstream(data->buffer, samples_to_do, data->layers[current_layer]);
|
||||
|
||||
/* 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 + layer_ch;
|
||||
size_t buffer_sample = (samples_written+s)*data->output_channels + ch;
|
||||
|
||||
outbuf[buffer_sample] = data->buffer[layer_sample];
|
||||
}
|
||||
ch++;
|
||||
}
|
||||
sbuf_copy_layers(outbuf, data->output_channels, data->buffer, layer_channels, samples_to_do, samples_filled, ch);
|
||||
ch += layer_channels;
|
||||
}
|
||||
|
||||
|
||||
samples_written += samples_to_do;
|
||||
samples_filled += samples_to_do;
|
||||
vgmstream->current_sample += samples_to_do;
|
||||
vgmstream->samples_into_block += samples_to_do;
|
||||
}
|
||||
|
||||
return;
|
||||
decode_fail:
|
||||
memset(outbuf + samples_written * data->output_channels, 0, (sample_count - samples_written) * data->output_channels * sizeof(sample_t));
|
||||
sbuf_silence(outbuf, sample_len, data->output_channels, samples_filled);
|
||||
}
|
||||
|
||||
|
||||
void seek_layout_layered(VGMSTREAM* vgmstream, int32_t seek_sample) {
|
||||
int layer;
|
||||
layered_layout_data* data = vgmstream->layout_data;
|
||||
|
||||
for (layer = 0; layer < data->layer_count; layer++) {
|
||||
for (int layer = 0; layer < data->layer_count; layer++) {
|
||||
seek_vgmstream(data->layers[layer], seek_sample);
|
||||
}
|
||||
|
||||
@ -89,11 +73,9 @@ void seek_layout_layered(VGMSTREAM* vgmstream, int32_t seek_sample) {
|
||||
}
|
||||
|
||||
void loop_layout_layered(VGMSTREAM* vgmstream, int32_t loop_sample) {
|
||||
int layer;
|
||||
layered_layout_data* data = vgmstream->layout_data;
|
||||
|
||||
|
||||
for (layer = 0; layer < data->layer_count; layer++) {
|
||||
for (int layer = 0; layer < data->layer_count; layer++) {
|
||||
if (data->external_looping) {
|
||||
/* looping is applied over resulting decode, as each layer is its own "solid" block with
|
||||
* config and needs 'external' seeking */
|
||||
@ -130,37 +112,35 @@ layered_layout_data* init_layout_layered(int layer_count) {
|
||||
data = calloc(1, sizeof(layered_layout_data));
|
||||
if (!data) goto fail;
|
||||
|
||||
data->layer_count = layer_count;
|
||||
|
||||
data->layers = calloc(layer_count, sizeof(VGMSTREAM*));
|
||||
if (!data->layers) goto fail;
|
||||
|
||||
data->layer_count = layer_count;
|
||||
|
||||
return data;
|
||||
fail:
|
||||
free_layout_layered(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int setup_layout_layered(layered_layout_data* data) {
|
||||
int i, max_input_channels = 0, max_output_channels = 0;
|
||||
sample_t *outbuf_re = NULL;
|
||||
|
||||
bool setup_layout_layered(layered_layout_data* data) {
|
||||
|
||||
/* setup each VGMSTREAM (roughly equivalent to vgmstream.c's init_vgmstream_internal stuff) */
|
||||
for (i = 0; i < data->layer_count; i++) {
|
||||
int layer_input_channels, layer_output_channels;
|
||||
|
||||
int max_input_channels = 0;
|
||||
int max_output_channels = 0;
|
||||
for (int i = 0; i < data->layer_count; i++) {
|
||||
if (data->layers[i] == NULL) {
|
||||
VGM_LOG("LAYERED: no vgmstream in %i\n", i);
|
||||
goto fail;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data->layers[i]->num_samples <= 0) {
|
||||
VGM_LOG("LAYERED: no samples in %i\n", i);
|
||||
goto fail;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* different layers may have different input/output channels */
|
||||
int layer_input_channels, layer_output_channels;
|
||||
mixing_info(data->layers[i], &layer_input_channels, &layer_output_channels);
|
||||
|
||||
max_output_channels += layer_output_channels;
|
||||
@ -171,12 +151,15 @@ int setup_layout_layered(layered_layout_data* data) {
|
||||
/* a bit weird, but no matter */
|
||||
if (data->layers[i]->sample_rate != data->layers[i-1]->sample_rate) {
|
||||
VGM_LOG("LAYERED: layer %i has different sample rate\n", i);
|
||||
//TO-DO: setup resampling
|
||||
}
|
||||
|
||||
/* also weird */
|
||||
#if 0
|
||||
/* also weird but less so */
|
||||
if (data->layers[i]->coding_type != data->layers[i-1]->coding_type) {
|
||||
VGM_LOG("LAYERED: layer %i has different coding type\n", i);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* loops and other values could be mismatched, but should be handled on allocate */
|
||||
@ -192,44 +175,38 @@ int setup_layout_layered(layered_layout_data* data) {
|
||||
}
|
||||
|
||||
if (max_output_channels > VGMSTREAM_MAX_CHANNELS || max_input_channels > VGMSTREAM_MAX_CHANNELS)
|
||||
goto fail;
|
||||
return false;
|
||||
|
||||
/* create internal buffer big enough for mixing */
|
||||
outbuf_re = realloc(data->buffer, VGMSTREAM_LAYER_SAMPLE_BUFFER*max_input_channels*sizeof(sample_t));
|
||||
/* create internal buffer big enough for mixing all layers */
|
||||
sample_t* outbuf_re = realloc(data->buffer, VGMSTREAM_LAYER_SAMPLE_BUFFER * max_input_channels * sizeof(sample_t));
|
||||
if (!outbuf_re) goto fail;
|
||||
data->buffer = outbuf_re;
|
||||
|
||||
data->input_channels = max_input_channels;
|
||||
data->output_channels = max_output_channels;
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
fail:
|
||||
return 0; /* caller is expected to free */
|
||||
return false; /* caller is expected to free */
|
||||
}
|
||||
|
||||
void free_layout_layered(layered_layout_data *data) {
|
||||
int i;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
if (data->layers) {
|
||||
for (i = 0; i < data->layer_count; i++) {
|
||||
close_vgmstream(data->layers[i]);
|
||||
}
|
||||
free(data->layers);
|
||||
for (int i = 0; i < data->layer_count; i++) {
|
||||
close_vgmstream(data->layers[i]);
|
||||
}
|
||||
free(data->layers);
|
||||
free(data->buffer);
|
||||
free(data);
|
||||
}
|
||||
|
||||
void reset_layout_layered(layered_layout_data *data) {
|
||||
int i;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
for (i = 0; i < data->layer_count; i++) {
|
||||
for (int i = 0; i < data->layer_count; i++) {
|
||||
reset_vgmstream(data->layers[i]);
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ void render_vgmstream_flat(sample_t* buffer, int32_t sample_count, VGMSTREAM* vg
|
||||
|
||||
void render_vgmstream_interleave(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
|
||||
|
||||
|
||||
/* segmented layout */
|
||||
/* for files made of "continuous" segments, one per section of a song (using a complete sub-VGMSTREAM) */
|
||||
typedef struct {
|
||||
@ -25,12 +26,13 @@ typedef struct {
|
||||
|
||||
void render_vgmstream_segmented(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
|
||||
segmented_layout_data* init_layout_segmented(int segment_count);
|
||||
int setup_layout_segmented(segmented_layout_data* data);
|
||||
bool setup_layout_segmented(segmented_layout_data* data);
|
||||
void free_layout_segmented(segmented_layout_data* data);
|
||||
void reset_layout_segmented(segmented_layout_data* data);
|
||||
void seek_layout_segmented(VGMSTREAM* vgmstream, int32_t seek_sample);
|
||||
void loop_layout_segmented(VGMSTREAM* vgmstream, int32_t loop_sample);
|
||||
|
||||
|
||||
/* layered layout */
|
||||
/* for files made of "parallel" layers, one per group of channels (using a complete sub-VGMSTREAM) */
|
||||
typedef struct {
|
||||
@ -45,12 +47,13 @@ typedef struct {
|
||||
|
||||
void render_vgmstream_layered(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
|
||||
layered_layout_data* init_layout_layered(int layer_count);
|
||||
int setup_layout_layered(layered_layout_data* data);
|
||||
bool setup_layout_layered(layered_layout_data* data);
|
||||
void free_layout_layered(layered_layout_data* data);
|
||||
void reset_layout_layered(layered_layout_data* data);
|
||||
void seek_layout_layered(VGMSTREAM* vgmstream, int32_t seek_sample);
|
||||
void loop_layout_layered(VGMSTREAM* vgmstream, int32_t loop_sample);
|
||||
|
||||
|
||||
/* blocked layouts */
|
||||
void render_vgmstream_blocked(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
|
||||
void block_update(off_t block_offset, VGMSTREAM* vgmstream);
|
||||
|
@ -3,34 +3,35 @@
|
||||
#include "../base/decode.h"
|
||||
#include "../base/mixing.h"
|
||||
#include "../base/plugins.h"
|
||||
#include "../base/sbuf.h"
|
||||
|
||||
#define VGMSTREAM_MAX_SEGMENTS 1024
|
||||
#define VGMSTREAM_SEGMENT_SAMPLE_BUFFER 8192
|
||||
|
||||
static inline void copy_samples(sample_t* outbuf, segmented_layout_data* data, int current_channels, int32_t samples_to_do, int32_t samples_written);
|
||||
|
||||
/* 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_t* outbuf, int32_t sample_count, VGMSTREAM* vgmstream) {
|
||||
int samples_written = 0, samples_this_block;
|
||||
segmented_layout_data* data = vgmstream->layout_data;
|
||||
int use_internal_buffer = 0;
|
||||
int current_channels = 0;
|
||||
bool use_internal_buffer = 0;
|
||||
|
||||
/* normally uses outbuf directly (faster?) but could need internal buffer if downmixing */
|
||||
if (vgmstream->channels != data->input_channels || data->mixed_channels) {
|
||||
use_internal_buffer = 1;
|
||||
use_internal_buffer = true;
|
||||
}
|
||||
|
||||
if (data->current_segment >= data->segment_count) {
|
||||
VGM_LOG_ONCE("SEGMENT: wrong current segment\n");
|
||||
goto decode_fail;
|
||||
sbuf_silence(outbuf, sample_count, data->output_channels, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
samples_this_block = vgmstream_get_samples(data->segments[data->current_segment]);
|
||||
int current_channels = 0;
|
||||
mixing_info(data->segments[data->current_segment], NULL, ¤t_channels);
|
||||
int samples_this_block = vgmstream_get_samples(data->segments[data->current_segment]);
|
||||
|
||||
int samples_written = 0;
|
||||
while (samples_written < sample_count) {
|
||||
int samples_to_do;
|
||||
|
||||
@ -71,14 +72,11 @@ void render_vgmstream_segmented(sample_t* outbuf, int32_t sample_count, VGMSTREA
|
||||
goto decode_fail;
|
||||
}
|
||||
|
||||
render_vgmstream(
|
||||
use_internal_buffer ?
|
||||
data->buffer : &outbuf[samples_written * data->output_channels],
|
||||
samples_to_do,
|
||||
data->segments[data->current_segment]);
|
||||
sample_t* buf = use_internal_buffer ? data->buffer : &outbuf[samples_written * data->output_channels];
|
||||
render_vgmstream(buf, samples_to_do, data->segments[data->current_segment]);
|
||||
|
||||
if (use_internal_buffer) {
|
||||
copy_samples(outbuf, data, current_channels, samples_to_do, samples_written);
|
||||
sbuf_copy_samples(outbuf, data->output_channels, data->buffer, current_channels, samples_to_do, samples_written);
|
||||
}
|
||||
|
||||
samples_written += samples_to_do;
|
||||
@ -88,39 +86,16 @@ void render_vgmstream_segmented(sample_t* outbuf, int32_t sample_count, VGMSTREA
|
||||
|
||||
return;
|
||||
decode_fail:
|
||||
memset(outbuf + samples_written * data->output_channels, 0, (sample_count - samples_written) * data->output_channels * sizeof(sample_t));
|
||||
sbuf_silence(outbuf, sample_count, data->output_channels, samples_written);
|
||||
}
|
||||
|
||||
static inline void copy_samples(sample_t* outbuf, segmented_layout_data* data, int current_channels, int32_t samples_to_do, int32_t samples_written) {
|
||||
int ch_out = data->output_channels;
|
||||
int ch_in = current_channels;
|
||||
int pos = samples_written * ch_out;
|
||||
int s;
|
||||
if (ch_in == ch_out) { /* most common and probably faster */
|
||||
for (s = 0; s < samples_to_do * ch_out; s++) {
|
||||
outbuf[pos + s] = data->buffer[s];
|
||||
}
|
||||
}
|
||||
else {
|
||||
int ch;
|
||||
for (s = 0; s < samples_to_do; s++) {
|
||||
for (ch = 0; ch < ch_in; ch++) {
|
||||
outbuf[pos + s*ch_out + ch] = data->buffer[s*ch_in + ch];
|
||||
}
|
||||
for (ch = ch_in; ch < ch_out; ch++) {
|
||||
outbuf[pos + s*ch_out + ch] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void seek_layout_segmented(VGMSTREAM* vgmstream, int32_t seek_sample) {
|
||||
int segment, total_samples;
|
||||
segmented_layout_data* data = vgmstream->layout_data;
|
||||
|
||||
segment = 0;
|
||||
total_samples = 0;
|
||||
int segment = 0;
|
||||
int total_samples = 0;
|
||||
while (total_samples < vgmstream->num_samples) {
|
||||
int32_t segment_samples = vgmstream_get_samples(data->segments[segment]);
|
||||
|
||||
@ -133,13 +108,13 @@ void seek_layout_segmented(VGMSTREAM* vgmstream, int32_t seek_sample) {
|
||||
vgmstream->samples_into_block = seek_relative;
|
||||
break;
|
||||
}
|
||||
|
||||
total_samples += segment_samples;
|
||||
segment++;
|
||||
}
|
||||
|
||||
if (segment == data->segment_count) {
|
||||
VGM_LOG("SEGMENTED: can't find seek segment\n");
|
||||
}
|
||||
// ???
|
||||
VGM_ASSERT(segment == data->segment_count, "SEGMENTED: can't find seek segment\n");
|
||||
}
|
||||
|
||||
void loop_layout_segmented(VGMSTREAM* vgmstream, int32_t loop_sample) {
|
||||
@ -156,35 +131,34 @@ segmented_layout_data* init_layout_segmented(int segment_count) {
|
||||
data = calloc(1, sizeof(segmented_layout_data));
|
||||
if (!data) goto fail;
|
||||
|
||||
data->segment_count = segment_count;
|
||||
data->current_segment = 0;
|
||||
|
||||
data->segments = calloc(segment_count, sizeof(VGMSTREAM*));
|
||||
if (!data->segments) goto fail;
|
||||
|
||||
data->segment_count = segment_count;
|
||||
data->current_segment = 0;
|
||||
|
||||
return data;
|
||||
fail:
|
||||
free_layout_segmented(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int setup_layout_segmented(segmented_layout_data* data) {
|
||||
int i, max_input_channels = 0, max_output_channels = 0, mixed_channels = 0;
|
||||
sample_t *outbuf_re = NULL;
|
||||
bool setup_layout_segmented(segmented_layout_data* data) {
|
||||
int max_input_channels = 0, max_output_channels = 0, mixed_channels = 0;
|
||||
sample_t* outbuf_re = NULL;
|
||||
|
||||
|
||||
/* setup each VGMSTREAM (roughly equivalent to vgmstream.c's init_vgmstream_internal stuff) */
|
||||
for (i = 0; i < data->segment_count; i++) {
|
||||
int segment_input_channels, segment_output_channels;
|
||||
for (int i = 0; i < data->segment_count; i++) {
|
||||
|
||||
if (data->segments[i] == NULL) {
|
||||
VGM_LOG("SEGMENTED: no vgmstream in segment %i\n", i);
|
||||
goto fail;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data->segments[i]->num_samples <= 0) {
|
||||
VGM_LOG("SEGMENTED: no samples in segment %i\n", i);
|
||||
goto fail;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* allow config if set for fine-tuned parts (usually TXTP only) */
|
||||
@ -200,8 +174,8 @@ int setup_layout_segmented(segmented_layout_data* data) {
|
||||
}
|
||||
}
|
||||
|
||||
/* different segments may have different input or output channels, we
|
||||
* need to know maxs to properly handle */
|
||||
/* different segments may have different input or output channels (in rare cases of using ex. 2ch + 4ch) */
|
||||
int segment_input_channels, segment_output_channels;
|
||||
mixing_info(data->segments[i], &segment_input_channels, &segment_output_channels);
|
||||
if (max_input_channels < segment_input_channels)
|
||||
max_input_channels = segment_input_channels;
|
||||
@ -247,45 +221,42 @@ int setup_layout_segmented(segmented_layout_data* data) {
|
||||
data->output_channels = max_output_channels;
|
||||
data->mixed_channels = mixed_channels;
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
fail:
|
||||
return 0; /* caller is expected to free */
|
||||
return false; /* caller is expected to free */
|
||||
}
|
||||
|
||||
void free_layout_segmented(segmented_layout_data* data) {
|
||||
int i, j;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
if (data->segments) {
|
||||
for (i = 0; i < data->segment_count; i++) {
|
||||
int is_repeat = 0;
|
||||
for (int i = 0; i < data->segment_count; i++) {
|
||||
bool is_repeat = true;
|
||||
|
||||
/* segments are allowed to be repeated so don't close the same thing twice */
|
||||
for (j = 0; j < i; j++) {
|
||||
if (data->segments[i] == data->segments[j])
|
||||
is_repeat = 1;
|
||||
/* segments are allowed to be repeated so don't close the same thing twice */
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (data->segments[i] == data->segments[j]) {
|
||||
is_repeat = true;
|
||||
break;
|
||||
}
|
||||
if (is_repeat)
|
||||
continue;
|
||||
|
||||
close_vgmstream(data->segments[i]);
|
||||
}
|
||||
free(data->segments);
|
||||
|
||||
if (is_repeat)
|
||||
continue;
|
||||
close_vgmstream(data->segments[i]);
|
||||
}
|
||||
free(data->segments);
|
||||
free(data->buffer);
|
||||
free(data);
|
||||
}
|
||||
|
||||
void reset_layout_segmented(segmented_layout_data* data) {
|
||||
int i;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
data->current_segment = 0;
|
||||
for (i = 0; i < data->segment_count; i++) {
|
||||
for (int i = 0; i < data->segment_count; i++) {
|
||||
reset_vgmstream(data->segments[i]);
|
||||
}
|
||||
|
||||
data->current_segment = 0;
|
||||
}
|
||||
|
@ -231,6 +231,7 @@
|
||||
<ClCompile Include="base\play_state.c" />
|
||||
<ClCompile Include="base\plugins.c" />
|
||||
<ClCompile Include="base\render.c" />
|
||||
<ClCompile Include="base\sbuf.c" />
|
||||
<ClCompile Include="base\seek.c" />
|
||||
<ClCompile Include="base\streamfile_api.c" />
|
||||
<ClCompile Include="base\streamfile_buffer.c" />
|
||||
|
@ -523,6 +523,9 @@
|
||||
<ClCompile Include="base\render.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\sbuf.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base\seek.c">
|
||||
<Filter>base\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
Loading…
Reference in New Issue
Block a user