src/main/java/net/sourceforge/jaad/aac/ps/PS.java
private void ps_decorrelate(float[][][] X_left, float[][][] X_right,
		float[][][] X_hybrid_left, float[][][] X_hybrid_right) {
		int gr, n, m, bk;
		int temp_delay = 0;
		int sb, maxsb;
		int[] temp_delay_ser = new int[NO_ALLPASS_LINKS];
		float P_SmoothPeakDecayDiffNrg, nrg;
		float[][] P = new float[32][34];
		float[][] G_TransientRatio = new float[32][34];
		float[] inputLeft = new float[2];


		/* chose hybrid filterbank: 20 or 34 band case */
		float[][] Phi_Fract_SubQmf;
		if(this.use34hybrid_bands) {
			Phi_Fract_SubQmf = Phi_Fract_SubQmf34;
		}
		else {
			Phi_Fract_SubQmf = Phi_Fract_SubQmf20;
		}

		/* clear the energy values */
		for(n = 0; n<32; n++) {
			for(bk = 0; bk<34; bk++) {
				P[n][bk] = 0;
			}
		}

		/* calculate the energy in each parameter band b(k) */
		for(gr = 0; gr<this.num_groups; gr++) {
			/* select the parameter index b(k) to which this group belongs */
			bk = (~NEGATE_IPD_MASK)&this.map_group2bk[gr];

			/* select the upper subband border for this group */
			maxsb = (gr<this.num_hybrid_groups) ? this.group_border[gr]+1 : this.group_border[gr+1];

			for(sb = this.group_border[gr]; sb<maxsb; sb++) {
				for(n = this.border_position[0]; n<this.border_position[this.num_env]; n++) {

					/* input from hybrid subbands or QMF subbands */
					if(gr<this.num_hybrid_groups) {
						inputLeft[0] = X_hybrid_left[n][sb][0];
						inputLeft[1] = X_hybrid_left[n][sb][1];
					}
					else {
						inputLeft[0] = X_left[n][sb][0];
						inputLeft[1] = X_left[n][sb][1];
					}

					/* accumulate energy */
					P[n][bk] += (inputLeft[0]*inputLeft[0])+(inputLeft[1]*inputLeft[1]);
				}
			}
		}

		/* calculate transient reduction ratio for each parameter band b(k) */
		for(bk = 0; bk<this.nr_par_bands; bk++) {
			for(n = this.border_position[0]; n<this.border_position[this.num_env]; n++) {
				float gamma = 1.5f;

				this.P_PeakDecayNrg[bk] = (this.P_PeakDecayNrg[bk]*this.alpha_decay);
				if(this.P_PeakDecayNrg[bk]<P[n][bk])
					this.P_PeakDecayNrg[bk] = P[n][bk];

				/* apply smoothing filter to peak decay energy */
				P_SmoothPeakDecayDiffNrg = this.P_SmoothPeakDecayDiffNrg_prev[bk];
				P_SmoothPeakDecayDiffNrg += ((this.P_PeakDecayNrg[bk]-P[n][bk]-this.P_SmoothPeakDecayDiffNrg_prev[bk])*alpha_smooth);
				this.P_SmoothPeakDecayDiffNrg_prev[bk] = P_SmoothPeakDecayDiffNrg;

				/* apply smoothing filter to energy */
				nrg = this.P_prev[bk];
				nrg += ((P[n][bk]-this.P_prev[bk])*this.alpha_smooth);
				this.P_prev[bk] = nrg;

				/* calculate transient ratio */
				if((P_SmoothPeakDecayDiffNrg*gamma)<=nrg) {
					G_TransientRatio[n][bk] = 1.0f;
				}
				else {
					G_TransientRatio[n][bk] = (nrg/(P_SmoothPeakDecayDiffNrg*gamma));
				}
			}
		}

		/* apply stereo decorrelation filter to the signal */
		for(gr = 0; gr<this.num_groups; gr++) {
			if(gr<this.num_hybrid_groups)
				maxsb = this.group_border[gr]+1;
			else
				maxsb = this.group_border[gr+1];

			/* QMF channel */
			for(sb = this.group_border[gr]; sb<maxsb; sb++) {
				float g_DecaySlope;
				float[] g_DecaySlope_filt = new float[NO_ALLPASS_LINKS];

				/* g_DecaySlope: [0..1] */
				if(gr<this.num_hybrid_groups||sb<=this.decay_cutoff) {
					g_DecaySlope = 1.0f;
				}
				else {
					int decay = this.decay_cutoff-sb;
					if(decay<=-20 /* -1/DECAY_SLOPE */) {
						g_DecaySlope = 0;
					}
					else {
						/* decay(int)*decay_slope(frac) = g_DecaySlope(frac) */
						g_DecaySlope = 1.0f+DECAY_SLOPE*decay;
					}
				}

				/* calculate g_DecaySlope_filt for every m multiplied by filter_a[m] */
				for(m = 0; m<NO_ALLPASS_LINKS; m++) {
					g_DecaySlope_filt[m] = g_DecaySlope*filter_a[m];
				}


				/* set delay indices */
				temp_delay = this.saved_delay;
				for(n = 0; n<NO_ALLPASS_LINKS; n++) {
					temp_delay_ser[n] = this.delay_buf_index_ser[n];
				}

				for(n = this.border_position[0]; n<this.border_position[this.num_env]; n++) {
					float[] tmp = new float[2], tmp0 = new float[2], R0 = new float[2];

					if(gr<this.num_hybrid_groups) {
						/* hybrid filterbank input */
						inputLeft[0] = X_hybrid_left[n][sb][0];
						inputLeft[1] = X_hybrid_left[n][sb][1];
					}
					else {
						/* QMF filterbank input */
						inputLeft[0] = X_left[n][sb][0];
						inputLeft[1] = X_left[n][sb][1];
					}

					if(sb>this.nr_allpass_bands&&gr>=this.num_hybrid_groups) {
						/* delay */

						/* never hybrid subbands here, always QMF subbands */
						tmp[0] = this.delay_Qmf[this.delay_buf_index_delay[sb]][sb][0];
						tmp[1] = this.delay_Qmf[this.delay_buf_index_delay[sb]][sb][1];
						R0[0] = tmp[0];
						R0[1] = tmp[1];
						this.delay_Qmf[this.delay_buf_index_delay[sb]][sb][0] = inputLeft[0];
						this.delay_Qmf[this.delay_buf_index_delay[sb]][sb][1] = inputLeft[1];
					}
					else {
						/* allpass filter */
						//int m;
						float[] Phi_Fract = new float[2];

						/* fetch parameters */
						if(gr<this.num_hybrid_groups) {
							/* select data from the hybrid subbands */
							tmp0[0] = this.delay_SubQmf[temp_delay][sb][0];
							tmp0[1] = this.delay_SubQmf[temp_delay][sb][1];

							this.delay_SubQmf[temp_delay][sb][0] = inputLeft[0];
							this.delay_SubQmf[temp_delay][sb][1] = inputLeft[1];

							Phi_Fract[0] = Phi_Fract_SubQmf[sb][0];
							Phi_Fract[1] = Phi_Fract_SubQmf[sb][1];
						}
						else {
							/* select data from the QMF subbands */
							tmp0[0] = this.delay_Qmf[temp_delay][sb][0];
							tmp0[1] = this.delay_Qmf[temp_delay][sb][1];

							this.delay_Qmf[temp_delay][sb][0] = inputLeft[0];
							this.delay_Qmf[temp_delay][sb][1] = inputLeft[1];

							Phi_Fract[0] = Phi_Fract_Qmf[sb][0];
							Phi_Fract[1] = Phi_Fract_Qmf[sb][1];
						}

						/* z^(-2) * Phi_Fract[k] */
						tmp[0] = (tmp[0]*Phi_Fract[0])+(tmp0[1]*Phi_Fract[1]);
						tmp[1] = (tmp0[1]*Phi_Fract[0])-(tmp0[0]*Phi_Fract[1]);

						R0[0] = tmp[0];
						R0[1] = tmp[1];
						for(m = 0; m<NO_ALLPASS_LINKS; m++) {
							float[] Q_Fract_allpass = new float[2], tmp2 = new float[2];

							/* fetch parameters */
							if(gr<this.num_hybrid_groups) {
								/* select data from the hybrid subbands */
								tmp0[0] = this.delay_SubQmf_ser[m][temp_delay_ser[m]][sb][0];
								tmp0[1] = this.delay_SubQmf_ser[m][temp_delay_ser[m]][sb][1];

								if(this.use34hybrid_bands) {
									Q_Fract_allpass[0] = Q_Fract_allpass_SubQmf34[sb][m][0];
									Q_Fract_allpass[1] = Q_Fract_allpass_SubQmf34[sb][m][1];
								}
								else {
									Q_Fract_allpass[0] = Q_Fract_allpass_SubQmf20[sb][m][0];
									Q_Fract_allpass[1] = Q_Fract_allpass_SubQmf20[sb][m][1];
								}
							}
							else {
								/* select data from the QMF subbands */
								tmp0[0] = this.delay_Qmf_ser[m][temp_delay_ser[m]][sb][0];
								tmp0[1] = this.delay_Qmf_ser[m][temp_delay_ser[m]][sb][1];

								Q_Fract_allpass[0] = Q_Fract_allpass_Qmf[sb][m][0];
								Q_Fract_allpass[1] = Q_Fract_allpass_Qmf[sb][m][1];
							}

							/* delay by a fraction */
							/* z^(-d(m)) * Q_Fract_allpass[k,m] */
							tmp[0] = (tmp0[0]*Q_Fract_allpass[0])+(tmp0[1]*Q_Fract_allpass[1]);
							tmp[1] = (tmp0[1]*Q_Fract_allpass[0])-(tmp0[0]*Q_Fract_allpass[1]);

							/* -a(m) * g_DecaySlope[k] */
							tmp[0] += -(g_DecaySlope_filt[m]*R0[0]);
							tmp[1] += -(g_DecaySlope_filt[m]*R0[1]);

							/* -a(m) * g_DecaySlope[k] * Q_Fract_allpass[k,m] * z^(-d(m)) */
							tmp2[0] = R0[0]+(g_DecaySlope_filt[m]*tmp[0]);
							tmp2[1] = R0[1]+(g_DecaySlope_filt[m]*tmp[1]);

							/* store sample */
							if(gr<this.num_hybrid_groups) {
								this.delay_SubQmf_ser[m][temp_delay_ser[m]][sb][0] = tmp2[0];
								this.delay_SubQmf_ser[m][temp_delay_ser[m]][sb][1] = tmp2[1];
							}
							else {
								this.delay_Qmf_ser[m][temp_delay_ser[m]][sb][0] = tmp2[0];
								this.delay_Qmf_ser[m][temp_delay_ser[m]][sb][1] = tmp2[1];
							}

							/* store for next iteration (or as output value if last iteration) */
							R0[0] = tmp[0];
							R0[1] = tmp[1];
						}
					}

					/* select b(k) for reading the transient ratio */
					bk = (~NEGATE_IPD_MASK)&this.map_group2bk[gr];

					/* duck if a past transient is found */
					R0[0] = (G_TransientRatio[n][bk]*R0[0]);
					R0[1] = (G_TransientRatio[n][bk]*R0[1]);

					if(gr<this.num_hybrid_groups) {
						/* hybrid */
						X_hybrid_right[n][sb][0] = R0[0];
						X_hybrid_right[n][sb][1] = R0[1];
					}
					else {
						/* QMF */
						X_right[n][sb][0] = R0[0];
						X_right[n][sb][1] = R0[1];
					}

					/* Update delay buffer index */
					if(++temp_delay>=2) {
						temp_delay = 0;
					}

					/* update delay indices */
					if(sb>this.nr_allpass_bands&&gr>=this.num_hybrid_groups) {
						/* delay_D depends on the samplerate, it can hold the values 14 and 1 */
						if(++this.delay_buf_index_delay[sb]>=this.delay_D[sb]) {
							this.delay_buf_index_delay[sb] = 0;
						}
					}

					for(m = 0; m<NO_ALLPASS_LINKS; m++) {
						if(++temp_delay_ser[m]>=this.num_sample_delay_ser[m]) {
							temp_delay_ser[m] = 0;
						}
					}
				}
			}
		}

		/* update delay indices */
		this.saved_delay = temp_delay;
		for(m = 0; m<NO_ALLPASS_LINKS; m++) {
			this.delay_buf_index_ser[m] = temp_delay_ser[m];
		}
	}
