/* * 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 org.tritonus.lowlevel.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 { 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); } }