/* * Copyright (c) 2011-2019 Belledonne Communications SARL. * * This file is part of bcg729. * * 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 3 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, see . */ #include #include #include "typedef.h" #include "codecParameters.h" #include "basicOperationsMacros.h" #include "utils.h" #include "dtx.h" #include "computeLP.h" #include "g729FixedPointMath.h" #include "LP2LSPConversion.h" #include "LSPQuantization.h" #include "codebooks.h" #include "cng.h" #include "interpolateqLSP.h" #include "qLSP2LP.h" #define SID_FRAME 2 #define UNTRANSMITTED_FRAME 0 /*** local functions ***/ static void sumAutocorrelationCoefficients(word32_t autoCorrelationCoefficients[][NB_LSP_COEFF+1], int8_t *autocorrelationCoefficientsScale, uint8_t nbElements, word32_t *autoCorrelationCoefficientsResult, int8_t *autocorrelationCoefficientsScaleResults) { int i,j; word64_t autoCorrelationSumBuffer[NB_LSP_COEFF+1]; /* used to temporary store sum on 64 bits */ word64_t max=0; word32_t rescaledAutocorrelationCoefficients[7][NB_LSP_COEFF+1]; /* used to temporary stored rescaled elements */ int8_t rightShiftToNormalise = 0; /* get lowest scale */ int8_t minScale = autocorrelationCoefficientsScale[0]; for (i=1; imax) max = ABS(autoCorrelationSumBuffer[i]); } /* normalise result on 32 bits */ if (max>MAXINT32) { do { max = SHR(max,1); rightShiftToNormalise++; } while (max>MAXINT32); for (i=0; i acc still in Q15 */ } steps = SHR(acc,15); *decodedLogEnergy = -2 +4*steps; return 1+steps; } else if (acc<216268) { /* check that log(E') is not > 66dB (216268 is 6.6 in Q15) */ uint8_t steps; acc = (acc-49152); /* -1.5 in Q15 */ if (acc<0) { acc = 0; } else { acc = MULT16_32_Q12(20480, acc); /* step by 0.2, 20480 is 1/0.2 in Q12 -> acc still in Q15 */ } steps = SHR(acc,15); *decodedLogEnergy = 16 +2*steps; return 6+steps; } else { /* quantized energy support up to 66dB */ *decodedLogEnergy = 66; return 31; } } /*****************************************************************************/ /* compute LP Coefficients auto correlation as in eq B.13 */ /* parameters: */ /* -(i) LPCoefficients : in Q12, 10 values, 1 LP Coeff is always 1 and not*/ /* stored in this buffer */ /* -(o) LPCautocorrelation : 11 values in Q20 */ /* */ /*****************************************************************************/ static void computeLPCoefficientAutocorrelation(word16_t *LPCoefficients, word32_t *LPCautocorrelation) { int j,k; /* first compute Ra0 */ LPCautocorrelation[0] = 4096*4096>>4; /* LPCoefficients are in Q12 -> acc in Q24, init: acc = LP(0)*LP(0) -> 1 in Q20 as LP(0) is not stored because always 1 */ for (k=0; k Q24 >> Q4: result in Q20 */ } /* and the rest */ for (j=1; j Q24 >> 3 : *2 and result in Q20 */ } } } /********************************************************************************/ /* compare LPC filters: as in spec B.4.1.3 eq B.12 */ /* parameters: */ /* -(i) LPCoefficientsAutocorrelation: 11 values in Q20, Ra in spec */ /* -(i) autocorrelationCoefficients: 11 values in variable scale, Rt in spec */ /* -(i) residualEnergy : in the same scale as previous value, Et in spec */ /* -(i) threshold : in Q20 */ /* return 1 if the filter significantly differs (eq B.12 is true) */ /* */ /********************************************************************************/ static uint8_t compareLPCFilters(word32_t *LPCoefficientsAutocorrelation, word32_t *autocorrelationCoefficients, word32_t residualEnergy, word32_t threshold) { /* on the left term of the comparison we have Ra in Q20 an Rt in variable scale */ /* on the right term of the comparison we have Threshold in Q20 an Et in variable scale but same as Rt */ word64_t acc = 0; int i; for (i=0; i= MULT32_32(residualEnergy, threshold)) { return 1; } else { return 0; } } /*****************************************************************************/ /* initBcg729DTXChannel : create context structure and initialise it */ /* return value : */ /* - the DTX channel context data */ /* */ /*****************************************************************************/ bcg729DTXChannelContextStruct *initBcg729DTXChannel() { int i; /* create the context structure */ bcg729DTXChannelContextStruct *DTXChannelContext = malloc(sizeof(bcg729DTXChannelContextStruct)); memset(DTXChannelContext, 0, sizeof(*DTXChannelContext)); /* set autocorrelation buffers to 0 */ /* avoid arithmetics problem: set past autocorrelation[0] to 1 */ for (i=0; i<7; i++) { DTXChannelContext->autocorrelationCoefficients[i][0] = ONE_IN_Q30; DTXChannelContext->autocorrelationCoefficientsScale[i] = 30; } DTXChannelContext->previousVADflag = 1; /* previous VAD flag must be initialised to VOICE */ DTXChannelContext->pseudoRandomSeed = CNG_DTX_RANDOM_SEED_INIT; return DTXChannelContext; } /*******************************************************************************************/ /* updateDTXContext : save autocorrelation value in DTX context as requested in B4.1.1 */ /* parameters: */ /* -(i/o) DTXChannelContext : the DTX context to be updated */ /* -(i) autocorrelationsCoefficients : 11 values of variable scale, values are copied */ /* in DTX context */ /* -(i) autocorrelationCoefficientsScale : the scale of previous buffer(can be <0) */ /* */ /*******************************************************************************************/ void updateDTXContext(bcg729DTXChannelContextStruct *DTXChannelContext, word32_t *autocorrelationCoefficients, int8_t autocorrelationCoefficientsScale) { /* move previous autocorrelation coefficients and store the new one */ /* TODO: optimise it buy using rolling index */ memcpy(DTXChannelContext->autocorrelationCoefficients[6], DTXChannelContext->autocorrelationCoefficients[5], (NB_LSP_COEFF+1)*sizeof(word32_t)); DTXChannelContext->autocorrelationCoefficientsScale[6] = DTXChannelContext->autocorrelationCoefficientsScale[5]; memcpy(DTXChannelContext->autocorrelationCoefficients[5], DTXChannelContext->autocorrelationCoefficients[4], (NB_LSP_COEFF+1)*sizeof(word32_t)); DTXChannelContext->autocorrelationCoefficientsScale[5] = DTXChannelContext->autocorrelationCoefficientsScale[4]; memcpy(DTXChannelContext->autocorrelationCoefficients[4], DTXChannelContext->autocorrelationCoefficients[3], (NB_LSP_COEFF+1)*sizeof(word32_t)); DTXChannelContext->autocorrelationCoefficientsScale[4] = DTXChannelContext->autocorrelationCoefficientsScale[3]; memcpy(DTXChannelContext->autocorrelationCoefficients[3], DTXChannelContext->autocorrelationCoefficients[2], (NB_LSP_COEFF+1)*sizeof(word32_t)); DTXChannelContext->autocorrelationCoefficientsScale[3] = DTXChannelContext->autocorrelationCoefficientsScale[2]; memcpy(DTXChannelContext->autocorrelationCoefficients[2], DTXChannelContext->autocorrelationCoefficients[1], (NB_LSP_COEFF+1)*sizeof(word32_t)); DTXChannelContext->autocorrelationCoefficientsScale[2] = DTXChannelContext->autocorrelationCoefficientsScale[1]; memcpy(DTXChannelContext->autocorrelationCoefficients[1], DTXChannelContext->autocorrelationCoefficients[0], (NB_LSP_COEFF+1)*sizeof(word32_t)); DTXChannelContext->autocorrelationCoefficientsScale[1] = DTXChannelContext->autocorrelationCoefficientsScale[0]; memcpy(DTXChannelContext->autocorrelationCoefficients[0], autocorrelationCoefficients, (NB_LSP_COEFF+1)*sizeof(word32_t)); DTXChannelContext->autocorrelationCoefficientsScale[0] = autocorrelationCoefficientsScale; } /*******************************************************************************************/ /* encodeSIDFrame: called at eache frame even if VADflag is set to active speech */ /* Update the previousVADflag and if curent is set to NOISE, compute the SID params */ /* parameters: */ /* -(i/o) DTXChannelContext: current DTX context, is updated by this function */ /* -(o) previousLSPCoefficients : 10 values in Q15, is updated by this function */ /* -(i/o) previousqLSPCoefficients : 10 values in Q15, is updated by this function */ /* -(i) VADflag : 1 active voice frame, 0 noise frame */ /* -(i/o) previousqLSF : set of 4 last frames qLSF in Q2.13, is updated */ /* -(i/o) excicationVector : in Q0, accessed in range [-L_PAST_EXCITATION,L_FRAME-1] */ /* -(o) qLPCoefficients : 20 values in Q3.12 the quantized LP coefficients */ /* -(o) bitStream : SID frame parameters on 2 bytes, may be null if no frame is to be */ /* transmitted */ /* -(o) bitStreamLength : length of bitStream buffer to be transmitted (2 for SID, 0 for */ /* untransmitted frame) */ /* */ /*******************************************************************************************/ void encodeSIDFrame(bcg729DTXChannelContextStruct *DTXChannelContext, word16_t *previousLSPCoefficients, word16_t *previousqLSPCoefficients, uint8_t VADflag, word16_t previousqLSF[MA_MAX_K][NB_LSP_COEFF], word16_t *excitationVector, word16_t *qLPCoefficients, uint8_t *bitStream, uint8_t *bitStreamLength) { int i; word32_t summedAutocorrelationCoefficients[NB_LSP_COEFF+1]; word16_t LPCoefficients[NB_LSP_COEFF]; /* in Q12 */ word16_t LSPCoefficients[NB_LSP_COEFF]; /* in Q15 */ word32_t reflectionCoefficients[NB_LSP_COEFF]; /* product of LP Computation, may be used if we need to generate the RFC3389 payload */ word32_t residualEnergy; /* in variable scale(summedAutocorrelationCoefficientsScale) computed together with LP coefficients */ int8_t summedAutocorrelationCoefficientsScale; uint8_t frameType; word32_t meanEnergy; int8_t meanEnergyScale; uint8_t quantizedResidualEnergy; int8_t decodedLogEnergy; uint8_t parameters[3]; /* array of the first 3 output parameters, 4th is in quantizedResidualEnergy */ word16_t interpolatedqLSP[NB_LSP_COEFF]; /* the interpolated qLSP used for first subframe in Q15 */ if (VADflag == 1) {/* this is a voice frame, just update the VADflag history and return */ DTXChannelContext->pseudoRandomSeed = CNG_DTX_RANDOM_SEED_INIT; /* re-init pseudo random seed at each active frame to keep CNG and DTX in sync */ DTXChannelContext->previousVADflag = 1; return; } /* NOISE frame */ /* compute the autocorrelation coefficients sum on the current and previous frame */ sumAutocorrelationCoefficients((DTXChannelContext->autocorrelationCoefficients), DTXChannelContext->autocorrelationCoefficientsScale, 2, summedAutocorrelationCoefficients, &summedAutocorrelationCoefficientsScale); /* compute LP filter coefficients */ autoCorrelation2LP(summedAutocorrelationCoefficients, LPCoefficients, reflectionCoefficients, &residualEnergy); /* output residualEnergy with the same scale of input summedAutocorrelationCoefficients */ /* determine type of frame SID or untrasmitted */ if (DTXChannelContext->previousVADflag == 1) { /* if previous frame was active : we must generate a SID frame spec B.10 */ frameType = SID_FRAME; meanEnergy = residualEnergy; meanEnergyScale = summedAutocorrelationCoefficientsScale; quantizedResidualEnergy = residualEnergyQuantization(meanEnergy, meanEnergyScale, &decodedLogEnergy); } else { /* previous frame was already non active, check if we have to generate a new SID frame according to spec 4.1.2-4.1.4 */ int8_t flag_chang = 0; /* update meanEnergy using current and previous frame Energy : meanE = current+previous/2 : rescale both of them dividing by 2 and sum */ /* eqB14 doesn't divide by KE but it's done in eqB15, do it now */ if (summedAutocorrelationCoefficientsScalepreviousResidualEnergyScale) { meanEnergyScale = summedAutocorrelationCoefficientsScale; meanEnergy = ADD32(SHR(residualEnergy,1), VSHR32(DTXChannelContext->previousResidualEnergy, DTXChannelContext->previousResidualEnergyScale - summedAutocorrelationCoefficientsScale + 1)); } else { meanEnergyScale = DTXChannelContext->previousResidualEnergyScale; meanEnergy = ADD32(VSHR32(residualEnergy,summedAutocorrelationCoefficientsScale - DTXChannelContext->previousResidualEnergyScale + 1), SHR(DTXChannelContext->previousResidualEnergy, 1)); } quantizedResidualEnergy = residualEnergyQuantization(meanEnergy, meanEnergyScale, &decodedLogEnergy); /* comparison of LPC filters B4.1.3 : DTXChannelContext->SIDLPCoefficientAutocorrelation contains the last used filter LP coeffecients autocorrelation in Q20 */ if (compareLPCFilters(DTXChannelContext->SIDLPCoefficientAutocorrelation, summedAutocorrelationCoefficients, residualEnergy, THRESHOLD1_IN_Q20) != 0) { flag_chang = 1; } /* comparison of the energies B4.1.4 */ if (ABS(DTXChannelContext->previousDecodedLogEnergy - decodedLogEnergy)>2) { flag_chang = 1; } /* check if we have to transmit a SID frame eq B.11 */ DTXChannelContext->count_fr++; if (DTXChannelContext->count_fr<3) { /* min 3 frames between 2 consecutive SID frames */ frameType = UNTRANSMITTED_FRAME; } else { if (flag_chang == 1) { frameType = SID_FRAME; } else { frameType = UNTRANSMITTED_FRAME; } DTXChannelContext->count_fr = 3; /* counter on 8 bits, keep value low, we just need to know if it is > 3 */ } } /* generate the SID frame */ if (frameType == SID_FRAME) { word32_t SIDLPCAutocorrelationCoefficients[NB_LSP_COEFF+1]; int8_t SIDLPCAutocorrelationCoefficientsScale; word16_t pastAverageLPCoefficients[NB_LSP_COEFF]; /* in Q12 */ word32_t pastAverageReflectionCoefficients[NB_LSP_COEFF]; /* produced by LP computation, may be used if we have to generate RFC3389 payload */ word32_t pastAverageResidualEnergy; /* not used here, by-product of LP coefficients computation */ /* reset frame count */ DTXChannelContext->count_fr = 0; /*** compute the past average filter on the last 6 past frames ***/ sumAutocorrelationCoefficients(&(DTXChannelContext->autocorrelationCoefficients[1]), &(DTXChannelContext->autocorrelationCoefficientsScale[1]), 6, SIDLPCAutocorrelationCoefficients, &SIDLPCAutocorrelationCoefficientsScale); /* compute past average LP filter coefficients Ap in B4.2.2 */ autoCorrelation2LP(SIDLPCAutocorrelationCoefficients, pastAverageLPCoefficients, pastAverageReflectionCoefficients, &pastAverageResidualEnergy); /* output residualEnergy with the same scale of input summedAutocorrelationCoefficients */ /* select coefficients according to eq B.17 we have Ap in SIDLPCoefficients and At in LPCoefficients, store result, in Q12 in SIDLPCoefficients */ /* check distance beetwen currently used filter and past filter : compute LPCoefficentAutocorrelation for the past average filter */ computeLPCoefficientAutocorrelation(pastAverageLPCoefficients, DTXChannelContext->SIDLPCoefficientAutocorrelation); DTXChannelContext->decodedLogEnergy = decodedLogEnergy; /* store frame mean energy for RFC3389 payload generation */ if (compareLPCFilters(DTXChannelContext->SIDLPCoefficientAutocorrelation, summedAutocorrelationCoefficients, residualEnergy, THRESHOLD3_IN_Q20) == 0) { /* use the past average filter */ /* generate LSP coefficient using the past LP coefficients */ if (!LP2LSPConversion(pastAverageLPCoefficients, LSPCoefficients)) { /* unable to find the 10 roots repeat previous LSP */ memcpy(LSPCoefficients, previousqLSPCoefficients, NB_LSP_COEFF*sizeof(word16_t)); } /* LPCoefficientAutocorrelation are already in DTXChannelContext */ /* save the reflection coefficients in the DTX context as they will be requested to generate RFC3389 payload */ memcpy(DTXChannelContext->reflectionCoefficients, pastAverageReflectionCoefficients, NB_LSP_COEFF*sizeof(word32_t)); } else { /* use filter computed on current and previous frame */ /* compute the LPCoefficientAutocorrelation for this filter and store them in DTXChannel */ computeLPCoefficientAutocorrelation(LPCoefficients, DTXChannelContext->SIDLPCoefficientAutocorrelation); /* generate LSP coefficient current LP coefficients */ if (!LP2LSPConversion(LPCoefficients, LSPCoefficients)) { /* unable to find the 10 roots repeat previous LSP */ memcpy(LSPCoefficients, previousqLSPCoefficients, NB_LSP_COEFF*sizeof(word16_t)); } /* save the reflection coefficients in the DTX context as they will be requested to generate RFC3389 payload */ memcpy(DTXChannelContext->reflectionCoefficients, reflectionCoefficients, NB_LSP_COEFF*sizeof(word32_t)); } /* update previousLSP coefficient buffer */ memcpy(previousLSPCoefficients, LSPCoefficients, NB_LSP_COEFF*sizeof(word16_t)); /* LSP quantization */ noiseLSPQuantization(previousqLSF, LSPCoefficients, DTXChannelContext->qLSPCoefficients, parameters); /* update previousDecodedLogEnergy and SIDGain */ DTXChannelContext->previousDecodedLogEnergy = decodedLogEnergy; DTXChannelContext->currentSIDGain = SIDGainCodebook[quantizedResidualEnergy]; } /* save current Frame Energy */ DTXChannelContext->previousResidualEnergy = residualEnergy; DTXChannelContext->previousResidualEnergyScale = summedAutocorrelationCoefficientsScale; /* apply target gain smoothing eq B.19 */ if(DTXChannelContext->previousVADflag == 1) { DTXChannelContext->smoothedSIDGain = DTXChannelContext->currentSIDGain; } else { DTXChannelContext->smoothedSIDGain = SUB16(DTXChannelContext->smoothedSIDGain, (DTXChannelContext->smoothedSIDGain>>3)); DTXChannelContext->smoothedSIDGain = ADD16(DTXChannelContext->smoothedSIDGain, (DTXChannelContext->currentSIDGain>>3)); } /* update excitation vector */ computeComfortNoiseExcitationVector(DTXChannelContext->smoothedSIDGain, &(DTXChannelContext->pseudoRandomSeed), excitationVector); /* Interpolate qLSP and update the previousqLSP buffer */ interpolateqLSP(previousqLSPCoefficients, DTXChannelContext->qLSPCoefficients, interpolatedqLSP); /* in case of untransmitted frame, use qLSP generated for the last transmitted one */ for (i=0; iqLSPCoefficients[i]; } /* first subframe */ qLSP2LP(interpolatedqLSP, qLPCoefficients); /* second subframe */ qLSP2LP(DTXChannelContext->qLSPCoefficients, &(qLPCoefficients[NB_LSP_COEFF])); /* set parameters into the bitStream if a frame must be transmitted */ if (frameType == SID_FRAME) { *bitStreamLength = 2; bitStream[0] = (((parameters[0]&0x01)<<7) /* L0 1 bit */ | ((parameters[1]&0x1F)<<2) /* L1 5 bits */ | ((parameters[2]>>2)%0x03)); /* L2 is 4 bits 2 MSB in this byte */ bitStream[1] = (((parameters[2]&0x03)<<6) /* 2 LSB of 4 bits L2 */ | ((quantizedResidualEnergy&0x1F)<<1)); /* Gain 5 bits, last bit is left to 0 */ } else { *bitStreamLength = 0; } /* update the previousVADflag in context */ DTXChannelContext->previousVADflag = 0; }