Skip to content

Instantly share code, notes, and snippets.

@bnnm
Created December 27, 2019 01:24
Show Gist options
  • Save bnnm/bf6d4d3cb4335ff1d09ff46481eea2f4 to your computer and use it in GitHub Desktop.
Save bnnm/bf6d4d3cb4335ff1d09ff46481eea2f4 to your computer and use it in GitHub Desktop.
Relic Codec dec.exe decompilation
/* Relic's dec.exe decompilation (by bnnm)
*
* Decodes .AIF files using Relic Codec (Homeworld 1/2, Warhammer 40000).
* dec.exe and the codec was presumably written by Janik Joire (he did
* the Winamp plugin and sound programming).
*
* Program should decode nearly identical to the original, with minor +-1 sample
* differences that probably depend on using the original Intel compiler and flags
* or minor double/float differences.
*
* This was mainly for learning purposes, some parts weren't cleaned up (see
* vgmstream's source for updated names).
*/
#include <windows.h>
#include <math.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
//-------------------------------------------------------------------------
#define FQ_OK 0
#define FQ_ERR -1
float g_window2_128[128] = { 0.0 }; //aWHBlock
float g_window1_512[512] = { 0.0 }; //aCHBlock
float g_window2_512[512];//aWBlock
float g_window1_256[256];//aCBlock
//void fft(int n, float *xRe, float *xIm, float *yRe, float *yIm);
//-----------------------------------------------------------------------------
// MIXFFT.C
//-----------------------------------------------------------------------------
//-------------------------------------------------------------------------
// Data declarations
#define maxPrimeFactor 37
#define maxPrimeFactorDiv2 ((maxPrimeFactor+1)/2)
#define maxFactorCount 20
float g_c3_1 = -1.5f; // -1.5
float g_c3_2 = 0.8660254f; // 0.866025388240814208984375
//float u8 = 1.2566371f // 1.256637096405029296875
float g_c5_1 = -1.25f; // -1.25
float g_c5_2 = 0.559017f; // 0.559017002582550048828125
float g_c5_3 = -0.95105654f; // -0.951056540012359619140625
float g_c5_4 = -1.5388417f; // -1.538841724395751953125
float g_c5_5 = 0.36327127f; // 0.3632712662220001220703125
float g_c8 = 0.70710677f; // 0.707106769084930419921875
//double g_max_80b = 1.797693134862316e308;
float g_twiddleRe[maxPrimeFactor];
float g_twiddleIm[maxPrimeFactor];
float g_trigRe[maxPrimeFactor];
float g_trigIm[maxPrimeFactor];
float g_zRe[maxPrimeFactor];
float g_zIm[maxPrimeFactor];
float g_vRe[maxPrimeFactorDiv2]; // idb
float g_vIm[maxPrimeFactorDiv2]; // idb
float g_wRe[maxPrimeFactorDiv2]; // idb
float g_wIm[maxPrimeFactorDiv2]; // idb
float g_pi; // weak
float g_tw_re;
float g_tw_im;
float g_omega; // weak
int g_blockNo; // weak
int g_twNo; // weak
int g_adr; // weak
int g_groupNo; // weak
int g_dataNo; // weak
int g_groupOffset; // weak
int g_dataOffset; // weak
static void factorize(int n, int *nFact, int *fact) {
double dtemp; // ST54_8
int factors[maxFactorCount]; // [esp+5Ch] [ebp-7Ch]
int radices[7]; // [esp+ACh] [ebp-2Ch]
int nRadix; // [esp+C8h] [ebp-10h]
int i, j, k;
nRadix = 6;
radices[0] = 1; // unused
radices[1] = 2;
radices[2] = 3;
radices[3] = 4;
radices[4] = 5;
radices[5] = 8;
radices[6] = 10;
if (n == 1) {
j = 1;
factors[1] = 1;
} else {
j = 0;
}
i = nRadix;
while (n > 1 && i > 0) {
if (n % radices[i]) {
--i;
} else {
n /= radices[i];
factors[++j] = radices[i];
}
}
if (factors[j] == 2) // substitute factors 2*8 with 4*4
{
for (i = j - 1; 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;
factors[j] = k;
}
}
if (n > 1)
++j;
factors[j] = n;
}
for (i = 1; i <= j; ++i) {
fact[i] = factors[j - i + 1];
}
*nFact = j;
}
static void transTableSetup(int *sofar, int *actual, int *remain,
signed int *nFact, int *nPoints) {
int i;
factorize(*nPoints, nFact, actual);
if (actual[*nFact] > 37) {
printf("\nPrime factor of FFT length too large : %6d", actual[*nFact]);
exit(1);
}
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];
}
}
static void permute(int nPoint, int nFact, int *fact, int *remain, float *xRe,
float *xIm, float *yRe, float *yIm) {
int count[maxFactorCount];
int i, j, k;
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 += remain[1];
++count[1];
while (count[j] >= fact[j]) {
count[j] = 0;
k = remain[j + 1] + k - remain[j - 1];
++count[++j];
}
}
yRe[nPoint - 1] = xRe[nPoint - 1];
yIm[nPoint - 1] = xIm[nPoint - 1];
}
static void initTrig(int radix) {
int i;
float w, xre, xim;
w = 2.0 * g_pi / (double) radix;
g_trigRe[0] = 1.0;
g_trigIm[0] = 0.0;
xre = cos(w);
xim = -sin(w);
g_trigRe[1] = xre;
g_trigIm[1] = xim;
for (i = 2; i < radix; ++i) {
g_trigRe[i] = xre * g_trigRe[i - 1] - xim * g_trigIm[i - 1];
g_trigIm[i] = xim * g_trigRe[i - 1] + xre * g_trigIm[i - 1];
}
}
static void fft_4(float *aRe, float *aIm) {
float t1_re; // ST68_4
float t1_im; // ST64_4
float t2_re; // ST60_4
float t2_im; // ST5C_4
float m2_re; // ST58_4
float m2_im; // ST54_4
float m3_re; // ST50_4
float m3_im; // ST4C_4
t1_re = *aRe + aRe[2];
t1_im = *aIm + aIm[2];
t2_re = aRe[1] + aRe[3];
t2_im = aIm[1] + aIm[3];
m2_re = *aRe - aRe[2];
m2_im = *aIm - aIm[2];
m3_re = aIm[1] - aIm[3];
m3_im = aRe[3] - aRe[1];
*aRe = t1_re + t2_re;
*aIm = 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;
}
static void fft_5(float *aRe, float *aIm) {
float t1_re; // STC0_4
float t1_im; // STBC_4
float t2_re; // STB8_4
float t2_im; // STB4_4
float t3_re; // STB0_4
float t3_im; // STAC_4
float t4_re; // STA8_4
float t4_im; // STA4_4
float t5_re; // STA0_4
float t5_im; // ST9C_4
float m1_re; // ST80_4
float m1_im; // ST7C_4
float m2_re; // ST98_4
float m2_im; // ST94_4
float m3_re; // ST90_4
float m3_im; // ST8C_4
float m4_re; // ST88_4
float m4_im; // ST84_4
float m5_re; // ST78_4
float m5_im; // ST74_4
float s3_re; // ST60_4
float s3_im; // ST5C_4
float s5_re; // ST50_4
float s5_im; // ST4C_4
float s1_re; // ST70_4
float s1_im; // ST6C_4
float s2_re; // ST68_4
float s2_im; // ST64_4
float s4_re; // ST58_4
float s4_im; // ST54_4
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 = t5_re + *aRe;
*aIm = t5_im + *aIm;
m1_re = g_c5_1 * t5_re;
m1_im = g_c5_1 * t5_im;
m2_re = (t1_re - t2_re) * g_c5_2;
m2_im = (t1_im - t2_im) * g_c5_2;
m3_re = -g_c5_3 * (t3_im + t4_im);
m3_im = (t3_re + t4_re) * g_c5_3;
m4_re = -g_c5_4 * t4_im;
m4_im = g_c5_4 * t4_re;
m5_re = -g_c5_5 * t3_im;
m5_im = g_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 = m1_re + *aRe;
s1_im = m1_im + *aIm;
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;
}
static void fft_8() {
float gem; // ST54_4 MAPDST
float bIm[4]; // [esp+50h] [ebp-40h]
float bRe[4]; // [esp+60h] [ebp-30h]
float aIm[4]; // [esp+70h] [ebp-20h]
float aRe[4]; // [esp+80h] [ebp-10h]
aRe[0] = g_zRe[0];
bRe[0] = g_zRe[1];
aRe[1] = g_zRe[2];
bRe[1] = g_zRe[3];
aRe[2] = g_zRe[4];
bRe[2] = g_zRe[5];
aRe[3] = g_zRe[6];
bRe[3] = g_zRe[7];
aIm[0] = g_zIm[0];
bIm[0] = g_zIm[1];
aIm[1] = g_zIm[2];
bIm[1] = g_zIm[3];
aIm[2] = g_zIm[4];
bIm[2] = g_zIm[5];
aIm[3] = g_zIm[6];
bIm[3] = g_zIm[7];
fft_4(aRe, aIm);
fft_4(bRe, bIm);
gem = (bRe[1] + bIm[1]) * g_c8;
bIm[1] = (bIm[1] - bRe[1]) * g_c8;
bRe[1] = gem;
gem = bIm[2];
bIm[2] = -bRe[2];
bRe[2] = gem;
gem = (bIm[3] - bRe[3]) * g_c8;
bIm[3] = -g_c8 * (bRe[3] + bIm[3]);
g_zRe[0] = aRe[0] + bRe[0];
g_zRe[4] = aRe[0] - bRe[0];
g_zRe[1] = aRe[1] + bRe[1];
g_zRe[5] = aRe[1] - bRe[1];
g_zRe[2] = aRe[2] + bRe[2];
g_zRe[6] = aRe[2] - bRe[2];
g_zRe[3] = aRe[3] + gem;
g_zRe[7] = aRe[3] - gem;
g_zIm[0] = aIm[0] + bIm[0];
g_zIm[4] = aIm[0] - bIm[0];
g_zIm[1] = aIm[1] + bIm[1];
g_zIm[5] = aIm[1] - bIm[1];
g_zIm[2] = aIm[2] + bIm[2];
g_zIm[6] = aIm[2] - bIm[2];
g_zIm[3] = aIm[3] + bIm[3];
g_zIm[7] = aIm[3] - bIm[3];
}
static void fft_10() {
float bIm[5]; // [esp+4Ch] [ebp-50h]
float bRe[5]; // [esp+60h] [ebp-3Ch]
float aIm[5]; // [esp+74h] [ebp-28h]
float aRe[5]; // [esp+88h] [ebp-14h]
aRe[0] = g_zRe[0];
bRe[0] = g_zRe[5];
aRe[1] = g_zRe[2];
bRe[1] = g_zRe[7];
aRe[2] = g_zRe[4];
bRe[2] = g_zRe[9];
aRe[3] = g_zRe[6];
bRe[3] = g_zRe[1];
aRe[4] = g_zRe[8];
bRe[4] = g_zRe[3];
aIm[0] = g_zIm[0];
bIm[0] = g_zIm[5];
aIm[1] = g_zIm[2];
bIm[1] = g_zIm[7];
aIm[2] = g_zIm[4];
bIm[2] = g_zIm[9];
aIm[3] = g_zIm[6];
bIm[3] = g_zIm[1];
aIm[4] = g_zIm[8];
bIm[4] = g_zIm[3];
fft_5(aRe, aIm);
fft_5(bRe, bIm);
g_zRe[0] = aRe[0] + bRe[0];
g_zRe[5] = aRe[0] - bRe[0];
g_zRe[6] = aRe[1] + bRe[1];
g_zRe[1] = aRe[1] - bRe[1];
g_zRe[2] = aRe[2] + bRe[2];
g_zRe[7] = aRe[2] - bRe[2];
g_zRe[8] = aRe[3] + bRe[3];
g_zRe[3] = aRe[3] - bRe[3];
g_zRe[4] = aRe[4] + bRe[4];
g_zRe[9] = aRe[4] - bRe[4];
g_zIm[0] = aIm[0] + bIm[0];
g_zIm[5] = aIm[0] - bIm[0];
g_zIm[6] = aIm[1] + bIm[1];
g_zIm[1] = aIm[1] - bIm[1];
g_zIm[2] = aIm[2] + bIm[2];
g_zIm[7] = aIm[2] - bIm[2];
g_zIm[8] = aIm[3] + bIm[3];
g_zIm[3] = aIm[3] - bIm[3];
g_zIm[4] = aIm[4] + bIm[4];
g_zIm[9] = aIm[4] - bIm[4];
}
static void fft_odd(int radix) {
float rere; // ST6C_4
float imim; // ST60_4
float reim; // ST68_4
float imre; // ST64_4
int max; // [esp+4Ch] [ebp-24h]
int k; // [esp+54h] [ebp-1Ch]
int j; // [esp+58h] [ebp-18h] MAPDST
int i; // [esp+5Ch] [ebp-14h]
max = (radix + 1) / 2;
for (j = 1; j < max; ++j) {
g_vRe[j] = g_zRe[j] + g_zRe[radix - j];
g_vIm[j] = g_zIm[j] - g_zIm[radix - j];
g_wRe[j] = g_zRe[j] - g_zRe[radix - j];
g_wIm[j] = g_zIm[j] + g_zIm[radix - j];
}
for (j = 1; j < max; ++j) {
g_zRe[j] = g_zRe[0];
g_zIm[j] = g_zIm[0];
g_zRe[radix - j] = g_zRe[0];
g_zIm[radix - j] = g_zIm[0];
k = j;
for (i = 1; i < max; ++i) {
rere = g_trigRe[k] * g_vRe[i];
imim = g_trigIm[k] * g_vIm[i];
reim = g_trigRe[k] * g_wIm[i];
imre = g_trigIm[k] * g_wRe[i];
g_zRe[radix - j] = rere + imim + g_zRe[radix - j];
g_zIm[radix - j] = reim - imre + g_zIm[radix - j];
g_zRe[j] = rere - imim + g_zRe[j];
g_zIm[j] = reim + imre + g_zIm[j];
k += j;
if (k >= radix)
k -= radix;
}
}
for (j = 1; j < max; ++j) {
g_zRe[0] = g_zRe[0] + g_vRe[j];
g_zIm[0] = g_zIm[0] + g_wIm[j];
}
}
static void twiddleTransf(int sofarRadix, int radix, int remainRadix,
float *yRe, float *yIm) {
float cosw, sinw, gem;
float t1_re, t1_im; // STD0_4 MAPDST
float m1_re; // ST94_4 MAPDST
float m1_im; // ST90_4 MAPDST
float m2_re; // STAC_4 MAPDST
float m2_im; // STA8_4 MAPDST
float s1_re; // ST84_4
float s1_im; // ST80_4
float t2_re; // STCC_4 MAPDST
float t2_im; // STC8_4 MAPDST
float m3_re; // STA4_4 MAPDST
float m3_im; // STA0_4 MAPDST
float t3_re; // STC4_4
float t3_im; // STC0_4
float t4_re; // STBC_4
float t4_im; // STB8_4
float t5_re; // STB4_4
float t5_im; // STB0_4
float m4_re; // ST9C_4
float m4_im; // ST98_4
float m5_re; // ST8C_4
float m5_im; // ST88_4
float s3_re; // ST74_4
float s3_im; // ST70_4
float s5_re; // ST64_4
float s5_im; // ST60_4
float s2_re; // ST7C_4
float s2_im; // ST78_4
float s4_re; // ST6C_4
float s4_im; // ST68_4
initTrig(radix);
g_omega = 2.0 * g_pi / (double) (sofarRadix * radix);
cosw = cos(g_omega);
sinw = -sin(g_omega);
g_tw_re = 1.0;
g_tw_im = 0.0;
g_dataOffset = 0;
g_groupOffset = g_dataOffset;
g_adr = g_groupOffset;
for (g_dataNo = 0; g_dataNo < sofarRadix; ++g_dataNo) {
if (sofarRadix > 1) {
g_twiddleRe[0] = 1.0;
g_twiddleIm[0] = 0.0;
g_twiddleRe[1] = g_tw_re;
g_twiddleIm[1] = g_tw_im;
for (g_twNo = 2; g_twNo < radix; ++g_twNo) {
g_twiddleRe[g_twNo] = g_tw_re * g_twiddleRe[g_twNo - 1]
- g_tw_im * g_twiddleIm[g_twNo - 1];
g_twiddleIm[g_twNo] = g_tw_im * g_twiddleRe[g_twNo - 1]
+ g_tw_re * g_twiddleIm[g_twNo - 1];
}
gem = cosw * g_tw_re - sinw * g_tw_im;
g_tw_im = sinw * g_tw_re + cosw * g_tw_im;
g_tw_re = gem;
}
for (g_groupNo = 0; g_groupNo < remainRadix; ++g_groupNo) {
if (sofarRadix <= 1 || g_dataNo <= 0) {
for (g_blockNo = 0; g_blockNo < radix; ++g_blockNo) {
g_zRe[g_blockNo] = yRe[g_adr];
g_zIm[g_blockNo] = yIm[g_adr];
g_adr += sofarRadix;
}
} else {
g_zRe[0] = yRe[g_adr];
g_zIm[0] = yIm[g_adr];
g_blockNo = 1;
do {
g_adr += sofarRadix;
g_zRe[g_blockNo] = g_twiddleRe[g_blockNo] * yRe[g_adr]
- g_twiddleIm[g_blockNo] * yIm[g_adr];
g_zIm[g_blockNo] = g_twiddleRe[g_blockNo] * yIm[g_adr]
+ g_twiddleIm[g_blockNo] * yRe[g_adr];
++g_blockNo;
} while (g_blockNo < radix);
}
switch (radix) {
case 2:
gem = g_zRe[0] + g_zRe[1];
g_zRe[1] = g_zRe[0] - g_zRe[1];
g_zRe[0] = gem;
gem = g_zIm[0] + g_zIm[1];
g_zIm[1] = g_zIm[0] - g_zIm[1];
g_zIm[0] = gem;
break;
case 3:
t1_re = g_zRe[1] + g_zRe[2];
t1_im = g_zIm[1] + g_zIm[2];
g_zRe[0] = g_zRe[0] + t1_re;
g_zIm[0] = g_zIm[0] + t1_im;
m1_re = g_c3_1 * t1_re;
m1_im = g_c3_1 * t1_im;
m2_re = (g_zIm[1] - g_zIm[2]) * g_c3_2;
m2_im = (g_zRe[2] - g_zRe[1]) * g_c3_2;
s1_re = g_zRe[0] + m1_re;
s1_im = g_zIm[0] + m1_im;
g_zRe[1] = s1_re + m2_re;
g_zIm[1] = s1_im + m2_im;
g_zRe[2] = s1_re - m2_re;
g_zIm[2] = s1_im - m2_im;
break;
case 4:
t1_re = g_zRe[0] + g_zRe[2];
t1_im = g_zIm[0] + g_zIm[2];
t2_re = g_zRe[1] + g_zRe[3];
t2_im = g_zIm[1] + g_zIm[3];
m2_re = g_zRe[0] - g_zRe[2];
m2_im = g_zIm[0] - g_zIm[2];
m3_re = g_zIm[1] - g_zIm[3];
m3_im = g_zRe[3] - g_zRe[1];
g_zRe[0] = t1_re + t2_re;
g_zIm[0] = t1_im + t2_im;
g_zRe[2] = t1_re - t2_re;
g_zIm[2] = t1_im - t2_im;
g_zRe[1] = m2_re + m3_re;
g_zIm[1] = m2_im + m3_im;
g_zRe[3] = m2_re - m3_re;
g_zIm[3] = m2_im - m3_im;
break;
case 5:
t1_re = g_zRe[1] + g_zRe[4];
t1_im = g_zIm[1] + g_zIm[4];
t2_re = g_zRe[2] + g_zRe[3];
t2_im = g_zIm[2] + g_zIm[3];
t3_re = g_zRe[1] - g_zRe[4];
t3_im = g_zIm[1] - g_zIm[4];
t4_re = g_zRe[3] - g_zRe[2];
t4_im = g_zIm[3] - g_zIm[2];
t5_re = t1_re + t2_re;
t5_im = t1_im + t2_im;
g_zRe[0] = g_zRe[0] + t5_re;
g_zIm[0] = g_zIm[0] + t5_im;
m1_re = g_c5_1 * t5_re;
m1_im = g_c5_1 * t5_im;
m2_re = (t1_re - t2_re) * g_c5_2;
m2_im = (t1_im - t2_im) * g_c5_2;
m3_re = -g_c5_3 * (t3_im + t4_im);
m3_im = (t3_re + t4_re) * g_c5_3;
m4_re = -g_c5_4 * t4_im;
m4_im = g_c5_4 * t4_re;
m5_re = -g_c5_5 * t3_im;
m5_im = g_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 = g_zRe[0] + m1_re;
s1_im = g_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;
g_zRe[1] = s2_re + s3_re;
g_zIm[1] = s2_im + s3_im;
g_zRe[2] = s4_re + s5_re;
g_zIm[2] = s4_im + s5_im;
g_zRe[3] = s4_re - s5_re;
g_zIm[3] = s4_im - s5_im;
g_zRe[4] = s2_re - s3_re;
g_zIm[4] = s2_im - s3_im;
break;
case 8:
fft_8();
break;
case 10:
fft_10();
break;
default:
fft_odd(radix);
break;
}
g_adr = g_groupOffset;
for (g_blockNo = 0; g_blockNo < radix; ++g_blockNo) {
yRe[g_adr] = g_zRe[g_blockNo];
yIm[g_adr] = g_zIm[g_blockNo];
g_adr += sofarRadix;
}
g_groupOffset += radix * sofarRadix;
g_adr = g_groupOffset;
}
g_dataOffset = g_dataOffset + 1;
g_groupOffset = g_dataOffset;
g_adr = g_groupOffset;
}
}
void fft(int n, float *xRe, float *xIm, float *yRe, float *yIm) {
int count; // [esp+4Ch] [ebp-F8h]
int nFactor; // [esp+50h] [ebp-F4h]
int remainRadix[maxFactorCount]; // [esp+54h] [ebp-F0h]
int actualRadix[maxFactorCount]; // [esp+A4h] [ebp-A0h]
int sofarRadix[maxFactorCount]; // [esp+F4h] [ebp-50h]
g_pi = 3.1415927;
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);
}
//-----------------------------------------------------------------------------
// DCT.C
//-----------------------------------------------------------------------------
#define FQ_PI 3.14159265358979323846f
#define DOUBSIZE 512
#define FULLSIZE 256
#define HALFSIZE 128
//int Initdct(float *c,unsigned long n);
static int init_dct(float *window, uint32_t size) {
int i;
uint32_t half;
half = size >> 2;
for (i = 0; i < half; ++i) {
double temp = ((float)i + 0.125f) * (FQ_PI * 2.0f) * (1.0f / (float)size);
window[i] = sin(temp);
window[half + i] = cos(temp);
}
return 0;
}
//int idct(float *f,float *g,float *c,unsigned long n);
static int apply_idct(const float *spectra, float *samples, const float *window, uint32_t size) {
float size_sqrt; // ST84_4
float coef1; // ST8C_4
float coef2; // ST88_4
float fft_temp; // ST7C_4
uint32_t size_3quarter; // [esp+5Ch] [ebp-1028h]
uint32_t size_quarter; // [esp+60h] [ebp-1024h]
uint32_t size_half; // [esp+64h] [ebp-1020h]
int i;
float factor;
float fft_out_im[128]; // [esp+84h] [ebp-1000h]
float fft_out_re[128]; // [esp+284h] [ebp-E00h]
float fft_im[128]; // [esp+484h] [ebp-C00h]
float fft_re[128]; // [esp+684h] [ebp-A00h]
float samples_tmp[512]; // [esp+884h] [ebp-800h]
size_half = size >> 1;
size_quarter = size >> 2;
size_3quarter = 3 * (size >> 2);
factor = 8.0 / sqrt(size);
for (i = 0; i < size_quarter; ++i) { // prerotation?
coef1 = spectra[2 * i] * 0.5;
coef2 = spectra[size_half - 1 - 2 * i] * 0.5;
fft_re[i] = coef1 * window[size_quarter + i] + coef2 * window[i];
fft_im[i] = -coef1 * window[i] + coef2 * window[size_quarter + i];
}
fft(size_quarter, fft_re, fft_im, fft_out_re, fft_out_im);
for (i = 0; i < size_quarter; i++) { // postrotation, window and reorder?
fft_temp = fft_out_re[i];
fft_out_re[i] = (fft_out_re[i] * window[size_quarter + i] + fft_out_im[i] * window[i]) * factor;
fft_out_im[i] = (-fft_temp * window[i] + fft_out_im[i] * window[size_quarter + i]) * factor;
}
for (i = 0; i < size_quarter; i++) {
samples_tmp[2 * i] = fft_out_re[i];
samples_tmp[2 * i + size_half] = fft_out_im[i];
}
for (i = 1; i < size; i += 2) {
samples_tmp[i] = -samples_tmp[size - 1 - i];
}
for (i = 0; i < size_3quarter; i++) {
samples[i] = samples_tmp[size_quarter + i];
}
for (i = size_3quarter; i < size; i++) {
samples[i] = -samples_tmp[i - size_3quarter];
}
return 0;
}
//-----------------------------------------------------------------------------
// FQCODEC.C
//-----------------------------------------------------------------------------
// Rate constants
#define FQ_HRATE 11025L // Hz
#define FQ_RATE 22050L // Hz
#define FQ_DRATE 44100L // Hz
// Size constants
#define FQ_QSIZE 64
#define FQ_HSIZE 128
#define FQ_SIZE 256
#define FQ_DSIZE 512
// Coef constants
#define FQ_HCOEF aCHBlock
#define FQ_COEF aCBlock
#define FQ_DCOEF aCDBlock
// Window constants
#define FQ_HWIN aWHBlock
#define FQ_WIN aWBlock
#define FQ_DWIN aWDBlock
// Mode constants
#define FQ_MINIT 0x0000 // Initialize CODEC
#define FQ_MDOUBLE 0x0001 // Double mode
#define FQ_MNORM 0x0002 // Normal mode
#define FQ_MHALF 0x0004 // Half mode
// Macro constants
#define FQ_BNUM ((float)(1<<26)*(1<<26)*1.5)
extern double fChopT;
// Macros
#define rfabs(x) ((x<0.0F)?(-(x)):(x)) // Fast floating point absolute value
#define rmax(x,y) ((x>y)?(x):(y)) // Fast maximize
#define rint(x) ((fChopT = (double)(x)+FQ_BNUM), *(int*)(&fChopT)) // Fast integer cast
//int fqDecOver(float *aFPBlock,float *aFSBlock,float *aTPBlock,float *aTSBlock, float *aCBlock,float *aWBlock,unsigned long nSize);
static int decode_window(const float *spectra_hi, const float *spectra_lo,
float *samples_cur, float *samples_prv, const float *window1,
const float *window2, uint32_t size) {
float samples_tmp[FQ_DSIZE];
int i;
uint32_t half;
half = size >> 1;
memcpy(samples_cur, samples_prv, FQ_DSIZE * sizeof(float));
apply_idct(spectra_hi, samples_tmp, window1, size);
apply_idct(spectra_lo, samples_prv, window1, size);
for (i = 0; i < half; ++i) {
samples_cur[half + i] = samples_tmp[i] * window2[i]
+ samples_cur[half + i] * window2[half + i];
samples_prv[i] = samples_prv[i] * window2[i]
+ samples_tmp[half + i] * window2[half + i];
}
return 0;
}
//int fqDecBlock(float *aFPBlock,float *aFSBlock, float *aTPBlock,float *aTSBlock,int nMode,int nFact);
static int decode_frame(const float *spectra_hi, const float *spectra_lo,
float *samples_cur, float *samples_prv, int mode, int decode_submode) {
int result; // eax
float samples_tmp[FQ_DSIZE];
uint32_t i; // [esp+870h] [ebp-4h]
if (mode == FQ_MINIT) {
/* lapping windows */
memset(samples_prv, 0, FQ_DSIZE * sizeof(float));
for (i = 0; i < FQ_HSIZE; ++i) {
g_window2_128[i] = sin((float)i * (FQ_PI / FQ_HSIZE));
}
for (i = 0; i < FQ_SIZE; ++i) {
g_window1_512[i + 320] = sin((float)i * (FQ_PI / FQ_SIZE));
}
for (i = 0; i < FQ_DSIZE; ++i) {
g_window2_512[i] = sin((float)i * (FQ_PI / FQ_DSIZE));
}
if (init_dct(&g_window1_512[256], FQ_HSIZE) == -1)
return FQ_ERR;
if (init_dct(g_window1_256, FQ_SIZE) == -1)
return FQ_ERR;
if (init_dct(g_window1_512, FQ_DSIZE) == -1)
return FQ_ERR;
return FQ_OK;
}
else {
if (decode_submode == 4) {
result = decode_window(spectra_hi, spectra_lo, samples_cur,
samples_prv, &g_window1_512[256], g_window2_128, 128);
return result ;
}
else if (decode_submode == 2) {
if (mode == 4) {
decode_window(spectra_hi, spectra_lo, samples_tmp, samples_prv,
&g_window1_512[256], g_window2_128, 128);
for (i = 0; i < 255; i += 2) {
samples_cur[i] = samples_tmp[i >> 1];
samples_cur[i + 1] = samples_tmp[i >> 1];
}
return FQ_OK;
} else {
result = decode_window(spectra_hi, spectra_lo, samples_cur,
samples_prv, g_window1_256, &g_window1_512[320], 256);
}
} else if (mode == 4) {
decode_window(spectra_hi, spectra_lo, samples_tmp, samples_prv,
&g_window1_512[256], g_window2_128, 128);
for (i = 0; i < 511; i += 4) {
samples_cur[i] = samples_tmp[i >> 2];
samples_cur[i + 1] = samples_tmp[i >> 2];
samples_cur[i + 2] = samples_tmp[i >> 2];
samples_cur[i + 3] = samples_tmp[i >> 2];
}
return FQ_OK;
} else if (mode == 2) {
decode_window(spectra_hi, spectra_lo, samples_tmp, samples_prv,
g_window1_256, &g_window1_512[320], 256);
for (i = 0; i < 511; i += 2) {
samples_cur[i] = samples_tmp[i >> 1];
samples_cur[i + 1] = samples_tmp[i >> 1];
}
return FQ_OK;
} else { // default (mode=1, submode=1)
result = decode_window(spectra_hi, spectra_lo, samples_cur,
samples_prv, g_window1_512, g_window2_512, 512);
}
return result;
}
}
//-----------------------------------------------------------------------------
// FQUANT.C
//-----------------------------------------------------------------------------
// General constants
#define FQ_LEN 260 // Block length (bytes)
#define FQ_SCALE 10.0F // Quantization scale
#define FQ_EXP 6 // # of exponents
#define FQ_FMASK 1.0F // Frequency masking factor
#define FQ_TPMASK 2.0F // Primary time masking factor
#define FQ_TSMASK 4.0F // Secondary time masking factor
#define FQ_THRES aTBlock // Hearing thresholds
#define FQ_STAT pSStream // Statistics stream
// Scale constants
#define FQ_SDATA aSDBlock // Scale data
// Encoder flags
#define FQ_ENORM 0x0000 // Normal
#define FQ_ERESET 0x0001 // Reset exponents
#define FQ_EMIX 0x0002 // Mix primary and secondary blocks
// Quantization limits (# of bits)
#define FQ_NBMAX 6 // Maximum
#define FQ_NBMIN 1 // Minimum
// Compression bitrates (per block)
// Name Bits/block Kbps/channel
#define FQ_BR176 2048 // 176
#define FQ_BR88 1024 // 88
#define FQ_BR44 512 // 44
#define FQ_BR22 256 // 22
// Critical band constants
#define FQ_CBDATA aCBBlock // Critical band data
#define FQ_CBNUM 27 // # of critical bands
// Sub-band constants
#define FQ_SBMODE 22 // # of modes
#define FQ_SBSIZE aSBSBlock // Sub-band sizes
#define FQ_SBDATA aSBDBlock // Sub-band data
#define FQ_SBNUM 256 // # of sub-bands
float g_scales[FQ_EXP]; //aSDBlock
//aCBBlock
int16_t g_codebook[FQ_CBNUM] = {
0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u,
9u, 11u, 13u, 15u, 17u, 20u, 23u, 27u,
31u, 37u, 43u, 51u, 62u, 74u, 89u, 110u,
139u, 180u, 256u
};
//_inline long fqSUnpack(unsigned long nLen,unsigned long nPos,char *aBlock);
static int read_sbits(uint8_t bits, uint32_t offset, uint8_t *buf) {
int val; // edx
val = (*(int *) &buf[offset >> 3]
& (uint32_t) (((1 << bits) - 1) << (offset - 8 * (offset >> 3))))
>> (offset - 8 * (offset >> 3));
if ((uint32_t) val >> (bits - 1) == 1)
val = -((uint32_t) (val << (32 - bits + 1)) >> (32 - bits + 1));
return val;
}
//_inline unsigned long fqUnpack(unsigned long nLen,unsigned long nPos,char *aBlock);
static uint32_t read_ubits(uint8_t bits, uint32_t offset, uint8_t *buf) {
return (*(int *) &buf[offset >> 3]
& (uint32_t) (((1 << bits) - 1) << (offset - 8 * (offset >> 3))))
>> (offset - 8 * (offset >> 3));
}
//int fqInitDequant(void);
static void init_dequant() {
int i;
g_scales[0] = FQ_SCALE;
for (i = 1; i < FQ_EXP; i++) {
g_scales[i] = g_scales[i - 1] * FQ_SCALE;
}
for (i = 0; i < FQ_EXP; i++) {
g_scales[i] = FQ_FMASK / (double) ((1 << (i + 1)) - 1) * g_scales[i];
}
}
//todo remove NUMu
//todo aEBlock = codes
//int fqDequantBlock(char *aQBlock,float *aFPBlock,float *aFSBlock,unsigned char *aEBlock,
// unsigned long nLen,unsigned long nRate,unsigned long nSize);
static int unpack_frame1(uint8_t *buf, float *spectra_hi, float *spectra_lo,
uint8_t *codes, int buf_size, int frame_bits, uint32_t size_half) {
float quant; // [esp+54h] [ebp-38h] MAPDST
uint8_t flags; // [esp+58h] [ebp-34h]
uint8_t code_value; // [esp+5Ch] [ebp-30h]
uint8_t gain_bits; // [esp+60h] [ebp-2Ch] MAPDST
uint8_t move; // [esp+64h] [ebp-28h] MAPDST
uint8_t pos; // [esp+68h] [ebp-24h] MAPDST
uint32_t index_bits; // [esp+70h] [ebp-1Ch]
uint32_t code_bits; // [esp+74h] [ebp-18h]
uint32_t move_bits; // [esp+78h] [ebp-14h]
uint32_t buf_bits; // [esp+7Ch] [ebp-10h]
uint32_t bit_offset; // [esp+80h] [ebp-Ch] MAPDST
int i, j;
memset(spectra_hi, 0, FQ_SIZE * sizeof(float));
memset(spectra_lo, 0, FQ_SIZE * sizeof(float));
buf_bits = 8 * buf_size;
flags = read_ubits(2u, 0, buf);
move_bits = read_ubits(3u, 2u, buf);
code_bits = read_ubits(2u, 5u, buf);
index_bits = read_ubits(4u, 7u, buf);
bit_offset = 11;
if ((flags & 1) == 1) // reset codes
memset(codes, 0, FQ_SIZE);
if (move_bits > 0 && code_bits > 0) { // read codes
pos = 0;
for (i = 0; i < FQ_CBNUM - 1; ++i) {
if (bit_offset >= frame_bits || bit_offset >= buf_bits)
break;
move = read_ubits(move_bits, bit_offset, buf);
bit_offset += move_bits;
if (i > 0 && move == 0)
break;
pos += move;
code_value = read_ubits(code_bits, bit_offset, buf);
bit_offset += code_bits;
for (j = g_codebook[pos]; j < g_codebook[pos + 1]; ++j)
codes[j] = code_value;
}
}
if (size_half > 0 && index_bits > 0) {
pos = 0;
// read spectra_hi
for (i = 0; i < 256; ++i) {
if (bit_offset >= frame_bits || bit_offset >= buf_bits)
break;
move = read_ubits(index_bits, bit_offset, buf);
bit_offset += index_bits;
if (i > 0 && move == 0)
break;
pos += move;
gain_bits = codes[pos];
quant = (double) read_sbits(gain_bits + 2, bit_offset, buf);
bit_offset += gain_bits + 2;
if (quant != 0.0 && pos < size_half && (signed int) codes[pos] < 6)
spectra_hi[pos] = quant * g_scales[gain_bits];
}
if ((flags & 2) == 2) {
// copy hi to lo spectra
memcpy(spectra_lo, spectra_hi, 0x400u);
}
else {
// read spectra_lo
pos = 0;
for (i = 0; i < 256; ++i) {
if (bit_offset >= frame_bits || bit_offset >= buf_bits)
break;
move = read_ubits(index_bits, bit_offset, buf);
bit_offset += index_bits;
if (i > 0 && move == 0)
break;
pos += move;
gain_bits = codes[pos];
quant = (double) read_sbits(gain_bits + 2, bit_offset, buf);
bit_offset += gain_bits + 2;
if (quant != 0.0 && pos < size_half && (signed int) codes[pos] < 6)
spectra_lo[pos] = quant * g_scales[gain_bits];
}
}
}
return FQ_OK;
}
static int unpack_frame0(FILE *file, float *spectra_hi, float *spectra_lo,
uint8_t *codes, int16_t size_half, int16_t frame_bits) {
uint8_t buf[FQ_LEN];
memset(buf, 0, FQ_LEN);
fread(buf, 1u, frame_bits >> 3, file);
if (file->_flag & 0x10) { // IOEOF
memset(spectra_hi, 0, 0x400u);
memset(spectra_lo, 0, 0x400u);
return -1;
} else {
unpack_frame1(buf, spectra_hi, spectra_lo, codes, FQ_LEN, frame_bits,
size_half);
return 0;
}
}
//-----------------------------------------------------------------------------
// MAIN.C (assumed)
//-----------------------------------------------------------------------------
static int16_t write_16le(int16_t val, FILE *file) {
fputc((uint8_t) val, file);
fputc(val >> 8, file);
return val;
}
static int write_32le(int val, FILE *file) {
fputc((uint8_t) val, file);
fputc((val >> 8) & 0xFF, file);
fputc((val >> 16) & 0xFF, file);
fputc(val >> 24, file);
return val;
}
static int16_t read_16le(FILE *file) {
int16_t val; // si
val = (int16_t) fgetc(file) << 8;
return fgetc(file) | val;
}
static int16_t read_16le2(FILE *a1) {
int16_t v1; // ST50_2
v1 = fgetc(a1);
return ((int16_t) fgetc(a1) << 8) | v1;
}
static int read_32le2(FILE *infile) {
int v1; // ST50_4
int v2; // ST50_4
int v3; // ST50_4
v1 = fgetc(infile);
v2 = (fgetc(infile) << 8) | v1;
v3 = (fgetc(infile) << 16) | v2;
return (fgetc(infile) << 24) | v3;
}
static int read_32le(FILE *infile) {
int v1; // esi
int v2; // esi
int v3; // ST50_4
v1 = fgetc(infile) << 8;
v2 = (fgetc(infile) | v1) << 8;
v3 = fgetc(infile) | v2;
return fgetc(infile) | (v3 << 8);
}
//this uses vgmstream's code, didn't get what the original was going for
static uint32_t read_80le(FILE *file) {
uint8_t buf[10];
int32_t exponent;
int32_t mantissa;
int i;
fread(buf, 1u, 10u, file);
exponent = ((buf[0] << 8) | (buf[1])) & 0x7fff;
exponent -= 16383;
mantissa = 0;
for (i = 0; i < 8; i++) {
int32_t shift = exponent - 7 - i * 8;
if (shift >= 0)
mantissa |= buf[i + 2] << shift;
else if (shift > -8)
mantissa |= buf[i + 2] >> -shift;
}
return mantissa * ((buf[0] & 0x80) ? -1 : 1);
}
static int parse_riff(FILE *file, int16_t *codec, int16_t *channels,
int *num_samples, int16_t *bps, int *sample_rate) {
int offset; // eax
int offset2; // eax
char chunk_id[4];
int16_t data_found; // [esp+50h] [ebp-14h]
int16_t fact_found; // [esp+54h] [ebp-10h]
int16_t fmt_found; // [esp+58h] [ebp-Ch]
int offset3; // [esp+5Ch] [ebp-8h]
int chunk_size; // [esp+60h] [ebp-4h]
fmt_found = 0;
fact_found = 0;
data_found = 0;
*codec = 0;
*channels = 0;
*num_samples = 0;
*bps = 0;
*sample_rate = 0;
offset3 = 0;
rewind(file);
if (fread(chunk_id, 4u, 1u, file) != 1 || memcmp(chunk_id, "RIFF", 4u))
return -2;
read_32le2(file);
if (fread(chunk_id, 4u, 1u, file) != 1 || memcmp(chunk_id, "WAVE", 4u))
return -2;
while (!fmt_found || !fact_found || !data_found) {
if (fread(chunk_id, 4u, 1u, file) != 1) {
if (!fmt_found)
return -4;
if (!fact_found)
return -5;
if (!data_found)
return -6;
}
chunk_size = read_32le2(file);
if (chunk_size % 2 > 0)
++chunk_size;
offset = ftell(file);
chunk_size += offset;
if (!fmt_found && !memcmp(chunk_id, "fmt ", 4u)) {
*codec = read_16le2(file) != 1;
*channels = read_16le2(file);
if (*channels < 1)
return -7;
*sample_rate = read_32le2(file);
read_32le2(file);
read_16le2(file);
if (*codec) {
*bps = 0;
} else {
*bps = read_16le2(file);
if (*bps < 1 || *bps > 32)
return -8;
}
fmt_found = 1;
}
if (!fact_found && !memcmp(chunk_id, "fact", 4u)) {
*num_samples = read_32le2(file);
fact_found = 1;
}
if (!data_found && !memcmp(chunk_id, "data", 4u)) {
offset3 = ftell(file);
if (!fact_found && !*codec) {
fseek(file, offset3 - 4, 0);
*num_samples = read_32le2(file)
/ (((*bps - 1) / 8 + 1) * *channels);
fact_found = 1;
}
data_found = 1;
}
if (file->_flag & 0x10)
return -3;
offset2 = ftell(file);
fseek(file, chunk_size - offset2, 1);
}
fseek(file, offset3, 0);
if (!*bps)
return -9;
if (*num_samples)
return offset3;
return -10;
}
static int write_riff(FILE *file, int16_t codec, int16_t channels,
int num_samples, int16_t bps, int sample_rate) {
int riff_size; // [esp+4Ch] [ebp-4h] MAPDST
fwrite("RIFF", 4u, 1u, file);
riff_size = write_32le(4, file);
fwrite("WAVE", 4u, 1u, file);
fwrite("fmt ", 4u, 1u, file);
if (codec) // pcm8 flag?
{
riff_size += write_32le(0xE, file) + 8;
write_16le(0, file);
} else {
riff_size += write_32le(0x10, file) + 8;
write_16le(1, file);
}
write_16le(channels, file);
write_32le(sample_rate, file);
write_32le(((bps - 1) / 8 + 1) * sample_rate * channels, file);
write_16le(((bps - 1) / 8 + 1) * channels, file);
if (!codec)
write_16le(bps, file);
fwrite("fact", 4u, 1u, file);
riff_size += write_32le(4, file) + 8;
write_32le(num_samples, file);
fwrite("data", 4u, 1u, file);
riff_size += write_32le(0, file) + 8;
fseek(file, 4, 0);
write_32le(riff_size, file);
fseek(file, 0, 2);
return 0;
}
static int update_riff(FILE *file) {
int file_size; // eax
int riff8_size; // eax
int sample_rate; // [esp+4Ch] [ebp-1Ch]
int data_size; // [esp+50h] [ebp-18h]
int data_offset; // [esp+54h] [ebp-14h]
int16_t bps; // [esp+58h] [ebp-10h]
int16_t channels; // [esp+5Ch] [ebp-Ch]
int16_t codec; // [esp+60h] [ebp-8h]
int num_samples; // [esp+64h] [ebp-4h]
data_offset = parse_riff(file, &codec, &channels, &num_samples, &bps,
&sample_rate);
if (data_offset < 0)
return data_offset;
fseek(file, 0, 2);
file_size = ftell(file);
data_size = file_size - data_offset;
if ((file_size - data_offset) % 2 > 0)
fputc(0, file);
if (num_samples
> (uint32_t) (data_size / (((bps - 1) / 8 + 1) * channels))) {
num_samples = data_size / (((bps - 1) / 8 + 1) * channels);
rewind(file);
write_riff(file, codec, channels, num_samples, bps, sample_rate);
}
fseek(file, data_offset - 4, 0);
write_32le(data_size, file);
fseek(file, 4, 0);
riff8_size = read_32le2(file);
data_size += riff8_size;
fseek(file, 4, 0);
write_32le(data_size, file);
fseek(file, 0, 2);
return 0;
}
static int parse_aifc(FILE *infile, int16_t *version, int16_t *channels,
int *blocks, int16_t *bps, int *sample_rate) {
int result; // eax
int pos; // eax
int pos_; // eax
char codec[256]; // [esp+4Ch] [ebp-11Ch]
char chunk_id[4]; // [esp+14Ch] [ebp-1Ch]
int16_t is_ssnd; // [esp+150h] [ebp-18h]
int16_t is_comm; // [esp+154h] [ebp-14h]
int16_t is_aiff; // [esp+158h] [ebp-10h]
int offset; // [esp+15Ch] [ebp-Ch]
int size; // [esp+160h] [ebp-8h] MAPDST
is_aiff = 0;
is_comm = 0;
is_ssnd = 0;
*version = 0;
*channels = 0;
*blocks = 0;
*bps = 0;
*sample_rate = 0;
offset = 0;
rewind(infile);
if (fread(chunk_id, 4u, 1u, infile) != 1 || memcmp(chunk_id, "FORM", 4u))
return -2;
read_32le(infile); // skip size
if (fread(chunk_id, 4u, 1u, infile) != 1)
return -2;
if (!memcmp(chunk_id, "AIFF", 4u)) {
is_aiff = 1;
*version = 0;
}
if (is_aiff) {
LABEL_12: while (!is_aiff || !is_comm || !is_ssnd) {
if (fread(chunk_id, 4u, 1u, infile) != 1) {
if (!is_aiff)
return -5;
if (!is_comm)
return -6;
if (!is_ssnd)
return -7;
}
size = read_32le(infile);
if (size % 2 > 0)
++size;
pos = ftell(infile);
size += pos;
if (!is_aiff && !memcmp(chunk_id, "FVER", 4u)) {
if (read_32le(infile) != 0xA2805140) // fver id
return -4;
is_aiff = 1;
}
if (!is_comm && !memcmp(chunk_id, "COMM", 4u)) {
*channels = read_16le(infile);
if (*channels < 1)
return -8;
*blocks = read_32le(infile);
if (!*blocks)
return -11;
*bps = read_16le(infile);
if (*bps < 1 || *bps > 32)
return -9;
*sample_rate = read_80le(infile);
if (*version == 4) {
fread(chunk_id, 4u, 1u, infile);
if (!memcmp(chunk_id, "NONE", 4u)) {
*version = 1;
} else if (!memcmp(chunk_id, "COMP", 4u)) {
*version = 3;
fread(codec, size, 1u, infile);
if (!memcmp(&codec[1], "Relic Codec v1.6", codec[0])) // size is in first char
*version = 2;
else
*bps = 0;
} else {
*bps = 0;
}
}
is_comm = 1;
}
if (!is_ssnd && !memcmp(chunk_id, "SSND", 4u)) {
read_32le(infile);
read_32le(infile);
offset = ftell(infile);
is_ssnd = 1;
}
if (infile->_flag & 0x10) // EOF
return -3;
pos_ = ftell(infile);
fseek(infile, size - pos_, 1);
}
fseek(infile, offset, 0);
if (*version == 4)
result = -10;
else
result = offset;
} else {
if (!memcmp(chunk_id, "AIFC", 4u)) {
*version = 4;
goto LABEL_12;
}
result = -2;
}
return result;
}
const char *get_riff_errstr(int error) {
const char *result;
switch (error + 10) // negative value
{
case 0:
result = "No sound data in WAV file";
break;
case 1:
result = "Invalid sound data in WAV file";
break;
case 2:
result = "Invalid # of bits/sample in WAV file";
break;
case 3:
result = "Invalid # of channels in WAV file";
break;
case 4:
result = "No data chunk in WAV file";
break;
case 5:
result = "No fact chunk in WAV file";
break;
case 6:
result = "No format chunk in WAV file";
break;
case 7:
result = "Corrupt WAV file";
break;
case 8:
result = "Invalid WAV file";
break;
case 10:
result = "No error";
break;
default:
result = "Undefined error";
break;
}
return result;
}
const char *get_aifc_errstr(int error) {
const char *result; // eax
switch (error + 14) // negative values
{
case 0:
result = "Unable to allocate memory for name";
break;
case 1:
result = "No mark chunk in AIFF/C file";
break;
case 2:
result = "No name chunk in AIFF/C file";
break;
case 3:
result = "No sound data in AIFF/C file";
break;
case 4:
result = "Invalid sound data in AIFC file";
break;
case 5:
result = "Invalid # of bits/sample in AIFF/C file";
break;
case 6:
result = "Invalid # of channels in AIFF/C file";
break;
case 7:
result = "No sound data chunk in AIFF/C file";
break;
case 8:
result = "No common chunk in AIFF/C file";
break;
case 9:
result = "No format version chunk in AIFC file";
break;
case 10:
result = "Invalid format version in AIFC file";
break;
case 11:
result = "Corrupt AIFF/C file";
break;
case 12:
result = "Invalid AIFF/C file";
break;
case 14:
result = "No error";
break;
default:
result = "Undefined error";
break;
}
return result;
}
#define LODWORD(x) (*((int*)&(x))) // low dword
int main(int argc, const char **argv) {
int result; // eax
FILE *file_out; // [esp+60h] [ebp-2AD4h]
FILE *file_in; // [esp+64h] [ebp-2AD0h]
float spectra_lo[256]; // [esp+68h] [ebp-2ACCh]
float spectra_hi[256]; // [esp+468h] [ebp-26CCh]
float samples_prv_r[512]; // [esp+868h] [ebp-22CCh]
float samples_cur_r[512]; // [esp+1068h] [ebp-1ACCh]
float samples_prv_l[512]; // [esp+1868h] [ebp-12CCh]
float samples_cur_l[512]; // [esp+2068h] [ebp-ACCh]
char filename_out[80]; // [esp+2868h] [ebp-2CCh]
char filename_in[80]; // [esp+28B8h] [ebp-27Ch]
int codec_rate;
int16_t frame_bits; // [esp+290Ch] [ebp-228h]
int16_t bps; // [esp+2910h] [ebp-224h]
int16_t channels; // [esp+2914h] [ebp-220h]
int16_t version; // [esp+2918h] [ebp-21Ch]
int pcm_sample; // [esp+291Ch] [ebp-218h]
int res; // [esp+2920h] [ebp-214h]
uint8_t codes_r[256]; // [esp+2924h] [ebp-210h]
uint8_t codes_l[256]; // [esp+2A24h] [ebp-110h]
int blocks; // [esp+2B24h] [ebp-10h]
uint32_t samples_done; // [esp+2B28h] [ebp-Ch]
int16_t frame_samples; // [esp+2B2Ch] [ebp-8h]
int16_t samples_block_done; // [esp+2B30h] [ebp-4h]
double d64_sample;
int err;
printf("AIFR decoder\n");
printf("%s\n", "Relic Codec v1.6");
printf("Copyright (c) 1997-99 Relic Entertainment Inc.\n");
if (argc < 3) {
printf("Usage: dec <aifr_file> <wav_file>\n");
return FQ_ERR;
}
strcpy(filename_in, argv[1]);
strcpy(filename_out, argv[2]);
file_in = fopen(filename_in, "rb");
if (!file_in) {
printf("Error: unable to open AIFR file %s!\n", filename_in);
return FQ_ERR;
}
file_out = fopen(filename_out, "w+b");
if (!file_out) {
fclose(file_in);
printf("Error: unable to open WAV file %s!\n", filename_out);
return FQ_ERR;
}
printf("Reading AIFR header...\n");
res = parse_aifc(file_in, &version, &channels, &blocks, &bps, &codec_rate);
if (res < 0) {
printf("Error: %s!\n", get_aifc_errstr(res));
fclose(file_in);
fclose(file_out);
return FQ_ERR;
}
frame_bits = read_16le(file_in); // always 0x800
printf("\nVersion: %d (%d for AIFR)\n", version, 2);
printf("Channels: %d\n", channels);
printf("Blocks: %ld\n", blocks);
printf("Bits: %d\n", frame_bits);
printf(" Was: %d\n", bps);
printf("Rate: %.3f (Kbps)\n", (double) (channels * 22050 * frame_bits) / 256000.0);
printf(" Was: %ld (Hz)\n", codec_rate);
printf("Time: %.3f (sec)\n\n", (double) (uint32_t) (blocks << 8) / 22050.0);
if (version != 2) {
printf("Error: Invalid AIFF/C version!\n", get_aifc_errstr(res));
fclose(file_in);
fclose(file_out);
return FQ_ERR;
}
if (codec_rate < 22050)
frame_samples = 128;
if (codec_rate == 22050)
frame_samples = 256;
if (codec_rate > 22050)
frame_samples = 512;
printf("Writing WAV header...\n");
res = write_riff(file_out, 0, channels, blocks << 9, bps, 44100);
if (res > 0) {
printf("Error: %s!\n", get_riff_errstr(res));
fclose(file_in);
fclose(file_out);
return FQ_ERR;
}
printf("Decoding file %s at %d Hz...\n", filename_in, 44100);
init_dequant();
if (decode_frame(spectra_hi, spectra_lo, samples_cur_l, samples_prv_l, FQ_MINIT, 0) == -1) {
printf("Error: fqDecLBlock failed!\n");
fclose(file_in);
fclose(file_out);
return FQ_ERR;
}
if (decode_frame(spectra_hi, spectra_lo, samples_cur_r, samples_prv_r, FQ_MINIT, 0) == -1) {
printf("Error: fqDecRBlock failed!\n");
fclose(file_in);
fclose(file_out);
return FQ_ERR;
}
samples_done = 0;
while (!(file_in->_flag & 0x10) && samples_done <= blocks << 9) {
{
err = unpack_frame0(file_in, spectra_hi, spectra_lo, codes_l, frame_samples >> 1, frame_bits);
if (err == -1)
break;
err = decode_frame(spectra_hi, spectra_lo, samples_cur_l, samples_prv_l, 1, 1);
if (err == -1) {
printf("Error: fqDecLBlock failed!\n");
fclose(file_in);
fclose(file_out);
return FQ_ERR;
}
}
if (channels > 1) {
err = unpack_frame0(file_in, spectra_hi, spectra_lo, codes_r, frame_samples >> 1, frame_bits);
if (err == -1)
break;
err = decode_frame(spectra_hi, spectra_lo, samples_cur_r, samples_prv_r, 1, 1);
if (err == -1) {
printf("Error: fqDecRBlock failed!\n");
fclose(file_in);
fclose(file_out);
return FQ_ERR;
}
}
//int fqWriteTBlock(float *aLBlock,float *aRBlock,short nChan, void *pBuf1,unsigned long nSize1,void *pBuf2,unsigned long nSize2);
for (samples_block_done = 0; samples_block_done < 512 && !(file_in->_flag & 0x10) && samples_done <= blocks << 9;
++samples_block_done) {
//d64_sample = samples_cur_l[samples_block_done];
//pcm_sample = d64_sample;
d64_sample = samples_cur_l[samples_block_done] + 6.755399441055744e15;
pcm_sample = LODWORD(d64_sample);
//d64_sample = samples_cur_l[samples_block_done];
//pcm_sample = rint(d64_sample);
if (pcm_sample > 32767)
pcm_sample = 32767;
if (pcm_sample < -32768)
pcm_sample = -32768;
if (bps <= 8)
fputc( (char) (pcm_sample / 256 + 128), file_out);
else
write_16le(pcm_sample, file_out);
if (channels > 1) {
//d64_sample = samples_cur_r[samples_block_done];
//pcm_sample = d64_sample;
d64_sample = samples_cur_r[samples_block_done] + 6.755399441055744e15; //krint
pcm_sample = LODWORD(d64_sample);
//d64_sample = samples_cur_r[samples_block_done];
//pcm_sample = rint(d64_sample);
if (pcm_sample > 32767)
pcm_sample = 32767;
if (pcm_sample < -32768)
pcm_sample = -32768;
if (bps <= 8)
fputc( (char) (pcm_sample / 256 + -128), file_out);
else
write_16le(pcm_sample, file_out);
}
++samples_done;
}
}
printf("Updating WAV header...\n");
res = update_riff(file_out);
if (res > 0) {
printf("Error: %s!\n", get_riff_errstr(res));
fclose(file_in);
fclose(file_out);
return FQ_ERR;
}
fclose(file_in);
fclose(file_out);
printf("\nDone.\n");
result = 0;
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment