Voxifera/src/fdct.c

182 lines
5.0 KiB
C

/***************************************************************************
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "fdct.h"
void fdct_init( fdct_t *dct, unsigned char *data ){
int i, group, base, item, nitems;
double factor;
/* alloc transform vector and fill with data */
dct->transform = (double *)calloc( FDCT_TOTSIZE, sizeof(double) );
for( i = 0; i < FDCT_TOTSIZE; i++ ){
dct->transform[i] = (double)data[i];
}
/* alloc and fill cosines table */
dct->ctable = (double *)calloc( FDCT_TOTSIZE, sizeof(double) );
for( i = 0; i <= FDCT_TSO2 - 1; i++ ){
dct->ctable[FDCT_TSO2 + i] = 4 * i + 1;
}
for( group = 1; group <= FDCT_POW - 1; group++ ){
nitems = base = 1 << (group - 1);
factor = 1.0 * (1 << (FDCT_POW - group));
for( item = 1; item <= nitems; item++ ){
dct->ctable[base + item - 1] = factor * dct->ctable[FDCT_TSO2 + item - 1];
}
}
for( i = 1; i <= FDCT_TOTSIZE - 1; i++ ){
dct->ctable[i] = 1.0 / (2.0 * cos( dct->ctable[i] * M_PI / (2.0 * FDCT_TOTSIZE) ));
}
return dct;
}
inline void fdct_bitrev( double *data, unsigned int size ){
int i, m,
j = 1,
hsize = size >> 1;
double tmp;
if( size <= 2 ){ return; }
for( i = 1; i <= size; i++ ){
if(i < j){
tmp = data[j - 1];
data[j - 1] = data[i - 1];
data[i - 1] = tmp;
}
m = hsize;
while(j > m){
j = j - m;
m = (m + 1) >> 1;
}
j = j + m;
}
}
inline void fdct_scramble( double *data ){
double tmp;
int i, ii1, ii2;
fdct_bitrev( data, FDCT_TOTSIZE );
fdct_bitrev( &data[0], FDCT_TSO2 );
fdct_bitrev( &data[FDCT_TSO2], FDCT_TSO2);
ii1 = FDCT_TOTSIZE - 1;
ii2 = FDCT_TSO2;
for( i = 0; i <= FDCT_TSO4 - 1; i++, ii1--, ii2++ ){
tmp = data[ii1];
data[ii1] = data[ii2];
data[ii2] = tmp;
}
}
inline void fdct_butterflies( fdct_t *dct ){
int stage, ii1, ii2,
butterfly,
ngroups,
group,
wingspan,
inc,
ptr;
double cosine, value;
for( stage = FDCT_POW; stage >= 1; stage-- ){
ngroups = 1 << (FDCT_POW - stage);
wingspan = 1 << (stage - 1);
inc = wingspan << 1;
for( butterfly = 1; butterfly <= wingspan; butterfly++ ){
cosine = dct->ctable[ wingspan + butterfly - 1 ];
ptr = 0;
for( group = 1; group <= ngroups; group++ ){
ii1 = ptr + butterfly - 1;
ii2 = ii1 + wingspan;
value = dct->transform[ii2];
dct->transform[ii2] = cosine *(dct->transform[ii1] - value);
dct->transform[ii1] = dct->transform[ii1] + value;
ptr += inc;
}
}
}
}
inline void fdct_sums(double *data){
int stepsize,
stage, i,
nthreads,
thread,
step,
nsteps;
for( stage = FDCT_POW - 1; stage >= 1; stage-- ){
nthreads = 1 << (stage - 1);
stepsize = nthreads << 1;
nsteps = (1 << (FDCT_POW - stage)) - 1;
for( thread = 1; thread <= nthreads; thread++ ){
i = nthreads + thread - 1;
for( step = 1; step <= nsteps; step++ ){
data[i] += data[i + stepsize];
i += stepsize;
}
}
}
}
inline void fdct_compute( fdct_t *dct ){
int i;
fdct_scramble( dct->transform );
fdct_butterflies( dct );
fdct_bitrev( dct->transform, FDCT_TOTSIZE );
fdct_sums(dct->transform);
dct->transform[0] *= FDCT_FACTOR;
for( i = 0; i <= FDCT_TOTSIZE - 1; i++ ){
dct->transform[i] *= FDCT_2OTS_SQ;
}
}
inline double fdct_sum( fdct_t *dct, double div, unsigned char *neutral, unsigned int neutral_size ){
int i;
double sum = 0.0;
fdct_compute( dct );
if( neutral ){
for( i = 0; i < FDCT_TOTSIZE; i++ ){
sum += dct->transform[i] - neutral[i % neutral_size];
}
}
else{
for( i = 0; i < FDCT_TOTSIZE; i++ ){
sum += dct->transform[i];
}
}
return fabs(sum / div);
}
void fdct_release( fdct_t *dct ){
free(dct->ctable);
free(dct->transform);
}