private void ps_decorrelate(float[][][] X_left, float[][][] X_right,
		float[][][] X_hybrid_left, float[][][] X_hybrid_right) {
		int gr, n, m, bk;
		int temp_delay = 0;
		int sb, maxsb;
		int[] temp_delay_ser = new int[NO_ALLPASS_LINKS];
		float P_SmoothPeakDecayDiffNrg, nrg;
		float[][] P = new float[32][34];
		float[][] G_TransientRatio = new float[32][34];
		float[] inputLeft = new float[2];


		/* chose hybrid filterbank: 20 or 34 band case */
		float[][] Phi_Fract_SubQmf;
		if(this.use34hybrid_bands) {
			Phi_Fract_SubQmf = Phi_Fract_SubQmf34;
		}
		else {
			Phi_Fract_SubQmf = Phi_Fract_SubQmf20;
		}

		/* clear the energy values */
		for(n = 0; n<32; n++) {
			for(bk = 0; bk<34; bk++) {
				P[n][bk] = 0;
			}
		}

		/* calculate the energy in each parameter band b(k) */
		for(gr = 0; gr<this.num_groups; gr++) {
			/* select the parameter index b(k) to which this group belongs */
			bk = (~NEGATE_IPD_MASK)&this.map_group2bk[gr];

			/* select the upper subband border for this group */
			maxsb = (gr<this.num_hybrid_groups) ? this.group_border[gr]+1 : this.group_border[gr+1];

			for(sb = this.group_border[gr]; sb<maxsb; sb++) {
				for(n = this.border_position[0]; n<this.border_position[this.num_env]; n++) {

					/* input from hybrid subbands or QMF subbands */
					if(gr<this.num_hybrid_groups) {
						inputLeft[0] = X_hybrid_left[n][sb][0];
						inputLeft[1] = X_hybrid_left[n][sb][1];
					}
					else {
						inputLeft[0] = X_left[n][sb][0];
						inputLeft[1] = X_left[n][sb][1];
					}

					/* accumulate energy */
					P[n][bk] += (inputLeft[0]*inputLeft[0])+(inputLeft[1]*inputLeft[1]);
				}
			}
		}

		/* calculate transient reduction ratio for each parameter band b(k) */
		for(bk = 0; bk<this.nr_par_bands; bk++) {
			for(n = this.border_position[0]; n<this.border_position[this.num_env]; n++) {
				float gamma = 1.5f;

				this.P_PeakDecayNrg[bk] = (this.P_PeakDecayNrg[bk]*this.alpha_decay);
				if(this.P_PeakDecayNrg[bk]<P[n][bk])
					this.P_PeakDecayNrg[bk] = P[n][bk];

				/* apply smoothing filter to peak decay energy */
				P_SmoothPeakDecayDiffNrg = this.P_SmoothPeakDecayDiffNrg_prev[bk];
				P_SmoothPeakDecayDiffNrg += ((this.P_PeakDecayNrg[bk]-P[n][bk]-this.P_SmoothPeakDecayDiffNrg_prev[bk])*alpha_smooth);
				this.P_SmoothPeakDecayDiffNrg_prev[bk] = P_SmoothPeakDecayDiffNrg;

				/* apply smoothing filter to energy */
				nrg = this.P_prev[bk];
				nrg += ((P[n][bk]-this.P_prev[bk])*this.alpha_smooth);
				this.P_prev[bk] = nrg;

				/* calculate transient ratio */
				if((P_SmoothPeakDecayDiffNrg*gamma)<=nrg) {
					G_TransientRatio[n][bk] = 1.0f;
				}
				else {
					G_TransientRatio[n][bk] = (nrg/(P_SmoothPeakDecayDiffNrg*gamma));
				}
			}
		}

		/* apply stereo decorrelation filter to the signal */
		for(gr = 0; gr<this.num_groups; gr++) {
			if(gr<this.num_hybrid_groups)
				maxsb = this.group_border[gr]+1;
			else
				maxsb = this.group_border[gr+1];

			/* QMF channel */
			for(sb = this.group_border[gr]; sb<maxsb; sb++) {
				float g_DecaySlope;
				float[] g_DecaySlope_filt = new float[NO_ALLPASS_LINKS];

				/* g_DecaySlope: [0..1] */
				if(gr<this.num_hybrid_groups||sb<=this.decay_cutoff) {
					g_DecaySlope = 1.0f;
				}
				else {
					int decay = this.decay_cutoff-sb;
					if(decay<=-20 /* -1/DECAY_SLOPE */) {
						g_DecaySlope = 0;
					}
					else {
						/* decay(int)*decay_slope(frac) = g_DecaySlope(frac) */
						g_DecaySlope = 1.0f+DECAY_SLOPE*decay;
					}
				}

				/* calculate g_DecaySlope_filt for every m multiplied by filter_a[m] */
				for(m = 0; m<NO_ALLPASS_LINKS; m++) {
					g_DecaySlope_filt[m] = g_DecaySlope*filter_a[m];
				}


				/* set delay indices */
				temp_delay = this.saved_delay;
				for(n = 0; n<NO_ALLPASS_LINKS; n++) {
					temp_delay_ser[n] = this.delay_buf_index_ser[n];
				}

				for(n = this.border_position[0]; n<this.border_position[this.num_env]; n++) {
					float[] tmp = new float[2], tmp0 = new float[2], R0 = new float[2];

					if(gr<this.num_hybrid_groups) {
						/* hybrid filterbank input */
						inputLeft[0] = X_hybrid_left[n][sb][0];
						inputLeft[1] = X_hybrid_left[n][sb][1];
					}
					else {
						/* QMF filterbank input */
						inputLeft[0] = X_left[n][sb][0];
						inputLeft[1] = X_left[n][sb][1];
					}

					if(sb>this.nr_allpass_bands&&gr>=this.num_hybrid_groups) {
						/* delay */

						/* never hybrid subbands here, always QMF subbands */
						tmp[0] = this.delay_Qmf[this.delay_buf_index_delay[sb]][sb][0];
						tmp[1] = this.delay_Qmf[this.delay_buf_index_delay[sb]][sb][1];
						R0[0] = tmp[0];
						R0[1] = tmp[1];
						this.delay_Qmf[this.delay_buf_index_delay[sb]][sb][0] = inputLeft[0];
						this.delay_Qmf[this.delay_buf_index_delay[sb]][sb][1] = inputLeft[1];
					}
					else {
						/* allpass filter */
						//int m;
						float[] Phi_Fract = new float[2];

						/* fetch parameters */
						if(gr<this.num_hybrid_groups) {
							/* select data from the hybrid subbands */
							tmp0[0] = this.delay_SubQmf[temp_delay][sb][0];
							tmp0[1] = this.delay_SubQmf[temp_delay][sb][1];

							this.delay_SubQmf[temp_delay][sb][0] = inputLeft[0];
							this.delay_SubQmf[temp_delay][sb][1] = inputLeft[1];

							Phi_Fract[0] = Phi_Fract_SubQmf[sb][0];
							Phi_Fract[1] = Phi_Fract_SubQmf[sb][1];
						}
						else {
							/* select data from the QMF subbands */
							tmp0[0] = this.delay_Qmf[temp_delay][sb][0];
							tmp0[1] = this.delay_Qmf[temp_delay][sb][1];

							this.delay_Qmf[temp_delay][sb][0] = inputLeft[0];
							this.delay_Qmf[temp_delay][sb][1] = inputLeft[1];

							Phi_Fract[0] = Phi_Fract_Qmf[sb][0];
							Phi_Fract[1] = Phi_Fract_Qmf[sb][1];
						}

						/* z^(-2) * Phi_Fract[k] */
						tmp[0] = (tmp[0]*Phi_Fract[0])+(tmp0[1]*Phi_Fract[1]);
						tmp[1] = (tmp0[1]*Phi_Fract[0])-(tmp0[0]*Phi_Fract[1]);

						R0[0] = tmp[0];
						R0[1] = tmp[1];
						for(m = 0; m<NO_ALLPASS_LINKS; m++) {
							float[] Q_Fract_allpass = new float[2], tmp2 = new float[2];

							/* fetch parameters */
							if(gr<this.num_hybrid_groups) {
								/* select data from the hybrid subbands */
								tmp0[0] = this.delay_SubQmf_ser[m][temp_delay_ser[m]][sb][0];
								tmp0[1] = this.delay_SubQmf_ser[m][temp_delay_ser[m]][sb][1];

								if(this.use34hybrid_bands) {
									Q_Fract_allpass[0] = Q_Fract_allpass_SubQmf34[sb][m][0];
									Q_Fract_allpass[1] = Q_Fract_allpass_SubQmf34[sb][m][1];
								}
								else {
									Q_Fract_allpass[0] = Q_Fract_allpass_SubQmf20[sb][m][0];
									Q_Fract_allpass[1] = Q_Fract_allpass_SubQmf20[sb][m][1];
								}
							}
							else {
								/* select data from the QMF subbands */
								tmp0[0] = this.delay_Qmf_ser[m][temp_delay_ser[m]][sb][0];
								tmp0[1] = this.delay_Qmf_ser[m][temp_delay_ser[m]][sb][1];

								Q_Fract_allpass[0] = Q_Fract_allpass_Qmf[sb][m][0];
								Q_Fract_allpass[1] = Q_Fract_allpass_Qmf[sb][m][1];
							}

							/* delay by a fraction */
							/* z^(-d(m)) * Q_Fract_allpass[k,m] */
							tmp[0] = (tmp0[0]*Q_Fract_allpass[0])+(tmp0[1]*Q_Fract_allpass[1]);
							tmp[1] = (tmp0[1]*Q_Fract_allpass[0])-(tmp0[0]*Q_Fract_allpass[1]);

							/* -a(m) * g_DecaySlope[k] */
							tmp[0] += -(g_DecaySlope_filt[m]*R0[0]);
							tmp[1] += -(g_DecaySlope_filt[m]*R0[1]);

							/* -a(m) * g_DecaySlope[k] * Q_Fract_allpass[k,m] * z^(-d(m)) */
							tmp2[0] = R0[0]+(g_DecaySlope_filt[m]*tmp[0]);
							tmp2[1] = R0[1]+(g_DecaySlope_filt[m]*tmp[1]);

							/* store sample */
							if(gr<this.num_hybrid_groups) {
								this.delay_SubQmf_ser[m][temp_delay_ser[m]][sb][0] = tmp2[0];
								this.delay_SubQmf_ser[m][temp_delay_ser[m]][sb][1] = tmp2[1];
							}
							else {
								this.delay_Qmf_ser[m][temp_delay_ser[m]][sb][0] = tmp2[0];
								this.delay_Qmf_ser[m][temp_delay_ser[m]][sb][1] = tmp2[1];
							}

							/* store for next iteration (or as output value if last iteration) */
							R0[0] = tmp[0];
							R0[1] = tmp[1];
						}
					}

					/* select b(k) for reading the transient ratio */
					bk = (~NEGATE_IPD_MASK)&this.map_group2bk[gr];

					/* duck if a past transient is found */
					R0[0] = (G_TransientRatio[n][bk]*R0[0]);
					R0[1] = (G_TransientRatio[n][bk]*R0[1]);

					if(gr<this.num_hybrid_groups) {
						/* hybrid */
						X_hybrid_right[n][sb][0] = R0[0];
						X_hybrid_right[n][sb][1] = R0[1];
					}
					else {
						/* QMF */
						X_right[n][sb][0] = R0[0];
						X_right[n][sb][1] = R0[1];
					}

					/* Update delay buffer index */
					if(++temp_delay>=2) {
						temp_delay = 0;
					}

					/* update delay indices */
					if(sb>this.nr_allpass_bands&&gr>=this.num_hybrid_groups) {
						/* delay_D depends on the samplerate, it can hold the values 14 and 1 */
						if(++this.delay_buf_index_delay[sb]>=this.delay_D[sb]) {
							this.delay_buf_index_delay[sb] = 0;
						}
					}

					for(m = 0; m<NO_ALLPASS_LINKS; m++) {
						if(++temp_delay_ser[m]>=this.num_sample_delay_ser[m]) {
							temp_delay_ser[m] = 0;
						}
					}
				}
			}
		}

		/* update delay indices */
		this.saved_delay = temp_delay;
		for(m = 0; m<NO_ALLPASS_LINKS; m++) {
			this.delay_buf_index_ser[m] = temp_delay_ser[m];
		}
	}
