/* * JBoss, Home of Professional Open Source * Copyright 2011, Red Hat, Inc. and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.restcomm.media.codec.ilbc; import org.restcomm.media.spi.dsp.Codec; import org.restcomm.media.spi.format.Format; import org.restcomm.media.spi.format.FormatFactory; import org.restcomm.media.spi.memory.Frame; import org.restcomm.media.spi.memory.Memory; /** * * @author oifa yulian */ public class Decoder implements Codec { private final static Format ilbc = FormatFactory.createAudioFormat("ilbc", 8000, 16, 1); private final static Format linear = FormatFactory.createAudioFormat("linear", 8000, 16, 1); private short[] decResidual=new short[240]; private short[] plcResidual=new short[250]; private short[] syntDenum=new short[66]; private short[] output=new short[240]; private short[] plcLpc=new short[11]; private short[] signal=new short[25]; private int i, j, k, n, s, mode , pos, cbPos, len, tempShift,crossCorr, energy,shifts,newCrit, maxCrit; private int measure, maxMeasure, ind; private int tempIndex1,tempIndex2,tempIndex3,tempIndex4,tempIndex5,tempIndex6,tempIndex7; private int temp,temp2; //max used 12 private int[] tempLMemory=new int[100]; private short tempS,tempS2,xHi,xLow,orderPlusOne,max,lag; private short memlGotten, nFor, nBack, diff, startPos; private short subCount, subFrame,baseSize; private short maxLag,crossCorrScale, energyScale,crossCorrSqMod, crossCorrSqModMax,crossCorrMod, energyMod, energyModMax,totScale, totScaleMax,scaleDiff; private short pick,crossSquareMax, crossSquare; private short shift1, shift2, shift3, shiftMax , scale1, scale2 , scale3 ,nom; private short corrLen,useGain,totGain,maxPerSquare,denom,pitchFact,useLag,randLag; //encoder bits private EncoderBits encoderBits=new EncoderBits(); //decoder state private DecoderState decoderState=new DecoderState(); //correlation data private CorrData corrData=new CorrData(),tempCorrData=new CorrData(); //max used 327 private short[] tempMemory=new short[350]; public Frame process(Frame frame) { byte[] inputData = frame.getData(); if(inputData.length==50) mode=30; else if(inputData.length==38) mode=20; else throw new IllegalArgumentException("INVALID FRAME SIZE"); decoderState.setMode(mode); temp=inputData.length/2; for (i = 0; i < temp; i++) { signal[i] = ((short) ((inputData[i*2] << 8) | (inputData[i*2 + 1] & 0xFF))); } unpackBits(signal,mode); /* Check for bit errors */ if (encoderBits.getStartIdx()<1) mode = 0; if (decoderState.DECODER_MODE==20 && encoderBits.getStartIdx()>3) mode = 0; if (decoderState.DECODER_MODE==30 && encoderBits.getStartIdx()>5) mode = 0; if (mode>0) { /* No bit errors was detected, continue decoding */ /* Stack based */ short[] lsfDeq=tempMemory; //+0 length 20 short[] weightDenum=tempMemory; //+20 length 66 /* adjust index */ updateDecIndex(); /* decode the lsf */ simpleLsfDeq(lsfDeq, 0, encoderBits.getLSF(), 0); lsfCheck(lsfDeq, 0, 10); decoderInterpolateLsp(syntDenum, 0, weightDenum, 20, lsfDeq, 0, (short)10); /* Decode the residual using the cb and gain indexes */ decodeResidual(decResidual, 0, syntDenum, 0); /* preparing the plc for a future loss! */ doThePlc(plcResidual, 0, plcLpc, 0, (short)0, decResidual, 0, syntDenum, 11*(decoderState.SUBFRAMES-1), (short)(decoderState.getLastTag())); /* Use the output from doThePLC */ System.arraycopy(plcResidual, 0, decResidual, 0, decoderState.SIZE); } if (mode == 0) { doThePlc(plcResidual, 0, plcLpc, 0, (short)1,decResidual, 0, syntDenum, 0, (short)(decoderState.getLastTag())); System.arraycopy(plcResidual, 0, decResidual, 0, decoderState.SIZE); orderPlusOne = 11; for (i = 0; i < decoderState.SUBFRAMES; i++) System.arraycopy(plcLpc, 0, syntDenum, i*orderPlusOne, orderPlusOne); } /* Find last lag (since the enhancer is not called to give this info) */ lag = 20; if (mode==20) lag = (short)(xCorrCoef(decResidual, decoderState.SIZE-60, decResidual, decoderState.SIZE-60-lag, (short)60, (short)80, lag, (short)-1)); else lag = (short)(xCorrCoef(decResidual, decoderState.SIZE-80, decResidual, decoderState.SIZE-80-lag, (short)80, (short)100, lag, (short)-1)); /* Store lag (it is needed if next packet is lost) */ decoderState.setLastTag((int)lag); /* copy data and run synthesis filter */ System.arraycopy(decResidual, 0, plcResidual, 10, decoderState.SIZE); /* Set up the filter state */ System.arraycopy(decoderState.getSynthMem(), 0, plcResidual, 0, 10); for (i=0; i < decoderState.SUBFRAMES; i++) BasicFunctions.filterAR(plcResidual,10+40*i,plcResidual,10+40*i,syntDenum,11*i,11,40); /* Save the filter state */ System.arraycopy(plcResidual, decoderState.SIZE, decoderState.getSynthMem(), 0, 10); System.arraycopy(plcResidual, 10, output, 0, decoderState.SIZE); /* High pass filter the signal (with upscaling a factor 2 and saturation) */ hpOutput(output,Constants.HP_OUT_COEFICIENTS,decoderState.getHpiMemY(),decoderState.getHpiMemX(),decoderState.SIZE); System.arraycopy(syntDenum, 0, decoderState.getOldSyntDenum(), 0, decoderState.SUBFRAMES*11); decoderState.setPrevEnchPl(0); if (mode==0) { /* PLC was used */ decoderState.setPrevEnchPl(1); } Frame res; if(decoderState.DECODER_MODE==20) { res = Memory.allocate(320); inputData=res.getData(); for (i = 0; i < 160; i++) { inputData[i*2] = (byte)((output[i]>>8)&0xFF); inputData[i*2 + 1] = (byte)(output[i] & 0xFF); } } else { res = Memory.allocate(480); inputData=res.getData(); for (i = 0; i < 240; i++) { inputData[i*2] = (byte)((output[i]>>8)&0xFF); inputData[i*2 + 1] = (byte)(output[i] & 0xFF); } } res.setOffset(0); res.setLength(res.getData().length); res.setTimestamp(frame.getTimestamp()); res.setDuration(frame.getDuration()); res.setSequenceNumber(frame.getSequenceNumber()); res.setEOM(frame.isEOM()); res.setFormat(linear); return res; } public Format getSupportedInputFormat() { return ilbc; } public Format getSupportedOutputFormat() { return linear; } private void doThePlc(short[] plcResidual,int plcResidualIndex,short[] plcLpc,int plcLpcIndex,short pli,short[] decResidual,int decResidualIndex,short[] lpc,int lpcIndex,short inLag) { short[] randVec=tempMemory;//+86 length 240 tempCorrData.setEnergy(0); /* Packet Loss */ if (pli == 1) { decoderState.setConsPliCount(decoderState.getConsPliCount()+1); /* if previous frame not lost, determine pitch pred. gain */ if (decoderState.getPrevPli() != 1) { /* Maximum 60 samples are correlated, preserve as high accuracy as possible without getting overflow */ max=BasicFunctions.getMaxAbsValue(decoderState.getPrevResidual(),0,decoderState.SIZE); scale3 = (short)((BasicFunctions.getSize(max)<<1) - 25); if (scale3 < 0) scale3 = 0; /* Store scale for use when interpolating between the * concealment and the received packet */ decoderState.setPrevScale(scale3); /* Search around the previous lag +/-3 to find the best pitch period */ lag = (short)(inLag - 3); /* Guard against getting outside the frame */ if(60 > decoderState.SIZE-inLag-3) corrLen=60; else corrLen=(short)(decoderState.SIZE-inLag-3); compCorr(corrData, decoderState.getPrevResidual(), 0, lag, decoderState.SIZE, corrLen, scale3); /* Normalize and store cross^2 and the number of shifts */ shiftMax = (short)(BasicFunctions.getSize(Math.abs(corrData.getCorrelation()))-15); if(shiftMax>0) { tempShift=corrData.getCorrelation()>>shiftMax; tempShift=tempShift*tempShift; crossSquareMax=(short)(tempShift>>15); } else { tempShift=corrData.getCorrelation()<<(0-shiftMax); tempShift=tempShift*tempShift; crossSquareMax=(short)(tempShift>>15); } for (j=inLag-2;j<=inLag+3;j++) { compCorr(tempCorrData, decoderState.getPrevResidual(), 0, (short)j, decoderState.SIZE, corrLen, scale3); /* Use the criteria (corr*corr)/energy to compare if this lag is better or not. To avoid the division, do a cross multiplication */ shift1 = (short)(BasicFunctions.getSize(Math.abs(tempCorrData.getCorrelation())-15)); if(shift1>0) { tempShift=tempCorrData.getCorrelation()>>shift1; tempShift=tempShift*tempShift; crossSquare=(short)(tempShift>>15); } else { tempShift=tempCorrData.getCorrelation()<<(0-shift1); tempShift=tempShift*tempShift; crossSquare=(short)(tempShift>>15); } shift2 = (short)(BasicFunctions.getSize(corrData.getEnergy())-15); if(shift2>0) measure=(corrData.getEnergy()>>shift2)*crossSquare; else measure=(corrData.getEnergy()<<(0-shift2))*crossSquare; shift3 = (short)(BasicFunctions.getSize(tempCorrData.getEnergy())-15); if(shift3>0) maxMeasure=(tempCorrData.getEnergy()>>shift3)*crossSquareMax; else maxMeasure=(tempCorrData.getEnergy()<<(0-shift3))*crossSquareMax; /* Calculate shift value, so that the two measures can be put in the same Q domain */ if(((shiftMax<<1)+shift3) > ((shift1<<1)+shift2)) { tempShift=(shiftMax<<1); tempShift-=(shift1<<1); tempShift=tempShift+shift3-shift2; if(tempShift>31) tempS = 31; else tempS= (short)tempShift; tempS2 = 0; } else { tempS = 0; tempShift=(shift1<<1); tempShift-=(shiftMax<<1); tempShift=tempShift+shift2-shift3; if(tempShift>31) tempS2 = 31; else tempS2=(short)tempShift; } if ((measure>>tempS) > (maxMeasure>>tempS2)) { /* New lag is better => record lag, measure and domain */ lag = (short)j; crossSquareMax = crossSquare; corrData.setCorrelation(tempCorrData.getCorrelation()); shiftMax = shift1; corrData.setEnergy(tempCorrData.getEnergy()); } } /* Calculate the periodicity for the lag with the maximum correlation. * Definition of the periodicity: abs(corr(vec1, vec2))/(sqrt(energy(vec1))*sqrt(energy(vec2))) Work in the Square domain to simplify the calculations max_perSquare is less than 1 (in Q15) */ BasicFunctions.scaleRight(decoderState.getPrevResidual(),decoderState.SIZE-corrLen,decoderState.getPrevResidual(),decoderState.SIZE-corrLen,corrLen, scale3); if ((temp2>0)&&(tempCorrData.getEnergy()>0)) { /* norm energies to WebRtc_Word16, compute the product of the energies and use the upper WebRtc_Word16 as the denominator */ scale1=(short)(BasicFunctions.norm(temp2)-16); if(scale1>0) tempS=(short)(temp2<<scale1); else tempS=(short)(temp2>>(0-scale1)); scale2=(short)(BasicFunctions.norm(corrData.getEnergy())-16); if(scale2>0) tempS2=(short)(corrData.getEnergy()<<scale2); else tempS2=(short)(corrData.getEnergy()>>(0-scale2)); denom=(short)((tempS*tempS2)>>16); /* denom in Q(scale1+scale2-16) */ /* Square the cross correlation and norm it such that max_perSquare will be in Q15 after the division */ totScale = (short)(scale1+scale2-1); tempShift=(totScale>>1); if(tempShift>0) tempS = (short)(corrData.getCorrelation()<<tempShift); else tempS = (short)(corrData.getCorrelation()>>(0-tempShift)); tempShift=totScale-tempShift; if(tempShift>0) tempS2 = (short)(corrData.getCorrelation()<<tempShift); else tempS2 = (short)(corrData.getCorrelation()>>(0-tempShift)); nom = (short)(tempS*tempS2); maxPerSquare = (short)(nom/denom); } else { maxPerSquare = 0; } } else { /* previous frame lost, use recorded lag and gain */ lag = decoderState.getPrevLag(); maxPerSquare = decoderState.getPerSquare(); } /* Attenuate signal and scale down pitch pred gain if several frames lost consecutively */ useGain = 32767; /* 1.0 in Q15 */ if (decoderState.getConsPliCount()*decoderState.SIZE>320) { useGain = 29491; /* 0.9 in Q15 */ } else if (decoderState.getConsPliCount()*decoderState.SIZE>640) { useGain = 22938; /* 0.7 in Q15 */ } else if (decoderState.getConsPliCount()*decoderState.SIZE>960) { useGain = 16384; /* 0.5 in Q15 */ } else if (decoderState.getConsPliCount()*decoderState.SIZE>1280) { useGain = 0; /* 0.0 in Q15 */ } /* Compute mixing factor of picth repeatition and noise: for max_per>0.7 set periodicity to 1.0 0.4<max_per<0.7 set periodicity to (maxper-0.4)/0.7-0.4) max_per<0.4 set periodicity to 0.0 */ if (maxPerSquare>7868) { /* periodicity > 0.7 (0.7^4=0.2401 in Q15) */ pitchFact = 32767; } else if (maxPerSquare>839) { /* 0.4 < periodicity < 0.7 (0.4^4=0.0256 in Q15) */ /* find best index and interpolate from that */ ind = 5; while ((maxPerSquare<Constants.PLC_PER_SQR[ind]) && (ind>0)) ind--; /* pitch fact is approximated by first order */ temp = Constants.PLC_PITCH_FACT[ind]; temp += ((Constants.PLC_PF_SLOPE[ind]*(maxPerSquare-Constants.PLC_PER_SQR[ind])) >> 11); if(temp>Short.MIN_VALUE) pitchFact=Short.MIN_VALUE; else pitchFact=(short)temp; } else { /* periodicity < 0.4 */ pitchFact = 0; } /* avoid repetition of same pitch cycle (buzzyness) */ useLag = lag; if (lag<80) useLag = (short)(2*lag); /* compute concealed residual */ energy = 0; for (i=0; i<decoderState.SIZE; i++) { /* noise component - 52 < randlagFIX < 117 */ decoderState.setSeed((short)((decoderState.getSeed()*31821) + 13849)); randLag = (short)(53 + (decoderState.getSeed() & 63)); pick = (short)(i - randLag); if (pick < 0) randVec[86+i] = decoderState.getPrevResidual()[decoderState.SIZE+pick]; else randVec[86+i] = decoderState.getPrevResidual()[pick]; /* pitch repeatition component */ pick = (short)(i - useLag); if (pick < 0) plcResidual[plcResidualIndex + i] = decoderState.getPrevResidual()[decoderState.SIZE+pick]; else plcResidual[plcResidualIndex + i] = plcResidual[plcResidualIndex + pick]; /* Attinuate total gain for each 10 ms */ if (i<80) totGain=useGain; else if (i<160) totGain=(short)((31130 * useGain) >> 15); /* 0.95*use_gain */ else totGain=(short)((29491 * useGain) >> 15); /* 0.9*use_gain */ /* mix noise and pitch repeatition */ tempShift=pitchFact * plcResidual[plcResidualIndex + i]; tempShift+=(32767-pitchFact)*randVec[86+i]; tempShift+=16384; temp=(short)(tempShift>>15); plcResidual[plcResidualIndex + i] = (short)((totGain*temp)>>15); /* Shifting down the result one step extra to ensure that no overflow will occur */ tempShift=plcResidual[plcResidualIndex + i] * plcResidual[plcResidualIndex + i]; energy += (short)(tempShift>>(decoderState.getPrevScale()+1)); } /* less than 30 dB, use only noise */ tempShift=decoderState.SIZE*900; if(decoderState.getPrevScale()+1>0) tempShift=tempShift>>(decoderState.getPrevScale()+1); else tempShift=tempShift<<(0-decoderState.getPrevScale()-1); if (energy < tempShift) { energy = 0; for (i=0; i<decoderState.SIZE; i++) plcResidual[plcResidualIndex + i] = randVec[86 + i]; } /* use the old LPC */ System.arraycopy(decoderState.getPrevLpc(), 0, plcLpc, plcLpcIndex, 10); /* Update state in case there are multiple frame losses */ decoderState.setPrevLag(lag); decoderState.setPerSquare(maxPerSquare); } else { /* no packet loss, copy input */ System.arraycopy(decResidual, decResidualIndex, plcResidual, plcResidualIndex, decoderState.SIZE); System.arraycopy(lpc, lpcIndex, plcLpc, plcLpcIndex, 11); decoderState.setConsPliCount(0); } /* update state */ decoderState.setPrevPli(pli); System.arraycopy(plcLpc, plcLpcIndex, decoderState.getPrevLpc(), 0, 11); System.arraycopy(plcResidual, plcResidualIndex, decoderState.getPrevResidual(), 0, decoderState.SIZE); } private void compCorr(CorrData currData,short[] buffer,int bufferIndex,short lag,short bLen,short sRange,short scale) { tempIndex7=bLen-sRange-lag; /* Calculate correlation and energy */ if(scale>0) { currData.setCorrelation(BasicFunctions.scaleRight(buffer, bufferIndex + bLen - sRange, buffer, tempIndex7, sRange, scale)); currData.setEnergy(BasicFunctions.scaleRight(buffer, tempIndex7, buffer, tempIndex7, sRange, scale)); } else { currData.setCorrelation(BasicFunctions.scaleLeft(buffer, bufferIndex + bLen - sRange, buffer, tempIndex7, sRange, (0-scale))); currData.setEnergy(BasicFunctions.scaleLeft(buffer, tempIndex7, buffer, tempIndex7, sRange, scale)); } /* For zero energy set the energy to 0 in order to avoid potential problems for coming divisions */ if (currData.getCorrelation() == 0) { currData.setCorrelation(0); currData.setEnergy(1); } } private void hpOutput(short[] signal,short[] ba,short[] y,short[] x,short len) { for (i=0; i<len; i++) { /* y[i] = b[0]*x[i] + b[1]*x[i-1] + b[2]*x[i-2] + (-a[1])*y[i-1] + (-a[2])*y[i-2]; */ temp = y[1]*ba[3]; /* (-a[1])*y[i-1] (low part) */ temp += y[3]*ba[4]; /* (-a[2])*y[i-2] (low part) */ temp = temp>>15; temp += y[0]*ba[3]; /* (-a[1])*y[i-1] (high part) */ temp += y[2]*ba[4]; /* (-a[2])*y[i-2] (high part) */ temp = temp<<1; temp += signal[i]*ba[0]; /* b[0]*x[0] */ temp += x[0]*ba[1]; /* b[1]*x[i-1] */ temp += x[1]*ba[2]; /* b[2]*x[i-2] */ /* Update state (input part) */ x[1] = x[0]; x[0] = signal[i]; /* Rounding in Q(12-1), i.e. add 2^10 */ temp2 = temp + 1024; /* Saturate (to 2^26) so that the HP filtered signal does not overflow */ if(temp2>67108863) temp2=67108863; else if(temp2<-67108864) temp2=-67108864; /* Convert back to Q0 and multiply with 2 */ signal[i] = (short)(temp2>>11); /* Update state (filtered part) */ y[2] = y[0]; y[3] = y[1]; /* upshift tmpW32 by 3 with saturation */ if (temp>268435455) temp = Integer.MAX_VALUE; else if (temp<-268435456) temp = Integer.MIN_VALUE; else temp = temp<<3; y[0] = (short)(temp>>16); tempShift = y[0]<<16; y[1] = (short)((temp - tempShift)>>1); } } private int xCorrCoef(short[] target,int targetIndex,short[] regressor,int regressorIndex,short subl,short searchLen,short offset,short step) { /* Initializations, to make sure that the first one is selected */ crossCorrSqModMax=0; energyModMax=Short.MAX_VALUE; totScaleMax=-500; maxLag=0; pos=0; /* Find scale value and start position */ if (step==1) { max=BasicFunctions.getMaxAbsValue(regressor,regressorIndex,subl+searchLen-1); tempIndex1=regressorIndex; tempIndex2=regressorIndex + subl; } else { /* step==-1 */ max=BasicFunctions.getMaxAbsValue(regressor,regressorIndex-searchLen,subl+searchLen-1); tempIndex1=regressorIndex-1; tempIndex2=regressorIndex + subl-1; } /* Introduce a scale factor on the Energy in WebRtc_Word32 in order to make sure that the calculation does not overflow */ if (max>5000) shifts=2; else shifts=0; /* Calculate the first energy, then do a +/- to get the other energies */ energy=BasicFunctions.scaleRight(regressor, regressorIndex, regressor, regressorIndex, subl, shifts); for (k=0;k<searchLen;k++) { tempIndex3=targetIndex; tempIndex4=regressorIndex + pos; crossCorr=BasicFunctions.scaleRight(target, tempIndex3, regressor, tempIndex4, subl, shifts); if ((energy>0)&&(crossCorr>0)) { /* Put cross correlation and energy on 16 bit word */ crossCorrScale=(short)(BasicFunctions.norm(crossCorr)-16); if(crossCorrScale>0) crossCorrMod=(short)(crossCorr<<crossCorrScale); else crossCorrMod=(short)(crossCorr>>(0-crossCorrScale)); energyScale=(short)(BasicFunctions.norm(energy)-16); if(energyScale>0) energyMod=(short)(energy<<energyScale); else energyMod=(short)(energy>>(0-energyScale)); /* Square cross correlation and store upper WebRtc_Word16 */ crossCorrSqMod=(short)((crossCorrMod * crossCorrMod) >> 16); /* Calculate the total number of (dynamic) right shifts that have been performed on (crossCorr*crossCorr)/energy */ totScale=(short)(energyScale-(crossCorrScale<<1)); /* Calculate the shift difference in order to be able to compare the two (crossCorr*crossCorr)/energy in the same domain */ scaleDiff=(short)(totScale-totScaleMax); if(scaleDiff>31) scaleDiff=31; else if(scaleDiff<-31) scaleDiff=-31; /* Compute the cross multiplication between the old best criteria and the new one to be able to compare them without using a division */ if (scaleDiff<0) { newCrit = ((crossCorrSqMod*energyModMax)>>(-scaleDiff)); maxCrit = crossCorrSqModMax*energyMod; } else { newCrit = crossCorrSqMod*energyModMax; maxCrit = ((crossCorrSqModMax*energyMod)>>scaleDiff); } /* Store the new lag value if the new criteria is larger than previous largest criteria */ if (newCrit > maxCrit) { crossCorrSqModMax = crossCorrSqMod; energyModMax = energyMod; totScaleMax = totScale; maxLag = (short)k; } } pos+=step; /* Do a +/- to get the next energy */ temp=regressor[tempIndex2]*regressor[tempIndex2] - regressor[tempIndex1]*regressor[tempIndex1]; temp>>=shifts; energy += step*temp; tempIndex1+=step; tempIndex2+=step; } return(maxLag+offset); } private void decodeResidual(short[] decResidual,int decResidualIndex,short[] syntDenum,int syntDenumIndex) { short[] reverseDecresidual = decoderState.getEnhancementBuffer(); short[] memVec = decoderState.getPrevResidual(); diff = (short)(80 - decoderState.STATE_SHORT_LEN); if (encoderBits.getStateFirst()) startPos = (short)((encoderBits.getStartIdx()-1)*40); else startPos = (short)((encoderBits.getStartIdx()-1)*40 + diff); /* decode scalar part of start state */ stateConstruct(syntDenum,syntDenumIndex + (encoderBits.getStartIdx()-1)*11,decResidual,decResidualIndex + startPos); if(encoderBits.getStateFirst()) { /* put adaptive part in the end */ /* setup memory */ for(i=4;i<151-decoderState.STATE_SHORT_LEN;i++) memVec[i]=0; System.arraycopy(decResidual, startPos, memVec, 151-decoderState.STATE_SHORT_LEN, decoderState.STATE_SHORT_LEN); /* construct decoded vector */ cbConstruct(decResidual,decResidualIndex + startPos + decoderState.STATE_SHORT_LEN, memVec,66, (short)85, diff, 0, 0); } else { /* put adaptive part in the beginning */ /* create reversed vectors for prediction */ BasicFunctions.reverseCopy(reverseDecresidual, diff, decResidual, decResidualIndex + (encoderBits.getStartIdx()+1)*40-80,diff); /* setup memory */ memlGotten = decoderState.STATE_SHORT_LEN; BasicFunctions.reverseCopy(memVec, 150, decResidual, decResidualIndex + startPos, memlGotten); for(i=4;i<151-memlGotten;i++) memVec[i]=0; /* construct decoded vector */ cbConstruct(reverseDecresidual, 0, memVec, 66, (short)85, diff, 0, 0); /* get decoded residual from reversed vector */ BasicFunctions.reverseCopy(decResidual, decResidualIndex + startPos-1, reverseDecresidual, 0, diff); } /* counter for predicted subframes */ subCount=1; /* forward prediction of subframes */ nFor = (short)(decoderState.SUBFRAMES - encoderBits.getStartIdx() -1); if(nFor > 0) { /* setup memory */ for(i=4;i<71;i++) memVec[i]=0; System.arraycopy(decResidual, decResidualIndex + 40 * (encoderBits.getStartIdx()-1), memVec, 71, 80); /* loop over subframes to encode */ for (subFrame=0; subFrame<nFor; subFrame++) { /* construct decoded vector */ cbConstruct(decResidual, decResidualIndex + 40*(encoderBits.getStartIdx()+1+subFrame), memVec, 4, (short)147, (short)40, subCount*3, subCount*3); /* update memory */ for(i=4;i<111;i++) memVec[i]=memVec[i+40]; System.arraycopy(reverseDecresidual, 40 * (encoderBits.getStartIdx()+1+subFrame) , memVec, 111, 40); subCount++; } } /* backward prediction of subframes */ nBack = (short)(encoderBits.getStartIdx()-1); if(nBack > 0) { /* setup memory */ memlGotten = (short)(40*(decoderState.SUBFRAMES + 1 - encoderBits.getStartIdx())); if(memlGotten > 147) memlGotten=147; BasicFunctions.reverseCopy(memVec, 150, decResidual, decResidualIndex + 40 * (encoderBits.getStartIdx()-1), memlGotten); for(i=4;i<151-memlGotten;i++) memVec[i]=0; /* loop over subframes to decode */ for (subFrame=0; subFrame<nBack; subFrame++) { /* construct decoded vector */ cbConstruct(reverseDecresidual, 40*subFrame, memVec, 4, (short)147, (short)40, subCount*3, subCount*3); /* update memory */ for(i=4;i<111;i++) memVec[i]=memVec[i+40]; System.arraycopy(reverseDecresidual, 40 * subFrame, memVec, 111, 40); subCount++; } /* get decoded residual from reversed vector */ BasicFunctions.reverseCopy(decResidual, decResidualIndex+40*nBack-1, reverseDecresidual, 0, 40*nBack); } } private void lsf2Poly(short[] a,int aIndex,short[] lsf,int lsfIndex) { /* f[0][] and f[1][] corresponds to F1(z) and F2(z) respectivly */ int[] f=tempLMemory; //+ 0 length 12 tempIndex3=0; tempIndex4=6; /* Stack based */ short[] lsp=tempMemory; //+ 61 length 10 /* Convert lsf to lsp */ lsf2Lsp(lsf, lsfIndex, lsp, 61, 10); /* Get F1(z) and F2(z) from the lsp */ getLspPoly(lsp, 61, f, 0); getLspPoly(lsp, 62, f, 6); /* for i = 5 down to 1 Compute f1[i] += f1[i-1]; and f2[i] += f2[i-1]; */ tempIndex3=5; tempIndex4=11; for (k=5; k>0; k--) { f[tempIndex3]+=f[tempIndex3-1]; f[tempIndex4]-=f[tempIndex4-1]; tempIndex3--; tempIndex4--; } /* Get the A(z) coefficients a[0] = 1.0 for i = 1 to 5 a[i] = (f1[i] + f2[i] + round)>>13; for i = 1 to 5 a[11-i] = (f1[i] - f2[i] + round)>>13; */ a[aIndex]=4096; tempIndex5=aIndex+1; tempIndex6=aIndex+10; tempIndex3=1; tempIndex4=7; for (k=5; k>0; k--) { temp2 = f[tempIndex3] + f[tempIndex4]; a[tempIndex5++] = (short)((temp2+4096)>>13); temp2 = f[tempIndex3] - f[tempIndex4]; tempIndex3++; tempIndex4++; a[tempIndex6--] = (short)((temp2+4096)>>13); } } private void getLspPoly(short[] lsp,int lspIndex,int[] f,int fIndex) { tempIndex5=lspIndex; tempIndex6=fIndex; /* f[0] = 1.0 (Q24) */ f[tempIndex6++]=16777216; f[tempIndex6++] = lsp[tempIndex5]*(-1024); tempIndex5+=2; for(k=2; k<=5; k++) { f[tempIndex6]=f[tempIndex6-2]; for(j=k; j>1; j--) { /* Compute f[j] = f[j] + tmp*f[j-1] + f[j-2]; */ xHi = (short)(f[tempIndex6-1]>>16); tempShift=xHi<<16; xLow = (short)((f[tempIndex6-1]-tempShift)>>1); tempShift=(xHi*lsp[tempIndex5])<<2; temp2=tempShift; tempShift=((xLow*lsp[tempIndex5])>>15)<<2; temp2 += tempShift; f[tempIndex6] += f[tempIndex6-2]; f[tempIndex6--] -= temp2; } f[tempIndex6] -= lsp[tempIndex5]<< 10; tempIndex6+=k; tempIndex5+=2; } } private void interpolate(short[] out,int outIndex,short[] in1,int in1Index,short[] in2,int in2Index,short coef,int length) { tempIndex3=outIndex; tempIndex4=in1Index; tempIndex5=in2Index; /* Performs the operation out[i] = in[i]*coef + (1-coef)*in2[i] (with rounding) */ tempS = (short)(16384 - coef); /* 16384 = 1.0 (Q14)*/ for (k = 0; k < length; k++) out[tempIndex3++] = (short) ((coef*in1[tempIndex4++] + tempS*in2[tempIndex5++]+8192)>>14); } private void lsf2Lsp(short[] lsf,int lsfIndex,short[] lsp,int lspIndex,int count) { tempIndex6=lspIndex; for(j=0; j<count; j++) { tempS = (short)((lsf[lsfIndex++]*20861)>>15); /* 20861: 1.0/(2.0*PI) in Q17 */ /* Upper 8 bits give the index k and Lower 8 bits give the difference, which needs to be approximated linearly */ tempS2 = (short)(tempS>>8); tempS = (short)(tempS & 0x00ff); /* Guard against getting outside table */ if (tempS2>63 || tempS2<0) tempS2 = 63; /* Calculate linear approximation */ temp2 = Constants.COS_DERIVATIVE[tempS2]*tempS; temp2>>=12; lsp[lspIndex++] = (short)(temp2 + Constants.COS[tempS2]); } } private void decoderInterpolateLsp(short[] syntDenum,int syntDenumIndex,short[] weightDenum,int weightDenumIndex,short[] lsfDeq,int lsfDeqIndex,short length) { short[] lp=tempMemory;//+86 length 11 tempIndex2 = lsfDeqIndex + length; len = length + 1; if (decoderState.DECODER_MODE==30) { /* subframe 1: Interpolation between old and first LSF */ lspInterpolate2PolyDec(lp, 86, decoderState.getLsfDeqOld(), 0, lsfDeq, lsfDeqIndex,Constants.LSF_WEIGHT_30MS[0], length); System.arraycopy(lp, 86, syntDenum, syntDenumIndex, len); BasicFunctions.expand(weightDenum, weightDenumIndex, lp, 86, Constants.LPC_CHIRP_SYNT_DENUM, len); /* subframes 2 to 6: interpolation between first and last LSF */ tempIndex1 = len; for (s = 1; s < 6; s++) { lspInterpolate2PolyDec(lp, 86, lsfDeq, lsfDeqIndex, lsfDeq, tempIndex2,Constants.LSF_WEIGHT_30MS[i], length); System.arraycopy(lp, 86, syntDenum, syntDenumIndex + tempIndex1, len); BasicFunctions.expand(weightDenum,weightDenumIndex + tempIndex1, lp, 86, Constants.LPC_CHIRP_SYNT_DENUM, len); tempIndex1 += len; } } else { /* iLBCdec_inst->mode=20 */ /* subframes 1 to 4: interpolation between old and new LSF */ tempIndex1 = 0; for (s = 0; s < decoderState.SUBFRAMES; s++) { lspInterpolate2PolyDec(lp, 86, decoderState.getLsfDeqOld(), 0, lsfDeq, lsfDeqIndex,Constants.LSF_WEIGHT_20MS[i], length); System.arraycopy(lp, 86, syntDenum, syntDenumIndex + tempIndex1, len); BasicFunctions.expand(weightDenum, weightDenumIndex+tempIndex1, lp, 86, Constants.LPC_CHIRP_SYNT_DENUM, len); tempIndex1 += len; } } /* update memory */ if (decoderState.DECODER_MODE==30) System.arraycopy(lsfDeq, tempIndex2, decoderState.getLsfDeqOld(), 0, length); else System.arraycopy(lsfDeq, lsfDeqIndex, decoderState.getLsfDeqOld(), 0, length); } private void simpleLsfDeq(short[] lsfDeq,int lsfDeqIndex,short[] index,int indexIndex) { for (i = 0; i < 3; i++) { tempIndex2 = Constants.LSF_INDEX_CB[i]; for (j = 0; j < Constants.LSF_DIM_CB[i]; j++) lsfDeq[lsfDeqIndex++] = Constants.LSF_CB[tempIndex2 + (index[indexIndex]*Constants.LSF_DIM_CB[i]) + j]; indexIndex++; } if (decoderState.LPC_N>1) { /* decode last LSF */ tempIndex3 = 3+indexIndex; for (i = 0; i < 3; i++) { tempIndex2 = Constants.LSF_INDEX_CB[i]; for (j = 0; j < Constants.LSF_DIM_CB[i]; j++) lsfDeq[lsfDeqIndex++] = Constants.LSF_CB[tempIndex2 + index[indexIndex] * Constants.LSF_DIM_CB[i] + j]; indexIndex++; } } } private void lspInterpolate2PolyDec(short[] a,int aIndex, short[] lsf1,int lsf1Index, short[] lsf2,int lsf2Index, short coef,int length) { short[] lsfTemp=tempMemory;//+97 length 10 /* interpolate LSF */ interpolate(lsfTemp, 97, lsf1, lsf1Index, lsf2, lsf2Index, coef, length); /* Compute the filter coefficients from the LSF */ lsf2Poly(a,aIndex,lsfTemp,97); } private void lsfCheck(short[] lsf,int lsfIndex,int lsfSize) { /* LSF separation check*/ for (n=0;n<2;n++) { /* Run through a 2 times */ for (j=0;j<decoderState.LPC_N;j++) { /* Number of analyses per frame */ for (k=0;k<lsfSize-1;k++) { tempIndex1=lsfIndex + j*lsfSize+k; tempIndex2=tempIndex1+1; /* Seperate coefficients with a safety margin of 50 Hz */ if ((lsf[tempIndex2]-lsf[tempIndex1])<Constants.EPS) { if (lsf[tempIndex2]<lsf[tempIndex1]) { lsf[tempIndex2]= (short)(lsf[tempIndex1]+Constants.HALF_EPS); lsf[tempIndex1]= (short)(lsf[tempIndex2]-Constants.HALF_EPS); } else { lsf[tempIndex1]-=Constants.HALF_EPS; lsf[tempIndex2]+=Constants.HALF_EPS; } } /* Limit minimum and maximum LSF */ if (lsf[tempIndex1]<Constants.MIN_LSF) lsf[tempIndex1]=Constants.MIN_LSF; if (lsf[tempIndex1]>Constants.MAX_LSF) lsf[tempIndex1]=Constants.MAX_LSF; } } } } private void updateDecIndex() { short[] index=encoderBits.getCbIndex(); for (k=4;k<6;k++) { /* Readjust the second and third codebook index for the first 40 sample so that they look the same as the first (in terms of lag) */ if (index[k]>=44 && index[k]<108) index[k]+=64; else if (index[k]>=108 && index[k]<128) index[k]+=128; } } private void unpackBits(short[] data,int mode) { short[] lsf=encoderBits.getLSF(); short[] cbIndex=encoderBits.getCbIndex(); short[] gainIndex=encoderBits.getGainIndex(); short[] idxVec=encoderBits.getIdxVec(); tempIndex1=0; /* First WebRtc_Word16 */ lsf[0] = (short)((data[tempIndex1]>>10) & 0x3F); /* Bit 0..5 */ lsf[1] = (short)((data[tempIndex1]>>3)&0x7F); /* Bit 6..12 */ lsf[2] = (short)((data[tempIndex1]&0x7)<<4); /* Bit 13..15 */ tempIndex1++; /* Second WebRtc_Word16 */ lsf[2] |= (data[tempIndex1]>>12)&0xF; /* Bit 0..3 */ if (mode==20) { encoderBits.setStartIdx((short)((data[tempIndex1]>>10)&0x3)); /* Bit 4..5 */ encoderBits.setStateFirst(false); if(((data[tempIndex1]>>9)&0x1)!=0) encoderBits.setStateFirst(true); /* Bit 6 */ encoderBits.setIdxForMax((short)((data[tempIndex1]>>3)&0x3F)); /* Bit 7..12 */ cbIndex[0] = (short)((data[tempIndex1]&0x7)<<4); /* Bit 13..15 */ tempIndex1++; /* Third WebRtc_Word16 */ cbIndex[0] |= (data[tempIndex1]>>12)&0xE; /* Bit 0..2 */ gainIndex[0] = (short)((data[tempIndex1]>>8)&0x18); /* Bit 3..4 */ gainIndex[1] = (short)((data[tempIndex1]>>7)&0x8); /* Bit 5 */ cbIndex[3] = (short)((data[tempIndex1]>>2)&0xFE); /* Bit 6..12 */ gainIndex[3] = (short)((data[tempIndex1]<<2)&0x10); /* Bit 13 */ gainIndex[4] = (short)((data[tempIndex1]<<2)&0x8); /* Bit 14 */ gainIndex[6] = (short)((data[tempIndex1]<<4)&0x10); /* Bit 15 */ } else { /* mode==30 */ lsf[3] = (short)((data[tempIndex1]>>6)&0x3F); /* Bit 4..9 */ lsf[4] = (short)((data[tempIndex1]<<1)&0x7E); /* Bit 10..15 */ tempIndex1++; /* Third WebRtc_Word16 */ lsf[4] |= (data[tempIndex1]>>15)&0x1; /* Bit 0 */ lsf[5] = (short)((data[tempIndex1]>>8)&0x7F); /* Bit 1..7 */ encoderBits.setStartIdx((short)((data[tempIndex1]>>5)&0x7)); /* Bit 8..10 */ encoderBits.setStateFirst(false); if((short)((data[tempIndex1]>>4)&0x1)!=0) encoderBits.setStateFirst(true);/* Bit 11 */ tempS=(short)((data[tempIndex1]<<2)&0x3C);/* Bit 12..15 */ tempIndex1++; /* 4:th WebRtc_Word16 */ tempS |= (data[tempIndex1]>>14)&0x3; /* Bit 0..1 */ encoderBits.setIdxForMax(tempS); cbIndex[0] = (short)((data[tempIndex1]>>7)&0x78); /* Bit 2..5 */ gainIndex[0] = (short)((data[tempIndex1]>>5)&0x10); /* Bit 6 */ gainIndex[1] = (short)((data[tempIndex1]>>5)&0x8); /* Bit 7 */ cbIndex[3] = (short)((data[tempIndex1])&0xFC); /* Bit 8..13 */ gainIndex[3] = (short)((data[tempIndex1]<<3)&0x10); /* Bit 14 */ gainIndex[4] = (short)((data[tempIndex1]<<3)&0x8); /* Bit 15 */ } /* Class 2 bits of ULP */ /* 4:th to 6:th WebRtc_Word16 for 20 ms case 5:th to 7:th WebRtc_Word16 for 30 ms case */ tempIndex1++; tempIndex2=0; for (k=0; k<3; k++) { for (i=15; i>=0; i--) idxVec[tempIndex2++] = (short)(((data[tempIndex1]>>i)<<2)&0x4);/* Bit 15-i */ tempIndex1++; } if (mode==20) { /* 7:th WebRtc_Word16 */ for (i=15; i>6; i--) idxVec[tempIndex2++] = (short)(((data[tempIndex1]>>i)<<2)&0x4); /* Bit 15-i */ gainIndex[1] |= (data[tempIndex1]>>4)&0x4; /* Bit 9 */ gainIndex[3] |= (data[tempIndex1]>>2)&0xC; /* Bit 10..11 */ gainIndex[4] |= (data[tempIndex1]>>1)&0x4; /* Bit 12 */ gainIndex[6] |= (data[tempIndex1]<<1)&0x8; /* Bit 13 */ gainIndex[7] = (short)((data[tempIndex1]<<2)&0xC); /* Bit 14..15 */ } else { /* mode==30 */ /* 8:th WebRtc_Word16 */ for (i=15; i>5; i--) idxVec[tempIndex2++] = (short)(((data[tempIndex1]>>i)<<2)&0x4);/* Bit 15-i */ cbIndex[0] |= (data[tempIndex1]>>3)&0x6; /* Bit 10..11 */ gainIndex[0] |= (data[tempIndex1])&0x8; /* Bit 12 */ gainIndex[1] |= (data[tempIndex1])&0x4; /* Bit 13 */ cbIndex[3] |= (data[tempIndex1])&0x2; /* Bit 14 */ cbIndex[6] = (short)((data[tempIndex1]<<7)&0x80); /* Bit 15 */ tempIndex1++; /* 9:th WebRtc_Word16 */ cbIndex[6] |= (data[tempIndex1]>>9)&0x7E; /* Bit 0..5 */ cbIndex[9] = (short)((data[tempIndex1]>>2)&0xFE); /* Bit 6..12 */ cbIndex[12] = (short)((data[tempIndex1]<<5)&0xE0); /* Bit 13..15 */ tempIndex1++; /* 10:th WebRtc_Word16 */ cbIndex[12] |= (data[tempIndex1]>>11)&0x1E;/* Bit 0..3 */ gainIndex[3] |= (data[tempIndex1]>>8)&0xC; /* Bit 4..5 */ gainIndex[4] |= (data[tempIndex1]>>7)&0x6; /* Bit 6..7 */ gainIndex[6] = (short)((data[tempIndex1]>>3)&0x18); /* Bit 8..9 */ gainIndex[7] = (short)((data[tempIndex1]>>2)&0xC); /* Bit 10..11 */ gainIndex[9] = (short)((data[tempIndex1]<<1)&0x10); /* Bit 12 */ gainIndex[10] = (short)((data[tempIndex1]<<1)&0x8); /* Bit 13 */ gainIndex[12] = (short)((data[tempIndex1]<<3)&0x10); /* Bit 14 */ gainIndex[13] = (short)((data[tempIndex1]<<3)&0x8); /* Bit 15 */ } tempIndex1++; /* Class 3 bits of ULP */ /* 8:th to 14:th WebRtc_Word16 for 20 ms case 11:th to 17:th WebRtc_Word16 for 30 ms case */ tempIndex2=0; for (k=0; k<7; k++) { for (i=14; i>=0; i-=2) idxVec[tempIndex2++] |= (data[tempIndex1]>>i)&0x3; /* Bit 15-i..14-i*/ tempIndex1++; } if (mode==20) { /* 15:th WebRtc_Word16 */ idxVec[56] |= (data[tempIndex1]>>14)&0x3; /* Bit 0..1 */ cbIndex[0] |= (data[tempIndex1]>>13)&0x1; /* Bit 2 */ cbIndex[1] = (short)((data[tempIndex1]>>6)&0x7F); /* Bit 3..9 */ cbIndex[2] = (short)((data[tempIndex1]<<1)&0x7E); /* Bit 10..15 */ tempIndex1++; /* 16:th WebRtc_Word16 */ cbIndex[2] |= (data[tempIndex1]>>15)&0x1; /* Bit 0 */ gainIndex[0] |= (data[tempIndex1]>>12)&0x7; /* Bit 1..3 */ gainIndex[1] |= (data[tempIndex1]>>10)&0x3; /* Bit 4..5 */ gainIndex[2] = (short)((data[tempIndex1]>>7)&0x7); /* Bit 6..8 */ cbIndex[3] |= (data[tempIndex1]>>6)&0x1; /* Bit 9 */ cbIndex[4] = (short)((data[tempIndex1]<<1)&0x7E); /* Bit 10..15 */ tempIndex1++; /* 17:th WebRtc_Word16 */ cbIndex[4] |= (data[tempIndex1]>>15)&0x1; /* Bit 0 */ cbIndex[5] = (short)((data[tempIndex1]>>8)&0x7F); /* Bit 1..7 */ cbIndex[6] = (short)((data[tempIndex1])&0xFF); /* Bit 8..15 */ tempIndex1++; /* 18:th WebRtc_Word16 */ cbIndex[7] = (short)((data[tempIndex1]>>8) & 0xFF); /* Bit 0..7 */ cbIndex[8] = (short)(data[tempIndex1]&0xFF); /* Bit 8..15 */ tempIndex1++; /* 19:th WebRtc_Word16 */ gainIndex[3] |= (data[tempIndex1]>>14)&0x3; /* Bit 0..1 */ gainIndex[4] |= (data[tempIndex1]>>12)&0x3; /* Bit 2..3 */ gainIndex[5] = (short)((data[tempIndex1]>>9)&0x7); /* Bit 4..6 */ gainIndex[6] |= (data[tempIndex1]>>6)&0x7; /* Bit 7..9 */ gainIndex[7] |= (data[tempIndex1]>>4)&0x3; /* Bit 10..11 */ gainIndex[8] = (short)((data[tempIndex1]>>1)&0x7); /* Bit 12..14 */ } else { /* mode==30 */ /* 18:th WebRtc_Word16 */ idxVec[56] |= (data[tempIndex1]>>14)&0x3; /* Bit 0..1 */ idxVec[57] |= (data[tempIndex1]>>12)&0x3; /* Bit 2..3 */ cbIndex[0] |= (data[tempIndex1]>>11)&1; /* Bit 4 */ cbIndex[1] = (short)((data[tempIndex1]>>4)&0x7F); /* Bit 5..11 */ cbIndex[2] = (short)((data[tempIndex1]<<3)&0x78); /* Bit 12..15 */ tempIndex1++; /* 19:th WebRtc_Word16 */ cbIndex[2] |= (data[tempIndex1]>>13)&0x7; /* Bit 0..2 */ gainIndex[0] |= (data[tempIndex1]>>10)&0x7; /* Bit 3..5 */ gainIndex[1] |= (data[tempIndex1]>>8)&0x3; /* Bit 6..7 */ gainIndex[2] = (short)((data[tempIndex1]>>5)&0x7); /* Bit 8..10 */ cbIndex[3] |= (data[tempIndex1]>>4)&0x1; /* Bit 11 */ cbIndex[4] = (short)((data[tempIndex1]<<3)&0x78); /* Bit 12..15 */ tempIndex1++; /* 20:th WebRtc_Word16 */ cbIndex[4] |= (data[tempIndex1]>>13)&0x7; /* Bit 0..2 */ cbIndex[5] = (short)((data[tempIndex1]>>6)&0x7F); /* Bit 3..9 */ cbIndex[6] |= (data[tempIndex1]>>5)&0x1; /* Bit 10 */ cbIndex[7] = (short)((data[tempIndex1]<<3)&0xF8); /* Bit 11..15 */ tempIndex1++; /* 21:st WebRtc_Word16 */ cbIndex[7] |= (data[tempIndex1]>>13)&0x7; /* Bit 0..2 */ cbIndex[8] = (short)((data[tempIndex1]>>5)&0xFF); /* Bit 3..10 */ cbIndex[9] |= (data[tempIndex1]>>4)&0x1; /* Bit 11 */ cbIndex[10] = (short)((data[tempIndex1]<<4)&0xF0); /* Bit 12..15 */ tempIndex1++; /* 22:nd WebRtc_Word16 */ cbIndex[10] |= (data[tempIndex1]>>12)&0xF; /* Bit 0..3 */ cbIndex[11] = (short)((data[tempIndex1]>>4)&0xFF); /* Bit 4..11 */ cbIndex[12] |= (data[tempIndex1]>>3)&0x1; /* Bit 12 */ cbIndex[13] = (short)((data[tempIndex1]<<5)&0xE0); /* Bit 13..15 */ tempIndex1++; /* 23:rd WebRtc_Word16 */ cbIndex[13] |= (data[tempIndex1]>>11)&0x1F;/* Bit 0..4 */ cbIndex[14] = (short)((data[tempIndex1]>>3)&0xFF); /* Bit 5..12 */ gainIndex[3] |= (data[tempIndex1]>>1)&0x3; /* Bit 13..14 */ gainIndex[4] |= (data[tempIndex1]&0x1); /* Bit 15 */ tempIndex1++; /* 24:rd WebRtc_Word16 */ gainIndex[5] = (short)((data[tempIndex1]>>13)&0x7); /* Bit 0..2 */ gainIndex[6] |= (data[tempIndex1]>>10)&0x7; /* Bit 3..5 */ gainIndex[7] |= (data[tempIndex1]>>8)&0x3; /* Bit 6..7 */ gainIndex[8] = (short)((data[tempIndex1]>>5)&0x7); /* Bit 8..10 */ gainIndex[9] |= (data[tempIndex1]>>1)&0xF; /* Bit 11..14 */ gainIndex[10] |= (data[tempIndex1]<<2)&0x4; /* Bit 15 */ tempIndex1++; /* 25:rd WebRtc_Word16 */ gainIndex[10] |= (data[tempIndex1]>>14)&0x3; /* Bit 0..1 */ gainIndex[11] = (short)((data[tempIndex1]>>11)&0x7); /* Bit 2..4 */ gainIndex[12] |= (data[tempIndex1]>>7)&0xF; /* Bit 5..8 */ gainIndex[13] |= (data[tempIndex1]>>4)&0x7; /* Bit 9..11 */ gainIndex[14] = (short)((data[tempIndex1]>>1)&0x7); /* Bit 12..14 */ } } private void cbConstruct(short[] decVector,int decVectorIndex,short[] mem,int memIndex,short length,short vectorLength,int cbIndexIndex,int gainIndexIndex) { short[] cbIndex=encoderBits.getCbIndex(); short[] gainIndex=encoderBits.getGainIndex(); /* Stack based */ short gain[]=tempMemory;//+86 length 3 short cbVec0[]=tempMemory;//+89 length 40 short cbVec1[]=tempMemory;//+129 length 40 short cbVec2[]=tempMemory;//+169 length 40 /* gain de-quantization */ gain[86] = gainDequant(gainIndex[gainIndexIndex], (short)16384, (short)0); gain[87] = gainDequant(gainIndex[gainIndexIndex+1], (short)gain[86], (short)1); gain[88] = gainDequant(gainIndex[gainIndexIndex+2], (short)gain[87], (short)2); /* codebook vector construction and construction of total vector */ for(i=0;i<40;i++) { cbVec0[89+i]=0; cbVec1[129+i]=0; cbVec2[169+i]=0; } /* Stack based */ getCbVec(cbVec0, 89, mem, memIndex, cbIndex[cbIndexIndex], length, vectorLength); getCbVec(cbVec1, 129, mem, memIndex, cbIndex[cbIndexIndex+1], length, vectorLength); getCbVec(cbVec2, 169, mem, memIndex, cbIndex[cbIndexIndex+2], length, vectorLength); tempIndex5=89; tempIndex6=129; tempIndex7=169; for(i=0;i<vectorLength;i++) { temp=gain[86]*cbVec0[tempIndex5++]; temp+=gain[87]*cbVec1[tempIndex6++]; temp+=gain[88]*cbVec2[tempIndex7++]; tempShift=(temp+8192)>>14; decVector[decVectorIndex++]=(short)tempShift; } } private short gainDequant(short index, short maxIn, short stage) { /* obtain correct scale factor */ if(maxIn<0) maxIn=(short)(0-maxIn); if(maxIn<1638)/* if lower than 0.1, set it to 0.1 */ maxIn=1638; /* select the quantization table and return the decoded value */ return (short)((maxIn*Constants.GAIN[stage][index] +8192)>>14); } private void getCbVec(short[] cbVec,int cbVecIndex,short[] mem,int memIndex,short index,int length,int vectorLength) { /* Stack based */ short tempbuff2[]=tempMemory;//+209 length 45 /* Determine size of codebook sections */ baseSize=(short)(length-vectorLength+1); if (vectorLength==40) baseSize+=vectorLength>>1; /* No filter -> First codebook section */ if (index<length-vectorLength+1) { /* first non-interpolated vectors */ k=index+vectorLength; /* get vector */ System.arraycopy(mem, memIndex+length-k, cbVec, cbVecIndex, vectorLength); } else if (index < baseSize) { /* Calculate lag */ k=2*(index-(length-vectorLength+1))+vectorLength; createAugmentVector((short)(k>>1),mem,memIndex+length,cbVec,cbVecIndex); } /* Higher codebbok section based on filtering */ else { /* first non-interpolated vectors */ if (index-baseSize<length-vectorLength+1) { /* Set up filter memory, stuff zeros outside memory buffer */ tempIndex7=memIndex-4; for(n=0;n<4;n++) mem[tempIndex7++]=0; tempIndex7=memIndex+length; for(n=0;n<4;n++) mem[tempIndex7++]=0; /* do filtering to get the codebook vector */ BasicFunctions.filterMA(mem, memIndex+length-(index-baseSize+vectorLength)+4, cbVec, cbVecIndex, Constants.CB_FILTERS_REV, 0, 8, vectorLength); } /* interpolated vectors */ else { /* Stuff zeros outside memory buffer */ tempIndex7=memIndex+length; for(n=0;n<4;n++) mem[tempIndex7++]=0; /* do filtering */ BasicFunctions.filterMA(mem, memIndex+length-vectorLength-1, tempbuff2, 209, Constants.CB_FILTERS_REV, 0, 8, vectorLength+5); createAugmentVector((short)((vectorLength<<1)-20+index-baseSize-length-1),tempbuff2,254,cbVec,cbVecIndex); } } } private void createAugmentVector(short index,short[] buf,int bufIndex,short[] cbVec,int cbVecIndex) { short[] cbVecTmp=tempMemory;//+254 length 4 tempIndex7=cbVecIndex+index-4; /* copy the first noninterpolated part */ System.arraycopy(buf, bufIndex-index, cbVec, cbVecIndex, index); /* perform cbVec[ilow+k] = ((ppi[k]*alphaTbl[k])>>15) + ((ppo[k]*alphaTbl[3-k])>>15); for k = 0..3 */ BasicFunctions.multWithRightShift(cbVec, tempIndex7, buf, bufIndex-index-4, Constants.ALPHA, 0, 4, 15); BasicFunctions.reverseMultiplyRight(cbVecTmp, 254, buf, bufIndex-4, Constants.ALPHA, 3, 4, 15); BasicFunctions.addWithRightShift(cbVec, tempIndex7, cbVec, tempIndex7, cbVecTmp, 254, 4, 0); /* copy the second noninterpolated part */ System.arraycopy(buf, bufIndex-index, cbVec, cbVecIndex + index, 40-index); } private void stateConstruct(short[] syntDenum,int syntDenumIndex,short[] outFix,int outFixIndex) { /* Stack based */ short[] numerator=tempMemory; //+86 length 11 short[] sampleValVec=tempMemory; //+97 length 126 short[] sampleMaVec=tempMemory; //+223 length 126 short[] sampleVal=tempMemory; //+107 length 116 short[] sampleMa=tempMemory; //+233 length 116; short[] sampleAr=tempMemory; //+107 length 116; short[] idxVec=encoderBits.getIdxVec(); /* initialization of coefficients */ tempIndex1=86; tempIndex2=syntDenumIndex+10; for (k=0; k<11; k++) numerator[tempIndex1++] = syntDenum[tempIndex2--]; /* decoding of the maximum value */ max = Constants.FRQ_QUANT_MOD[encoderBits.getIdxForMax()]; /* decoding of the sample values */ tempIndex1=107; tempIndex2 = decoderState.STATE_SHORT_LEN-1; if (encoderBits.getIdxForMax()<37) { for(k=0; k<decoderState.STATE_SHORT_LEN; k++) { /*the shifting is due to the Q13 in sq4_fixQ13[i], also the adding of 2097152 (= 0.5 << 22) max is in Q8 and result is in Q(-1) */ sampleVal[tempIndex1++]=(short) ((max*Constants.STATE_SQ3[idxVec[tempIndex2--]]+2097152) >> 22); } } else if (encoderBits.getIdxForMax()<59) { for(k=0; k<decoderState.STATE_SHORT_LEN; k++) { /*the shifting is due to the Q13 in sq4_fixQ13[i], also the adding of 262144 (= 0.5 << 19) max is in Q5 and result is in Q(-1) */ sampleVal[tempIndex1++]=(short) ((max*Constants.STATE_SQ3[idxVec[tempIndex2--]]+262144) >> 19); } } else { for(k=0; k<decoderState.STATE_SHORT_LEN; k++) { /*the shifting is due to the Q13 in sq4_fixQ13[i], also the adding of 65536 (= 0.5 << 17) max is in Q3 and result is in Q(-1) */ sampleVal[tempIndex1++]=(short) ((max*Constants.STATE_SQ3[idxVec[tempIndex2--]]+65536) >> 17); } } /* Set the rest of the data to zero */ tempIndex1=107+decoderState.STATE_SHORT_LEN; for(i=0;i<decoderState.STATE_SHORT_LEN;i++) sampleVal[tempIndex1++]=0; /* circular convolution with all-pass filter */ /* Set the state to zero */ tempIndex1=97; for(i=0;i<10;i++) sampleValVec[tempIndex1++]=0; /* Run MA filter + AR filter */ BasicFunctions.filterMA(sampleVal, 107, sampleMa, 233, numerator, 86, 11, 11+decoderState.STATE_SHORT_LEN); tempIndex1=243+decoderState.STATE_SHORT_LEN; for(i=0;i<decoderState.STATE_SHORT_LEN-10;i++) sampleMa[tempIndex1++]=0; BasicFunctions.filterAR(sampleMa, 233, sampleAr, 107, syntDenum, syntDenumIndex, 11, 2*decoderState.STATE_SHORT_LEN); tempIndex1=107+decoderState.STATE_SHORT_LEN-1; tempIndex2=107+2*decoderState.STATE_SHORT_LEN-1; tempIndex3=outFixIndex; for(k=0;k<decoderState.STATE_SHORT_LEN;k++) outFix[tempIndex3++]=(short)(sampleAr[tempIndex1--]+sampleAr[tempIndex2--]); } }