Merge pull request #538 from bnnm/relic

relic-hx
This commit is contained in:
bnnm 2019-12-27 02:07:13 +01:00 committed by GitHub
commit 000f0a7295
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 2116 additions and 773 deletions

View File

@ -203,9 +203,16 @@ void flush_ea_mt(VGMSTREAM *vgmstream);
void seek_ea_mt(VGMSTREAM * vgmstream, int32_t num_sample); void seek_ea_mt(VGMSTREAM * vgmstream, int32_t num_sample);
void free_ea_mt(ea_mt_codec_data *data, int channels); void free_ea_mt(ea_mt_codec_data *data, int channels);
/* relic_decoder */
relic_codec_data* init_relic(int channels, int bitrate, int codec_rate);
void decode_relic(VGMSTREAMCHANNEL* stream, relic_codec_data* data, sample_t* outbuf, int32_t samples_to_do);
void reset_relic(relic_codec_data* data);
void seek_relic(relic_codec_data* data, int32_t num_sample);
void free_relic(relic_codec_data* data);
/* hca_decoder */ /* hca_decoder */
hca_codec_data *init_hca(STREAMFILE *streamFile); hca_codec_data *init_hca(STREAMFILE *streamFile);
void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do); void decode_hca(hca_codec_data * data, sample_t * outbuf, int32_t samples_to_do);
void reset_hca(hca_codec_data * data); void reset_hca(hca_codec_data * data);
void loop_hca(hca_codec_data * data, int32_t num_sample); void loop_hca(hca_codec_data * data, int32_t num_sample);
void free_hca(hca_codec_data * data); void free_hca(hca_codec_data * data);

500
src/coding/relic_decoder.c Normal file
View File

@ -0,0 +1,500 @@
#include "coding.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, improve validations (can segfault on bad data) and naming
*/
/* mixfft.c */
extern void fft(int n, float *xRe, float *xIm, float *yRe, float *yIm);
static relic_codec_data* 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_BITRATE_22 256
#define RELIC_BITRATE_44 512
#define RELIC_BITRATE_88 1024
#define RELIC_BITRATE_176 2048
#define RELIC_MAX_FRAME_SIZE ((RELIC_BITRATE_176 / 8) + 0x04) /* extra 0x04 for the bitreader */
struct relic_codec_data {
/* 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 */
/* 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 init_codec(channels, bitrate, codec_rate);
}
void decode_relic(VGMSTREAMCHANNEL* stream, relic_codec_data* data, sample_t* outbuf, int32_t samples_to_do) {
while (samples_to_do > 0) {
if (data->samples_consumed < data->samples_filled) {
/* consume samples */
int samples_to_get = (data->samples_filled - data->samples_consumed);
if (data->samples_discard) {
/* discard samples for looping */
if (samples_to_get > data->samples_discard)
samples_to_get = data->samples_discard;
data->samples_discard -= samples_to_get;
}
else {
/* get max samples and copy */
if (samples_to_get > samples_to_do)
samples_to_get = samples_to_do;
copy_samples(data, outbuf, samples_to_get);
samples_to_do -= samples_to_get;
outbuf += samples_to_get * data->channels;
}
/* mark consumed samples */
data->samples_consumed += samples_to_get;
}
else {
int ok = decode_frame_next(stream, data);
if (!ok) goto decode_fail;
}
}
return;
decode_fail:
/* on error just put some 0 samples */
VGM_LOG("RELIC: decode fail, missing %i samples\n", samples_to_do);
memset(outbuf, 0, samples_to_do * data->channels * sizeof(sample));
}
void reset_relic(relic_codec_data* data) {
if (!data) return;
reset_codec(data);
data->samples_filled = 0;
data->samples_consumed = 0;
data->samples_discard = 0;
}
void seek_relic(relic_codec_data* data, int32_t num_sample) {
if (!data) return;
reset_relic(data);
data->samples_discard = num_sample;
}
void free_relic(relic_codec_data* data) {
if (!data) return;
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 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);
if (val >> (bits - 1) == 1) { /* upper bit = sign */
uint32_t mask = (1 << (bits - 1)) - 1;
return -(val & mask);
}
return val;
}
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 void 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;
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;
/* 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 >= 8*buf_size)
break;
move = read_ubits(cb_bits, bit_offset, buf);
bit_offset += cb_bits;
if (i > 0 && move == 0)
break;
pos += move;
ev = read_ubits(ev_bits, bit_offset, buf);
bit_offset += ev_bits;
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 >= 8*buf_size)
break;
move = read_ubits(ei_bits, bit_offset, buf);
bit_offset += ei_bits;
if (i > 0 && move == 0)
break;
pos += move;
qv_bits = exponents[pos];
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 >= 8*buf_size)
break;
move = read_ubits(ei_bits, bit_offset, buf);
bit_offset += ei_bits;
if (i > 0 && move == 0)
break;
pos += move;
qv_bits = exponents[pos];
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];
}
}
}
}
static int decode_frame_next(VGMSTREAMCHANNEL* stream, relic_codec_data* data) {
int ch;
int bytes;
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;
unpack_frame(buf, sizeof(buf), data->freq1, data->freq2, data->scales, data->exponents[ch], data->freq_size);
decode_frame_base(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(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* init_codec(int channels, int bitrate, int codec_rate) {
relic_codec_data *data = NULL;
if (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;
if (codec_rate == 22050)
data->freq_size = RELIC_SIZE_MID;
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));
switch(bitrate) {
case RELIC_BITRATE_22:
case RELIC_BITRATE_44:
case RELIC_BITRATE_88:
case RELIC_BITRATE_176:
data->frame_size = (bitrate / 8); /* 0x100 and 0x80 are common */
break;
default:
goto fail;
}
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));
}

View File

