/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * code_LPC_UB.c * * This file contains definition of functions used to * encode LPC parameters (Shape & gain) of the upper band. * */ #include "encode_lpc_swb.h" #include "typedefs.h" #include "settings.h" #include "lpc_shape_swb12_tables.h" #include "lpc_shape_swb16_tables.h" #include "lpc_gain_swb_tables.h" #include #include #include /****************************************************************************** * WebRtcIsac_RemoveLarMean() * * Remove the means from LAR coefficients. * * Input: * -lar : pointer to lar vectors. LAR vectors are * concatenated. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -lar : pointer to mean-removed LAR:s. * * */ WebRtc_Word16 WebRtcIsac_RemoveLarMean( double* lar, WebRtc_Word16 bandwidth) { WebRtc_Word16 coeffCntr; WebRtc_Word16 vecCntr; WebRtc_Word16 numVec; const double* meanLAR; switch(bandwidth) { case isac12kHz: { numVec = UB_LPC_VEC_PER_FRAME; meanLAR = WebRtcIsac_kMeanLarUb12; break; } case isac16kHz: { numVec = UB16_LPC_VEC_PER_FRAME; meanLAR = WebRtcIsac_kMeanLarUb16; break; } default: return -1; } for(vecCntr = 0; vecCntr < numVec; vecCntr++) { for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) { // REMOVE MEAN *lar++ -= meanLAR[coeffCntr]; } } return 0; } /****************************************************************************** * WebRtcIsac_DecorrelateIntraVec() * * Remove the correlation amonge the components of LAR vectors. If LAR vectors * of one frame are put in a matrix where each column is a LAR vector of a * sub-frame, then this is equivalent to multiplying the LAR matrix with * a decorrelting mtrix from left. * * Input: * -inLar : pointer to mean-removed LAR vecrtors. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -out : decorrelated LAR vectors. */ WebRtc_Word16 WebRtcIsac_DecorrelateIntraVec( const double* data, double* out, WebRtc_Word16 bandwidth) { const double* ptrData; const double* ptrRow; WebRtc_Word16 rowCntr; WebRtc_Word16 colCntr; WebRtc_Word16 larVecCntr; WebRtc_Word16 numVec; const double* decorrMat; switch(bandwidth) { case isac12kHz: { decorrMat = &WebRtcIsac_kIntraVecDecorrMatUb12[0][0]; numVec = UB_LPC_VEC_PER_FRAME; break; } case isac16kHz: { decorrMat = &WebRtcIsac_kIintraVecDecorrMatUb16[0][0]; numVec = UB16_LPC_VEC_PER_FRAME; break; } default: return -1; } // // decorrMat * data // // data is assumed to contain 'numVec' of LAR // vectors (mean removed) each of dimension 'UB_LPC_ORDER' // concatenated one after the other. // ptrData = data; for(larVecCntr = 0; larVecCntr < numVec; larVecCntr++) { for(rowCntr = 0; rowCntr < UB_LPC_ORDER; rowCntr++) { ptrRow = &decorrMat[rowCntr * UB_LPC_ORDER]; *out = 0; for(colCntr = 0; colCntr < UB_LPC_ORDER; colCntr++) { *out += ptrData[colCntr] * ptrRow[colCntr]; } out++; } ptrData += UB_LPC_ORDER; } return 0; } /****************************************************************************** * WebRtcIsac_DecorrelateInterVec() * * Remover the correlation among mean-removed LAR vectors. If LAR vectors * of one frame are put in a matrix where each column is a LAR vector of a * sub-frame, then this is equivalent to multiplying the LAR matrix with * a decorrelting mtrix from right. * * Input: * -data : pointer to matrix of LAR vectors. The matrix * is stored column-wise. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -out : decorrelated LAR vectors. */ WebRtc_Word16 WebRtcIsac_DecorrelateInterVec( const double* data, double* out, WebRtc_Word16 bandwidth) { WebRtc_Word16 coeffCntr; WebRtc_Word16 rowCntr; WebRtc_Word16 colCntr; const double* decorrMat; WebRtc_Word16 interVecDim; switch(bandwidth) { case isac12kHz: { decorrMat = &WebRtcIsac_kInterVecDecorrMatUb12[0][0]; interVecDim = UB_LPC_VEC_PER_FRAME; break; } case isac16kHz: { decorrMat = &WebRtcIsac_kInterVecDecorrMatUb16[0][0]; interVecDim = UB16_LPC_VEC_PER_FRAME; break; } default: return -1; } // // data * decorrMat // // data is of size 'interVecDim' * 'UB_LPC_ORDER' // That is 'interVecDim' of LAR vectors (mean removed) // in columns each of dimension 'UB_LPC_ORDER'. // matrix is stored column-wise. // for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) { for(colCntr = 0; colCntr < interVecDim; colCntr++) { out[coeffCntr + colCntr * UB_LPC_ORDER] = 0; for(rowCntr = 0; rowCntr < interVecDim; rowCntr++) { out[coeffCntr + colCntr * UB_LPC_ORDER] += data[coeffCntr + rowCntr * UB_LPC_ORDER] * decorrMat[rowCntr * interVecDim + colCntr]; } } } return 0; } /****************************************************************************** * WebRtcIsac_QuantizeUncorrLar() * * Quantize the uncorrelated parameters. * * Input: * -data : uncorrelated LAR vectors. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -data : quantized version of the input. * -idx : pointer to quantization indices. */ double WebRtcIsac_QuantizeUncorrLar( double* data, int* recIdx, WebRtc_Word16 bandwidth) { WebRtc_Word16 cntr; WebRtc_Word32 idx; WebRtc_Word16 interVecDim; const double* leftRecPoint; double quantizationStepSize; const WebRtc_Word16* numQuantCell; switch(bandwidth) { case isac12kHz: { leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb12; quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb12; numQuantCell = WebRtcIsac_kLpcShapeNumRecPointUb12; interVecDim = UB_LPC_VEC_PER_FRAME; break; } case isac16kHz: { leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb16; quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb16; numQuantCell = WebRtcIsac_kLpcShapeNumRecPointUb16; interVecDim = UB16_LPC_VEC_PER_FRAME; break; } default: return -1; } // // Quantize the parametrs. // for(cntr = 0; cntr < UB_LPC_ORDER * interVecDim; cntr++) { idx = (WebRtc_Word32)floor((*data - leftRecPoint[cntr]) / quantizationStepSize + 0.5); if(idx < 0) { idx = 0; } else if(idx >= numQuantCell[cntr]) { idx = numQuantCell[cntr] - 1; } *data++ = leftRecPoint[cntr] + idx * quantizationStepSize; *recIdx++ = idx; } return 0; } /****************************************************************************** * WebRtcIsac_DequantizeLpcParam() * * Get the quantized value of uncorrelated LARs given the quantization indices. * * Input: * -idx : pointer to quantiztion indices. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -out : pointer to quantized values. */ WebRtc_Word16 WebRtcIsac_DequantizeLpcParam( const int* idx, double* out, WebRtc_Word16 bandwidth) { WebRtc_Word16 cntr; WebRtc_Word16 interVecDim; const double* leftRecPoint; double quantizationStepSize; switch(bandwidth) { case isac12kHz: { leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb12; quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb12; interVecDim = UB_LPC_VEC_PER_FRAME; break; } case isac16kHz: { leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb16; quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb16; interVecDim = UB16_LPC_VEC_PER_FRAME; break; } default: return -1; } // // Dequantize given the quantization indices // for(cntr = 0; cntr < UB_LPC_ORDER * interVecDim; cntr++) { *out++ = leftRecPoint[cntr] + *idx++ * quantizationStepSize; } return 0; } /****************************************************************************** * WebRtcIsac_CorrelateIntraVec() * * This is the inverse of WebRtcIsac_DecorrelateIntraVec(). * * Input: * -data : uncorrelated parameters. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -out : correlated parametrs. */ WebRtc_Word16 WebRtcIsac_CorrelateIntraVec( const double* data, double* out, WebRtc_Word16 bandwidth) { WebRtc_Word16 vecCntr; WebRtc_Word16 rowCntr; WebRtc_Word16 colCntr; WebRtc_Word16 numVec; const double* ptrData; const double* intraVecDecorrMat; switch(bandwidth) { case isac12kHz: { numVec = UB_LPC_VEC_PER_FRAME; intraVecDecorrMat = &WebRtcIsac_kIntraVecDecorrMatUb12[0][0]; break; } case isac16kHz: { numVec = UB16_LPC_VEC_PER_FRAME; intraVecDecorrMat = &WebRtcIsac_kIintraVecDecorrMatUb16[0][0]; break; } default: return -1; } ptrData = data; for(vecCntr = 0; vecCntr < numVec; vecCntr++) { for(colCntr = 0; colCntr < UB_LPC_ORDER; colCntr++) { *out = 0; for(rowCntr = 0; rowCntr < UB_LPC_ORDER; rowCntr++) { *out += ptrData[rowCntr] * intraVecDecorrMat[rowCntr * UB_LPC_ORDER + colCntr]; } out++; } ptrData += UB_LPC_ORDER; } return 0; } /****************************************************************************** * WebRtcIsac_CorrelateInterVec() * * This is the inverse of WebRtcIsac_DecorrelateInterVec(). * * Input: * -data * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -out : correlated parametrs. */ WebRtc_Word16 WebRtcIsac_CorrelateInterVec( const double* data, double* out, WebRtc_Word16 bandwidth) { WebRtc_Word16 coeffCntr; WebRtc_Word16 rowCntr; WebRtc_Word16 colCntr; WebRtc_Word16 interVecDim; double myVec[UB16_LPC_VEC_PER_FRAME]; const double* interVecDecorrMat; switch(bandwidth) { case isac12kHz: { interVecDim = UB_LPC_VEC_PER_FRAME; interVecDecorrMat = &WebRtcIsac_kInterVecDecorrMatUb12[0][0]; break; } case isac16kHz: { interVecDim = UB16_LPC_VEC_PER_FRAME; interVecDecorrMat = &WebRtcIsac_kInterVecDecorrMatUb16[0][0]; break; } default: return -1; } for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) { for(rowCntr = 0; rowCntr < interVecDim; rowCntr++) { myVec[rowCntr] = 0; for(colCntr = 0; colCntr < interVecDim; colCntr++) { myVec[rowCntr] += data[coeffCntr + colCntr * UB_LPC_ORDER] * //*ptrData * interVecDecorrMat[rowCntr * interVecDim + colCntr]; //ptrData += UB_LPC_ORDER; } } for(rowCntr = 0; rowCntr < interVecDim; rowCntr++) { out[coeffCntr + rowCntr * UB_LPC_ORDER] = myVec[rowCntr]; } } return 0; } /****************************************************************************** * WebRtcIsac_AddLarMean() * * This is the inverse of WebRtcIsac_RemoveLarMean() * * Input: * -data : pointer to mean-removed LAR:s. * -bandwidth : indicates if the given LAR vectors belong * to SWB-12kHz or SWB-16kHz. * * Output: * -data : pointer to LARs. */ WebRtc_Word16 WebRtcIsac_AddLarMean( double* data, WebRtc_Word16 bandwidth) { WebRtc_Word16 coeffCntr; WebRtc_Word16 vecCntr; WebRtc_Word16 numVec; const double* meanLAR; switch(bandwidth) { case isac12kHz: { numVec = UB_LPC_VEC_PER_FRAME; meanLAR = WebRtcIsac_kMeanLarUb12; break; } case isac16kHz: { numVec = UB16_LPC_VEC_PER_FRAME; meanLAR = WebRtcIsac_kMeanLarUb16; break; } default: return -1; } for(vecCntr = 0; vecCntr < numVec; vecCntr++) { for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) { *data++ += meanLAR[coeffCntr]; } } return 0; } /****************************************************************************** * WebRtcIsac_ToLogDomainRemoveMean() * * Transform the LPC gain to log domain then remove the mean value. * * Input: * -lpcGain : pointer to LPC Gain, expecting 6 LPC gains * * Output: * -lpcGain : mean-removed in log domain. */ WebRtc_Word16 WebRtcIsac_ToLogDomainRemoveMean( double* data) { WebRtc_Word16 coeffCntr; for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) { data[coeffCntr] = log(data[coeffCntr]) - WebRtcIsac_kMeanLpcGain; } return 0; } /****************************************************************************** * WebRtcIsac_DecorrelateLPGain() * * Decorrelate LPC gains. There are 6 LPC Gains per frame. This is like * multiplying gain vector with decorrelating matrix. * * Input: * -data : LPC gain in log-domain with mean removed. * * Output: * -out : decorrelated parameters. */ WebRtc_Word16 WebRtcIsac_DecorrelateLPGain( const double* data, double* out) { WebRtc_Word16 rowCntr; WebRtc_Word16 colCntr; for(colCntr = 0; colCntr < UB_LPC_GAIN_DIM; colCntr++) { *out = 0; for(rowCntr = 0; rowCntr < UB_LPC_GAIN_DIM; rowCntr++) { *out += data[rowCntr] * WebRtcIsac_kLpcGainDecorrMat[rowCntr][colCntr]; } out++; } return 0; } /****************************************************************************** * WebRtcIsac_QuantizeLpcGain() * * Quantize the decorrelated log-domain gains. * * Input: * -lpcGain : uncorrelated LPC gains. * * Output: * -idx : quantization indices * -lpcGain : quantized value of the inpt. */ double WebRtcIsac_QuantizeLpcGain( double* data, int* idx) { WebRtc_Word16 coeffCntr; for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) { *idx = (int)floor((*data - WebRtcIsac_kLeftRecPointLpcGain[coeffCntr]) / WebRtcIsac_kQSizeLpcGain + 0.5); if(*idx < 0) { *idx = 0; } else if(*idx >= WebRtcIsac_kNumQCellLpcGain[coeffCntr]) { *idx = WebRtcIsac_kNumQCellLpcGain[coeffCntr] - 1; } *data = WebRtcIsac_kLeftRecPointLpcGain[coeffCntr] + *idx * WebRtcIsac_kQSizeLpcGain; data++; idx++; } return 0; } /****************************************************************************** * WebRtcIsac_DequantizeLpcGain() * * Get the quantized values given the quantization indices. * * Input: * -idx : pointer to quantization indices. * * Output: * -lpcGains : quantized values of the given parametes. */ WebRtc_Word16 WebRtcIsac_DequantizeLpcGain( const int* idx, double* out) { WebRtc_Word16 coeffCntr; for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) { *out = WebRtcIsac_kLeftRecPointLpcGain[coeffCntr] + *idx * WebRtcIsac_kQSizeLpcGain; out++; idx++; } return 0; } /****************************************************************************** * WebRtcIsac_CorrelateLpcGain() * * This is the inverse of WebRtcIsac_DecorrelateLPGain(). * * Input: * -data : decorrelated parameters. * * Output: * -out : correlated parameters. */ WebRtc_Word16 WebRtcIsac_CorrelateLpcGain( const double* data, double* out) { WebRtc_Word16 rowCntr; WebRtc_Word16 colCntr; for(rowCntr = 0; rowCntr < UB_LPC_GAIN_DIM; rowCntr++) { *out = 0; for(colCntr = 0; colCntr < UB_LPC_GAIN_DIM; colCntr++) { *out += WebRtcIsac_kLpcGainDecorrMat[rowCntr][colCntr] * data[colCntr]; } out++; } return 0; } /****************************************************************************** * WebRtcIsac_AddMeanToLinearDomain() * * This is the inverse of WebRtcIsac_ToLogDomainRemoveMean(). * * Input: * -lpcGain : LPC gain in log-domain & mean removed * * Output: * -lpcGain : LPC gain in normal domain. */ WebRtc_Word16 WebRtcIsac_AddMeanToLinearDomain( double* lpcGains) { WebRtc_Word16 coeffCntr; for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) { lpcGains[coeffCntr] = exp(lpcGains[coeffCntr] + WebRtcIsac_kMeanLpcGain); } return 0; }