Created
December 27, 2019 01:24
-
-
Save bnnm/bf6d4d3cb4335ff1d09ff46481eea2f4 to your computer and use it in GitHub Desktop.
Relic Codec dec.exe decompilation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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