/*
* 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.ps;
class Filterbank implements FilterbankTables {
private static final int FB_LEN = 32;
//=============================== analysis =============================
//out: [91][32][2], buf: [5][44][2], in:[38][64][2]
static void performAnalysis(float[][][] in, float[][][] out, float[][][] buf, boolean use34) {
int i, j;
for(i = 0; i<5; i++) {
for(j = 0; j<38; j++) {
buf[i][j+6][0] = in[j][i][0];
buf[i][j+6][1] = in[j][i][1];
}
}
if(use34) {
perfomFilter4C(buf[0], out, 0, F34_0_12, 12);
perfomFilter4C(buf[1], out, 12, F34_1_8, 8);
perfomFilter4C(buf[2], out, 20, F34_2_4, 4);
perfomFilter4C(buf[3], out, 24, F34_2_4, 4);
perfomFilter4C(buf[4], out, 28, F34_2_4, 4);
for(i = 0; i<59; i++) {
for(j = 0; j<FB_LEN; j++) {
out[i+32][j][0] = in[j][i+5][0];
out[i+32][j][1] = in[j][i+5][1];
}
}
}
else {
performFilter6C(buf[0], out, 0, F20_0_8);
performFilter2R(buf[1], out, 6, G1_Q2, true);
performFilter2R(buf[2], out, 8, G1_Q2, false);
for(i = 0; i<61; i++) {
for(j = 0; j<FB_LEN; j++) {
out[i+10][j][0] = in[j][i+3][0];
out[i+10][j][1] = in[j][i+3][1];
}
}
}
//update in_buf
for(i = 0; i<5; i++) {
System.arraycopy(buf[i], 32, buf[i], 0, 6);
//memcpy(in[i], in[i]+32, 6*sizeof(in[i][0]));
}
}
//splits one subband into 2 sub-subbands with a symmetric real filter
//the filter must have its non-center even coefficients equal to zero
private static void performFilter2R(float[][] in, float[][][] out, int outOff, float[] filter, boolean reverse) {
int i, j;
int inOff = 0;
for(i = 0; i<FB_LEN; i++, inOff++) {
float re_in = filter[6]*in[inOff+6][0]; //real inphase
float re_op = 0.0f; //real out of phase
float im_in = filter[6]*in[inOff+6][1]; //imag inphase
float im_op = 0.0f; //imag out of phase
for(j = 0; j<6; j += 2) {
re_op += filter[j+1]*(in[inOff+j+1][0]+in[inOff+12-j-1][0]);
im_op += filter[j+1]*(in[inOff+j+1][1]+in[inOff+12-j-1][1]);
}
out[outOff+(reverse ? 1 : 0)][i][0] = re_in+re_op;
out[outOff+(reverse ? 1 : 0)][i][1] = im_in+im_op;
out[outOff+(reverse ? 0 : 1)][i][0] = re_in-re_op;
out[outOff+(reverse ? 0 : 1)][i][1] = im_in-im_op;
}
}
//splits one subband into 6 sub-subbands with a complex filter
private static void performFilter6C(float[][] in, float[][][] out, int outOff, float[][][] filter) {
final int N = 8;
final float[][] temp = new float[8][2];
int i, j, ssb;
int inOff = 0;
for(i = 0; i<FB_LEN; i++, inOff++) {
for(ssb = 0; ssb<N; ssb++) {
float sum_re = filter[ssb][6][0]*in[inOff+6][0], sum_im = filter[ssb][6][0]*in[inOff+6][1];
for(j = 0; j<6; j++) {
float in0_re = in[inOff+j][0];
float in0_im = in[inOff+j][1];
float in1_re = in[inOff+12-j][0];
float in1_im = in[inOff+12-j][1];
sum_re += filter[ssb][j][0]*(in0_re+in1_re)-filter[ssb][j][1]*(in0_im-in1_im);
sum_im += filter[ssb][j][0]*(in0_im+in1_im)+filter[ssb][j][1]*(in0_re-in1_re);
}
temp[ssb][0] = sum_re;
temp[ssb][1] = sum_im;
}
out[outOff+0][i][0] = temp[6][0];
out[outOff+0][i][1] = temp[6][1];
out[outOff+1][i][0] = temp[7][0];
out[outOff+1][i][1] = temp[7][1];
out[outOff+2][i][0] = temp[0][0];
out[outOff+2][i][1] = temp[0][1];
out[outOff+3][i][0] = temp[1][0];
out[outOff+3][i][1] = temp[1][1];
out[outOff+4][i][0] = temp[2][0]+temp[5][0];
out[outOff+4][i][1] = temp[2][1]+temp[5][1];
out[outOff+5][i][0] = temp[3][0]+temp[4][0];
out[outOff+5][i][1] = temp[3][1]+temp[4][1];
}
}
private static void perfomFilter4C(float[][] in, float[][][] out, int outOff, float[][][] filter, int len) {
int i, j, ssb;
int inOff = 0;
for(i = 0; i<FB_LEN; i++, inOff++) {
for(ssb = 0; ssb<len; ssb++) {
float sum_re = filter[ssb][6][0]*in[inOff+6][0], sum_im = filter[ssb][6][0]*in[inOff+6][1];
for(j = 0; j<6; j++) {
float in0_re = in[inOff+j][0];
float in0_im = in[inOff+j][1];
float in1_re = in[inOff+12-j][0];
float in1_im = in[inOff+12-j][1];
sum_re += filter[ssb][j][0]*(in0_re+in1_re)-filter[ssb][j][1]*(in0_im-in1_im);
sum_im += filter[ssb][j][0]*(in0_im+in1_im)+filter[ssb][j][1]*(in0_re-in1_re);
}
out[outOff+ssb][i][0] = sum_re;
out[outOff+ssb][i][1] = sum_im;
}
}
}
//=============================== synthesis =============================
//out: [38][64][2], in: [91][32][2]
static void performSynthesis(float[][][] in, float[][][] out, boolean use34) {
int i, n;
if(use34) {
for(n = 0; n<FB_LEN; n++) {
for(i = 0; i<5; i++) {
out[n][i][0] = 0;
out[n][i][1] = 0;
}
for(i = 0; i<12; i++) {
out[n][0][0] += in[i][n][0];
out[n][0][1] += in[i][n][1];
}
for(i = 0; i<8; i++) {
out[n][1][0] += in[12+i][n][0];
out[n][1][1] += in[12+i][n][1];
}
for(i = 0; i<4; i++) {
out[n][2][0] += in[20+i][n][0];
out[n][2][1] += in[20+i][n][1];
out[n][3][0] += in[24+i][n][0];
out[n][3][1] += in[24+i][n][1];
out[n][4][0] += in[28+i][n][0];
out[n][4][1] += in[28+i][n][1];
}
}
for(i = 0; i<59; i++) {
for(n = 0; n<FB_LEN; n++) {
out[n][i+5][0] = in[i+32][n][0];
out[n][i+5][1] = in[i+32][n][1];
}
}
}
else {
for(n = 0; n<FB_LEN; n++) {
out[n][0][0] = in[0][n][0]+in[1][n][0]+in[2][n][0]
+in[3][n][0]+in[4][n][0]+in[5][n][0];
out[n][0][1] = in[0][n][1]+in[1][n][1]+in[2][n][1]
+in[3][n][1]+in[4][n][1]+in[5][n][1];
out[n][1][0] = in[6][n][0]+in[7][n][0];
out[n][1][1] = in[6][n][1]+in[7][n][1];
out[n][2][0] = in[8][n][0]+in[9][n][0];
out[n][2][1] = in[8][n][1]+in[9][n][1];
}
for(i = 0; i<61; i++) {
for(n = 0; n<FB_LEN; n++) {
out[n][i+3][0] = in[i+10][n][0];
out[n][i+3][1] = in[i+10][n][1];
}
}
}
}
}