diff --git a/src/base/decode.c b/src/base/decode.c index f1f30cac..43938b2e 100644 --- a/src/base/decode.c +++ b/src/base/decode.c @@ -6,10 +6,34 @@ #include "plugins.h" #include "sbuf.h" +#if VGM_TEST_DECODER +#include "../util/log.h" +#include "decode_state.h" + + +static void* decode_state_init() { + return calloc(1, sizeof(decode_state_t)); +} + +static void decode_state_reset(VGMSTREAM* vgmstream) { + memset(vgmstream->decode_state, 0, sizeof(decode_state_t)); +} + +// this could be part of the VGMSTREAM but for now keep separate as it simplifies +// some loop-related stuff +void* decode_init() { + return decode_state_init(); +} +#endif + + /* custom codec handling, not exactly "decode" stuff but here to simplify adding new codecs */ - void decode_free(VGMSTREAM* vgmstream) { +#if VGM_TEST_DECODER + free(vgmstream->decode_state); +#endif + if (!vgmstream->codec_data) return; @@ -127,6 +151,10 @@ void decode_free(VGMSTREAM* vgmstream) { void decode_seek(VGMSTREAM* vgmstream) { +#if VGM_TEST_DECODER + decode_state_reset(vgmstream); +#endif + if (!vgmstream->codec_data) return; @@ -228,6 +256,10 @@ void decode_seek(VGMSTREAM* vgmstream) { void decode_reset(VGMSTREAM* vgmstream) { +#if VGM_TEST_DECODER + decode_state_reset(vgmstream); +#endif + if (!vgmstream->codec_data) return; @@ -825,11 +857,74 @@ bool decode_uses_internal_offset_updates(VGMSTREAM* vgmstream) { return vgmstream->coding_type == coding_MS_IMA || vgmstream->coding_type == coding_MS_IMA_mono; } +#if VGM_TEST_DECODER +// decode frames for decoders which have their own sample buffer +static void decode_frames(sbuf_t* sbuf, VGMSTREAM* vgmstream) { + const int max_empty = 10000; + int num_empty = 0; + + decode_state_t* ds = vgmstream->decode_state; + + while (sbuf->filled < sbuf->samples) { + + // decode new frame if all was consumed + if (ds->sbuf.filled == 0) { + bool ok = false; + switch (vgmstream->coding_type) { + case coding_TAC: + ok = decode_tac_frame(vgmstream); + break; + default: + break; + } + + if (!ok) + goto decode_fail; + } + + if (ds->discard) { + // decode may signal that decoded samples need to be discarded, because of encoder delay + // (first samples of a file need to be ignored) or a loop + int current_discard = ds->discard; + if (current_discard > ds->sbuf.filled) + current_discard = ds->sbuf.filled; + + sbuf_consume(&ds->sbuf, current_discard); + + ds->discard -= current_discard; + } + else { + // copy + consume + int samples_copy = ds->sbuf.filled; + if (samples_copy > sbuf->samples - sbuf->filled) + samples_copy = sbuf->samples - sbuf->filled; + + sbuf_copy_segments(sbuf, &ds->sbuf); + sbuf_consume(&ds->sbuf, samples_copy); + + sbuf->filled += samples_copy; + } + } + + return; +decode_fail: + /* on error just put some 0 samples */ + VGM_LOG("VGMSTREAM: decode fail, missing %i samples\n", sbuf->samples - sbuf->filled); + sbuf_silence_rest(sbuf); +} +#endif + /* 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 (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) { +#if VGM_TEST_DECODER + sbuf_t sbuf_tmp = {0}; + sbuf_t* sbuf = &sbuf_tmp; + sbuf_init_s16(sbuf, buffer, samples_filled + samples_to_do, vgmstream->channels); + sbuf->filled = samples_filled; +#endif int ch; buffer += samples_filled * vgmstream->channels; /* passed externally to simplify I guess */ @@ -1566,6 +1661,9 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_filled, int samples_to_d } break; default: +#if VGM_TEST_DECODER + decode_frames(sbuf, vgmstream); +#endif break; } } diff --git a/src/base/decode.h b/src/base/decode.h index f959a464..4731eab4 100644 --- a/src/base/decode.h +++ b/src/base/decode.h @@ -3,6 +3,9 @@ #include "../vgmstream.h" +#if VGM_TEST_DECODER +void* decode_init(); +#endif void decode_free(VGMSTREAM* vgmstream); void decode_seek(VGMSTREAM* vgmstream); void decode_reset(VGMSTREAM* vgmstream); diff --git a/src/base/decode_state.h b/src/base/decode_state.h new file mode 100644 index 00000000..64bf7267 --- /dev/null +++ b/src/base/decode_state.h @@ -0,0 +1,13 @@ +#ifndef _DECODE_STATE_H +#define _DECODE_STATE_H + +#if VGM_TEST_DECODER +#include "sbuf.h" + +typedef struct { + int discard; + sbuf_t sbuf; +} decode_state_t; +#endif + +#endif diff --git a/src/coding/coding.h b/src/coding/coding.h index 2adb81f8..6e052438 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -372,6 +372,9 @@ typedef struct tac_codec_data tac_codec_data; tac_codec_data* init_tac(STREAMFILE* sf); void decode_tac(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do); +#if VGM_TEST_DECODER +bool decode_tac_frame(VGMSTREAM* vgmstream); +#endif void reset_tac(tac_codec_data* data); void seek_tac(tac_codec_data* data, int32_t num_sample); void free_tac(tac_codec_data* data); diff --git a/src/coding/tac_decoder.c b/src/coding/tac_decoder.c index 5bf1f6fa..ad0c21a1 100644 --- a/src/coding/tac_decoder.c +++ b/src/coding/tac_decoder.c @@ -1,6 +1,8 @@ #include "coding.h" #include "coding_utils_samples.h" - +#if VGM_TEST_DECODER +#include "../base/decode_state.h" +#endif #include "libs/tac_lib.h" @@ -129,6 +131,34 @@ fail: s16buf_silence(&outbuf, &samples_to_do, data->sbuf.channels); } +#if VGM_TEST_DECODER +bool decode_tac_frame(VGMSTREAM* vgmstream) { + VGMSTREAMCHANNEL* stream = &vgmstream->ch[0]; + tac_codec_data* data = vgmstream->codec_data; + decode_state_t* ds = vgmstream->decode_state; + + sbuf_init_s16(&ds->sbuf, data->samples, TAC_FRAME_SAMPLES, vgmstream->channels); + + bool ok; + + ok = read_frame(data, stream->streamfile); + if (!ok) return false; + + ok = decode_frame(data); + if (!ok) return false; + + ds->sbuf.filled = TAC_FRAME_SAMPLES; //TODO call sbuf_fill(samples); + + // copy and let decoder handle + if (data->samples_discard) { + ds->discard = data->samples_discard; + data->samples_discard = 0; + } + + return true; +} +#endif + void reset_tac(tac_codec_data* data) { if (!data) return; diff --git a/src/vgmstream.h b/src/vgmstream.h index 59bd5270..10d522fc 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -242,6 +242,9 @@ typedef struct { void* tmpbuf; /* garbage buffer used for seeking/trimming */ size_t tmpbuf_size; /* for all channels (samples = tmpbuf_size / channels / sample_size) */ +#if VGM_TEST_DECODER + void* decode_state; /* for some decoders (TO-DO: to be mover around) */ +#endif } VGMSTREAM;