/*
* Copyright (C) 2011 in-somnia
*
* This file is part of JAAD.
*
* JAAD is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* JAAD 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 Lesser General
* Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
* If not, see <http://www.gnu.org/licenses/>.
*/
package net.sourceforge.jaad.aac.filterbank;
import net.sourceforge.jaad.aac.AACException;
class MDCT implements MDCTTables {
private final int N, N2, N4, N8;
private final float[][] sincos;
private final FFT fft;
private final float[][] buf;
private final float[] tmp;
MDCT(int length) throws AACException {
N = length;
N2 = length>>1;
N4 = length>>2;
N8 = length>>3;
switch(length) {
case 2048:
sincos = MDCT_TABLE_2048;
break;
case 256:
sincos = MDCT_TABLE_128;
break;
case 1920:
sincos = MDCT_TABLE_1920;
break;
case 240:
sincos = MDCT_TABLE_240;
default:
throw new AACException("unsupported MDCT length: "+length);
}
fft = new FFT(N4);
buf = new float[N4][2];
tmp = new float[2];
}
void process(float[] in, int inOff, float[] out, int outOff) {
int k;
//pre-IFFT complex multiplication
for(k = 0; k<N4; k++) {
buf[k][1] = (in[inOff+2*k]*sincos[k][0])+(in[inOff+N2-1-2*k]*sincos[k][1]);
buf[k][0] = (in[inOff+N2-1-2*k]*sincos[k][0])-(in[inOff+2*k]*sincos[k][1]);
}
//complex IFFT, non-scaling
fft.process(buf, false);
//post-IFFT complex multiplication
for(k = 0; k<N4; k++) {
tmp[0] = buf[k][0];
tmp[1] = buf[k][1];
buf[k][1] = (tmp[1]*sincos[k][0])+(tmp[0]*sincos[k][1]);
buf[k][0] = (tmp[0]*sincos[k][0])-(tmp[1]*sincos[k][1]);
}
//reordering
for(k = 0; k<N8; k += 2) {
out[outOff+2*k] = buf[N8+k][1];
out[outOff+2+2*k] = buf[N8+1+k][1];
out[outOff+1+2*k] = -buf[N8-1-k][0];
out[outOff+3+2*k] = -buf[N8-2-k][0];
out[outOff+N4+2*k] = buf[k][0];
out[outOff+N4+2+2*k] = buf[1+k][0];
out[outOff+N4+1+2*k] = -buf[N4-1-k][1];
out[outOff+N4+3+2*k] = -buf[N4-2-k][1];
out[outOff+N2+2*k] = buf[N8+k][0];
out[outOff+N2+2+2*k] = buf[N8+1+k][0];
out[outOff+N2+1+2*k] = -buf[N8-1-k][1];
out[outOff+N2+3+2*k] = -buf[N8-2-k][1];
out[outOff+N2+N4+2*k] = -buf[k][1];
out[outOff+N2+N4+2+2*k] = -buf[1+k][1];
out[outOff+N2+N4+1+2*k] = buf[N4-1-k][0];
out[outOff+N2+N4+3+2*k] = buf[N4-2-k][0];
}
}
void processForward(float[] in, float[] out) {
int n, k;
//pre-FFT complex multiplication
for(k = 0; k<N8; k++) {
n = k<<1;
tmp[0] = in[N-N4-1-n]+in[N-N4+n];
tmp[1] = in[N4+n]-in[N4-1-n];
buf[k][0] = (tmp[0]*sincos[k][0])+(tmp[1]*sincos[k][1]);
buf[k][1] = (tmp[1]*sincos[k][0])-(tmp[0]*sincos[k][1]);
buf[k][0] *= N;
buf[k][1] *= N;
tmp[0] = in[N2-1-n]-in[n];
tmp[1] = in[N2+n]+in[N-1-n];
buf[k+N8][0] = (tmp[0]*sincos[k+N8][0])+(tmp[1]*sincos[k+N8][1]);
buf[k+N8][1] = (tmp[1]*sincos[k+N8][0])-(tmp[0]*sincos[k+N8][1]);
buf[k+N8][0] *= N;
buf[k+N8][1] *= N;
}
//complex FFT, non-scaling
fft.process(buf, true);
//post-FFT complex multiplication
for(k = 0; k<N4; k++) {
n = k<<1;
tmp[0] = (buf[k][0]*sincos[k][0])+(buf[k][1]*sincos[k][1]);
tmp[1] = (buf[k][1]*sincos[k][0])-(buf[k][0]*sincos[k][1]);
out[n] = -tmp[0];
out[N2-1-n] = tmp[1];
out[N2+n] = -tmp[1];
out[N-1-n] = tmp[0];
}
}
}