diff --git a/src/base/api_decode_play.c b/src/base/api_decode_play.c index bc1dad7c..31b7173b 100644 --- a/src/base/api_decode_play.c +++ b/src/base/api_decode_play.c @@ -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); diff --git a/src/base/decode.c b/src/base/decode.c index 0e914e59..157fec3c 100644 --- a/src/base/decode.c +++ b/src/base/decode.c @@ -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; } } diff --git a/src/base/decode.h b/src/base/decode.h index 4556b272..deef7187 100644 --- a/src/base/decode.h +++ b/src/base/decode.h @@ -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); diff --git a/src/base/info.c b/src/base/info.c index b1b94b17..f6610ed6 100644 --- a/src/base/info.c +++ b/src/base/info.c @@ -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) { diff --git a/src/base/mixing.c b/src/base/mixing.c index 3db330d2..fd7e22ae 100644 --- a/src/base/mixing.c +++ b/src/base/mixing.c @@ -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) { diff --git a/src/base/render.c b/src/base/render.c index de878d4f..bdabb6e1 100644 --- a/src/base/render.c +++ b/src/base/render.c @@ -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); diff --git a/src/base/sbuf.c b/src/base/sbuf.c index 184c63e0..5f7538ce 100644 --- a/src/base/sbuf.c +++ b/src/base/sbuf.c @@ -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; } diff --git a/src/layout/blocked.c b/src/layout/blocked.c index ad3355ae..acea36ae 100644 --- a/src/layout/blocked.c +++ b/src/layout/blocked.c @@ -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 */ diff --git a/src/layout/flat.c b/src/layout/flat.c index 5a58605c..83220af4 100644 --- a/src/layout/flat.c +++ b/src/layout/flat.c @@ -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); } diff --git a/src/layout/interleave.c b/src/layout/interleave.c index 63bde81a..54d78aa9 100644 --- a/src/layout/interleave.c +++ b/src/layout/interleave.c @@ -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); } diff --git a/src/layout/layout.h b/src/layout/layout.h index 1c298c36..3c35ec6d 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -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);