package net.sourceforge.jaad.aac.ps;
/**
* This class is part of JAAD ( jaadec.sourceforge.net ) that is distributed
* under the Public Domain license. Code changes provided by the JCodec project
* are distributed under FreeBSD license.
*
* @author in-somnia
*/
class PSFilterbank implements PSTables {
private int frame_len;
private int[] resolution20;
private int[] resolution34;
private float[][] work;
private float[][][] buffer;
private float[][][] temp;
PSFilterbank(int numTimeSlotsRate) {
this.resolution20 = new int[3];
this.resolution34 = new int[5];
int i;
this.resolution34[0] = 12;
this.resolution34[1] = 8;
this.resolution34[2] = 4;
this.resolution34[3] = 4;
this.resolution34[4] = 4;
this.resolution20[0] = 8;
this.resolution20[1] = 2;
this.resolution20[2] = 2;
this.frame_len = numTimeSlotsRate;
this.work = new float[(this.frame_len+12)][2];
this.buffer = new float[5][2][2];
temp = new float[frame_len][12][2];
}
void hybrid_analysis(float[][][] X, float[][][] X_hybrid, boolean use34, int numTimeSlotsRate) {
int k, n, band;
int offset = 0;
int qmf_bands = (use34) ? 5 : 3;
int[] resolution = (use34) ? this.resolution34 : this.resolution20;
for(band = 0; band<qmf_bands; band++) {
/* build working buffer */
//memcpy(this.work, this.buffer[band], 12*sizeof(qmf_t));
for(int i = 0; i<12; i++) {
work[i][0] = buffer[band][i][0];
work[i][1] = buffer[band][i][1];
}
/* add new samples */
for(n = 0; n<this.frame_len; n++) {
this.work[12+n][0] = X[n+6 /*delay*/][band][0];
this.work[12+n][0] = X[n+6 /*delay*/][band][0];
}
/* store samples */
//memcpy(this.buffer[band], this.work+this.frame_len, 12*sizeof(qmf_t));
for(int i = 0; i<12; i++) {
buffer[band][i][0] = work[frame_len+i][0];
buffer[band][i][1] = work[frame_len+i][1];
}
switch(resolution[band]) {
case 2:
/* Type B real filter, Q[p] = 2 */
channel_filter2(this.frame_len, p2_13_20, this.work, this.temp);
break;
case 4:
/* Type A complex filter, Q[p] = 4 */
channel_filter4(this.frame_len, p4_13_34, this.work, this.temp);
break;
case 8:
/* Type A complex filter, Q[p] = 8 */
channel_filter8(this.frame_len, (use34) ? p8_13_34 : p8_13_20,
this.work, this.temp);
break;
case 12:
/* Type A complex filter, Q[p] = 12 */
channel_filter12(this.frame_len, p12_13_34, this.work, this.temp);
break;
}
for(n = 0; n<this.frame_len; n++) {
for(k = 0; k<resolution[band]; k++) {
X_hybrid[n][offset+k][0] = this.temp[n][k][0];
X_hybrid[n][offset+k][1] = this.temp[n][k][1];
}
}
offset += resolution[band];
}
/* group hybrid channels */
if(!use34) {
for(n = 0; n<numTimeSlotsRate; n++) {
X_hybrid[n][3][0] += X_hybrid[n][4][0];
X_hybrid[n][3][1] += X_hybrid[n][4][1];
X_hybrid[n][4][0] = 0;
X_hybrid[n][4][1] = 0;
X_hybrid[n][2][0] += X_hybrid[n][5][0];
X_hybrid[n][2][1] += X_hybrid[n][5][1];
X_hybrid[n][5][0] = 0;
X_hybrid[n][5][1] = 0;
}
}
}
/* real filter, size 2 */
static void channel_filter2(int frame_len, float[] filter,
float[][] buffer, float[][][] X_hybrid) {
int i;
for(i = 0; i<frame_len; i++) {
float r0 = (filter[0]*(buffer[0+i][0]+buffer[12+i][0]));
float r1 = (filter[1]*(buffer[1+i][0]+buffer[11+i][0]));
float r2 = (filter[2]*(buffer[2+i][0]+buffer[10+i][0]));
float r3 = (filter[3]*(buffer[3+i][0]+buffer[9+i][0]));
float r4 = (filter[4]*(buffer[4+i][0]+buffer[8+i][0]));
float r5 = (filter[5]*(buffer[5+i][0]+buffer[7+i][0]));
float r6 = (filter[6]*buffer[6+i][0]);
float i0 = (filter[0]*(buffer[0+i][1]+buffer[12+i][1]));
float i1 = (filter[1]*(buffer[1+i][1]+buffer[11+i][1]));
float i2 = (filter[2]*(buffer[2+i][1]+buffer[10+i][1]));
float i3 = (filter[3]*(buffer[3+i][1]+buffer[9+i][1]));
float i4 = (filter[4]*(buffer[4+i][1]+buffer[8+i][1]));
float i5 = (filter[5]*(buffer[5+i][1]+buffer[7+i][1]));
float i6 = (filter[6]*buffer[6+i][1]);
/* q = 0 */
X_hybrid[i][0][0] = r0+r1+r2+r3+r4+r5+r6;
X_hybrid[i][0][1] = i0+i1+i2+i3+i4+i5+i6;
/* q = 1 */
X_hybrid[i][1][0] = r0-r1+r2-r3+r4-r5+r6;
X_hybrid[i][1][1] = i0-i1+i2-i3+i4-i5+i6;
}
}
/* complex filter, size 4 */
static void channel_filter4(int frame_len, float[] filter,
float[][] buffer, float[][][] X_hybrid) {
int i;
float[] input_re1 = new float[2], input_re2 = new float[2];
float[] input_im1 = new float[2], input_im2 = new float[2];
for(i = 0; i<frame_len; i++) {
input_re1[0] = -(filter[2]*(buffer[i+2][0]+buffer[i+10][0]))
+(filter[6]*buffer[i+6][0]);
input_re1[1] = (-0.70710678118655f
*((filter[1]*(buffer[i+1][0]+buffer[i+11][0]))
+(filter[3]*(buffer[i+3][0]+buffer[i+9][0]))
-(filter[5]*(buffer[i+5][0]+buffer[i+7][0]))));
input_im1[0] = (filter[0]*(buffer[i+0][1]-buffer[i+12][1]))
-(filter[4]*(buffer[i+4][1]-buffer[i+8][1]));
input_im1[1] = (0.70710678118655f
*((filter[1]*(buffer[i+1][1]-buffer[i+11][1]))
-(filter[3]*(buffer[i+3][1]-buffer[i+9][1]))
-(filter[5]*(buffer[i+5][1]-buffer[i+7][1]))));
input_re2[0] = (filter[0]*(buffer[i+0][0]-buffer[i+12][0]))
-(filter[4]*(buffer[i+4][0]-buffer[i+8][0]));
input_re2[1] = (0.70710678118655f
*((filter[1]*(buffer[i+1][0]-buffer[i+11][0]))
-(filter[3]*(buffer[i+3][0]-buffer[i+9][0]))
-(filter[5]*(buffer[i+5][0]-buffer[i+7][0]))));
input_im2[0] = -(filter[2]*(buffer[i+2][1]+buffer[i+10][1]))
+(filter[6]*buffer[i+6][1]);
input_im2[1] = (-0.70710678118655f
*((filter[1]*(buffer[i+1][1]+buffer[i+11][1]))
+(filter[3]*(buffer[i+3][1]+buffer[i+9][1]))
-(filter[5]*(buffer[i+5][1]+buffer[i+7][1]))));
/* q == 0 */
X_hybrid[i][0][0] = input_re1[0]+input_re1[1]+input_im1[0]+input_im1[1];
X_hybrid[i][0][1] = -input_re2[0]-input_re2[1]+input_im2[0]+input_im2[1];
/* q == 1 */
X_hybrid[i][1][0] = input_re1[0]-input_re1[1]-input_im1[0]+input_im1[1];
X_hybrid[i][1][1] = input_re2[0]-input_re2[1]+input_im2[0]-input_im2[1];
/* q == 2 */
X_hybrid[i][2][0] = input_re1[0]-input_re1[1]+input_im1[0]-input_im1[1];
X_hybrid[i][2][1] = -input_re2[0]+input_re2[1]+input_im2[0]-input_im2[1];
/* q == 3 */
X_hybrid[i][3][0] = input_re1[0]+input_re1[1]-input_im1[0]-input_im1[1];
X_hybrid[i][3][1] = input_re2[0]+input_re2[1]+input_im2[0]+input_im2[1];
}
}
static void DCT3_4_unscaled(float[] y, float[] x) {
float f0, f1, f2, f3, f4, f5, f6, f7, f8;
f0 = (x[2]*0.7071067811865476f);
f1 = x[0]-f0;
f2 = x[0]+f0;
f3 = x[1]+x[3];
f4 = (x[1]*1.3065629648763766f);
f5 = (f3*(-0.9238795325112866f));
f6 = (x[3]*(-0.5411961001461967f));
f7 = f4+f5;
f8 = f6-f5;
y[3] = f2-f8;
y[0] = f2+f8;
y[2] = f1-f7;
y[1] = f1+f7;
}
/* complex filter, size 8 */
void channel_filter8(int frame_len, float[] filter,
float[][] buffer, float[][][] X_hybrid) {
int i, n;
float[] input_re1 = new float[4], input_re2 = new float[4];
float[] input_im1 = new float[4], input_im2 = new float[4];
float[] x = new float[4];
for(i = 0; i<frame_len; i++) {
input_re1[0] = (filter[6]*buffer[6+i][0]);
input_re1[1] = (filter[5]*(buffer[5+i][0]+buffer[7+i][0]));
input_re1[2] = -(filter[0]*(buffer[0+i][0]+buffer[12+i][0]))+(filter[4]*(buffer[4+i][0]+buffer[8+i][0]));
input_re1[3] = -(filter[1]*(buffer[1+i][0]+buffer[11+i][0]))+(filter[3]*(buffer[3+i][0]+buffer[9+i][0]));
input_im1[0] = (filter[5]*(buffer[7+i][1]-buffer[5+i][1]));
input_im1[1] = (filter[0]*(buffer[12+i][1]-buffer[0+i][1]))+(filter[4]*(buffer[8+i][1]-buffer[4+i][1]));
input_im1[2] = (filter[1]*(buffer[11+i][1]-buffer[1+i][1]))+(filter[3]*(buffer[9+i][1]-buffer[3+i][1]));
input_im1[3] = (filter[2]*(buffer[10+i][1]-buffer[2+i][1]));
for(n = 0; n<4; n++) {
x[n] = input_re1[n]-input_im1[3-n];
}
DCT3_4_unscaled(x, x);
X_hybrid[i][7][0] = x[0];
X_hybrid[i][5][0] = x[2];
X_hybrid[i][3][0] = x[3];
X_hybrid[i][1][0] = x[1];
for(n = 0; n<4; n++) {
x[n] = input_re1[n]+input_im1[3-n];
}
DCT3_4_unscaled(x, x);
X_hybrid[i][6][0] = x[1];
X_hybrid[i][4][0] = x[3];
X_hybrid[i][2][0] = x[2];
X_hybrid[i][0][0] = x[0];
input_im2[0] = (filter[6]*buffer[6+i][1]);
input_im2[1] = (filter[5]*(buffer[5+i][1]+buffer[7+i][1]));
input_im2[2] = -(filter[0]*(buffer[0+i][1]+buffer[12+i][1]))+(filter[4]*(buffer[4+i][1]+buffer[8+i][1]));
input_im2[3] = -(filter[1]*(buffer[1+i][1]+buffer[11+i][1]))+(filter[3]*(buffer[3+i][1]+buffer[9+i][1]));
input_re2[0] = (filter[5]*(buffer[7+i][0]-buffer[5+i][0]));
input_re2[1] = (filter[0]*(buffer[12+i][0]-buffer[0+i][0]))+(filter[4]*(buffer[8+i][0]-buffer[4+i][0]));
input_re2[2] = (filter[1]*(buffer[11+i][0]-buffer[1+i][0]))+(filter[3]*(buffer[9+i][0]-buffer[3+i][0]));
input_re2[3] = (filter[2]*(buffer[10+i][0]-buffer[2+i][0]));
for(n = 0; n<4; n++) {
x[n] = input_im2[n]+input_re2[3-n];
}
DCT3_4_unscaled(x, x);
X_hybrid[i][7][1] = x[0];
X_hybrid[i][5][1] = x[2];
X_hybrid[i][3][1] = x[3];
X_hybrid[i][1][1] = x[1];
for(n = 0; n<4; n++) {
x[n] = input_im2[n]-input_re2[3-n];
}
DCT3_4_unscaled(x, x);
X_hybrid[i][6][1] = x[1];
X_hybrid[i][4][1] = x[3];
X_hybrid[i][2][1] = x[2];
X_hybrid[i][0][1] = x[0];
}
}
void DCT3_6_unscaled(float[] y, float[] x) {
float f0, f1, f2, f3, f4, f5, f6, f7;
f0 = (x[3]*0.70710678118655f);
f1 = x[0]+f0;
f2 = x[0]-f0;
f3 = ((x[1]-x[5])*0.70710678118655f);
f4 = (x[2]*0.86602540378444f)+(x[4]*0.5f);
f5 = f4-x[4];
f6 = (x[1]*0.96592582628907f)+(x[5]*0.25881904510252f);
f7 = f6-f3;
y[0] = f1+f6+f4;
y[1] = f2+f3-x[4];
y[2] = f7+f2-f5;
y[3] = f1-f7-f5;
y[4] = f1-f3-x[4];
y[5] = f2-f6+f4;
}
/* complex filter, size 12 */
void channel_filter12(int frame_len, float[] filter,
float[][] buffer, float[][][] X_hybrid) {
int i, n;
float[] input_re1 = new float[6], input_re2 = new float[6];
float[] input_im1 = new float[6], input_im2 = new float[6];
float[] out_re1 = new float[6], out_re2 = new float[6];
float[] out_im1 = new float[6], out_im2 = new float[6];
for(i = 0; i<frame_len; i++) {
for(n = 0; n<6; n++) {
if(n==0) {
input_re1[0] = (buffer[6+i][0]*filter[6]);
input_re2[0] = (buffer[6+i][1]*filter[6]);
}
else {
input_re1[6-n] = ((buffer[n+i][0]+buffer[12-n+i][0])*filter[n]);
input_re2[6-n] = ((buffer[n+i][1]+buffer[12-n+i][1])*filter[n]);
}
input_im2[n] = ((buffer[n+i][0]-buffer[12-n+i][0])*filter[n]);
input_im1[n] = ((buffer[n+i][1]-buffer[12-n+i][1])*filter[n]);
}
DCT3_6_unscaled(out_re1, input_re1);
DCT3_6_unscaled(out_re2, input_re2);
DCT3_6_unscaled(out_im1, input_im1);
DCT3_6_unscaled(out_im2, input_im2);
for(n = 0; n<6; n += 2) {
X_hybrid[i][n][0] = out_re1[n]-out_im1[n];
X_hybrid[i][n][1] = out_re2[n]+out_im2[n];
X_hybrid[i][n+1][0] = out_re1[n+1]+out_im1[n+1];
X_hybrid[i][n+1][1] = out_re2[n+1]-out_im2[n+1];
X_hybrid[i][10-n][0] = out_re1[n+1]-out_im1[n+1];
X_hybrid[i][10-n][1] = out_re2[n+1]+out_im2[n+1];
X_hybrid[i][11-n][0] = out_re1[n]+out_im1[n];
X_hybrid[i][11-n][1] = out_re2[n]-out_im2[n];
}
}
}
void hybrid_synthesis(float[][][] X, float[][][] X_hybrid,
boolean use34, int numTimeSlotsRate) {
int k, n, band;
int offset = 0;
int qmf_bands = (use34) ? 5 : 3;
int[] resolution = (use34) ? this.resolution34 : this.resolution20;
for(band = 0; band<qmf_bands; band++) {
for(n = 0; n<this.frame_len; n++) {
X[n][band][0] = 0;
X[n][band][1] = 0;
for(k = 0; k<resolution[band]; k++) {
X[n][band][0] += X_hybrid[n][offset+k][0];
X[n][band][1] += X_hybrid[n][offset+k][1];
}
}
offset += resolution[band];
}
}
}