/*
* 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 "typedef.h"
#include "codecParameters.h"
#include "basicOperationsMacros.h"
#include "utils.h"
#include
#include "fixedCodebookSearch.h"
/*** local functions ***/
void computeImpulseResponseCorrelationMatrix(word16_t impulseResponse[], word16_t correlationSignal[], int correlationSignalSign[], word32_t Phi[L_SUBFRAME][L_SUBFRAME]);
void computePhiDiagonal(int j, word16_t impulseResponse[], word32_t Phi[L_SUBFRAME][L_SUBFRAME], uint16_t PhiScaling);
/*****************************************************************************/
/* fixedCodebookSearch: compute fixed codebook parameters (codeword and sign)*/
/* compute also fixed codebook vector as in spec 3.8.1 */
/* parameters: */
/* -(i) targetSignal: 40 values as in spec A.3.6 in Q0 */
/* -(i) impulseResponse: 40 values as in spec A.3.5 in Q12 */
/* -(i) intPitchDelay: current integer pitch delay */
/* -(i) lastQuantizedAdaptativeCodebookGain: previous subframe pitch */
/* gain quantized in Q14 */
/* -(i) filteredAdaptativeCodebookVector : 40 values in Q0 */
/* -(i) adaptativeCodebookGain : in Q14 */
/* -(o) fixedCodebookParameter */
/* -(o) fixedCodebookPulsesSigns */
/* -(o) fixedCodebookVector : 40 values as in spec 3.8, eq45 in Q13 */
/* -(o) fixedCodebookVectorConvolved : 40 values as in spec 3.9, eq64 */
/* in Q12. */
/* */
/*****************************************************************************/
void fixedCodebookSearch(word16_t targetSignal[], word16_t impulseResponse[], int16_t intPitchDelay, word16_t lastQuantizedAdaptativeCodebookGain, word16_t filteredAdaptativeCodebookVector[], word16_t adaptativeCodebookGain,
uint16_t *fixedCodebookParameter, uint16_t *fixedCodebookPulsesSigns, word16_t fixedCodebookVector[], word16_t fixedCodebookVectorConvolved[])
{
int i,j,n;
word16_t fixedCodebookTargetSignal[L_SUBFRAME];
word32_t correlationSignal32[L_SUBFRAME]; /* on 32 bits in Q12 */
word16_t correlationSignal[L_SUBFRAME]; /* normalised to fit on 13 bits */
word32_t correlationSignalMax = 0;
word32_t abscCrrelationSignal32;
uint16_t correlationSignalMaxNorm;
int correlationSignalSign[L_SUBFRAME]; /* to store the sign of each correlationSignal element */
/* build the matrix Ф' : impulseResponse correlation matrix spec 3.8.1 eq51, eq56 and eq57 */
/* correlationSignal turns to absolute values and sign of elements is stored in correlationSignalSign */
word32_t Phi[L_SUBFRAME][L_SUBFRAME] = {{0}};
int m3Base;
int i0=0, i1=0, i2=0, i3=0;
word32_t correlationSquareMax = -1;
word32_t energyMax = 1;
int m0=0, m1=0, m2=0, m3=0;
int mSwitch[2][4] = {{2,3,0,1},{3,0,1,2}};
int mIndex;
int jx = 0;
/* compute the target signal for fixed codebook spec 3.8.1 eq50 : fixedCodebookTargetSignal[i] = targetSignal[i] - (adaptativeCodebookGain * filteredAdaptativeCodebookVector[i]) */
for (i=0; i=0?correlationSignal32[n]:-correlationSignal32[n];
if (abscCrrelationSignal32>correlationSignalMax) {
correlationSignalMax = abscCrrelationSignal32;
}
}
/* normalise on 13 bits */
correlationSignalMaxNorm = countLeadingZeros(correlationSignalMax);
if (correlationSignalMaxNorm<18) { /* if it doesn't already fit on 13 bits */
for (i=0; i select m2 */
if (correlationSignal[j]>correlationM2 && j!=firstM2) {
currentM2 = j;
correlationM2=correlationSignal[j];
}
}
firstM2 = currentM2; /* to avoid selecting the same maximum at next iteration */
energyM2 = Phi[currentM2][currentM2]; /* compute the energy with terms of eq55 using m2 only: Phi'(m2,m2) */
/* with selected m2, test the 8 m3 possibilities for the current m3 track */
for (j=mSwitch[mIndex][1]; j C^2/E > C^2max/Emax => Emax*C^2 > C^2max*E */
if (MULT32_32(m3TrackEnergy,correlationM2M3Square) > MULT32_32(energyM2M3, m3TrackCorrelationSquare)) {
m3TrackCorrelationSquare = correlationM2M3Square;
m3TrackEnergy = energyM2M3;
correlationM2M3Max = correlationM2M3;
m3 = j;
m2 = currentM2;
}
}
}
energyM2M3Max = m3TrackEnergy;
/* reset the current m3 track correlationSquare and energy */
m3TrackCorrelationSquare = -1;
m3TrackEnergy = 1;
for (i=mSwitch[mIndex][2]; i C^2/E > C^2max/Emax => Emax*C^2 > C^2max*E */
if (MULT32_32(m3TrackEnergy,correlationM2M3M0M1Square) > MULT32_32(energyM2M3M0M1, m3TrackCorrelationSquare)) {
m3TrackCorrelationSquare = correlationM2M3M0M1Square;
m3TrackEnergy = energyM2M3M0M1;
m1 = j;
m0 = i;
}
}
}
/* check with currently selected indexes if this one is better */
if (MULT32_32(energyMax,m3TrackCorrelationSquare) > MULT32_32(m3TrackEnergy, correlationSquareMax)) {
correlationSquareMax = m3TrackCorrelationSquare;
energyMax = m3TrackEnergy;
if (mIndex==0) {
i0 = m0;
i1 = m1;
i2 = m2;
i3 = m3;
} else {
i0 = m3;
i1 = m0;
i2 = m1;
i3 = m2;
}
jx = m3Base - 3; /* needed for parameter computation apec 3.8.2 eq62 */
}
}
mSwitch[0][1]++; mSwitch[1][0]++; /*increment the m3Base into the mSwitch */
}
/* compute the fixedCodebookVector */
for (i=0; i>1) | /* as in spec 3.8.2 eq61 */
(uint16_t)(((correlationSignalSign[i1]+1)>>1)<<1) |
(uint16_t)(((correlationSignalSign[i2]+1)>>1)<<2) |
(uint16_t)(((correlationSignalSign[i3]+1)>>1)<<3);
/* compute the fixedCodebook vector convolved with impulse response spec 3.9 eq64 */
/* this vector is used in gain quantization but computed here because it's faster doing it having directly the impulses positions */
/* eq64 make use of fixedCodebook vector adapted by eq48, using the impulse position(and thus fixed codebook vector before the adaptation) but */
/* the impulse response adapted as in eq49 gives the same output */
/* reset the vector */
for (i=0; i 0) {
for(i=i0, j=0; i 0) {
for(i=i1, j=0; i 0) {
for(i=i2, j=0; i 0) {
for(i=i3, j=0; i acc in Q24 */
Phi[iComp][iComp] = SHR(acc,1); /* divide by 2: eq57*/
}
/* check for possible overflow: Phi will be summed 10 times, so max Phi (by construction Phi[0][0]*2 is the max of Phi-> 2*Phi[0][0]*10 must be < 0x7fff ffff -> Phi[0][0]< 0x06666666 - otherwise scale Phi)*/
if (Phi[0][0]>0x6666666) {
PhiScaling = 3 - countLeadingZeros((Phi[0][0]<<1) + 0x3333333); /* complement 0xccccccc adding 0x3333333 to shift by one when max(2*Phi[0][0]) is in 0x0fffffff < max < 0xcccccc */
for (i=0; i absolute value and get sign (and his inverse in an array) */
for (i=0; i= 0) {
correlationSignalSign[i] = 1;
correlationSignalSignInv[i] = -1;
} else { /* correlationSignal < 0 */
correlationSignalSign[i] = -1;
correlationSignalSignInv[i] = 1;
correlationSignal[i] = -correlationSignal[i];
}
}
/* modify the signs according to eq56 */
for (i=0; i0) { /* is sign(correlationSignal[i]) is positive, use the correlationSignalSign otherwise the inverted one */
signOfCorrelationSignalJ = correlationSignalSign;
} else {
signOfCorrelationSignalJ = correlationSignalSignInv;
}
for (j=0; j<=i; j++) { /* multiply by the selected sign the matrix element */
/* Note : even the not needed and thus not computed elements are multiplicated... might found other way to do this sign stuff to be more efficient */
Phi[i][j] = Phi[i][j] * signOfCorrelationSignalJ[j];
}
}
/* duplicate the usefull values to their symetric part to get easier acces to the matrix elements */
for (i=0; i<8; i++) {
for (j=0; j<4; j++) {
int k;
int startIndex = 5*i+j;
for(k=0; k<=startIndex; k++) {
Phi[startIndex-k][L_SUBFRAME-1-k] = Phi[L_SUBFRAME-1-k][startIndex-k];
}
}
}
return;
}
/* compute a diagonal of Phi values: start from Phi(39,j) and step Phi(38, j-1) down to Phi(39-j, 0) */
/* Phi(i,j) = Phi(i+1,j+1) + h(39-i)*h(39-j) */
void computePhiDiagonal(int j, word16_t impulseResponse[], word32_t Phi[L_SUBFRAME][L_SUBFRAME], uint16_t PhiScaling)
{
word32_t acc = 0;
int i=L_SUBFRAME -1;
int iComp = 0;
int jComp = L_SUBFRAME - 1 - j;
if (PhiScaling == 0) {
for (; j>=0; j--, i--, jComp++, iComp++) {
acc = MAC16_16(acc, impulseResponse[iComp], impulseResponse[jComp]);
Phi[i][j] = acc;
}
} else {
for (; j>=0; j--, i--, jComp++, iComp++) {
acc = MAC16_16(acc, impulseResponse[iComp], impulseResponse[jComp]);
Phi[i][j] = SHR(acc,PhiScaling);
}
}
}