@ -0,0 +1,618 @@
/* Original Relic code uses mixfft.c v1 by Jens Jorgen Nielsen, though was
* modified to use floats instead of doubles. This is a 100% decompilation
* that somehow resulted in the exact same code (no compiler optims set?),
* so restores comments back but removes/cleans globals (could be simplified). */
#include <math.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
/* ------------------------------------------------------------------------- */
/************************************************************************
fft(int n, double xRe[], double xIm[], double yRe[], double yIm[])
------------------------------------------------------------------------
NOTE : This is copyrighted material, Not public domain. See below.
------------------------------------------------------------------------
Input/output:
int n transformation length.
double xRe[] real part of input sequence.
double xIm[] imaginary part of input sequence.
double yRe[] real part of output sequence.
double yIm[] imaginary part of output sequence.
------------------------------------------------------------------------
Function:
The procedure performs a fast discrete Fourier transform (FFT) of
a complex sequence, x, of an arbitrary length, n. The output, y,
is also a complex sequence of length n.
y[k] = sum(x[m]*exp(-i*2*pi*k*m/n), m=0..(n-1)), k=0,...,(n-1)
The largest prime factor of n must be less than or equal to the
constant maxPrimeFactor defined below.
------------------------------------------------------------------------
Author:
Jens Joergen Nielsen For non-commercial use only.
Bakkehusene 54 A $100 fee must be paid if used
DK-2970 Hoersholm commercially. Please contact.
DENMARK
E-mail : jjn@get2net.dk All rights reserved. October 2000.
Homepage : http://home.get2net.dk/jjn
------------------------------------------------------------------------
Implementation notes:
The general idea is to factor the length of the DFT, n, into
factors that are efficiently handled by the routines.
A number of short DFT's are implemented with a minimum of
arithmetical operations and using (almost) straight line code
resulting in very fast execution when the factors of n belong
to this set. Especially radix-10 is optimized.
Prime factors, that are not in the set of short DFT's are handled
with direct evaluation of the DFP expression.
Please report any problems to the author.
Suggestions and improvements are welcomed.
------------------------------------------------------------------------
Benchmarks:
The Microsoft Visual C++ compiler was used with the following
compile options:
/nologo /Gs /G2 /W4 /AH /Ox /D "NDEBUG" /D "_DOS" /FR
and the FFTBENCH test executed on a 50MHz 486DX :
Length Time [s] Accuracy [dB]
128 0.0054 -314.8
256 0.0116 -309.8
512 0.0251 -290.8
1024 0.0567 -313.6
2048 0.1203 -306.4
4096 0.2600 -291.8
8192 0.5800 -305.1
100 0.0040 -278.5
200 0.0099 -280.3
500 0.0256 -278.5
1000 0.0540 -278.5
2000 0.1294 -280.6
5000 0.3300 -278.4
10000 0.7133 -278.5
------------------------------------------------------------------------
The following procedures are used :
factorize : factor the transformation length.
transTableSetup : setup table with sofar-, actual-, and remainRadix.
permute : permutation allows in-place calculations.
twiddleTransf : twiddle multiplications and DFT's for one stage.
initTrig : initialise sine/cosine table.
fft_4 : length 4 DFT, a la Nussbaumer.
fft_5 : length 5 DFT, a la Nussbaumer.
fft_10 : length 10 DFT using prime factor FFT.
fft_odd : length n DFT, n odd.
*************************************************************************/
#define maxPrimeFactor 37
#define maxPrimeFactorDiv2 ((maxPrimeFactor+1)/2)
#define maxFactorCount 20
static const float c3_1 = -1.5f; /* c3_1 = cos(2*pi/3)-1; */
static const float c3_2 = 0.866025388240814208984375f; /* c3_2 = sin(2*pi/3); */
// static const float u5 = 1.256637096405029296875f; /* u5 = 2*pi/5; */
static const float c5_1 = -1.25f; /* c5_1 = (cos(u5)+cos(2*u5))/2-1;*/
static const float c5_2 = 0.559017002582550048828125f; /* c5_2 = (cos(u5)-cos(2*u5))/2; */
static const float c5_3 = -0.951056540012359619140625f; /* c5_3 = -sin(u5); */
static const float c5_4 = -1.538841724395751953125f; /* c5_4 = -(sin(u5)+sin(2*u5)); */
static const float c5_5 = 0.3632712662220001220703125f; /* c5_5 = (sin(u5)-sin(2*u5)); */
static const float c8 = 0.707106769084930419921875f; /* c8 = 1/sqrt(2); */
static const float pi = 3.1415927410125732421875f;
#if 0 /* extra */
static int groupOffset,dataOffset,adr; //,blockOffset
static int groupNo,dataNo,blockNo,twNo;
static float omega, tw_re,tw_im;
static float twiddleRe[maxPrimeFactor], twiddleIm[maxPrimeFactor],
trigRe[maxPrimeFactor], trigIm[maxPrimeFactor],
zRe[maxPrimeFactor], zIm[maxPrimeFactor];
static float vRe[maxPrimeFactorDiv2], vIm[maxPrimeFactorDiv2];
static float wRe[maxPrimeFactorDiv2], wIm[maxPrimeFactorDiv2];
#endif
static void factorize(int n, int *nFact, int *fact)
{
int i,j,k;
int nRadix;
int radices[7];
int factors[maxFactorCount];
nRadix = 6;
radices[1]= 2;
radices[2]= 3;
radices[3]= 4;
radices[4]= 5;
radices[5]= 8;
radices[6]= 10;
radices[0]= 1; /* extra (assumed) */
factors[0]= 0; /* extra (assumed) */
fact[0]= 0; /* extra (assumed) */
fact[1]= 0; /* extra (assumed) */
if (n==1)
{
j=1;
factors[1]=1;
}
else j=0;
i=nRadix;
while ((n>1) && (i>0))
{
if ((n % radices[i]) == 0)
{
n=n / radices[i];
j=j+1;
factors[j]=radices[i];
}
else i=i-1;
}
if (factors[j] == 2) /*substitute factors 2*8 with 4*4 */
{
i = j-1;
while ((i>0) && (factors[i] != 8)) i--;
if (i>0)
{
factors[j] = 4;
factors[i] = 4;
}
}
if (n>1)
{
for (k=2; k<sqrt(n)+1; k++)
while ((n % k) == 0)
{
n=n / k;
j=j+1;
factors[j]=k;
}
if (n>1)
{
j=j+1;
factors[j]=n;
}
}
for (i=1; i<=j; i++)
{
fact[i] = factors[j-i+1];
}
*nFact=j;
} /* factorize */
/****************************************************************************
After N is factored the parameters that control the stages are generated.
For each stage we have:
sofar : the product of the radices so far.
actual : the radix handled in this stage.
remain : the product of the remaining radices.
****************************************************************************/
static void transTableSetup(int *sofar, int *actual, int *remain,
int *nFact,
int *nPoints)
{
int i;
factorize(*nPoints, nFact, actual);
if (actual[*nFact] > maxPrimeFactor)
{
#if 0 /* extra */
printf("\nPrime factor of FFT length too large : %6d", actual[*nFact]);
exit(1);
#endif
actual[*nFact] = maxPrimeFactor - 1; /* extra */
}
remain[0]=*nPoints;
sofar[1]=1;
remain[1]=*nPoints / actual[1];
for (i=2; i<=*nFact; i++)
{
sofar[i]=sofar[i-1]*actual[i-1];
remain[i]=remain[i-1] / actual[i];
}
} /* transTableSetup */
/****************************************************************************
The sequence y is the permuted input sequence x so that the following
transformations can be performed in-place, and the final result is the
normal order.
****************************************************************************/
static void permute(int nPoint, int nFact,
int *fact, int *remain,
float *xRe, float *xIm,
float *yRe, float *yIm)
{
int i,j,k;
int count[maxFactorCount];
for (i=1; i<=nFact; i++) count[i]=0;
k=0;
for (i=0; i<=nPoint-2; i++)
{
yRe[i] = xRe[k];
yIm[i] = xIm[k];
j=1;
k=k+remain[j];
count[1] = count[1]+1;
while (count[j] >= fact[j])
{
count[j]=0;
k=k-remain[j-1]+remain[j+1];
j=j+1;
count[j]=count[j]+1;
}
}
yRe[nPoint-1]=xRe[nPoint-1];
yIm[nPoint-1]=xIm[nPoint-1];
} /* permute */
/****************************************************************************
Twiddle factor multiplications and transformations are performed on a
group of data. The number of multiplications with 1 are reduced by skipping
the twiddle multiplication of the first stage and of the first group of the
following stages.
***************************************************************************/
static void initTrig(int radix, float *trigRe, float*trigIm)
{
int i;
float w,xre,xim;
w=2*pi/radix;
trigRe[0]=1; trigIm[0]=0;
xre=cos(w);
xim=-sin(w);
trigRe[1]=xre; trigIm[1]=xim;
for (i=2; i<radix; i++)
{
trigRe[i]=xre*trigRe[i-1] - xim*trigIm[i-1];
trigIm[i]=xim*trigRe[i-1] + xre*trigIm[i-1];
}
} /* initTrig */
static void fft_4(float *aRe, float *aIm)
{
float t1_re,t1_im, t2_re,t2_im;
float m2_re,m2_im, m3_re,m3_im;
t1_re=aRe[0] + aRe[2]; t1_im=aIm[0] + aIm[2];
t2_re=aRe[1] + aRe[3]; t2_im=aIm[1] + aIm[3];
m2_re=aRe[0] - aRe[2]; m2_im=aIm[0] - aIm[2];
m3_re=aIm[1] - aIm[3]; m3_im=aRe[3] - aRe[1];
aRe[0]=t1_re + t2_re; aIm[0]=t1_im + t2_im;
aRe[2]=t1_re - t2_re; aIm[2]=t1_im - t2_im;
aRe[1]=m2_re + m3_re; aIm[1]=m2_im + m3_im;
aRe[3]=m2_re - m3_re; aIm[3]=m2_im - m3_im;
} /* fft_4 */
static void fft_5(float *aRe, float *aIm)
{
float t1_re,t1_im, t2_re,t2_im, t3_re,t3_im;
float t4_re,t4_im, t5_re,t5_im;
float m2_re,m2_im, m3_re,m3_im, m4_re,m4_im;
float m1_re,m1_im, m5_re,m5_im;
float s1_re,s1_im, s2_re,s2_im, s3_re,s3_im;
float s4_re,s4_im, s5_re,s5_im;
t1_re=aRe[1] + aRe[4]; t1_im=aIm[1] + aIm[4];
t2_re=aRe[2] + aRe[3]; t2_im=aIm[2] + aIm[3];
t3_re=aRe[1] - aRe[4]; t3_im=aIm[1] - aIm[4];
t4_re=aRe[3] - aRe[2]; t4_im=aIm[3] - aIm[2];
t5_re=t1_re + t2_re; t5_im=t1_im + t2_im;
aRe[0]=aRe[0] + t5_re; aIm[0]=aIm[0] + t5_im;
m1_re=c5_1*t5_re; m1_im=c5_1*t5_im;
m2_re=c5_2*(t1_re - t2_re); m2_im=c5_2*(t1_im - t2_im);
m3_re=-c5_3*(t3_im + t4_im); m3_im=c5_3*(t3_re + t4_re);
m4_re=-c5_4*t4_im; m4_im=c5_4*t4_re;
m5_re=-c5_5*t3_im; m5_im=c5_5*t3_re;
s3_re=m3_re - m4_re; s3_im=m3_im - m4_im;
s5_re=m3_re + m5_re; s5_im=m3_im + m5_im;
s1_re=aRe[0] + m1_re; s1_im=aIm[0] + m1_im;
s2_re=s1_re + m2_re; s2_im=s1_im + m2_im;
s4_re=s1_re - m2_re; s4_im=s1_im - m2_im;
aRe[1]=s2_re + s3_re; aIm[1]=s2_im + s3_im;
aRe[2]=s4_re + s5_re; aIm[2]=s4_im + s5_im;
aRe[3]=s4_re - s5_re; aIm[3]=s4_im - s5_im;
aRe[4]=s2_re - s3_re; aIm[4]=s2_im - s3_im;
} /* fft_5 */
static void fft_8(float *zRe, float *zIm)
{
float aRe[4], aIm[4], bRe[4], bIm[4], gem;
aRe[0] = zRe[0]; bRe[0] = zRe[1];
aRe[1] = zRe[2]; bRe[1] = zRe[3];
aRe[2] = zRe[4]; bRe[2] = zRe[5];
aRe[3] = zRe[6]; bRe[3] = zRe[7];
aIm[0] = zIm[0]; bIm[0] = zIm[1];
aIm[1] = zIm[2]; bIm[1] = zIm[3];
aIm[2] = zIm[4]; bIm[2] = zIm[5];
aIm[3] = zIm[6]; bIm[3] = zIm[7];
fft_4(aRe, aIm); fft_4(bRe, bIm);
gem = c8*(bRe[1] + bIm[1]);
bIm[1] = c8*(bIm[1] - bRe[1]);
bRe[1] = gem;
gem = bIm[2];
bIm[2] =-bRe[2];
bRe[2] = gem;
gem = c8*(bIm[3] - bRe[3]);
bIm[3] =-c8*(bRe[3] + bIm[3]);
bRe[3] = gem;
zRe[0] = aRe[0] + bRe[0]; zRe[4] = aRe[0] - bRe[0];
zRe[1] = aRe[1] + bRe[1]; zRe[5] = aRe[1] - bRe[1];
zRe[2] = aRe[2] + bRe[2]; zRe[6] = aRe[2] - bRe[2];
zRe[3] = aRe[3] + bRe[3]; zRe[7] = aRe[3] - bRe[3];
zIm[0] = aIm[0] + bIm[0]; zIm[4] = aIm[0] - bIm[0];
zIm[1] = aIm[1] + bIm[1]; zIm[5] = aIm[1] - bIm[1];
zIm[2] = aIm[2] + bIm[2]; zIm[6] = aIm[2] - bIm[2];
zIm[3] = aIm[3] + bIm[3]; zIm[7] = aIm[3] - bIm[3];
} /* fft_8 */
static void fft_10(float *zRe, float *zIm)
{
float aRe[5], aIm[5], bRe[5], bIm[5];
aRe[0] = zRe[0]; bRe[0] = zRe[5];
aRe[1] = zRe[2]; bRe[1] = zRe[7];
aRe[2] = zRe[4]; bRe[2] = zRe[9];
aRe[3] = zRe[6]; bRe[3] = zRe[1];
aRe[4] = zRe[8]; bRe[4] = zRe[3];
aIm[0] = zIm[0]; bIm[0] = zIm[5];
aIm[1] = zIm[2]; bIm[1] = zIm[7];
aIm[2] = zIm[4]; bIm[2] = zIm[9];
aIm[3] = zIm[6]; bIm[3] = zIm[1];
aIm[4] = zIm[8]; bIm[4] = zIm[3];
fft_5(aRe, aIm); fft_5(bRe, bIm);
zRe[0] = aRe[0] + bRe[0]; zRe[5] = aRe[0] - bRe[0];
zRe[6] = aRe[1] + bRe[1]; zRe[1] = aRe[1] - bRe[1];
zRe[2] = aRe[2] + bRe[2]; zRe[7] = aRe[2] - bRe[2];
zRe[8] = aRe[3] + bRe[3]; zRe[3] = aRe[3] - bRe[3];
zRe[4] = aRe[4] + bRe[4]; zRe[9] = aRe[4] - bRe[4];
zIm[0] = aIm[0] + bIm[0]; zIm[5] = aIm[0] - bIm[0];
zIm[6] = aIm[1] + bIm[1]; zIm[1] = aIm[1] - bIm[1];
zIm[2] = aIm[2] + bIm[2]; zIm[7] = aIm[2] - bIm[2];
zIm[8] = aIm[3] + bIm[3]; zIm[3] = aIm[3] - bIm[3];
zIm[4] = aIm[4] + bIm[4]; zIm[9] = aIm[4] - bIm[4];
} /* fft_10 */
static void fft_odd(int radix, float *trigRe, float *trigIm, float *zRe, float* zIm)
{
float rere, reim, imre, imim;
int i,j,k,n,max;
float vRe[maxPrimeFactorDiv2] = {0}, vIm[maxPrimeFactorDiv2] = {0}; /* extra */
float wRe[maxPrimeFactorDiv2] = {0}, wIm[maxPrimeFactorDiv2] = {0}; /* extra */
n = radix;
max = (n + 1)/2;
for (j=1; j < max; j++)
{
vRe[j] = zRe[j] + zRe[n-j];
vIm[j] = zIm[j] - zIm[n-j];
wRe[j] = zRe[j] - zRe[n-j];
wIm[j] = zIm[j] + zIm[n-j];
}
for (j=1; j < max; j++)
{
zRe[j]=zRe[0];
zIm[j]=zIm[0];
zRe[n-j]=zRe[0];
zIm[n-j]=zIm[0];
k=j;
for (i=1; i < max; i++)
{
rere = trigRe[k] * vRe[i];
imim = trigIm[k] * vIm[i];
reim = trigRe[k] * wIm[i];
imre = trigIm[k] * wRe[i];
zRe[n-j] += rere + imim;
zIm[n-j] += reim - imre;
zRe[j] += rere - imim;
zIm[j] += reim + imre;
k = k + j;
if (k >= n) k = k - n;
}
}
for (j=1; j < max; j++)
{
zRe[0]=zRe[0] + vRe[j];
zIm[0]=zIm[0] + wIm[j];
}
} /* fft_odd */
static void twiddleTransf(int sofarRadix, int radix, int remainRadix,
float *yRe, float *yIm)
{ /* twiddleTransf */
float cosw, sinw, gem;
float t1_re,t1_im, t2_re,t2_im, t3_re,t3_im;
float t4_re,t4_im, t5_re,t5_im;
float m1_re,m1_im, m2_re,m2_im, m3_re,m3_im;
float m4_re,m4_im, m5_re,m5_im;
float s1_re,s1_im, s2_re,s2_im, s3_re,s3_im;
float s4_re,s4_im, s5_re,s5_im;
int groupOffset,dataOffset,adr; //,blockOffset /* extra */
int groupNo,dataNo,blockNo,twNo; /* extra */
float omega, tw_re,tw_im; /* extra */
float twiddleRe[maxPrimeFactor] = {0}, twiddleIm[maxPrimeFactor] = {0}, /* extra */
trigRe[maxPrimeFactor] = {0}, trigIm[maxPrimeFactor] = {0}, /* extra */
zRe[maxPrimeFactor] = {0}, zIm[maxPrimeFactor] = {0}; /* extra */
initTrig(radix, trigRe, trigIm);
omega = 2*pi/(double)(sofarRadix*radix);
cosw = cos(omega);
sinw = -sin(omega);
tw_re = 1.0;
tw_im = 0;
dataOffset=0;
groupOffset=dataOffset;
adr=groupOffset;
for (dataNo=0; dataNo<sofarRadix; dataNo++)
{
if (sofarRadix>1)
{
twiddleRe[0] = 1.0;
twiddleIm[0] = 0.0;
twiddleRe[1] = tw_re;
twiddleIm[1] = tw_im;
for (twNo=2; twNo<radix; twNo++)
{
twiddleRe[twNo]=tw_re*twiddleRe[twNo-1]
- tw_im*twiddleIm[twNo-1];
twiddleIm[twNo]=tw_im*twiddleRe[twNo-1]
+ tw_re*twiddleIm[twNo-1];
}
gem = cosw*tw_re - sinw*tw_im;
tw_im = sinw*tw_re + cosw*tw_im;
tw_re = gem;
}
for (groupNo=0; groupNo<remainRadix; groupNo++)
{
if ((sofarRadix>1) && (dataNo > 0))
{
zRe[0]=yRe[adr];
zIm[0]=yIm[adr];
blockNo=1;
do {
adr = adr + sofarRadix;
zRe[blockNo]= twiddleRe[blockNo] * yRe[adr]
- twiddleIm[blockNo] * yIm[adr];
zIm[blockNo]= twiddleRe[blockNo] * yIm[adr]
+ twiddleIm[blockNo] * yRe[adr];
blockNo++;
} while (blockNo < radix);
}
else {
for (blockNo=0; blockNo<radix; blockNo++)
{
zRe[blockNo]=yRe[adr];
zIm[blockNo]=yIm[adr];
adr=adr+sofarRadix;
}
}
switch(radix) {
case 2 : gem=zRe[0] + zRe[1];
zRe[1]=zRe[0] - zRe[1]; zRe[0]=gem;
gem=zIm[0] + zIm[1];
zIm[1]=zIm[0] - zIm[1]; zIm[0]=gem;
break;
case 3 : t1_re=zRe[1] + zRe[2]; t1_im=zIm[1] + zIm[2];
zRe[0]=zRe[0] + t1_re; zIm[0]=zIm[0] + t1_im;
m1_re=c3_1*t1_re; m1_im=c3_1*t1_im;
m2_re=c3_2*(zIm[1] - zIm[2]);
m2_im=c3_2*(zRe[2] - zRe[1]);
s1_re=zRe[0] + m1_re; s1_im=zIm[0] + m1_im;
zRe[1]=s1_re + m2_re; zIm[1]=s1_im + m2_im;
zRe[2]=s1_re - m2_re; zIm[2]=s1_im - m2_im;
break;
case 4 : t1_re=zRe[0] + zRe[2]; t1_im=zIm[0] + zIm[2];
t2_re=zRe[1] + zRe[3]; t2_im=zIm[1] + zIm[3];
m2_re=zRe[0] - zRe[2]; m2_im=zIm[0] - zIm[2];
m3_re=zIm[1] - zIm[3]; m3_im=zRe[3] - zRe[1];
zRe[0]=t1_re + t2_re; zIm[0]=t1_im + t2_im;
zRe[2]=t1_re - t2_re; zIm[2]=t1_im - t2_im;
zRe[1]=m2_re + m3_re; zIm[1]=m2_im + m3_im;
zRe[3]=m2_re - m3_re; zIm[3]=m2_im - m3_im;
break;
case 5 : t1_re=zRe[1] + zRe[4]; t1_im=zIm[1] + zIm[4];
t2_re=zRe[2] + zRe[3]; t2_im=zIm[2] + zIm[3];
t3_re=zRe[1] - zRe[4]; t3_im=zIm[1] - zIm[4];
t4_re=zRe[3] - zRe[2]; t4_im=zIm[3] - zIm[2];
t5_re=t1_re + t2_re; t5_im=t1_im + t2_im;
zRe[0]=zRe[0] + t5_re; zIm[0]=zIm[0] + t5_im;
m1_re=c5_1*t5_re; m1_im=c5_1*t5_im;
m2_re=c5_2*(t1_re - t2_re);
m2_im=c5_2*(t1_im - t2_im);
m3_re=-c5_3*(t3_im + t4_im);
m3_im=c5_3*(t3_re + t4_re);
m4_re=-c5_4*t4_im; m4_im=c5_4*t4_re;
m5_re=-c5_5*t3_im; m5_im=c5_5*t3_re;
s3_re=m3_re - m4_re; s3_im=m3_im - m4_im;
s5_re=m3_re + m5_re; s5_im=m3_im + m5_im;
s1_re=zRe[0] + m1_re; s1_im=zIm[0] + m1_im;
s2_re=s1_re + m2_re; s2_im=s1_im + m2_im;
s4_re=s1_re - m2_re; s4_im=s1_im - m2_im;
zRe[1]=s2_re + s3_re; zIm[1]=s2_im + s3_im;
zRe[2]=s4_re + s5_re; zIm[2]=s4_im + s5_im;
zRe[3]=s4_re - s5_re; zIm[3]=s4_im - s5_im;
zRe[4]=s2_re - s3_re; zIm[4]=s2_im - s3_im;
break;
case 8 : fft_8(zRe, zIm); break;
case 10 : fft_10(zRe, zIm); break;
default : fft_odd(radix, trigRe, trigIm, zRe, zIm); break;
}
adr=groupOffset;
for (blockNo=0; blockNo<radix; blockNo++)
{
yRe[adr]=zRe[blockNo]; yIm[adr]=zIm[blockNo];
adr=adr+sofarRadix;
}
groupOffset=groupOffset+sofarRadix*radix;
adr=groupOffset;
}
dataOffset=dataOffset+1;
groupOffset=dataOffset;
adr=groupOffset;
}
} /* twiddleTransf */
/*static*/ void fft(int n, float *xRe, float *xIm,
float *yRe, float *yIm)
{
int sofarRadix[maxFactorCount],
actualRadix[maxFactorCount],
remainRadix[maxFactorCount];
int nFactor;
int count;
#if 0
pi = 4*atan(1);
#endif
transTableSetup(sofarRadix, actualRadix, remainRadix, &nFactor, &n);
permute(n, nFactor, actualRadix, remainRadix, xRe, xIm, yRe, yIm);
for (count=1; count<=nFactor; count++)
twiddleTransf(sofarRadix[count], actualRadix[count], remainRadix[count],
yRe, yIm);
} /* fft */

