/* * Rpe 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 Rpe { private short exp_in; /* IN */ private short mant_in; /* IN */ private short exp_out; /* OUT */ private short mant_out; /* OUT */ private int xMp_point = 0; private static final int ENCODE = 0; private static final int DECODE = 1; private short[] x = new short[40]; /* signal [0..39] OUT */ public void Gsm_RPE_Encoding( short[] e, /* -5..-1][0..39][40..44 IN/OUT */ short[] xmaxc, /* [0..3] Coded maximum amplitude OUT */ short[] Mc, /* [0..3] RPE grid selection OUT */ int xmaxc_Mc_index, /* Ref. point for xmaxc and Mc */ short[] xMc, /* [0..12] OUT */ int xMc_index /* Ref. for xmc, '+=13' */) { short[] xM = new short[13]; short[] xMp = new short[13]; Weighting_filter(e); /* Sets up the private data member 'x[40]' */ RPE_grid_selection(xM, Mc, xmaxc_Mc_index); /* Sets up xM[13] */ /* Sets up xmc (13 array locations starting from xMc_index), * xmaxc (one array location at xmaxc_Mc_index), * exp_in and mant_in */ APCM_quantization(xM, xMc, xMc_index, xmaxc, xmaxc_Mc_index); /* Sets up xMp[13] */ APCM_inverse_quantization(xMc, xMp, xMc_index, ENCODE); RPE_grid_positioning(Mc[xmaxc_Mc_index], xMp, e, ENCODE); } /* * The coefficients of the weighting filter are stored in a table * (see table 4.4). The following scaling is used: * * H[0..10] = integer( real_H[ 0..10] * 8192 ); */ private void Weighting_filter( short[] e) /* signal [-5..0.39.44] IN */ { int L_result = 0; int i = 0; /* * (e[-5..-1] and e[40..44] are allocated by the caller, * are initially zero and are not written anywhere.) * * e -= 5; * * The above case is true with the C code, although java * does not have pointers so e[0..49] is all set for this * method. */ /* Compute the signal x[0..39] */ for (int k = 0; k <= 39; k++) { L_result = 8192 >> 1; /* Every one of these multiplications is done twice -- * but I don't see an elegant way to optimize this. * Do you? */ /* #define STEP( i, H ) (e[ k + i ] * H) */ i = 0; L_result += (e[k + 0] * -134) + (e[k + 1] * -374) /* + STEP( 2, 0 ) no sense in adding zero */ + (e[k + 3] * 2054) + (e[k + 4] * 5741) + (e[k + 5] * 8192) + (e[k + 6] * 5741) + (e[k + 7] * 2054) /* + STEP( 8, 0 ) no sense in adding zero */ + (e[k + 9] * -374) + (e[k + 10] * -134); /* 2 adds vs. >>16 => 14, minus one shift to compensate for * those we lost when replacing L_MULT by '*'. */ L_result = Add.SASR(L_result, 13); x[k] = (short) ((L_result < Gsm_Def.MIN_WORD ? Gsm_Def.MIN_WORD : (L_result > Gsm_Def.MAX_WORD ? Gsm_Def.MAX_WORD : L_result))); } } /* * The signal x[0..39] is used to select the RPE grid which is * represented by Mc. */ private void RPE_grid_selection( short[] xM, /* [0..12] OUT */ short[] Mc_out, /* OUT */ int Mc_index) { int m = 0; int L_result = 0; int EM = 0; /* xxx should be L_EM? */ short Mc = 0; int L_common_0_3; /* common part of 0 and 3 */ L_result = 0; L_result += STEP(0, 1) + STEP(0, 2) + STEP(0, 3) + STEP(0, 4) + STEP(0, 5) + STEP(0, 6) + STEP(0, 7) + STEP(0, 8) + STEP(0, 9) + STEP(0, 10) + STEP(0, 11) + STEP(0, 12); L_common_0_3 = L_result; /* i = 0 */ L_result += STEP(0, 0); L_result <<= 1; /* implicit in L_MULT */ EM = L_result; /* i = 1 */ L_result = 0; L_result += STEP(1, 0) + STEP(1, 1) + STEP(1, 2) + STEP(1, 3) + STEP(1, 4) + STEP(1, 5) + STEP(1, 6) + STEP(1, 7) + STEP(1, 8) + STEP(1, 9) + STEP(1, 10) + STEP(1, 11) + STEP(1, 12); L_result <<= 1; if (L_result > EM) { Mc = 1; EM = L_result; } /* i = 2 */ L_result = 0; L_result += STEP(2, 0) + STEP(2, 1) + STEP(2, 2) + STEP(2, 3) + STEP(2, 4) + STEP(2, 5) + STEP(2, 6) + STEP(2, 7) + STEP(2, 8) + STEP(2, 9) + STEP(2, 10) + STEP(2, 11) + STEP(2, 12); L_result <<= 1; if (L_result > EM) { Mc = 2; EM = L_result; } /* i = 3 */ L_result = L_common_0_3; L_result += STEP(3, 12); L_result <<= 1; if (L_result > EM) { Mc = 3; EM = L_result; } /* Down-sampling by a factor 3 to get the selected xM[0..12] * RPE sequence. */ for (int i = 0; i <= 12; i++) { xM[i] = x[Mc + 3 * i]; } Mc_out[Mc_index] = Mc; } private int STEP(int m, int i) { int L_temp; L_temp = Add.SASR(x[m + 3 * i], 2); return (L_temp * L_temp); } private void APCM_quantization( short[] xM, /* [0..12] IN */ short[] xMc, /* [0..12] OUT */ int xMc_index, short[] xmaxc_out, /* OUT */ int xmaxc_index) throws IllegalArgumentException { int itest = 0; short xmax = 0, xmaxc = 0, temp = 0, temp1 = 0, temp2 = 0; short exp = 0, mant = 0; /* Find the maximum absolute value xmax of xM[0..12]. */ for (int i = 0; i <= 12; i++) { temp = xM[i]; temp = Add.GSM_ABS(temp); if (temp > xmax) { xmax = temp; } } /* Qantizing and coding of xmax to get xmaxc. */ exp = 0; temp = Add.SASR(xmax, 9); itest = 0; for (int i = 0; i <= 5; i++) { if (temp <= 0) { itest |= 1; } else { itest |= 0; } temp = Add.SASR(temp, 1); if (!(exp <= 5)) { throw new IllegalArgumentException("APCM_quantization: exp = " + exp + " is out of range. Should be <= 5"); } if (itest == 0) { exp++; /* exp = add (exp, 1) */ } } if (!(exp <= 6 && exp >= 0)) { throw new IllegalArgumentException("APCM_quantization: exp = " + exp + " is out of range. Should be >= -4 and <= 6"); } temp = (short) (exp + 5); if (!(temp <= 11 && temp >= 0)) { throw new IllegalArgumentException("APCM_quantization: temp = " + temp + " is out of range. Should be >= 0 and <= 11"); } xmaxc = Add.GSM_ADD(Add.SASR(xmax, temp), (short) (exp << 3)); /* Quantizing and coding of the xM[0..12] RPE sequence * to get the xMc[0..12] */ APCM_quantization_xmaxc_to_exp_mant(xmaxc, ENCODE); exp = exp_in; mant = mant_in; /* This computation uses the fact that the decoded version of xmaxc * can be calculated by using the exponent and the mantissa part of * xmaxc (logarithmic table). * So, this method avoids any division and uses only a scaling * of the RPE samples by a function of the exponent. A direct * multiplication by the inverse of the mantissa (NRFAC[0..7] * found in table 4.5) gives the 3 bit coded version xMc[0..12] * of the RPE samples. */ /* Direct computation of xMc[0..12] using table 4.5 */ if (!(exp <= 4096 && exp >= -4096)) { throw new IllegalArgumentException("APCM_quantization: exp = " + exp + " is out of range. Should be >= -4096 and <= 4096"); } if (!(mant >= 0 && mant <= 7)) { throw new IllegalArgumentException("APCM_quantization: mant = " + mant + " is out of range. Should be >= 0 and <= 7"); } temp1 = (short) (6 - exp); /* normalization by the exponent */ temp2 = Gsm_Def.gsm_NRFAC[mant]; /* inverse mantissa */ for (int i = 0; i <= 12; i++) { if (!(temp1 >= 0 && temp1 < 16)) { throw new IllegalArgumentException("APCM_quantization: temp = " + temp + " is out of range. Should be >= 0 and < 16"); } temp = (short) (xM[i] << temp1); temp = Add.GSM_MULT(temp, temp2); temp = Add.SASR(temp, 12); xMc[i + xMc_index] = (short) (temp + 4); /* see note below */ } /* NOTE: This equation is used to make all the xMc[i] positive. */ mant_in = mant; exp_in = exp; xmaxc_out[xmaxc_index] = xmaxc; } public void APCM_quantization_xmaxc_to_exp_mant( short xmaxc_elem, int METHOD_ID) throws IllegalArgumentException { short exp = 0, mant = 0; /* Compute exponent and mantissa of the decoded version of xmaxc */ if (xmaxc_elem > 15) { exp = (short) (Add.SASR(xmaxc_elem, 3) - 1); } mant = (short) (xmaxc_elem - (exp << 3)); if (mant == 0) { exp = (short) -4; mant = (short) 7; } else { while (mant <= 7) { mant = (short) (mant << 1 | 1); exp--; } mant -= (short) 8; } if (exp < -4 || exp > 6) { throw new IllegalArgumentException("APCM_quantization_xmaxc_to_exp_mant: exp = " + exp + " is out of range. Should be >= -4 and <= 6"); } if (mant < 0 || mant > 7) { throw new IllegalArgumentException("APCM_quantization_xmaxc_to_exp_mant: mant = " + mant + " is out of range. Should be >= 0 and <= 7"); } if (METHOD_ID == ENCODE) { exp_in = exp; mant_in = mant; } else { /* DECODE */ exp_out = exp; mant_out = mant; } } public void Gsm_RPE_Decoding_java( short xmaxc_elem, /* From Gsm_Decoder xmaxc short array */ short Mc_elem, /* From Gsm_Decoder Mc short array */ int xmc_start, /* Starting point for the three bit part of xmc */ short[] xmc, /* [0..12], 3 bits IN */ short[] erp /* [0..39] OUT */) { short xMp[] = new short[13]; /* exp_out and mant_out are modified in this method */ APCM_quantization_xmaxc_to_exp_mant(xmaxc_elem, DECODE); APCM_inverse_quantization(xmc, xMp, xmc_start, DECODE); RPE_grid_positioning(Mc_elem, xMp, erp, DECODE); } /* * This part is for decoding the RPE sequence of coded xMc[0..12] * samples to obtain the xMp[0..12] array. Table 4.6 is used to get * the mantissa of xmaxc (FAC[0..7]). */ public void APCM_inverse_quantization( short[] xmc, /* [0..12] IN */ short[] xMp, /* [0..12] OUT */ int xmc_start, int METHOD_ID) throws IllegalArgumentException { short temp, temp1, temp2, temp3; if (METHOD_ID == ENCODE) { temp1 = Gsm_Def.gsm_FAC[mant_in]; temp2 = Add.GSM_SUB((short) 6, exp_in); } else { /* DECODE */ temp1 = Gsm_Def.gsm_FAC[mant_out]; temp2 = Add.GSM_SUB((short) 6, exp_out); } temp3 = Add.gsm_asl((short) 1, Add.GSM_SUB(temp2, (short) 1)); xMp_point = 0; for (int i = 0; i < 13; i++) { /* restore sign */ temp = (short) ((xmc[xmc_start++] << 1) - 7); if (!(temp <= 7 && temp >= -7)) { /* 4 bit signed */ throw new IllegalArgumentException("APCM_inverse_quantization: temp = " + temp + " is out of range. Should be >= -7 and <= 7"); } temp <<= 12; /* 16 bit signed */ temp = Add.GSM_MULT_R(temp1, temp); temp = Add.GSM_ADD(temp, temp3); xMp[xMp_point++] = Add.gsm_asr(temp, temp2); } } /* * This method computes the reconstructed long term residual signal * ep[0..39] for the LTP analysis filter. The inputs are the Mc * which is the grid position selection and the xMp[0..12] decoded * RPE samples which are upsampled by a factor of 3 by inserting zero * values. */ public static void RPE_grid_positioning( short Mc, /* grid position IN */ short[] xMp, /* [0..12] IN */ short[] ep, /* [0..39] OUT */ int METHOD_ID) throws IllegalArgumentException { int i = 13; int xMp_index = 0; int ep_index; if (METHOD_ID == ENCODE) { ep_index = 5; } else { /* Decode */ ep_index = 0; } if (!(0 <= Mc && Mc <= 3)) { throw new IllegalArgumentException("RPE_grid_positioning: Mc = " + Mc + " is out of range. Should be >= 0 and <= 3"); } switch (Mc) { case 3: ep[ep_index++] = 0; do { ep[ep_index++] = 0; ep[ep_index++] = 0; ep[ep_index++] = xMp[xMp_index++]; --i; } while (i != 0); break; case 2: do { ep[ep_index++] = 0; ep[ep_index++] = 0; ep[ep_index++] = xMp[xMp_index++]; --i; } while (i != 0); break; case 1: do { ep[ep_index++] = 0; ep[ep_index++] = xMp[xMp_index++]; ep[ep_index++] = 0; --i; } while (i != 0); break; case 0: do { ep[ep_index++] = xMp[xMp_index++]; ep[ep_index++] = 0; ep[ep_index++] = 0; --i; } while (i != 0); break; } if (METHOD_ID == ENCODE) { ep[ep_index++] = 0; } } }