private void ps_decorrelate ( float [ ] [ ] [ ] X_left , float [ ] [ ] [ ] X_right , float [ ] [ ] [ ] X_hybrid_left , float [ ] [ ] [ ] X_hybrid_right ) { int gr , n , m , bk ; int temp_delay = 0 ; int sb , maxsb ; int [ ] temp_delay_ser = new int [ NO_ALLPASS_LINKS ] ; float P_SmoothPeakDecayDiffNrg , nrg ; float [ ] [ ] P = new float [ 32 ] [ 34 ] ; float [ ] [ ] G_TransientRatio = new float [ 32 ] [ 34 ] ; float [ ] inputLeft = new float [ 2 ] ; /* chose hybrid filterbank: 20 or 34 band case */ float [ ] [ ] Phi_Fract_SubQmf ; if ( this . use34hybrid_bands ) { Phi_Fract_SubQmf = Phi_Fract_SubQmf34 ; } else { Phi_Fract_SubQmf = Phi_Fract_SubQmf20 ; } /* clear the energy values */ for ( n = 0 ; n < 32 ; n ++ ) { for ( bk = 0 ; bk < 34 ; bk ++ ) { P [ n ] [ bk ] = 0 ; } } /* calculate the energy in each parameter band b(k) */ for ( gr = 0 ; gr < this . num_groups ; gr ++ ) { /* select the parameter index b(k) to which this group belongs */ bk = ( ~ NEGATE_IPD_MASK ) & this . map_group2bk [ gr ] ; /* select the upper subband border for this group */ maxsb = ( gr < this . num_hybrid_groups ) ? this . group_border [ gr ] + 1 : this . group_border [ gr + 1 ] ; for ( sb = this . group_border [ gr ] ; sb < maxsb ; sb ++ ) { for ( n = this . border_position [ 0 ] ; n < this . border_position [ this . num_env ] ; n ++ ) { /* input from hybrid subbands or QMF subbands */ if ( gr < this . num_hybrid_groups ) { inputLeft [ 0 ] = X_hybrid_left [ n ] [ sb ] [ 0 ] ; inputLeft [ 1 ] = X_hybrid_left [ n ] [ sb ] [ 1 ] ; } else { inputLeft [ 0 ] = X_left [ n ] [ sb ] [ 0 ] ; inputLeft [ 1 ] = X_left [ n ] [ sb ] [ 1 ] ; } /* accumulate energy */ P [ n ] [ bk ] += ( inputLeft [ 0 ] * inputLeft [ 0 ] ) + ( inputLeft [ 1 ] * inputLeft [ 1 ] ) ; } } } /* calculate transient reduction ratio for each parameter band b(k) */ for ( bk = 0 ; bk < this . nr_par_bands ; bk ++ ) { for ( n = this . border_position [ 0 ] ; n < this . border_position [ this . num_env ] ; n ++ ) { float gamma = 1.5f ; this . P_PeakDecayNrg [ bk ] = ( this . P_PeakDecayNrg [ bk ] * this . alpha_decay ) ; if ( this . P_PeakDecayNrg [ bk ] < P [ n ] [ bk ] ) this . P_PeakDecayNrg [ bk ] = P [ n ] [ bk ] ; /* apply smoothing filter to peak decay energy */ P_SmoothPeakDecayDiffNrg = this . P_SmoothPeakDecayDiffNrg_prev [ bk ] ; P_SmoothPeakDecayDiffNrg += ( ( this . P_PeakDecayNrg [ bk ] - P [ n ] [ bk ] - this . P_SmoothPeakDecayDiffNrg_prev [ bk ] ) * alpha_smooth ) ; this . P_SmoothPeakDecayDiffNrg_prev [ bk ] = P_SmoothPeakDecayDiffNrg ; /* apply smoothing filter to energy */ nrg = this . P_prev [ bk ] ; nrg += ( ( P [ n ] [ bk ] - this . P_prev [ bk ] ) * this . alpha_smooth ) ; this . P_prev [ bk ] = nrg ; /* calculate transient ratio */ if ( ( P_SmoothPeakDecayDiffNrg * gamma ) <= nrg ) { G_TransientRatio [ n ] [ bk ] = 1.0f ; } else { G_TransientRatio [ n ] [ bk ] = ( nrg / ( P_SmoothPeakDecayDiffNrg * gamma ) ) ; } } } /* apply stereo decorrelation filter to the signal */ for ( gr = 0 ; gr < this . num_groups ; gr ++ ) { if ( gr < this . num_hybrid_groups ) maxsb = this . group_border [ gr ] + 1 ; else maxsb = this . group_border [ gr + 1 ] ; /* QMF channel */ for ( sb = this . group_border [ gr ] ; sb < maxsb ; sb ++ ) { float g_DecaySlope ; float [ ] g_DecaySlope_filt = new float [ NO_ALLPASS_LINKS ] ; /* g_DecaySlope: [0..1] */ if ( gr < this . num_hybrid_groups || sb <= this . decay_cutoff ) { g_DecaySlope = 1.0f ; } else { int decay = this . decay_cutoff - sb ; if ( decay <= - 20 /* -1/DECAY_SLOPE */ ) { g_DecaySlope = 0 ; } else { /* decay(int)*decay_slope(frac) = g_DecaySlope(frac) */ g_DecaySlope = 1.0f + DECAY_SLOPE * decay ; } } /* calculate g_DecaySlope_filt for every m multiplied by filter_a[m] */ for ( m = 0 ; m < NO_ALLPASS_LINKS ; m ++ ) { g_DecaySlope_filt [ m ] = g_DecaySlope * filter_a [ m ] ; } /* set delay indices */ temp_delay = this . saved_delay ; for ( n = 0 ; n < NO_ALLPASS_LINKS ; n ++ ) { temp_delay_ser [ n ] = this . delay_buf_index_ser [ n ] ; } for ( n = this . border_position [ 0 ] ; n < this . border_position [ this . num_env ] ; n ++ ) { float [ ] tmp = new float [ 2 ] , tmp0 = new float [ 2 ] , R0 = new float [ 2 ] ; if ( gr < this . num_hybrid_groups ) { /* hybrid filterbank input */ inputLeft [ 0 ] = X_hybrid_left [ n ] [ sb ] [ 0 ] ; inputLeft [ 1 ] = X_hybrid_left [ n ] [ sb ] [ 1 ] ; } else { /* QMF filterbank input */ inputLeft [ 0 ] = X_left [ n ] [ sb ] [ 0 ] ; inputLeft [ 1 ] = X_left [ n ] [ sb ] [ 1 ] ; } if ( sb > this . nr_allpass_bands && gr >= this . num_hybrid_groups ) { /* delay */ /* never hybrid subbands here, always QMF subbands */ tmp [ 0 ] = this . delay_Qmf [ this . delay_buf_index_delay [ sb ] ] [ sb ] [ 0 ] ; tmp [ 1 ] = this . delay_Qmf [ this . delay_buf_index_delay [ sb ] ] [ sb ] [ 1 ] ; R0 [ 0 ] = tmp [ 0 ] ; R0 [ 1 ] = tmp [ 1 ] ; this . delay_Qmf [ this . delay_buf_index_delay [ sb ] ] [ sb ] [ 0 ] = inputLeft [ 0 ] ; this . delay_Qmf [ this . delay_buf_index_delay [ sb ] ] [ sb ] [ 1 ] = inputLeft [ 1 ] ; } else { /* allpass filter */ //int m; float [ ] Phi_Fract = new float [ 2 ] ; /* fetch parameters */ if ( gr < this . num_hybrid_groups ) { /* select data from the hybrid subbands */ tmp0 [ 0 ] = this . delay_SubQmf [ temp_delay ] [ sb ] [ 0 ] ; tmp0 [ 1 ] = this . delay_SubQmf [ temp_delay ] [ sb ] [ 1 ] ; this . delay_SubQmf [ temp_delay ] [ sb ] [ 0 ] = inputLeft [ 0 ] ; this . delay_SubQmf [ temp_delay ] [ sb ] [ 1 ] = inputLeft [ 1 ] ; Phi_Fract [ 0 ] = Phi_Fract_SubQmf [ sb ] [ 0 ] ; Phi_Fract [ 1 ] = Phi_Fract_SubQmf [ sb ] [ 1 ] ; } else { /* select data from the QMF subbands */ tmp0 [ 0 ] = this . delay_Qmf [ temp_delay ] [ sb ] [ 0 ] ; tmp0 [ 1 ] = this . delay_Qmf [ temp_delay ] [ sb ] [ 1 ] ; this . delay_Qmf [ temp_delay ] [ sb ] [ 0 ] = inputLeft [ 0 ] ; this . delay_Qmf [ temp_delay ] [ sb ] [ 1 ] = inputLeft [ 1 ] ; Phi_Fract [ 0 ] = Phi_Fract_Qmf [ sb ] [ 0 ] ; Phi_Fract [ 1 ] = Phi_Fract_Qmf [ sb ] [ 1 ] ; } /* z^(-2) * Phi_Fract[k] */ tmp [ 0 ] = ( tmp [ 0 ] * Phi_Fract [ 0 ] ) + ( tmp0 [ 1 ] * Phi_Fract [ 1 ] ) ; tmp [ 1 ] = ( tmp0 [ 1 ] * Phi_Fract [ 0 ] ) - ( tmp0 [ 0 ] * Phi_Fract [ 1 ] ) ; R0 [ 0 ] = tmp [ 0 ] ; R0 [ 1 ] = tmp [ 1 ] ; for ( m = 0 ; m < NO_ALLPASS_LINKS ; m ++ ) { float [ ] Q_Fract_allpass = new float [ 2 ] , tmp2 = new float [ 2 ] ; /* fetch parameters */ if ( gr < this . num_hybrid_groups ) { /* select data from the hybrid subbands */ tmp0 [ 0 ] = this . delay_SubQmf_ser [ m ] [ temp_delay_ser [ m ] ] [ sb ] [ 0 ] ; tmp0 [ 1 ] = this . delay_SubQmf_ser [ m ] [ temp_delay_ser [ m ] ] [ sb ] [ 1 ] ; if ( this . use34hybrid_bands ) { Q_Fract_allpass [ 0 ] = Q_Fract_allpass_SubQmf34 [ sb ] [ m ] [ 0 ] ; Q_Fract_allpass [ 1 ] = Q_Fract_allpass_SubQmf34 [ sb ] [ m ] [ 1 ] ; } else { Q_Fract_allpass [ 0 ] = Q_Fract_allpass_SubQmf20 [ sb ] [ m ] [ 0 ] ; Q_Fract_allpass [ 1 ] = Q_Fract_allpass_SubQmf20 [ sb ] [ m ] [ 1 ] ; } } else { /* select data from the QMF subbands */ tmp0 [ 0 ] = this . delay_Qmf_ser [ m ] [ temp_delay_ser [ m ] ] [ sb ] [ 0 ] ; tmp0 [ 1 ] = this . delay_Qmf_ser [ m ] [ temp_delay_ser [ m ] ] [ sb ] [ 1 ] ; Q_Fract_allpass [ 0 ] = Q_Fract_allpass_Qmf [ sb ] [ m ] [ 0 ] ; Q_Fract_allpass [ 1 ] = Q_Fract_allpass_Qmf [ sb ] [ m ] [ 1 ] ; } /* delay by a fraction */ /* z^(-d(m)) * Q_Fract_allpass[k,m] */ tmp [ 0 ] = ( tmp0 [ 0 ] * Q_Fract_allpass [ 0 ] ) + ( tmp0 [ 1 ] * Q_Fract_allpass [ 1 ] ) ; tmp [ 1 ] = ( tmp0 [ 1 ] * Q_Fract_allpass [ 0 ] ) - ( tmp0 [ 0 ] * Q_Fract_allpass [ 1 ] ) ; /* -a(m) * g_DecaySlope[k] */ tmp [ 0 ] += - ( g_DecaySlope_filt [ m ] * R0 [ 0 ] ) ; tmp [ 1 ] += - ( g_DecaySlope_filt [ m ] * R0 [ 1 ] ) ; /* -a(m) * g_DecaySlope[k] * Q_Fract_allpass[k,m] * z^(-d(m)) */ tmp2 [ 0 ] = R0 [ 0 ] + ( g_DecaySlope_filt [ m ] * tmp [ 0 ] ) ; tmp2 [ 1 ] = R0 [ 1 ] + ( g_DecaySlope_filt [ m ] * tmp [ 1 ] ) ; /* store sample */ if ( gr < this . num_hybrid_groups ) { this . delay_SubQmf_ser [ m ] [ temp_delay_ser [ m ] ] [ sb ] [ 0 ] = tmp2 [ 0 ] ; this . delay_SubQmf_ser [ m ] [ temp_delay_ser [ m ] ] [ sb ] [ 1 ] = tmp2 [ 1 ] ; } else { this . delay_Qmf_ser [ m ] [ temp_delay_ser [ m ] ] [ sb ] [ 0 ] = tmp2 [ 0 ] ; this . delay_Qmf_ser [ m ] [ temp_delay_ser [ m ] ] [ sb ] [ 1 ] = tmp2 [ 1 ] ; } /* store for next iteration (or as output value if last iteration) */ R0 [ 0 ] = tmp [ 0 ] ; R0 [ 1 ] = tmp [ 1 ] ; } } /* select b(k) for reading the transient ratio */ bk = ( ~ NEGATE_IPD_MASK ) & this . map_group2bk [ gr ] ; /* duck if a past transient is found */ R0 [ 0 ] = ( G_TransientRatio [ n ] [ bk ] * R0 [ 0 ] ) ; R0 [ 1 ] = ( G_TransientRatio [ n ] [ bk ] * R0 [ 1 ] ) ; if ( gr < this . num_hybrid_groups ) { /* hybrid */ X_hybrid_right [ n ] [ sb ] [ 0 ] = R0 [ 0 ] ; X_hybrid_right [ n ] [ sb ] [ 1 ] = R0 [ 1 ] ; } else { /* QMF */ X_right [ n ] [ sb ] [ 0 ] = R0 [ 0 ] ; X_right [ n ] [ sb ] [ 1 ] = R0 [ 1 ] ; } /* Update delay buffer index */ if ( ++ temp_delay >= 2 ) { temp_delay = 0 ; } /* update delay indices */ if ( sb > this . nr_allpass_bands && gr >= this . num_hybrid_groups ) { /* delay_D depends on the samplerate, it can hold the values 14 and 1 */ if ( ++ this . delay_buf_index_delay [ sb ] >= this . delay_D [ sb ] ) { this . delay_buf_index_delay [ sb ] = 0 ; } } for ( m = 0 ; m < NO_ALLPASS_LINKS ; m ++ ) { if ( ++ temp_delay_ser [ m ] >= this . num_sample_delay_ser [ m ] ) { temp_delay_ser [ m ] = 0 ; } } } } } /* update delay indices */ this . saved_delay = temp_delay ; for ( m = 0 ; m < NO_ALLPASS_LINKS ; m ++ ) { this . delay_buf_index_ser [ m ] = temp_delay_ser [ m ] ; } }
/* decorrelate the mono signal using an allpass filter
/ * decorrelate the mono signal using an allpass filter