From de074e503b1e0fdcb9206aa7eb79c0a570105db7 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 8 Aug 2021 00:11:55 +0200 Subject: [PATCH] relic: clean API for easier external lib usage --- src/coding/relic_decoder.c | 493 +++---------------------------- src/coding/relic_decoder_lib.c | 452 ++++++++++++++++++++++++++++ src/coding/relic_decoder_lib.h | 23 ++ src/libvgmstream.vcproj | 8 + src/libvgmstream.vcxproj | 2 + src/libvgmstream.vcxproj.filters | 6 + 6 files changed, 534 insertions(+), 450 deletions(-) create mode 100644 src/coding/relic_decoder_lib.c create mode 100644 src/coding/relic_decoder_lib.h diff --git a/src/coding/relic_decoder.c b/src/coding/relic_decoder.c index 267ba6ef..3dfcfc98 100644 --- a/src/coding/relic_decoder.c +++ b/src/coding/relic_decoder.c @@ -1,70 +1,57 @@ -#include #include "coding.h" +#include "relic_decoder_lib.h" -/* Relic Codec decoder, a fairly simple mono-interleave DCT-based codec. - * - * Decompiled from Relic's dec.exe with some info from Homeworld source code .h/lib - * files (released around 2003 through Relic Dev Network), accurate with minor +-1 - * samples due to double<>float ops or maybe original compiler (Intel's) diffs. - * - * TODO: clean API, fix looping - */ - -/* mixfft.c */ -extern void fft(int n, float* xRe, float* xIm, float* yRe, float* yIm); - -static relic_codec_data* relic_init_codec(int channels, int bitrate, int codec_rate); -static int decode_frame_next(VGMSTREAMCHANNEL* stream, relic_codec_data* data); -static void copy_samples(relic_codec_data* data, sample_t* outbuf, int32_t samples_to_get); -static void reset_codec(relic_codec_data* data); - -#define RELIC_MAX_CHANNELS 2 -#define RELIC_MAX_SCALES 6 -#define RELIC_BASE_SCALE 10.0f -#define RELIC_FREQUENCY_MASKING_FACTOR 1.0f -#define RELIC_CRITICAL_BAND_COUNT 27 -#define RELIC_PI 3.14159265358979323846f -#define RELIC_SIZE_LOW 128 -#define RELIC_SIZE_MID 256 -#define RELIC_SIZE_HIGH 512 -#define RELIC_MAX_SIZE RELIC_SIZE_HIGH -#define RELIC_MAX_FREQ (RELIC_MAX_SIZE / 2) -#define RELIC_MAX_FFT (RELIC_MAX_SIZE / 4) -#define RELIC_MIN_BITRATE 256 -#define RELIC_MAX_BITRATE 2048 -#define RELIC_MAX_FRAME_SIZE ((RELIC_MAX_BITRATE / 8) + 0x04) /* extra 0x04 for the bitreader */ - +//TODO: fix looping struct relic_codec_data { - /* decoder info */ + relic_handle_t* handle; int channels; int frame_size; - int wave_size; - int freq_size; - int dct_mode; - int samples_mode; - /* decoder init state */ - float scales[RELIC_MAX_SCALES]; /* quantization scales */ - float dct[RELIC_MAX_SIZE]; - float window[RELIC_MAX_SIZE]; - /* decoder frame state */ - uint8_t exponents[RELIC_MAX_CHANNELS][RELIC_MAX_FREQ]; /* quantization/scale indexes */ - float freq1[RELIC_MAX_FREQ]; /* dequantized spectrum */ - float freq2[RELIC_MAX_FREQ]; - float wave_cur[RELIC_MAX_CHANNELS][RELIC_MAX_SIZE]; /* current frame samples */ - float wave_prv[RELIC_MAX_CHANNELS][RELIC_MAX_SIZE]; /* previous frame samples */ - /* sample state */ int32_t samples_discard; int32_t samples_consumed; int32_t samples_filled; }; -/* ************************************* */ - relic_codec_data* init_relic(int channels, int bitrate, int codec_rate) { - return relic_init_codec(channels, bitrate, codec_rate); + relic_codec_data* data = NULL; + + data = calloc(1, sizeof(relic_codec_data)); + if (!data) goto fail; + + data->handle = relic_init(channels, bitrate, codec_rate); + if (!data->handle) goto fail; + + data->channels = channels; + data->frame_size = relic_get_frame_size(data->handle); + + return data; +fail: + free_relic(data); + return NULL; +} + +static int decode_frame_next(VGMSTREAMCHANNEL* stream, relic_codec_data* data) { + int ch; + int bytes; + int ok; + uint8_t buf[RELIC_BUFFER_SIZE]; + + for (ch = 0; ch < data->channels; ch++) { + bytes = read_streamfile(buf, stream->offset, data->frame_size, stream->streamfile); + if (bytes != data->frame_size) goto fail; + stream->offset += data->frame_size; + + ok = relic_decode_frame(data->handle, buf, ch); + if (!ok) goto fail; + } + + data->samples_consumed = 0; + data->samples_filled = RELIC_SAMPLES_PER_FRAME; + return 1; +fail: + return 0; } void decode_relic(VGMSTREAMCHANNEL* stream, relic_codec_data* data, sample_t* outbuf, int32_t samples_to_do) { @@ -86,7 +73,7 @@ void decode_relic(VGMSTREAMCHANNEL* stream, relic_codec_data* data, sample_t* ou if (samples_to_get > samples_to_do) samples_to_get = samples_to_do; - copy_samples(data, outbuf, samples_to_get); + relic_get_pcm16(data->handle, outbuf, samples_to_get, data->samples_consumed); samples_to_do -= samples_to_get; outbuf += samples_to_get * data->channels; @@ -111,7 +98,7 @@ decode_fail: void reset_relic(relic_codec_data* data) { if (!data) return; - reset_codec(data); + relic_reset(data->handle); data->samples_filled = 0; data->samples_consumed = 0; data->samples_discard = 0; @@ -127,404 +114,10 @@ void seek_relic(relic_codec_data* data, int32_t num_sample) { void free_relic(relic_codec_data* data) { if (!data) return; + relic_free(data->handle); free(data); } -/* ***************************************** */ - -static const int16_t critical_band_data[RELIC_CRITICAL_BAND_COUNT] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 9, 11, 13, 15, 17, 20, 23, 27, - 31, 37, 43, 51, 62, 74, 89, 110, - 139, 180, 256 -}; - -static void init_dct(float* dct, int dct_size) { - int i; - int dct_quarter = dct_size >> 2; - - for (i = 0; i < dct_quarter; i++) { - double temp = ((float)i + 0.125f) * (RELIC_PI * 2.0f) * (1.0f / (float)dct_size); - dct[i] = sin(temp); - dct[dct_quarter + i] = cos(temp); - } -} - -static int apply_idct(const float* freq, float* wave, const float* dct, int dct_size) { - int i; - float factor; - float out_re[RELIC_MAX_FFT]; - float out_im[RELIC_MAX_FFT]; - float in_re[RELIC_MAX_FFT]; - float in_im[RELIC_MAX_FFT]; - float wave_tmp[RELIC_MAX_SIZE]; - int dct_half = dct_size >> 1; - int dct_quarter = dct_size >> 2; - int dct_3quarter = 3 * (dct_size >> 2); - - /* prerotation? */ - for (i = 0; i < dct_quarter; i++) { - float coef1 = freq[2 * i] * 0.5f; - float coef2 = freq[dct_half - 1 - 2 * i] * 0.5f; - in_re[i] = coef1 * dct[dct_quarter + i] + coef2 * dct[i]; - in_im[i] = -coef1 * dct[i] + coef2 * dct[dct_quarter + i]; - } - - /* main FFT */ - fft(dct_quarter, in_re, in_im, out_re, out_im); - - /* postrotation, window and reorder? */ - factor = 8.0 / sqrt(dct_size); - for (i = 0; i < dct_quarter; i++) { - float out_re_i = out_re[i]; - out_re[i] = (out_re[i] * dct[dct_quarter + i] + out_im[i] * dct[i]) * factor; - out_im[i] = (-out_re_i * dct[i] + out_im[i] * dct[dct_quarter + i]) * factor; - wave_tmp[i * 2] = out_re[i]; - wave_tmp[i * 2 + dct_half] = out_im[i]; - } - for (i = 1; i < dct_size; i += 2) { - wave_tmp[i] = -wave_tmp[dct_size - 1 - i]; - } - - /* wave mix thing? */ - for (i = 0; i < dct_3quarter; i++) { - wave[i] = wave_tmp[dct_quarter + i]; - } - for (i = dct_3quarter; i < dct_size; i++) { - wave[i] = -wave_tmp[i - dct_3quarter]; - } - return 0; -} - -static void decode_frame(const float* freq1, const float* freq2, float* wave_cur, float* wave_prv, const float* dct, const float* window, int dct_size) { - int i; - float wave_tmp[RELIC_MAX_SIZE]; - int dct_half = dct_size >> 1; - - /* copy for first half(?) */ - memcpy(wave_cur, wave_prv, RELIC_MAX_SIZE * sizeof(float)); - - /* transform frequency domain to time domain with DCT/FFT */ - apply_idct(freq1, wave_tmp, dct, dct_size); - apply_idct(freq2, wave_prv, dct, dct_size); - - /* overlap and apply window function to filter this block's beginning */ - for (i = 0; i < dct_half; i++) { - wave_cur[dct_half + i] = wave_tmp[i] * window[i] + wave_cur[dct_half + i] * window[dct_half + i]; - wave_prv[i] = wave_prv[i] * window[i] + wave_tmp[dct_half + i] * window[dct_half + i]; - } -} - -static void init_window(float *window, int dct_size) { - int i; - - for (i = 0; i < dct_size; i++) { - window[i] = sin((float)i * (RELIC_PI / dct_size)); - } -} - -static void relic_decode_frame(const float* freq1, const float* freq2, float* wave_cur, float* wave_prv, const float* dct, const float* window, int dct_mode, int samples_mode) { - int i; - float wave_tmp[RELIC_MAX_SIZE]; - - /* dec_relic only uses 512/512 mode, source references 256/256 (effects only?) too */ - - if (samples_mode == RELIC_SIZE_LOW) { - { - /* 128 DCT to 128 samples */ - decode_frame(freq1, freq2, wave_cur, wave_prv, dct, window, RELIC_SIZE_LOW); - } - } - else if (samples_mode == RELIC_SIZE_MID) { - if (dct_mode == RELIC_SIZE_LOW) { - /* 128 DCT to 256 samples (repeat sample x2) */ - decode_frame(freq1, freq2, wave_tmp, wave_prv, dct, window, RELIC_SIZE_LOW); - for (i = 0; i < 256 - 1; i += 2) { - wave_cur[i + 0] = wave_tmp[i >> 1]; - wave_cur[i + 1] = wave_tmp[i >> 1]; - } - } - else { - /* 256 DCT to 256 samples */ - decode_frame(freq1, freq2, wave_cur, wave_prv, dct, window, RELIC_SIZE_MID); - } - } - else if (samples_mode == RELIC_SIZE_HIGH) { - if (dct_mode == RELIC_SIZE_LOW) { - /* 128 DCT to 512 samples (repeat sample x4) */ - decode_frame(freq1, freq2, wave_tmp, wave_prv, dct, window, RELIC_SIZE_LOW); - for (i = 0; i < 512 - 1; i += 4) { - wave_cur[i + 0] = wave_tmp[i >> 2]; - wave_cur[i + 1] = wave_tmp[i >> 2]; - wave_cur[i + 2] = wave_tmp[i >> 2]; - wave_cur[i + 3] = wave_tmp[i >> 2]; - } - } - else if (dct_mode == RELIC_SIZE_MID) { - /* 256 DCT to 512 samples (repeat sample x2) */ - decode_frame(freq1, freq2, wave_tmp, wave_prv, dct, window, RELIC_SIZE_MID); - for (i = 0; i < 512 - 1; i += 2) { - wave_cur[i + 0] = wave_tmp[i >> 1]; - wave_cur[i + 1] = wave_tmp[i >> 1]; - } - } - else { - /* 512 DCT to 512 samples */ - decode_frame(freq1, freq2, wave_cur, wave_prv, dct, window, RELIC_SIZE_HIGH); - } - } -} - - -/* reads 32b max, packed in LSB order per byte (like Vorbis), ex. - * with 0x45 6A=01000101 01101010 could read 4b=0101, 6b=100100, 3b=010 ... - * assumes buf has enough extra bits to read 32b (size +0x04) */ -static uint32_t read_ubits(uint8_t bits, uint32_t offset, uint8_t* buf) { - uint32_t shift, mask, pos, val; - - shift = offset - 8 * (offset / 8); - mask = (1 << bits) - 1; - pos = offset / 8; - val = (buf[pos+0]) | (buf[pos+1]<<8) | (buf[pos+2]<<16) | (buf[pos+3]<<24); - return (val >> shift) & mask; -} - -static int read_sbits(uint8_t bits, uint32_t offset, uint8_t* buf) { - uint32_t val = read_ubits(bits, offset, buf); - int outval; - if (val >> (bits - 1) == 1) { /* upper bit = sign */ - uint32_t mask = (1 << (bits - 1)) - 1; - outval = (int)(val & mask); - outval = -outval; - } - else { - outval = (int)val; - } - return outval; -} - -static void init_dequantization(float* scales) { - int i; - - scales[0] = RELIC_BASE_SCALE; - for (i = 1; i < RELIC_MAX_SCALES; i++) { - scales[i] = scales[i - 1] * scales[0]; - } - for (i = 0; i < RELIC_MAX_SCALES; i++) { - scales[i] = RELIC_FREQUENCY_MASKING_FACTOR / (double) ((1 << (i + 1)) - 1) * scales[i]; - } -} - -static int relic_unpack_frame(uint8_t* buf, int buf_size, float* freq1, float* freq2, const float* scales, uint8_t* exponents, int freq_size) { - uint8_t flags, cb_bits, ev_bits, ei_bits, qv_bits; - int qv; - uint8_t ev; - uint8_t move, pos; - uint32_t bit_offset, max_offset; - int i, j; - int freq_half = freq_size >> 1; - - - memset(freq1, 0, RELIC_MAX_FREQ * sizeof(float)); - memset(freq2, 0, RELIC_MAX_FREQ * sizeof(float)); - - flags = read_ubits(2u, 0u, buf); - cb_bits = read_ubits(3u, 2u, buf); - ev_bits = read_ubits(2u, 5u, buf); - ei_bits = read_ubits(4u, 7u, buf); - bit_offset = 11; - max_offset = buf_size * 8u; - - /* reset exponents indexes */ - if ((flags & 1) == 1) { - memset(exponents, 0, RELIC_MAX_FREQ); - } - - /* read packed exponents indexes for all bands */ - if (cb_bits > 0 && ev_bits > 0) { - pos = 0; - for (i = 0; i < RELIC_CRITICAL_BAND_COUNT - 1; i++) { - if (bit_offset + cb_bits > max_offset) - goto fail; - move = read_ubits(cb_bits, bit_offset, buf); - bit_offset += cb_bits; - - if (i > 0 && move == 0) - break; - pos += move; - - if (bit_offset + ev_bits > max_offset) - goto fail; - ev = read_ubits(ev_bits, bit_offset, buf); - bit_offset += ev_bits; - - if (pos + 1 >= sizeof(critical_band_data)) - goto fail; - for (j = critical_band_data[pos]; j < critical_band_data[pos + 1]; j++) { - exponents[j] = ev; - } - } - } - - /* read quantized values */ - if (freq_half > 0 && ei_bits > 0) { - - /* read first part */ - pos = 0; - for (i = 0; i < RELIC_MAX_FREQ; i++) { - if (bit_offset + ei_bits > max_offset) - goto fail; - move = read_ubits(ei_bits, bit_offset, buf); - bit_offset += ei_bits; - - if (i > 0 && move == 0) - break; - pos += move; - - if (pos >= RELIC_MAX_FREQ) - goto fail; - qv_bits = exponents[pos]; - - if (bit_offset + qv_bits + 2u > max_offset) - goto fail; - qv = read_sbits(qv_bits + 2u, bit_offset, buf); - bit_offset += qv_bits + 2u; - - if (qv != 0 && pos < freq_half && qv_bits < 6) { - freq1[pos] = (float)qv * scales[qv_bits]; - } - } - - /* read second part, or clone it */ - if ((flags & 2) == 2) { - memcpy(freq2, freq1, RELIC_MAX_FREQ * sizeof(float)); - } - else { - pos = 0; - for (i = 0; i < RELIC_MAX_FREQ; i++) { - if (bit_offset + ei_bits > max_offset) - goto fail; - move = read_ubits(ei_bits, bit_offset, buf); - bit_offset += ei_bits; - - if (i > 0 && move == 0) - break; - pos += move; - - if (pos >= RELIC_MAX_FREQ) - goto fail; - qv_bits = exponents[pos]; - - if (bit_offset + qv_bits + 2u > max_offset) - goto fail; - qv = read_sbits(qv_bits + 2u, bit_offset, buf); - bit_offset += qv_bits + 2u; - - if (qv != 0 && pos < freq_half && qv_bits < 6) { - freq2[pos] = (float)qv * scales[qv_bits]; - } - } - } - } - - return 1; -fail: - VGM_LOG("RELIC: unpack fail\n"); - return 0; /* original code doesn't check bad sizes so no return errcode */ -} - -static int decode_frame_next(VGMSTREAMCHANNEL* stream, relic_codec_data* data) { - int ch; - int bytes; - int ok; - uint8_t buf[RELIC_MAX_FRAME_SIZE]; - - for (ch = 0; ch < data->channels; ch++) { - /* clean extra bytes for bitreader */ - memset(buf + data->frame_size, 0, RELIC_MAX_FRAME_SIZE - data->frame_size); - - bytes = read_streamfile(buf, stream->offset, data->frame_size, stream->streamfile); - if (bytes != data->frame_size) goto fail; - stream->offset += data->frame_size; - - ok = relic_unpack_frame(buf, sizeof(buf), data->freq1, data->freq2, data->scales, data->exponents[ch], data->freq_size); - if (!ok) goto fail; - - relic_decode_frame(data->freq1, data->freq2, data->wave_cur[ch], data->wave_prv[ch], data->dct, data->window, data->dct_mode, data->samples_mode); - } - - data->samples_consumed = 0; - data->samples_filled = data->wave_size; - return 1; -fail: - return 0; -} - -static void copy_samples(relic_codec_data* data, sample_t* outbuf, int32_t samples) { - int s, ch; - int ichs = data->channels; - int skip = data->samples_consumed; - for (ch = 0; ch < ichs; ch++) { - for (s = 0; s < samples; s++) { - double d64_sample = data->wave_cur[ch][skip + s]; - int pcm_sample = clamp16((int32_t)d64_sample); - - /* f32 in PCM 32767.0 .. -32768.0 format, original code - * does some custom double-to-int rint() though */ - //FQ_BNUM ((float)(1<<26)*(1<<26)*1.5) - //rint(x) ((d64 = (double)(x)+FQ_BNUM), *(int*)(&d64)) - - outbuf[s*ichs + ch] = pcm_sample; - } - } -} - -static relic_codec_data* relic_init_codec(int channels, int bitrate, int codec_rate) { - relic_codec_data* data = NULL; - - if (channels < 0 || channels > RELIC_MAX_CHANNELS) - goto fail; - - data = calloc(1, sizeof(relic_codec_data)); - if (!data) goto fail; - - data->channels = channels; - - /* dequantized freq1+2 size (separate from DCT) */ - if (codec_rate < 22050) /* probably 11025 only */ - data->freq_size = RELIC_SIZE_LOW; - else if (codec_rate == 22050) - data->freq_size = RELIC_SIZE_MID; - else if (codec_rate > 22050) /* probably 44100 only */ - data->freq_size = RELIC_SIZE_HIGH; - - /* default for streams (only a few mode combos are valid, see decode) */ - data->wave_size = RELIC_SIZE_HIGH; - data->dct_mode = RELIC_SIZE_HIGH; - data->samples_mode = RELIC_SIZE_HIGH; - - init_dct(data->dct, RELIC_SIZE_HIGH); - init_window(data->window, RELIC_SIZE_HIGH); - init_dequantization(data->scales); - memset(data->wave_prv, 0, RELIC_MAX_CHANNELS * RELIC_MAX_SIZE * sizeof(float)); - - /* known bitrates: 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400, 0x800 - * dec.exe doesn't validate this, so there may be more */ - if (bitrate < RELIC_MIN_BITRATE || bitrate > RELIC_MAX_BITRATE) - goto fail; - data->frame_size = (bitrate / 8); /* 0x100 and 0x80 are common */ - - - return data; -fail: - free_relic(data); - return NULL; -} - -static void reset_codec(relic_codec_data* data) { - memset(data->wave_prv, 0, RELIC_MAX_CHANNELS * RELIC_MAX_SIZE * sizeof(float)); -} - int32_t relic_bytes_to_samples(size_t bytes, int channels, int bitrate) { return bytes / channels / (bitrate / 8) * 512; } diff --git a/src/coding/relic_decoder_lib.c b/src/coding/relic_decoder_lib.c new file mode 100644 index 00000000..c2f4ed47 --- /dev/null +++ b/src/coding/relic_decoder_lib.c @@ -0,0 +1,452 @@ +#include +#include +#include +#include "relic_decoder_lib.h" + +/* Relic Codec decoder, a fairly simple mono-interleave DCT-based codec. + * + * Decompiled from Relic's dec.exe with some info from Homeworld source code .h/lib + * files (released around 2003 through Relic Dev Network), accurate with minor +-1 + * samples due to double<>float ops or maybe original compiler (Intel's) diffs. + */ + +/* mixfft.c */ +extern void fft(int n, float* xRe, float* xIm, float* yRe, float* yIm); + + +#define RELIC_MAX_CHANNELS 2 +#define RELIC_MAX_SCALES 6 +#define RELIC_BASE_SCALE 10.0f +#define RELIC_FREQUENCY_MASKING_FACTOR 1.0f +#define RELIC_CRITICAL_BAND_COUNT 27 +#define RELIC_PI 3.14159265358979323846f +#define RELIC_SIZE_LOW 128 +#define RELIC_SIZE_MID 256 +#define RELIC_SIZE_HIGH 512 +#define RELIC_MAX_SIZE RELIC_SIZE_HIGH +#define RELIC_MAX_FREQ (RELIC_MAX_SIZE / 2) +#define RELIC_MAX_FFT (RELIC_MAX_SIZE / 4) +#define RELIC_MIN_BITRATE 256 +#define RELIC_MAX_BITRATE 2048 +//#define RELIC_MAX_FRAME_SIZE ((RELIC_MAX_BITRATE / 8) + 0x04) /* extra 0x04 for the bitreader */ + + +struct relic_handle_t { + /* decoder info */ + int channels; + int frame_size; + int wave_size; + int freq_size; + int dct_mode; + int samples_mode; + /* decoder init state */ + float scales[RELIC_MAX_SCALES]; /* quantization scales */ + float dct[RELIC_MAX_SIZE]; + float window[RELIC_MAX_SIZE]; + /* decoder frame state */ + uint8_t exponents[RELIC_MAX_CHANNELS][RELIC_MAX_FREQ]; /* quantization/scale indexes */ + float freq1[RELIC_MAX_FREQ]; /* dequantized spectrum */ + float freq2[RELIC_MAX_FREQ]; + float wave_cur[RELIC_MAX_CHANNELS][RELIC_MAX_SIZE]; /* current frame samples */ + float wave_prv[RELIC_MAX_CHANNELS][RELIC_MAX_SIZE]; /* previous frame samples */ +}; + +/* ************************************* */ + +static const int16_t critical_band_data[RELIC_CRITICAL_BAND_COUNT] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 9, 11, 13, 15, 17, 20, 23, 27, + 31, 37, 43, 51, 62, 74, 89, 110, + 139, 180, 256 +}; + +static void init_dct(float* dct, int dct_size) { + int i; + int dct_quarter = dct_size >> 2; + + for (i = 0; i < dct_quarter; i++) { + double temp = ((float)i + 0.125f) * (RELIC_PI * 2.0f) * (1.0f / (float)dct_size); + dct[i] = sin(temp); + dct[dct_quarter + i] = cos(temp); + } +} + +static int apply_idct(const float* freq, float* wave, const float* dct, int dct_size) { + int i; + float factor; + float out_re[RELIC_MAX_FFT]; + float out_im[RELIC_MAX_FFT]; + float in_re[RELIC_MAX_FFT]; + float in_im[RELIC_MAX_FFT]; + float wave_tmp[RELIC_MAX_SIZE]; + int dct_half = dct_size >> 1; + int dct_quarter = dct_size >> 2; + int dct_3quarter = 3 * (dct_size >> 2); + + /* prerotation? */ + for (i = 0; i < dct_quarter; i++) { + float coef1 = freq[2 * i] * 0.5f; + float coef2 = freq[dct_half - 1 - 2 * i] * 0.5f; + in_re[i] = coef1 * dct[dct_quarter + i] + coef2 * dct[i]; + in_im[i] = -coef1 * dct[i] + coef2 * dct[dct_quarter + i]; + } + + /* main FFT */ + fft(dct_quarter, in_re, in_im, out_re, out_im); + + /* postrotation, window and reorder? */ + factor = 8.0 / sqrt(dct_size); + for (i = 0; i < dct_quarter; i++) { + float out_re_i = out_re[i]; + out_re[i] = (out_re[i] * dct[dct_quarter + i] + out_im[i] * dct[i]) * factor; + out_im[i] = (-out_re_i * dct[i] + out_im[i] * dct[dct_quarter + i]) * factor; + wave_tmp[i * 2] = out_re[i]; + wave_tmp[i * 2 + dct_half] = out_im[i]; + } + for (i = 1; i < dct_size; i += 2) { + wave_tmp[i] = -wave_tmp[dct_size - 1 - i]; + } + + /* wave mix thing? */ + for (i = 0; i < dct_3quarter; i++) { + wave[i] = wave_tmp[dct_quarter + i]; + } + for (i = dct_3quarter; i < dct_size; i++) { + wave[i] = -wave_tmp[i - dct_3quarter]; + } + return 0; +} + +static void decode_frame(const float* freq1, const float* freq2, float* wave_cur, float* wave_prv, const float* dct, const float* window, int dct_size) { + int i; + float wave_tmp[RELIC_MAX_SIZE]; + int dct_half = dct_size >> 1; + + /* copy for first half(?) */ + memcpy(wave_cur, wave_prv, RELIC_MAX_SIZE * sizeof(float)); + + /* transform frequency domain to time domain with DCT/FFT */ + apply_idct(freq1, wave_tmp, dct, dct_size); + apply_idct(freq2, wave_prv, dct, dct_size); + + /* overlap and apply window function to filter this block's beginning */ + for (i = 0; i < dct_half; i++) { + wave_cur[dct_half + i] = wave_tmp[i] * window[i] + wave_cur[dct_half + i] * window[dct_half + i]; + wave_prv[i] = wave_prv[i] * window[i] + wave_tmp[dct_half + i] * window[dct_half + i]; + } +} + +static void init_window(float *window, int dct_size) { + int i; + + for (i = 0; i < dct_size; i++) { + window[i] = sin((float)i * (RELIC_PI / dct_size)); + } +} + +static void decode_frame_base(const float* freq1, const float* freq2, float* wave_cur, float* wave_prv, const float* dct, const float* window, int dct_mode, int samples_mode) { + int i; + float wave_tmp[RELIC_MAX_SIZE]; + + /* dec_relic only uses 512/512 mode, source references 256/256 (effects only?) too */ + + if (samples_mode == RELIC_SIZE_LOW) { + { + /* 128 DCT to 128 samples */ + decode_frame(freq1, freq2, wave_cur, wave_prv, dct, window, RELIC_SIZE_LOW); + } + } + else if (samples_mode == RELIC_SIZE_MID) { + if (dct_mode == RELIC_SIZE_LOW) { + /* 128 DCT to 256 samples (repeat sample x2) */ + decode_frame(freq1, freq2, wave_tmp, wave_prv, dct, window, RELIC_SIZE_LOW); + for (i = 0; i < 256 - 1; i += 2) { + wave_cur[i + 0] = wave_tmp[i >> 1]; + wave_cur[i + 1] = wave_tmp[i >> 1]; + } + } + else { + /* 256 DCT to 256 samples */ + decode_frame(freq1, freq2, wave_cur, wave_prv, dct, window, RELIC_SIZE_MID); + } + } + else if (samples_mode == RELIC_SIZE_HIGH) { + if (dct_mode == RELIC_SIZE_LOW) { + /* 128 DCT to 512 samples (repeat sample x4) */ + decode_frame(freq1, freq2, wave_tmp, wave_prv, dct, window, RELIC_SIZE_LOW); + for (i = 0; i < 512 - 1; i += 4) { + wave_cur[i + 0] = wave_tmp[i >> 2]; + wave_cur[i + 1] = wave_tmp[i >> 2]; + wave_cur[i + 2] = wave_tmp[i >> 2]; + wave_cur[i + 3] = wave_tmp[i >> 2]; + } + } + else if (dct_mode == RELIC_SIZE_MID) { + /* 256 DCT to 512 samples (repeat sample x2) */ + decode_frame(freq1, freq2, wave_tmp, wave_prv, dct, window, RELIC_SIZE_MID); + for (i = 0; i < 512 - 1; i += 2) { + wave_cur[i + 0] = wave_tmp[i >> 1]; + wave_cur[i + 1] = wave_tmp[i >> 1]; + } + } + else { + /* 512 DCT to 512 samples */ + decode_frame(freq1, freq2, wave_cur, wave_prv, dct, window, RELIC_SIZE_HIGH); + } + } +} + + +/* reads 32b max, packed in LSB order per byte (like Vorbis), ex. + * with 0x45 6A=01000101 01101010 could read 4b=0101, 6b=100100, 3b=010 ... + * assumes buf has enough extra bits to read 32b (size +0x04) */ +static uint32_t read_ubits(uint8_t bits, uint32_t offset, uint8_t* buf) { + uint32_t shift, mask, pos, val; + + shift = offset - 8 * (offset / 8); + mask = (1 << bits) - 1; + pos = offset / 8; + val = (buf[pos+0]) | (buf[pos+1]<<8) | (buf[pos+2]<<16) | (buf[pos+3]<<24); + return (val >> shift) & mask; +} + +static int read_sbits(uint8_t bits, uint32_t offset, uint8_t* buf) { + uint32_t val = read_ubits(bits, offset, buf); + int outval; + if (val >> (bits - 1) == 1) { /* upper bit = sign */ + uint32_t mask = (1 << (bits - 1)) - 1; + outval = (int)(val & mask); + outval = -outval; + } + else { + outval = (int)val; + } + return outval; +} + +static void init_dequantization(float* scales) { + int i; + + scales[0] = RELIC_BASE_SCALE; + for (i = 1; i < RELIC_MAX_SCALES; i++) { + scales[i] = scales[i - 1] * scales[0]; + } + for (i = 0; i < RELIC_MAX_SCALES; i++) { + scales[i] = RELIC_FREQUENCY_MASKING_FACTOR / (double) ((1 << (i + 1)) - 1) * scales[i]; + } +} + +static int unpack_frame(uint8_t* buf, int buf_size, float* freq1, float* freq2, const float* scales, uint8_t* exponents, int freq_size) { + uint8_t flags, cb_bits, ev_bits, ei_bits, qv_bits; + int qv; + uint8_t ev; + uint8_t move, pos; + uint32_t bit_offset, max_offset; + int i, j; + int freq_half = freq_size >> 1; + + + memset(freq1, 0, RELIC_MAX_FREQ * sizeof(float)); + memset(freq2, 0, RELIC_MAX_FREQ * sizeof(float)); + + flags = read_ubits(2u, 0u, buf); + cb_bits = read_ubits(3u, 2u, buf); + ev_bits = read_ubits(2u, 5u, buf); + ei_bits = read_ubits(4u, 7u, buf); + bit_offset = 11; + max_offset = buf_size * 8u; + + /* reset exponents indexes */ + if ((flags & 1) == 1) { + memset(exponents, 0, RELIC_MAX_FREQ); + } + + /* read packed exponents indexes for all bands */ + if (cb_bits > 0 && ev_bits > 0) { + pos = 0; + for (i = 0; i < RELIC_CRITICAL_BAND_COUNT - 1; i++) { + if (bit_offset + cb_bits > max_offset) + goto fail; + move = read_ubits(cb_bits, bit_offset, buf); + bit_offset += cb_bits; + + if (i > 0 && move == 0) + break; + pos += move; + + if (bit_offset + ev_bits > max_offset) + goto fail; + ev = read_ubits(ev_bits, bit_offset, buf); + bit_offset += ev_bits; + + if (pos + 1 >= sizeof(critical_band_data)) + goto fail; + for (j = critical_band_data[pos]; j < critical_band_data[pos + 1]; j++) { + exponents[j] = ev; + } + } + } + + /* read quantized values */ + if (freq_half > 0 && ei_bits > 0) { + + /* read first part */ + pos = 0; + for (i = 0; i < RELIC_MAX_FREQ; i++) { + if (bit_offset + ei_bits > max_offset) + goto fail; + move = read_ubits(ei_bits, bit_offset, buf); + bit_offset += ei_bits; + + if (i > 0 && move == 0) + break; + pos += move; + + if (pos >= RELIC_MAX_FREQ) + goto fail; + qv_bits = exponents[pos]; + + if (bit_offset + qv_bits + 2u > max_offset) + goto fail; + qv = read_sbits(qv_bits + 2u, bit_offset, buf); + bit_offset += qv_bits + 2u; + + if (qv != 0 && pos < freq_half && qv_bits < 6) { + freq1[pos] = (float)qv * scales[qv_bits]; + } + } + + /* read second part, or clone it */ + if ((flags & 2) == 2) { + memcpy(freq2, freq1, RELIC_MAX_FREQ * sizeof(float)); + } + else { + pos = 0; + for (i = 0; i < RELIC_MAX_FREQ; i++) { + if (bit_offset + ei_bits > max_offset) + goto fail; + move = read_ubits(ei_bits, bit_offset, buf); + bit_offset += ei_bits; + + if (i > 0 && move == 0) + break; + pos += move; + + if (pos >= RELIC_MAX_FREQ) + goto fail; + qv_bits = exponents[pos]; + + if (bit_offset + qv_bits + 2u > max_offset) + goto fail; + qv = read_sbits(qv_bits + 2u, bit_offset, buf); + bit_offset += qv_bits + 2u; + + if (qv != 0 && pos < freq_half && qv_bits < 6) { + freq2[pos] = (float)qv * scales[qv_bits]; + } + } + } + } + + return 1; +fail: + return 0; /* original code doesn't check bad sizes so no return errcode */ +} + +/*****************************************************************************/ + +relic_handle_t* relic_init(int channels, int bitrate, int codec_rate) { + relic_handle_t* handle = NULL; + + if (channels < 0 || channels > RELIC_MAX_CHANNELS) + goto fail; + + handle = calloc(1, sizeof(relic_handle_t)); + if (!handle) goto fail; + + handle->channels = channels; + + /* dequantized freq1+2 size (separate from DCT) */ + if (codec_rate < 22050) /* probably 11025 only */ + handle->freq_size = RELIC_SIZE_LOW; + else if (codec_rate == 22050) + handle->freq_size = RELIC_SIZE_MID; + else if (codec_rate > 22050) /* probably 44100 only */ + handle->freq_size = RELIC_SIZE_HIGH; + + /* default for streams (only a few mode combos are valid, see decode) */ + handle->wave_size = RELIC_SIZE_HIGH; + handle->dct_mode = RELIC_SIZE_HIGH; + handle->samples_mode = RELIC_SIZE_HIGH; + + init_dct(handle->dct, RELIC_SIZE_HIGH); + init_window(handle->window, RELIC_SIZE_HIGH); + init_dequantization(handle->scales); + memset(handle->wave_prv, 0, RELIC_MAX_CHANNELS * RELIC_MAX_SIZE * sizeof(float)); + + /* known bitrates: 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400, 0x800 + * dec.exe doesn't validate this, so there may be more */ + if (bitrate < RELIC_MIN_BITRATE || bitrate > RELIC_MAX_BITRATE) + goto fail; + handle->frame_size = (bitrate / 8); /* 0x100 and 0x80 are common */ + + + return handle; +fail: + relic_free(handle); + return NULL; +} + +void relic_free(relic_handle_t* handle) { + if (!handle) return; + free(handle); +} + +void relic_reset(relic_handle_t* handle) { + if (!handle) return; + memset(handle->wave_prv, 0, RELIC_MAX_CHANNELS * RELIC_MAX_SIZE * sizeof(float)); +} + +int relic_get_frame_size(relic_handle_t* handle) { + if (!handle) return 0; + return handle->frame_size; +} + +int relic_decode_frame(relic_handle_t* handle, uint8_t* buf, int channel) { + int ok; + + /* clean extra bytes for bitreader (due to a quirk in the original code it may read outside max frame size) */ + memset(buf + handle->frame_size, 0, RELIC_BUFFER_SIZE - handle->frame_size); + + ok = unpack_frame(buf, RELIC_BUFFER_SIZE, handle->freq1, handle->freq2, handle->scales, handle->exponents[channel], handle->freq_size); + if (!ok) return ok; + + decode_frame_base(handle->freq1, handle->freq2, handle->wave_cur[channel], handle->wave_prv[channel], handle->dct, handle->window, handle->dct_mode, handle->samples_mode); + + return 1; +} + +static inline int clamp16(int32_t val) { + if (val > 32767) return 32767; + else if (val < -32768) return -32768; + else return val; +} + +void relic_get_pcm16(relic_handle_t* handle, int16_t* outbuf, int32_t samples, int32_t skip) { + int s, ch; + int ichs = handle->channels; + + for (ch = 0; ch < ichs; ch++) { + for (s = 0; s < samples; s++) { + double d64_sample = handle->wave_cur[ch][skip + s]; + int pcm_sample = clamp16((int32_t)d64_sample); + + /* f32 in PCM 32767.0 .. -32768.0 format, original code + * does some custom double-to-int rint() though */ + //FQ_BNUM ((float)(1<<26)*(1<<26)*1.5) + //rint(x) ((d64 = (double)(x)+FQ_BNUM), *(int*)(&d64)) + + outbuf[s*ichs + ch] = pcm_sample; + } + } +} diff --git a/src/coding/relic_decoder_lib.h b/src/coding/relic_decoder_lib.h new file mode 100644 index 00000000..b9fae8e4 --- /dev/null +++ b/src/coding/relic_decoder_lib.h @@ -0,0 +1,23 @@ +#ifndef _RELIC_DECODER_LIB_H_ +#define _RELIC_DECODER_LIB_H_ + +#include + +#define RELIC_BUFFER_SIZE 0x104 +#define RELIC_SAMPLES_PER_FRAME 512 + +typedef struct relic_handle_t relic_handle_t; + +relic_handle_t* relic_init(int channels, int bitrate, int codec_rate); + +void relic_free(relic_handle_t* handle); + +void relic_reset(relic_handle_t* handle); + +int relic_get_frame_size(relic_handle_t* handle); + +int relic_decode_frame(relic_handle_t* handle, uint8_t* buf, int channel); + +void relic_get_pcm16(relic_handle_t* handle, int16_t* outbuf, int32_t samples, int32_t skip); + +#endif/*_RELIC_DECODER_LIB_H_ */ diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 81c3b9b0..f5ac660d 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -2094,6 +2094,10 @@ RelativePath=".\coding\nwa_decoder.h" > + + @@ -2338,6 +2342,10 @@ RelativePath=".\coding\relic_decoder.c" > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index abb8ca9c..616976cf 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -163,6 +163,7 @@ + @@ -644,6 +645,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 3ae31cb1..4ecb36cb 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -251,6 +251,9 @@ coding\Header Files + + coding\Header Files + coding\Header Files @@ -1399,6 +1402,9 @@ coding\Source Files + + coding\Source Files + coding\Source Files