View File

@ -164,6 +164,7 @@ static const char* extension_list[] = {
"ezw", "ezw",
"fag", "fag",
"fda",
"ffw", "ffw",
"filp", "filp",
//"flac", //common //"flac", //common
@ -745,6 +746,7 @@ static const coding_info coding_info_list[] = {
{coding_EA_MT, "Electronic Arts MicroTalk"}, {coding_EA_MT, "Electronic Arts MicroTalk"},
{coding_RELIC, "Relic Codec"},
{coding_CRI_HCA, "CRI HCA"}, {coding_CRI_HCA, "CRI HCA"},
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
@ -1252,6 +1254,7 @@ static const meta_info meta_info_list[] = {
{meta_ISB, "Creative ISACT header"}, {meta_ISB, "Creative ISACT header"},
{meta_XSSB, "Artoon XSSB header"}, {meta_XSSB, "Artoon XSSB header"},
{meta_XMA_UE3, "Unreal Engine XMA header"}, {meta_XMA_UE3, "Unreal Engine XMA header"},
{meta_FDA, "Relic FDA header"},
}; };

View File

@ -66,17 +66,30 @@ void block_update_ea_swvr(off_t block_offset, VGMSTREAM * vgmstream) {
header_size = 0x1c; header_size = 0x1c;
channel_size = (block_size - header_size) / vgmstream->channels; channel_size = (block_size - header_size) / vgmstream->channels;
break; break;
case 0x53484F43: /* "SHOC" (a generic block but hopefully has PC sounds) */ case 0x53484F43: /* "SHOC" (a generic block but hopefully has PC sounds) */
header_size = 0x14; //todo the first block is 0x18 if (read_32bit(block_offset+0x10, streamFile) == 0x53444154) { /* "SDAT" */
channel_size = (block_size - header_size) / vgmstream->channels; header_size = 0x14;
channel_size = (block_size - header_size) / vgmstream->channels;
}
else {
header_size = 0;
channel_size = 0;
}
break; break;
case 0x46494C4C: /* "FILL" (FILLs do that up to 0x6000, but at 0x5FFC don't actually have size) */ case 0x46494C4C: /* "FILL" (FILLs do that up to a block size, but near end don't actually have size) */
if ((block_offset + 0x04) % 0x6000 == 0) if ((block_offset + 0x04) % 0x6000 == 0)
block_size = 0x04; block_size = 0x04;
else if ((block_offset + 0x04) % 0x10000 == 0)
block_size = 0x04;
else if (block_size > 0x100000) { /* other unknown block sizes */
VGM_LOG("EA SWVR: bad block size at 0x%lx\n", block_offset);
block_size = 0x04;
}
header_size = 0x08; header_size = 0x08;
break; break;
case 0xFFFFFFFF: case 0xFFFFFFFF:
channel_size = -1; /* signal bad block */ channel_size = -1; /* signal bad block */
break; break;

View File

@ -1422,6 +1422,10 @@
RelativePath=".\meta\fag.c" RelativePath=".\meta\fag.c"
> >
</File> </File>
<File
RelativePath=".\meta\fda.c"
>
</File>
<File <File
RelativePath=".\meta\ffdl.c" RelativePath=".\meta\ffdl.c"
> >
@ -2073,6 +2077,14 @@
<File <File
RelativePath=".\coding\ptadpcm_decoder.c" RelativePath=".\coding\ptadpcm_decoder.c"
> >
</File>
<File
RelativePath=".\coding\relic_decoder.c"
>
</File>
<File
RelativePath=".\coding\relic_decoder_mixfft.c"
>
</File> </File>
<File <File
RelativePath=".\coding\sassc_decoder.c" RelativePath=".\coding\sassc_decoder.c"

View File

@ -443,6 +443,7 @@
<ClCompile Include="meta\mta2.c" /> <ClCompile Include="meta\mta2.c" />
<ClCompile Include="meta\xa.c" /> <ClCompile Include="meta\xa.c" />
<ClCompile Include="meta\fag.c" /> <ClCompile Include="meta\fag.c" />
<ClCompile Include="meta\fda.c" />
<ClCompile Include="meta\ffdl.c" /> <ClCompile Include="meta\ffdl.c" />
<ClCompile Include="meta\seb.c" /> <ClCompile Include="meta\seb.c" />
<ClCompile Include="meta\ea_swvr.c" /> <ClCompile Include="meta\ea_swvr.c" />
@ -570,6 +571,8 @@
<ClCompile Include="coding\psv_decoder.c" /> <ClCompile Include="coding\psv_decoder.c" />
<ClCompile Include="coding\psx_decoder.c" /> <ClCompile Include="coding\psx_decoder.c" />
<ClCompile Include="coding\ptadpcm_decoder.c" /> <ClCompile Include="coding\ptadpcm_decoder.c" />
<ClCompile Include="coding\relic_decoder.c" />
<ClCompile Include="coding\relic_decoder_mixfft.c" />
<ClCompile Include="coding\sassc_decoder.c" /> <ClCompile Include="coding\sassc_decoder.c" />
<ClCompile Include="coding\sdx2_decoder.c" /> <ClCompile Include="coding\sdx2_decoder.c" />
<ClCompile Include="coding\ubi_adpcm_decoder.c" /> <ClCompile Include="coding\ubi_adpcm_decoder.c" />

View File

@ -877,6 +877,9 @@
<ClCompile Include="meta\fag.c"> <ClCompile Include="meta\fag.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\fda.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ffdl.c"> <ClCompile Include="meta\ffdl.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
@ -1237,6 +1240,12 @@
<ClCompile Include="coding\ptadpcm_decoder.c"> <ClCompile Include="coding\ptadpcm_decoder.c">
<Filter>coding\Source Files</Filter> <Filter>coding\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="coding\relic_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\relic_decoder_mixfft.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\sassc_decoder.c"> <ClCompile Include="coding\sassc_decoder.c">
<Filter>coding\Source Files</Filter> <Filter>coding\Source Files</Filter>
</ClCompile> </ClCompile>

View File

@ -1,15 +1,17 @@
#include "meta.h" #include "meta.h"
#include "../layout/layout.h" #include "../layout/layout.h"
#include "../coding/coding.h"
/* for reading integers inexplicably packed into 80-bit ('double extended') floats */ /* for reading integers inexplicably packed into 80-bit ('double extended') floats */
static uint32_t read80bitSANE(off_t offset, STREAMFILE *streamFile) { static uint32_t read80bitSANE(off_t offset, STREAMFILE *streamFile) {
uint8_t buf[10]; uint8_t buf[0x0a];
int32_t exponent; int32_t exponent;
int32_t mantissa; int32_t mantissa;
int i; int i;
if (read_streamfile(buf,offset,10,streamFile) != 10) return 0; if (read_streamfile(buf,offset,0x0a,streamFile) != 0x0a)
return 0;
exponent = ((buf[0]<<8)|(buf[1]))&0x7fff; exponent = ((buf[0]<<8)|(buf[1]))&0x7fff;
exponent -= 16383; exponent -= 16383;
@ -26,13 +28,13 @@ static uint32_t read80bitSANE(off_t offset, STREAMFILE *streamFile) {
return mantissa*((buf[0]&0x80)?-1:1); return mantissa*((buf[0]&0x80)?-1:1);
} }
static uint32_t find_marker(STREAMFILE *streamFile, off_t MarkerChunkOffset, int marker_id) { static uint32_t find_marker(STREAMFILE *streamFile, off_t mark_offset, int marker_id) {
uint16_t marker_count; uint16_t marker_count;
int i; int i;
off_t marker_offset; off_t marker_offset;
marker_count = read_16bitBE(MarkerChunkOffset+8,streamFile); marker_count = read_16bitBE(mark_offset+8,streamFile);
marker_offset = MarkerChunkOffset+10; marker_offset = mark_offset+10;
for (i=0;i<marker_count;i++) { for (i=0;i<marker_count;i++) {
int name_length; int name_length;
@ -61,8 +63,8 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
int32_t loop_start = 0, loop_end = 0; int32_t loop_start = 0, loop_end = 0;
int is_aiff_ext = 0, is_aifc_ext = 0, is_aiff = 0, is_aifc = 0; int is_aiff_ext = 0, is_aifc_ext = 0, is_aiff = 0, is_aifc = 0;
int FormatVersionChunkFound = 0, CommonChunkFound = 0, SoundDataChunkFound = 0, MarkerChunkFound = 0, InstrumentChunkFound = 0; int fver_found = 0, comm_found = 0, data_found = 0, mark_found = 0, inst_found = 0;
off_t MarkerChunkOffset = -1, InstrumentChunkOffset = -1; off_t mark_offset = -1, inst_offset = -1;
/* checks */ /* checks */
@ -74,12 +76,13 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
* .acm: Crusader - No Remorse (SAT) * .acm: Crusader - No Remorse (SAT)
* .adp: Sonic Jam (SAT) * .adp: Sonic Jam (SAT)
* .ai: Dragon Force (SAT) * .ai: Dragon Force (SAT)
* (extensionless: Doom (3DO) */ * (extensionless: Doom (3DO)
* .fda: Homeworld 2 (PC) */
if (check_extensions(streamFile, "aif,laif,")) { if (check_extensions(streamFile, "aif,laif,")) {
is_aifc_ext = 1; is_aifc_ext = 1;
is_aiff_ext = 1; is_aiff_ext = 1;
} }
else if (check_extensions(streamFile, "aifc,laifc,aifcl,afc,cbd2,bgm")) { else if (check_extensions(streamFile, "aifc,laifc,aifcl,afc,cbd2,bgm,fda")) {
is_aifc_ext = 1; is_aifc_ext = 1;
} }
else if (check_extensions(streamFile, "aiff,laiff,acm,adp,ai,aiffl")) { else if (check_extensions(streamFile, "aiff,laiff,acm,adp,ai,aiffl")) {
@ -123,9 +126,9 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
switch(chunk_type) { switch(chunk_type) {
case 0x46564552: /* "FVER" (version info) */ case 0x46564552: /* "FVER" (version info) */
if (FormatVersionChunkFound) goto fail; if (fver_found) goto fail;
if (is_aiff) goto fail; /* plain AIFF shouldn't have */ if (is_aiff) goto fail; /* plain AIFF shouldn't have */
FormatVersionChunkFound = 1; fver_found = 1;
/* specific size */ /* specific size */
if (chunk_size != 4) goto fail; if (chunk_size != 4) goto fail;
@ -135,8 +138,8 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
break; break;
case 0x434F4D4D: /* "COMM" (main header) */ case 0x434F4D4D: /* "COMM" (main header) */
if (CommonChunkFound) goto fail; if (comm_found) goto fail;
CommonChunkFound = 1; comm_found = 1;
channel_count = read_16bitBE(current_chunk+8,streamFile); channel_count = read_16bitBE(current_chunk+8,streamFile);
if (channel_count <= 0) goto fail; if (channel_count <= 0) goto fail;
@ -146,24 +149,45 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
sample_rate = read80bitSANE(current_chunk+0x10,streamFile); sample_rate = read80bitSANE(current_chunk+0x10,streamFile);
if (is_aifc) { if (is_aifc) {
switch (read_32bitBE(current_chunk+0x1a,streamFile)) { uint32_t codec = read_32bitBE(current_chunk+0x1a,streamFile);
switch (codec) {
case 0x53445832: /* "SDX2" [3DO games: Super Street Fighter II Turbo (3DO), etc] */ case 0x53445832: /* "SDX2" [3DO games: Super Street Fighter II Turbo (3DO), etc] */
coding_type = coding_SDX2; coding_type = coding_SDX2;
interleave = 0x01; interleave = 0x01;
break; break;
case 0x43424432: /* "CBD2" [M2 (arcade 3DO) games: IMSA Racing (M2), etc] */ case 0x43424432: /* "CBD2" [M2 (arcade 3DO) games: IMSA Racing (M2), etc] */
coding_type = coding_CBD2; coding_type = coding_CBD2;
interleave = 0x01; interleave = 0x01;
break; break;
case 0x41445034: /* "ADP4" */ case 0x41445034: /* "ADP4" */
coding_type = coding_DVI_IMA_int; coding_type = coding_DVI_IMA_int;
if (channel_count != 1) break; /* don't know how stereo DVI is laid out */ if (channel_count != 1) break; /* don't know how stereo DVI is laid out */
break; break;
case 0x696D6134: /* "ima4" [Alida (PC), Lunar SSS (iOS)] */ case 0x696D6134: /* "ima4" [Alida (PC), Lunar SSS (iOS)] */
coding_type = coding_APPLE_IMA4; coding_type = coding_APPLE_IMA4;
interleave = 0x22; interleave = 0x22;
sample_count = sample_count * ((interleave-0x2)*2); sample_count = sample_count * ((interleave-0x2)*2);
break; break;
case 0x434F4D50: { /* "COMP" (generic compression) */
uint8_t comp_name[255] = {0};
uint8_t comp_size = read_8bit(current_chunk + 0x1e, streamFile);
if (comp_size >= sizeof(comp_name) - 1) goto fail;
read_streamfile(comp_name, current_chunk + 0x1f, comp_size, streamFile);
if (memcmp(comp_name, "Relic Codec v1.6", comp_size) == 0) { /* Homeworld 2 (PC) */
coding_type = coding_RELIC;
sample_count = sample_count * 512;
}
else {
goto fail;
}
break;
}
default: default:
VGM_LOG("AIFC: unknown codec\n"); VGM_LOG("AIFC: unknown codec\n");
goto fail; goto fail;
@ -192,25 +216,25 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
case 0x53534E44: /* "SSND" (main data) */ case 0x53534E44: /* "SSND" (main data) */
case 0x4150434D: /* "APCM" (main data for XA) */ case 0x4150434D: /* "APCM" (main data for XA) */
if (SoundDataChunkFound) goto fail; if (data_found) goto fail;
SoundDataChunkFound = 1; data_found = 1;
start_offset = current_chunk + 0x10 + read_32bitBE(current_chunk+0x08,streamFile); start_offset = current_chunk + 0x10 + read_32bitBE(current_chunk+0x08,streamFile);
/* when "APCM" XA frame size is at 0x0c, fixed to 0x914 */ /* when "APCM" XA frame size is at 0x0c, fixed to 0x914 */
break; break;
case 0x4D41524B: /* "MARK" (loops) */ case 0x4D41524B: /* "MARK" (loops) */
if (MarkerChunkFound) goto fail; if (mark_found) goto fail;
MarkerChunkFound = 1; mark_found = 1;
MarkerChunkOffset = current_chunk; mark_offset = current_chunk;
break; break;
case 0x494E5354: /* "INST" (loops) */ case 0x494E5354: /* "INST" (loops) */
if (InstrumentChunkFound) goto fail; if (inst_found) goto fail;
InstrumentChunkFound = 1; inst_found = 1;
InstrumentChunkOffset = current_chunk; inst_offset = current_chunk;
break; break;
default: default:
@ -223,28 +247,28 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
} }
if (is_aifc) { if (is_aifc) {
if (!FormatVersionChunkFound || !CommonChunkFound || !SoundDataChunkFound) if (!fver_found || !comm_found || !data_found)
goto fail; goto fail;
} else if (is_aiff) { } else if (is_aiff) {
if (!CommonChunkFound || !SoundDataChunkFound) if (!comm_found || !data_found)
goto fail; goto fail;
} }
/* read loop points */ /* read loop points */
if (InstrumentChunkFound && MarkerChunkFound) { if (inst_found && mark_found) {
int start_marker; int start_marker;
int end_marker; int end_marker;
/* use the sustain loop */ /* use the sustain loop */
/* if playMode=ForwardLooping */ /* if playMode=ForwardLooping */
if (read_16bitBE(InstrumentChunkOffset+16,streamFile) == 1) { if (read_16bitBE(inst_offset+16,streamFile) == 1) {
start_marker = read_16bitBE(InstrumentChunkOffset+18,streamFile); start_marker = read_16bitBE(inst_offset+18,streamFile);
end_marker = read_16bitBE(InstrumentChunkOffset+20,streamFile); end_marker = read_16bitBE(inst_offset+20,streamFile);
/* check for sustain markers != 0 (invalid marker no) */ /* check for sustain markers != 0 (invalid marker no) */
if (start_marker && end_marker) { if (start_marker && end_marker) {
/* find start marker */ /* find start marker */
loop_start = find_marker(streamFile,MarkerChunkOffset,start_marker); loop_start = find_marker(streamFile,mark_offset,start_marker);
loop_end = find_marker(streamFile,MarkerChunkOffset,end_marker); loop_end = find_marker(streamFile,mark_offset,end_marker);
/* find_marker is type uint32_t as the spec says that's the type /* find_marker is type uint32_t as the spec says that's the type
* of the position value, but it returns a -1 on error, and the * of the position value, but it returns a -1 on error, and the
@ -257,6 +281,8 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
loop_flag = 0; loop_flag = 0;
} }
} }
/* Relic has "beg loop" "end loop" comments but no actual looping? */
} }
@ -270,14 +296,28 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) {
vgmstream->loop_end_sample = loop_end; vgmstream->loop_end_sample = loop_end;
vgmstream->coding_type = coding_type; vgmstream->coding_type = coding_type;
if (coding_type == coding_XA) { switch(coding_type) {
vgmstream->layout_type = layout_blocked_xa_aiff; case coding_XA:
/* AIFF XA can use sample rates other than 37800/18900 */ vgmstream->layout_type = layout_blocked_xa_aiff;
/* some Crusader: No Remorse tracks have XA headers with incorrect 0xFF, rip bug/encoder feature? */ /* AIFF XA can use sample rates other than 37800/18900 */
} /* some Crusader: No Remorse tracks have XA headers with incorrect 0xFF, rip bug/encoder feature? */
else { break;
vgmstream->layout_type = (channel_count > 1) ? layout_interleave : layout_none;
vgmstream->interleave_block_size = interleave; case coding_RELIC: {
int bitrate = read_16bitBE(start_offset, streamFile);
start_offset += 0x02;
vgmstream->codec_data = init_relic(channel_count, bitrate, sample_rate);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
vgmstream->sample_rate = 44100; /* fixed output */
break;
}
default:
vgmstream->layout_type = (channel_count > 1) ? layout_interleave : layout_none;
vgmstream->interleave_block_size = interleave;
break;
} }
if (is_aifc) if (is_aifc)

View File

@ -89,7 +89,6 @@ VGMSTREAM * init_vgmstream_csb(STREAMFILE *streamFile) {
goto fail; goto fail;
if (!utf_query_s8(utf_sdl, i, "fmt", &fmt)) if (!utf_query_s8(utf_sdl, i, "fmt", &fmt))
goto fail; goto fail;
VGM_LOG("fmt=%i\n", fmt);
/* also nch/sfreq/nsmpl info */ /* also nch/sfreq/nsmpl info */
found = 1; found = 1;
@ -98,7 +97,7 @@ VGMSTREAM * init_vgmstream_csb(STREAMFILE *streamFile) {
if (!found) goto fail; if (!found) goto fail;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
VGM_LOG("5: %x, %x\n", sdl_offset, offset);
subfile_offset = /*sdl_offset +*/ offset; subfile_offset = /*sdl_offset +*/ offset;
subfile_size = size; subfile_size = size;
@ -107,14 +106,12 @@ VGM_LOG("5: %x, %x\n", sdl_offset, offset);
goto fail; goto fail;
} }
;VGM_LOG("CSB: subfile offset=%lx + %x\n", subfile_offset, subfile_size); //;VGM_LOG("CSB: subfile offset=%lx + %x\n", subfile_offset, subfile_size);
temp_sf = setup_subfile_streamfile(streamFile, subfile_offset, subfile_size, "aax"); temp_sf = setup_subfile_streamfile(streamFile, subfile_offset, subfile_size, "aax");
if (!temp_sf) goto fail; if (!temp_sf) goto fail;
VGM_LOG("7: %i\n", fmt);
switch(fmt) { switch(fmt) {
case 0: /* AAX */ case 0: /* AAX */
case 6: /* HCA */ case 6: /* HCA */
@ -132,8 +129,6 @@ VGM_LOG("5: %x, %x\n", sdl_offset, offset);
goto fail; goto fail;
} }
VGM_LOG("8\n");
vgmstream->num_streams = total_subsongs; vgmstream->num_streams = total_subsongs;
strncpy(vgmstream->stream_name, stream_name, STREAM_NAME_SIZE-1); strncpy(vgmstream->stream_name, stream_name, STREAM_NAME_SIZE-1);

View File

@ -39,7 +39,7 @@ static VGMSTREAM *parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint16
VGMSTREAM * init_vgmstream_gin_header(STREAMFILE *streamFile, off_t offset); VGMSTREAM * init_vgmstream_gin_header(STREAMFILE *streamFile, off_t offset);
/* .SNR+SNS - from EA latest games (~2008-2013), v0 header */ /* .SNR+SNS - from EA latest games (~2005-2010), v0 header */
VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE * streamFile) { VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE * streamFile) {
/* check extension, case insensitive */ /* check extension, case insensitive */
if (!check_extensions(streamFile,"snr")) if (!check_extensions(streamFile,"snr"))
@ -51,7 +51,7 @@ fail:
return NULL; return NULL;
} }
/* .SPS - from EA latest games (~2014), v1 header */ /* .SPS - from EA latest games (~2010~present), v1 header */
VGMSTREAM * init_vgmstream_ea_sps(STREAMFILE * streamFile) { VGMSTREAM * init_vgmstream_ea_sps(STREAMFILE * streamFile) {
/* check extension, case insensitive */ /* check extension, case insensitive */
if (!check_extensions(streamFile,"sps")) if (!check_extensions(streamFile,"sps"))
@ -1556,6 +1556,7 @@ static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_
uint8_t buf[0x100]; uint8_t buf[0x100];
int bytes, block_size, block_count; int bytes, block_size, block_count;
size_t stream_size; size_t stream_size;
int is_xma1;
temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, start_offset); temp_sf = setup_eaac_audio_streamfile(sf_data, eaac->version, eaac->codec, eaac->streamed,i,layers, start_offset);
if (!temp_sf) goto fail; if (!temp_sf) goto fail;
@ -1564,7 +1565,14 @@ static layered_layout_data* build_layered_eaaudiocore(STREAMFILE *sf_data, eaac_
block_size = 0x10000; /* unused */ block_size = 0x10000; /* unused */
block_count = stream_size / block_size + (stream_size % block_size ? 1 : 0); block_count = stream_size / block_size + (stream_size % block_size ? 1 : 0);
bytes = ffmpeg_make_riff_xma2(buf, 0x100, data->layers[i]->num_samples, stream_size, data->layers[i]->channels, data->layers[i]->sample_rate, block_count, block_size); /* EA adopted XMA2 when it appeared around 2006, but detection isn't so easy
* (SNS with XMA2 do exist). Decoder should work when playing XMA1 as XMA2, but
* the other way around can cause issues, so it's safer to just use XMA2. */
is_xma1 = 0; //eaac->version == EAAC_VERSION_V0; /* approximate */
if (is_xma1)
bytes = ffmpeg_make_riff_xma1(buf, 0x100, data->layers[i]->num_samples, stream_size, data->layers[i]->channels, data->layers[i]->sample_rate, 0);
else
bytes = ffmpeg_make_riff_xma2(buf, 0x100, data->layers[i]->num_samples, stream_size, data->layers[i]->channels, data->layers[i]->sample_rate, block_count, block_size);
data->layers[i]->codec_data = init_ffmpeg_header_offset(temp_sf, buf,bytes, 0x00, stream_size); data->layers[i]->codec_data = init_ffmpeg_header_offset(temp_sf, buf,bytes, 0x00, stream_size);
if (!data->layers[i]->codec_data) goto fail; if (!data->layers[i]->codec_data) goto fail;

View File

@ -102,9 +102,14 @@ VGMSTREAM * init_vgmstream_ea_swvr(STREAMFILE *streamFile) {
sample_rate = 14008; sample_rate = 14008;
break; break;
case 0x53484F43: /* "SHOC" (a generic block but hopefully has PC sounds) */ case 0x53484F43: /* "SHOC" (a generic block but hopefully has PC sounds) */
coding = coding_PCM8_U_int; if (read_32bit(start_offset+0x10, streamFile) == 0x53484F43) { /* SHDR */
channel_count = 1; coding = coding_PCM8_U_int; //todo there are other codecs
sample_rate = 14008; channel_count = 1;
sample_rate = 14008;
}
else {
goto fail;
}
break; break;
default: default:
VGM_LOG("EA SWVR: unknown block id\n"); VGM_LOG("EA SWVR: unknown block id\n");

96
src/meta/fda.c Normal file
View File

@ -0,0 +1,96 @@
#include "meta.h"
#include "../coding/coding.h"
/* FDA - from Relic Entertainment games [Warhammer 4000: Dawn of War (PC)] */
VGMSTREAM * init_vgmstream_fda(STREAMFILE *sf) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, bitrate, sample_rate, num_samples;
/* checks */
if (!check_extensions(sf, "fda"))
goto fail;
if (read_u32be(0x00, sf) != 0x52656C69 || /* "Reli" */
read_u32be(0x04, sf) != 0x63204368 || /* "c Ch" */
read_u32be(0x08, sf) != 0x756E6B79 || /* "unky" */
read_u32be(0x0c, sf) != 0x0D0A1A00) /* "\r\n\1a\00"*/
goto fail;
/* version? (later .fda change this) */
if (read_u32le(0x10, sf) != 1 ||
read_u32le(0x14, sf) != 1)
goto fail;
/* read chunks (abridged) */
{
off_t offset = 0x18;
size_t chunk_size, name_size, data_size;
/* Relic Chunkys have: type, subtype, version, data size, name size, then
* name (optional) and data. But format has fixed chunks so we'll simplify a bit. */
/* DATA-FBIF (file info) */
chunk_size = read_u32le(offset + 0x0c, sf);
name_size = read_u32le(offset + 0x10, sf);
offset += 0x14 + name_size + chunk_size;
/* FOLD-FDA (folder of chunks) */
if (read_u32be(offset + 0x04, sf) != 0x46444120) /* "FDA " */
goto fail;
offset += 0x14;
/* DATA-INFO (header) */
if (read_u32be(offset + 0x04, sf) != 0x494E464F) /* "INFO" */
goto fail;
chunk_size = read_u32le(offset + 0x0c, sf);
name_size = read_u32le(offset + 0x10, sf);
offset += 0x14 + name_size;
channel_count = read_s32le(offset + 0x00, sf);
/* 0x04: bps */
bitrate = read_s32le(offset + 0x08, sf);
sample_rate = read_s32le(offset + 0x0c, sf);
/* 0x10: loop start? (always 0) */
/* 0x14: loop end? (always -1) */
/* 0x18: loop offset? (always 0) */
loop_flag = 0; /* never set? */
offset += chunk_size;
/* DATA-DATA (data) */
if (read_u32be(offset + 0x04, sf) != 0x44415441) /* "DATA" */
goto fail;
chunk_size = read_u32le(offset + 0x0c, sf);
name_size = read_u32le(offset + 0x10, sf);
offset += 0x14 + name_size;
data_size = read_s32le(offset + 0x00, sf);
start_offset = offset + 0x04;
num_samples = data_size / channel_count / (bitrate / 8) * 512;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_FDA;
vgmstream->sample_rate = 44100; /* fixed output */
vgmstream->num_samples = num_samples;
vgmstream->codec_data = init_relic(channel_count, bitrate, sample_rate);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_RELIC;
vgmstream->layout_type = layout_none;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -877,4 +877,6 @@ VGMSTREAM* init_vgmstream_xma_ue3(STREAMFILE *sf);
VGMSTREAM* init_vgmstream_csb(STREAMFILE *sf); VGMSTREAM* init_vgmstream_csb(STREAMFILE *sf);
VGMSTREAM* init_vgmstream_fda(STREAMFILE *sf);
#endif /*_META_H*/ #endif /*_META_H*/

File diff suppressed because it is too large Load Diff

View File

@ -486,6 +486,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_xssb, init_vgmstream_xssb,
init_vgmstream_xma_ue3, init_vgmstream_xma_ue3,
init_vgmstream_csb, init_vgmstream_csb,
init_vgmstream_fda,
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ /* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */ init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
@ -656,6 +657,10 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
} }
#endif #endif
if (vgmstream->coding_type == coding_RELIC) {
reset_relic(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_CRI_HCA) { if (vgmstream->coding_type == coding_CRI_HCA) {
reset_hca(vgmstream->codec_data); reset_hca(vgmstream->codec_data);
} }
@ -823,6 +828,11 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
} }
#endif #endif
if (vgmstream->coding_type == coding_RELIC) {
free_relic(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
if (vgmstream->coding_type == coding_CRI_HCA) { if (vgmstream->coding_type == coding_CRI_HCA) {
free_hca(vgmstream->codec_data); free_hca(vgmstream->codec_data);
vgmstream->codec_data = NULL; vgmstream->codec_data = NULL;
@ -1273,6 +1283,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
return 0; /* varies per mode */ return 0; /* varies per mode */
case coding_EA_MT: case coding_EA_MT:
return 0; /* 432, but variable in looped files */ return 0; /* 432, but variable in looped files */
case coding_RELIC:
return 0; /* 512 */
case coding_CRI_HCA: case coding_CRI_HCA:
return 0; /* 1024 - delay/padding (which can be bigger than 1024) */ return 0; /* 1024 - delay/padding (which can be bigger than 1024) */
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
@ -1757,6 +1769,10 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
samples_to_do,vgmstream->channels); samples_to_do,vgmstream->channels);
break; break;
#endif #endif
case coding_RELIC:
decode_relic(&vgmstream->ch[0], vgmstream->codec_data, buffer+samples_written*vgmstream->channels,
samples_to_do);
break;
case coding_CRI_HCA: case coding_CRI_HCA:
decode_hca(vgmstream->codec_data, buffer+samples_written*vgmstream->channels, decode_hca(vgmstream->codec_data, buffer+samples_written*vgmstream->channels,
samples_to_do); samples_to_do);
@ -2191,6 +2207,10 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) {
/* prepare certain codecs' internal state for looping */ /* prepare certain codecs' internal state for looping */
if (vgmstream->coding_type == coding_RELIC) {
seek_relic(vgmstream->codec_data, vgmstream->loop_sample);
}
if (vgmstream->coding_type == coding_CRI_HCA) { if (vgmstream->coding_type == coding_CRI_HCA) {
loop_hca(vgmstream->codec_data, vgmstream->loop_sample); loop_hca(vgmstream->codec_data, vgmstream->loop_sample);
} }

View File

@ -183,6 +183,7 @@ typedef enum {
coding_EA_MT, /* Electronic Arts MicroTalk (linear-predictive speech codec) */ coding_EA_MT, /* Electronic Arts MicroTalk (linear-predictive speech codec) */
coding_RELIC, /* Relic Codec (DCT-based) */
coding_CRI_HCA, /* CRI High Compression Audio (MDCT-based) */ coding_CRI_HCA, /* CRI High Compression Audio (MDCT-based) */
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
@ -718,6 +719,7 @@ typedef enum {
meta_ISB, meta_ISB,
meta_XSSB, meta_XSSB,
meta_XMA_UE3, meta_XMA_UE3,
meta_FDA,
} meta_t; } meta_t;
@ -1147,6 +1149,7 @@ typedef struct {
NWAData *nwa; NWAData *nwa;
} nwa_codec_data; } nwa_codec_data;
typedef struct relic_codec_data relic_codec_data;
typedef struct { typedef struct {
STREAMFILE *streamfile; STREAMFILE *streamfile;