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]; } } }