/* * Long term port to Java. * Copyright (C) 1999 Christopher Edwards * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ package javaforce.codec.gsm; public class Long_term { public void Gsm_Long_Term_Predictor( short[] d, /* [0..39] residual signal IN */ int k, /* d entry point, which 40 */ short[] e, /* [0..39] add 5 to index OUT */ short[] dp, short[] dpp, int dp_dpp_point_dp0, short[] Nc, /* correlation lag OUT */ short[] bc, /* gain factor OUT */ int Nc_bc_index) { Calculation_of_the_LTP_parameters( d, k, dp, dp_dpp_point_dp0, bc, Nc, Nc_bc_index); Long_term_analysis_filtering( bc[Nc_bc_index], Nc[Nc_bc_index], dp, d, k, dpp, e, dp_dpp_point_dp0); } private void Calculation_of_the_LTP_parameters( short[] d, /* [0..39] IN */ int d_index, short[] dp, /* [-120..-1] IN */ int dp_start, short[] bc_out, /* OUT */ short[] Nc_out, /* OUT */ int Nc_bc_index) throws IllegalArgumentException { int lambda = 0; short Nc = 0; short[] wt = new short[40]; int L_max = 0, L_power = 0; short R = 0, S = 0, dmax = 0, scal = 0; short temp = 0; /* Search of the optimum scaling of d[0..39]. */ for (int k = 0; k <= 39; k++) { temp = d[k + d_index]; temp = Add.GSM_ABS(temp); if (temp > dmax) { dmax = temp; } } temp = 0; if (dmax == 0) { scal = 0; } else { if (!(dmax > 0)) { throw new IllegalArgumentException("Calculation_of_the_LTP_parameters: dmax = " + dmax + " should be > 0."); } temp = Add.gsm_norm(dmax << 16); } if (temp > 6) { scal = 0; } else { scal = (short) (6 - temp); } if (!(scal >= 0)) { throw new IllegalArgumentException("Calculation_of_the_LTP_parameters: scal = " + scal + " should be >= 0."); } /* Initialization of a working array wt */ for (int k = 0; k <= 39; k++) { wt[k] = Add.SASR(d[k + d_index], scal); } /* Search for the maximum cross-correlation and coding of the LTP lag */ L_max = 0; Nc = 40; /* index for the maximum cross-correlation */ for (lambda = 40; lambda <= 120; lambda++) { int L_result = 0; int step = 1; L_result = STEP(0, wt, dp, dp_start - lambda); L_result += STEP(1, wt, dp, step + dp_start - lambda); step++; L_result += STEP(2, wt, dp, step + dp_start - lambda); step++; L_result += STEP(3, wt, dp, step + dp_start - lambda); step++; L_result += STEP(4, wt, dp, step + dp_start - lambda); step++; L_result += STEP(5, wt, dp, step + dp_start - lambda); step++; L_result += STEP(6, wt, dp, step + dp_start - lambda); step++; L_result += STEP(7, wt, dp, step + dp_start - lambda); step++; L_result += STEP(8, wt, dp, step + dp_start - lambda); step++; L_result += STEP(9, wt, dp, step + dp_start - lambda); step++; L_result += STEP(10, wt, dp, step + dp_start - lambda); step++; L_result += STEP(11, wt, dp, step + dp_start - lambda); step++; L_result += STEP(12, wt, dp, step + dp_start - lambda); step++; L_result += STEP(13, wt, dp, step + dp_start - lambda); step++; L_result += STEP(14, wt, dp, step + dp_start - lambda); step++; L_result += STEP(15, wt, dp, step + dp_start - lambda); step++; L_result += STEP(16, wt, dp, step + dp_start - lambda); step++; L_result += STEP(17, wt, dp, step + dp_start - lambda); step++; L_result += STEP(18, wt, dp, step + dp_start - lambda); step++; L_result += STEP(19, wt, dp, step + dp_start - lambda); step++; L_result += STEP(20, wt, dp, step + dp_start - lambda); step++; L_result += STEP(21, wt, dp, step + dp_start - lambda); step++; L_result += STEP(22, wt, dp, step + dp_start - lambda); step++; L_result += STEP(23, wt, dp, step + dp_start - lambda); step++; L_result += STEP(24, wt, dp, step + dp_start - lambda); step++; L_result += STEP(25, wt, dp, step + dp_start - lambda); step++; L_result += STEP(26, wt, dp, step + dp_start - lambda); step++; L_result += STEP(27, wt, dp, step + dp_start - lambda); step++; L_result += STEP(28, wt, dp, step + dp_start - lambda); step++; L_result += STEP(29, wt, dp, step + dp_start - lambda); step++; L_result += STEP(30, wt, dp, step + dp_start - lambda); step++; L_result += STEP(31, wt, dp, step + dp_start - lambda); step++; L_result += STEP(32, wt, dp, step + dp_start - lambda); step++; L_result += STEP(33, wt, dp, step + dp_start - lambda); step++; L_result += STEP(34, wt, dp, step + dp_start - lambda); step++; L_result += STEP(35, wt, dp, step + dp_start - lambda); step++; L_result += STEP(36, wt, dp, step + dp_start - lambda); step++; L_result += STEP(37, wt, dp, step + dp_start - lambda); step++; L_result += STEP(38, wt, dp, step + dp_start - lambda); step++; L_result += STEP(39, wt, dp, step + dp_start - lambda); step++; if (L_result > L_max) { Nc = (short) lambda; L_max = L_result; } } Nc_out[Nc_bc_index] = Nc; L_max <<= 1; /* Rescaling of L_max */ if (!(scal <= 100 && scal >= -100)) { throw new IllegalArgumentException("Calculation_of_the_LTP_parameters: scal = " + scal + " should be >= -100 and <= 100."); } L_max = L_max >> (6 - scal); /* sub(6, scal) */ if (!(Nc <= 120 && Nc >= 40)) { throw new IllegalArgumentException("Calculation_of_the_LTP_parameters: Nc = " + Nc + " should be >= 40 and <= 120."); } /* Compute the power of the reconstructed short term residual * signal dp[..] */ L_power = 0; for (int k = 0; k <= 39; k++) { int L_temp; L_temp = Add.SASR(dp[k - Nc + dp_start], 3); L_power += L_temp * L_temp; } L_power <<= 1; /* from L_MULT */ /* Normalization of L_max and L_power */ if (L_max <= 0) { bc_out[Nc_bc_index] = 0; return; } if (L_max >= L_power) { bc_out[Nc_bc_index] = 3; return; } temp = Add.gsm_norm(L_power); R = Add.SASR(L_max << temp, 16); S = Add.SASR(L_power << temp, 16); /* Coding of the LTP gain */ /* Table 4.3a must be used to obtain the level DLB[i] for the * quantization of the LTP gain b to get the coded version bc. */ for (int bc = 0; bc <= 2; bc++) { if (R <= Add.GSM_MULT(S, Gsm_Def.gsm_DLB[bc])) { break; } bc_out[Nc_bc_index] = (short) bc; } } private int STEP(int k, short[] wt, short[] dp, int dp_i) { return (wt[k] * dp[dp_i]); } /* * In this part, we have to decode the bc parameter to compute * the samples of the estimate dpp[0..39]. The decoding of bc * needs the use of table 4.3b. The long term residual signal * e[0..39] is then calculated to be fed to the RPE encoding * section. */ static void Long_term_analysis_filtering( short bc, /* IN */ short Nc, /* IN */ short[] dp, /* previous d [-120..-1] IN */ short[] d, /* d [0..39] IN */ int d_index, short[] dpp, /* estimate [0..39] OUT */ short[] e, /* long term res. signal [0..39] OUT */ int dp_dpp_index) { short BP = 0; switch (bc) { case 0: BP = (short) 3277; for (int k = 0; k <= 39; k++) { dpp[k + dp_dpp_index] = Add.GSM_MULT_R(BP, dp[k - Nc + dp_dpp_index]); e[k + 5] = Add.GSM_SUB(d[k + d_index], dpp[k + dp_dpp_index]); } break; case 1: BP = (short) 11469; for (int k = 0; k <= 39; k++) { dpp[k + dp_dpp_index] = Add.GSM_MULT_R(BP, dp[k - Nc + dp_dpp_index]); e[k + 5] = Add.GSM_SUB(d[k + d_index], dpp[k + dp_dpp_index]); } break; case 2: BP = (short) 21299; for (int k = 0; k <= 39; k++) { dpp[k + dp_dpp_index] = Add.GSM_MULT_R(BP, dp[k - Nc + dp_dpp_index]); e[k + 5] = Add.GSM_SUB(d[k + d_index], dpp[k + dp_dpp_index]); } break; case 3: BP = (short) 32767; for (int k = 0; k <= 39; k++) { dpp[k + dp_dpp_index] = Add.GSM_MULT_R(BP, dp[k - Nc + dp_dpp_index]); e[k + 5] = Add.GSM_SUB(d[k + d_index], dpp[k + dp_dpp_index]); } break; } } /* * This procedure uses the bcr and Ncr parameter to realize the * long term synthesis filtering. The decoding of bcr needs * table 4.3b. */ public void Gsm_Long_Term_Synthesis_Filtering( Gsm_State S, short Ncr, short bcr, short[] erp, /* [0..39] IN */ int dp0_index_start_drp /* [-120..-1] IN, [0..40] OUT */ /* drp is a pointer into the Gsm_State * dp0 short array. */ ) throws IllegalArgumentException { int ltmp; /* for ADD */ short brp, drpp, Nr; short[] drp = S.getDp0(); /* Check the limits of Nr. */ Nr = Ncr < 40 || Ncr > 120 ? S.getNrp() : Ncr; S.setNrp(Nr); if (!(Nr >= 40 && Nr <= 120)) { throw new IllegalArgumentException("Gsm_Long_Term_Synthesis_Filtering Nr = " + Nr + " is out of range. Should be >= 40 and <= 120"); } /* Decoding of the LTP gain bcr */ brp = Gsm_Def.gsm_QLB[bcr]; /* Computation of the reconstructed short term residual * signal drp[0..39] */ if (brp == Gsm_Def.MIN_WORD) { throw new IllegalArgumentException("Gsm_Long_Term_Synthesis_Filtering brp = " + brp + " is out of range. Should be = " + Gsm_Def.MIN_WORD); } for (int k = 0; k <= 39; k++) { drpp = Add.GSM_MULT_R(brp, drp[k - Nr + dp0_index_start_drp]); drp[k + dp0_index_start_drp] = Add.GSM_ADD(erp[k], drpp); } /* * Update of the reconstructed short term residual signal * drp[ -1..-120 ] */ System.arraycopy(drp, (dp0_index_start_drp - 80), drp, (dp0_index_start_drp - 120), 120); S.setDp0(drp); } }