api: tweak some internals for float decoders

This commit is contained in:
bnnm 2025-01-22 01:43:38 +01:00
parent 6f8a8df1d2
commit 660484e64b
11 changed files with 78 additions and 54 deletions

View File

@ -1,5 +1,6 @@
#include "api_internal.h"
#include "mixing.h"
#include "render.h"
#if LIBVGMSTREAM_ENABLE
@ -17,24 +18,24 @@ static bool reset_buf(libvgmstream_priv_t* priv) {
int input_channels = 0, output_channels = 0;
vgmstream_mixing_enable(priv->vgmstream, 0, &input_channels, &output_channels); //query
int min_channels = input_channels;
if (min_channels < output_channels)
min_channels = output_channels;
int max_channels = input_channels;
if (max_channels < output_channels)
max_channels = output_channels;
sfmt_t input_sfmt = mixing_get_input_sample_type(priv->vgmstream);
sfmt_t output_sfmt = mixing_get_output_sample_type(priv->vgmstream);
int input_sample_size = sfmt_get_sample_size(input_sfmt);
int output_sample_size = sfmt_get_sample_size(output_sfmt);
int min_sample_size = input_sample_size;
if (min_sample_size < output_sample_size)
min_sample_size = output_sample_size;
int max_sample_size = input_sample_size;
if (max_sample_size < output_sample_size)
max_sample_size = output_sample_size;
priv->buf.max_samples = INTERNAL_BUF_SAMPLES;
priv->buf.sample_size = output_sample_size;
priv->buf.channels = output_channels;
int max_bytes = priv->buf.max_samples * min_sample_size * min_channels;
int max_bytes = priv->buf.max_samples * max_sample_size * max_channels;
priv->buf.data = malloc(max_bytes);
if (!priv->buf.data) return false;
@ -79,7 +80,11 @@ LIBVGMSTREAM_API int libvgmstream_render(libvgmstream_t* lib) {
if (!priv->pos.play_forever && to_get + priv->pos.current > priv->pos.play_samples)
to_get = priv->pos.play_samples - priv->pos.current;
int decoded = render_vgmstream(priv->buf.data, to_get, priv->vgmstream);
sbuf_t ssrc;
sfmt_t sfmt = mixing_get_input_sample_type(priv->vgmstream);
sbuf_init(&ssrc, sfmt, priv->buf.data, to_get, priv->vgmstream->channels);
int decoded = render_main(&ssrc, priv->vgmstream);
update_buf(priv, decoded);
update_decoder_info(priv, decoded);

View File

@ -935,10 +935,12 @@ decode_fail:
* buffer already, and we have samples_to_do consecutive samples ahead of us (won't call
* more than one frame if configured above to do so).
* Called by layouts since they handle samples written/to_do */
void decode_vgmstream(VGMSTREAM* vgmstream, int samples_filled, int samples_to_do, sample_t* buffer) {
void decode_vgmstream(sbuf_t* sdst, VGMSTREAM* vgmstream, int samples_to_do) {
int ch;
buffer += samples_filled * vgmstream->channels; /* passed externally to simplify I guess */
//TODO: this cast isn't correct for float sbuf-decoders but shouldn't be used/matter (for buffer+ch below)
int16_t* buffer = sdst->buf;
buffer += sdst->filled * vgmstream->channels; // passed externally to decoders to simplify I guess
//samples_to_do -= samples_filled; /* pre-adjusted */
switch (vgmstream->coding_type) {
@ -1673,14 +1675,10 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_filled, int samples_to_d
break;
default: {
sbuf_t sbuf_tmp = {0};
sbuf_t* sbuf = &sbuf_tmp;
sbuf_t stmp = *sdst;
stmp.samples = stmp.filled + samples_to_do; //TODO improve
// buffers already adjusted
sbuf_init_s16(sbuf, buffer, /*samples_filled +*/ samples_to_do, vgmstream->channels);
sbuf->filled = 0; // samples_filled;
decode_frames(sbuf, vgmstream);
decode_frames(&stmp, vgmstream);
break;
}
}

View File

@ -10,7 +10,7 @@ void decode_reset(VGMSTREAM* vgmstream);
/* Decode samples into the buffer. Assume that we have written samples_filled into the
* buffer already, and we have samples_to_do consecutive samples ahead of us. */
void decode_vgmstream(VGMSTREAM* vgmstream, int samples_filled, int samples_to_do, sample_t* buffer);
void decode_vgmstream(sbuf_t* sdst, VGMSTREAM* vgmstream, int samples_to_do);
/* Detect loop start and save values, or detect loop end and restore (loop back). Returns true if loop was done. */
bool decode_do_loop(VGMSTREAM* vgmstream);

View File

@ -171,6 +171,21 @@ void describe_vgmstream(VGMSTREAM* vgmstream, char* desc, int length) {
concatn(length,desc,temp);
}
sfmt_t sfmt = mixing_get_input_sample_type(vgmstream);
if (sfmt != SFMT_S16) {
const char* sfmt_desc;
switch(sfmt) {
case SFMT_FLT: sfmt_desc = "float"; break;
case SFMT_F32: sfmt_desc = "float32"; break;
case SFMT_S16: sfmt_desc = "pcm16"; break;
default: sfmt_desc = "???";
}
snprintf(temp,TEMPSIZE, "sample type: %s\n", sfmt_desc);
concatn(length,desc,temp);
}
if (vgmstream->config_enabled) {
int32_t samples = vgmstream->pstate.play_duration;
@ -178,6 +193,7 @@ void describe_vgmstream(VGMSTREAM* vgmstream, char* desc, int length) {
snprintf(temp,TEMPSIZE, "play duration: %d samples (%1.0f:%06.3f seconds)\n", samples, time_mm, time_ss);
concatn(length,desc,temp);
}
}
void describe_vgmstream_info(VGMSTREAM* vgmstream, vgmstream_info* info) {

View File

@ -143,10 +143,14 @@ void mixing_info(VGMSTREAM* vgmstream, int* p_input_channels, int* p_output_chan
}
sfmt_t mixing_get_input_sample_type(VGMSTREAM* vgmstream) {
// TODO: check vgmstream
// TODO: on layered/segments, detect biggest value and use that (ex. if one of the layers uses flt > flt)
switch(vgmstream->coding_type) {
case coding_KA1A:
return SFMT_FLT;
default:
return SFMT_S16;
}
}
sfmt_t mixing_get_output_sample_type(VGMSTREAM* vgmstream) {
sfmt_t input_fmt = mixing_get_input_sample_type(vgmstream);

View File

@ -73,7 +73,6 @@ void render_reset(VGMSTREAM* vgmstream) {
}
int render_layout(sbuf_t* sbuf, VGMSTREAM* vgmstream) {
void* buf = sbuf->buf;
int sample_count = sbuf->samples;
if (sample_count == 0)
@ -90,10 +89,10 @@ int render_layout(sbuf_t* sbuf, VGMSTREAM* vgmstream) {
switch (vgmstream->layout_type) {
case layout_interleave:
render_vgmstream_interleave(buf, sample_count, vgmstream);
render_vgmstream_interleave(sbuf, vgmstream);
break;
case layout_none:
render_vgmstream_flat(buf, sample_count, vgmstream);
render_vgmstream_flat(sbuf, vgmstream);
break;
case layout_blocked_mxch:
case layout_blocked_ast:
@ -134,7 +133,7 @@ int render_layout(sbuf_t* sbuf, VGMSTREAM* vgmstream) {
case layout_blocked_ubi_sce:
case layout_blocked_tt_ad:
case layout_blocked_vas:
render_vgmstream_blocked(buf, sample_count, vgmstream);
render_vgmstream_blocked(sbuf, vgmstream);
break;
case layout_segmented:
render_vgmstream_segmented(sbuf, vgmstream);

View File

@ -112,8 +112,6 @@ void sbuf_copy_to_f32(float* dst, sbuf_t* sbuf) {
}
break;
}
case SFMT_FLT:
case SFMT_F32: {
float* src = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
@ -121,6 +119,13 @@ void sbuf_copy_to_f32(float* dst, sbuf_t* sbuf) {
}
break;
}
case SFMT_FLT: {
float* src = sbuf->buf;
for (int s = 0; s < sbuf->filled * sbuf->channels; s++) {
dst[s] = src[s] * 32768.0f;
}
break;
}
default:
break;
}

View File

@ -8,7 +8,7 @@
/* 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_t* outbuf, int32_t sample_count, VGMSTREAM* vgmstream) {
void render_vgmstream_blocked(sbuf_t* sdst, VGMSTREAM* vgmstream) {
int frame_size = decode_get_frame_size(vgmstream);
int samples_per_frame = decode_get_samples_per_frame(vgmstream);
@ -25,8 +25,7 @@ void render_vgmstream_blocked(sample_t* outbuf, int32_t sample_count, VGMSTREAM*
samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame;
}
int samples_filled = 0;
while (samples_filled < sample_count) {
while (sdst->filled < sdst->samples) {
int samples_to_do;
if (vgmstream->loop_flag && decode_do_loop(vgmstream)) {
@ -54,15 +53,15 @@ void render_vgmstream_blocked(sample_t* outbuf, int32_t sample_count, VGMSTREAM*
}
samples_to_do = decode_get_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
if (samples_to_do > sample_count - samples_filled)
samples_to_do = sample_count - samples_filled;
if (samples_to_do > sdst->samples - sdst->filled)
samples_to_do = sdst->samples - sdst->filled;
if (samples_to_do > 0) {
/* samples_this_block = 0 is allowed (empty block, do nothing then move to next block) */
decode_vgmstream(vgmstream, samples_filled, samples_to_do, outbuf);
decode_vgmstream(sdst, vgmstream, samples_to_do);
}
samples_filled += samples_to_do;
sdst->filled += samples_to_do;
vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block += samples_to_do;
@ -92,7 +91,7 @@ void render_vgmstream_blocked(sample_t* outbuf, int32_t sample_count, VGMSTREAM*
return;
decode_fail:
sbuf_silence_s16(outbuf, sample_count, vgmstream->channels, samples_filled);
sbuf_silence_rest(sdst);
}
/* helper functions to parse new block */

View File

@ -6,14 +6,13 @@
/* 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_t* outbuf, int32_t sample_count, VGMSTREAM* vgmstream) {
void render_vgmstream_flat(sbuf_t* sdst, VGMSTREAM* vgmstream) {
int samples_per_frame = decode_get_samples_per_frame(vgmstream);
int samples_this_block = vgmstream->num_samples; /* do all samples if possible */
/* write samples */
int samples_filled = 0;
while (samples_filled < sample_count) {
while (sdst->filled < sdst->samples) {
if (vgmstream->loop_flag && decode_do_loop(vgmstream)) {
/* handle looping */
@ -21,22 +20,22 @@ void render_vgmstream_flat(sample_t* outbuf, int32_t sample_count, VGMSTREAM* vg
}
int samples_to_do = decode_get_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
if (samples_to_do > sample_count - samples_filled)
samples_to_do = sample_count - samples_filled;
if (samples_to_do > sdst->samples - sdst->filled)
samples_to_do = sdst->samples - sdst->filled;
if (samples_to_do <= 0) { /* when decoding more than num_samples */
VGM_LOG_ONCE("FLAT: wrong samples_to_do\n");
goto decode_fail;
}
decode_vgmstream(vgmstream, samples_filled, samples_to_do, outbuf);
decode_vgmstream(sdst, vgmstream, samples_to_do);
samples_filled += samples_to_do;
sdst->filled += samples_to_do;
vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block += samples_to_do;
}
return;
decode_fail:
sbuf_silence_s16(outbuf, sample_count, vgmstream->channels, samples_filled);
sbuf_silence_rest(sdst);
}

View File

@ -143,11 +143,11 @@ static void update_offsets(layout_config_t* layout, VGMSTREAM* vgmstream, int* p
* 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_t* outbuf, int32_t sample_count, VGMSTREAM* vgmstream) {
void render_vgmstream_interleave(sbuf_t* sdst, VGMSTREAM* vgmstream) {
layout_config_t layout = {0};
if (!setup_helper(&layout, vgmstream)) {
VGM_LOG_ONCE("INTERLEAVE: wrong config found\n");
sbuf_silence_s16(outbuf, sample_count, vgmstream->channels, 0);
sbuf_silence_rest(sdst);
return;
}
@ -160,8 +160,7 @@ void render_vgmstream_interleave(sample_t* outbuf, int32_t sample_count, VGMSTRE
if (samples_this_block == 0 && vgmstream->channels == 1)
samples_this_block = vgmstream->num_samples;
int samples_filled = 0;
while (samples_filled < sample_count) {
while (sdst->filled < sdst->samples) {
if (vgmstream->loop_flag && decode_do_loop(vgmstream)) {
/* handle looping, restore standard interleave sizes */
@ -170,17 +169,17 @@ void render_vgmstream_interleave(sample_t* outbuf, int32_t sample_count, VGMSTRE
}
int samples_to_do = decode_get_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
if (samples_to_do > sample_count - samples_filled)
samples_to_do = sample_count - samples_filled;
if (samples_to_do > sdst->samples - sdst->filled)
samples_to_do = sdst->samples - sdst->filled;
if (samples_to_do <= 0) { /* happens when interleave is not set */
VGM_LOG_ONCE("INTERLEAVE: wrong samples_to_do\n");
goto decode_fail;
}
decode_vgmstream(vgmstream, samples_filled, samples_to_do, outbuf);
decode_vgmstream(sdst, vgmstream, samples_to_do);
samples_filled += samples_to_do;
sdst->filled += samples_to_do;
vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block += samples_to_do;
@ -193,5 +192,5 @@ void render_vgmstream_interleave(sample_t* outbuf, int32_t sample_count, VGMSTRE
return;
decode_fail:
sbuf_silence_s16(outbuf, sample_count, vgmstream->channels, samples_filled);
sbuf_silence_rest(sdst);
}

View File

@ -8,9 +8,9 @@
#include "../base/sbuf.h"
/* basic layouts */
void render_vgmstream_flat(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
void render_vgmstream_flat(sbuf_t* sbuf, VGMSTREAM* vgmstream);
void render_vgmstream_interleave(sample_t* buffer, int32_t sample_count, VGMSTREAM* vgmstream);
void render_vgmstream_interleave(sbuf_t* sbuf, VGMSTREAM* vgmstream);
/* segmented layout */
@ -56,7 +56,7 @@ 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 render_vgmstream_blocked(sbuf_t* sbuf, VGMSTREAM* vgmstream);
void block_update(off_t block_offset, VGMSTREAM* vgmstream);
void block_update_ast(off_t block_ofset, VGMSTREAM* vgmstream);