mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-02-07 07:01:16 +01:00
api: tweak some internals for float decoders
This commit is contained in:
parent
6f8a8df1d2
commit
660484e64b
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -143,9 +143,13 @@ 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)
|
||||
return SFMT_S16;
|
||||
switch(vgmstream->coding_type) {
|
||||
case coding_KA1A:
|
||||
return SFMT_FLT;
|
||||
default:
|
||||
return SFMT_S16;
|
||||
}
|
||||
}
|
||||
|
||||
sfmt_t mixing_get_output_sample_type(VGMSTREAM* vgmstream) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user