blob: 87af1533ba886e11ae413d1641c96af2997ee3ca [file] [log] [blame]
/*
* 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.
*/
/*
* pitch_estimatorfilter.c
*
* Pitch filter functions
*
*/
#include <string.h>
#include "pitch_estimator.h"
/* Filter coefficicients in Q15 */
static const WebRtc_Word16 kDampFilter[PITCH_DAMPORDER] = {
-2294, 8192, 20972, 8192, -2294
};
/* Interpolation coefficients; generated by design_pitch_filter.m.
* Coefficients are stored in Q14.
*/
static const WebRtc_Word16 kIntrpCoef[PITCH_FRACS][PITCH_FRACORDER] = {
{-367, 1090, -2706, 9945, 10596, -3318, 1626, -781, 287},
{-325, 953, -2292, 7301, 12963, -3320, 1570, -743, 271},
{-240, 693, -1622, 4634, 14809, -2782, 1262, -587, 212},
{-125, 358, -817, 2144, 15982, -1668, 721, -329, 118},
{ 0, 0, -1, 1, 16380, 1, -1, 0, 0},
{ 118, -329, 721, -1668, 15982, 2144, -817, 358, -125},
{ 212, -587, 1262, -2782, 14809, 4634, -1622, 693, -240},
{ 271, -743, 1570, -3320, 12963, 7301, -2292, 953, -325}
};
static __inline WebRtc_Word32 CalcLrIntQ(WebRtc_Word32 fixVal, WebRtc_Word16 qDomain) {
WebRtc_Word32 intgr;
WebRtc_Word32 roundVal;
roundVal = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)1, qDomain-1);
intgr = WEBRTC_SPL_RSHIFT_W32(fixVal+roundVal, qDomain);
return intgr;
}
void WebRtcIsacfix_PitchFilter(WebRtc_Word16 *indatQQ, /* Q10 if type is 1 or 4, Q0 if type is 2 */
WebRtc_Word16 *outdatQQ,
PitchFiltstr *pfp,
WebRtc_Word16 *lagsQ7,
WebRtc_Word16 *gainsQ12,
WebRtc_Word16 type)
{
int k, n, m, ind;
WebRtc_Word16 sign = 1;
WebRtc_Word16 inystateQQ[PITCH_DAMPORDER];
WebRtc_Word16 ubufQQ[PITCH_INTBUFFSIZE+QLOOKAHEAD];
WebRtc_Word16 Gain = 21299; /* 1.3 in Q14 */
WebRtc_Word16 DivFactor = 6553; /* 0.2 in Q15 */
WebRtc_Word16 oldLagQ7, oldGainQ12,
lagdeltaQ7, curLagQ7,
gaindeltaQ12, curGainQ12;
WebRtc_Word16 tmpW16, indW16=0, frcQQ, cnt=0, pos, pos2;
const WebRtc_Word16 *fracoeffQQ=NULL;
WebRtc_Word32 tmpW32;
if (type==4)
sign = -1;
/* Set up buffer and states */
memcpy(ubufQQ, pfp->ubufQQ, WEBRTC_SPL_MUL_16_16(sizeof(WebRtc_Word16), PITCH_BUFFSIZE));
memcpy(inystateQQ, pfp->ystateQQ, WEBRTC_SPL_MUL_16_16(sizeof(WebRtc_Word16), PITCH_DAMPORDER));
/* Get old lag and gain value from memory */
oldLagQ7 = pfp->oldlagQ7;
oldGainQ12 = pfp->oldgainQ12;
if (type==4) {
/* make output more periodic */
/* Fixed 1.3 = 21299 in Q14 */
for (k=0;k<PITCH_SUBFRAMES;k++)
gainsQ12[k] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(gainsQ12[k], Gain, 14);
}
/* No interpolation if pitch lag step is big */
if ((WEBRTC_SPL_RSHIFT_W16(WEBRTC_SPL_MUL_16_16(lagsQ7[0], 3), 1) < oldLagQ7) ||
(lagsQ7[0] > WEBRTC_SPL_RSHIFT_W16(WEBRTC_SPL_MUL_16_16(oldLagQ7, 3), 1))) {
oldLagQ7 = lagsQ7[0];
oldGainQ12 = gainsQ12[0];
}
ind=0;
for (k=0;k<PITCH_SUBFRAMES;k++) {
/* Calculate interpolation steps */
lagdeltaQ7 = lagsQ7[k]-oldLagQ7;
lagdeltaQ7 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(lagdeltaQ7,DivFactor,15);
curLagQ7 = oldLagQ7;
gaindeltaQ12 = gainsQ12[k]-oldGainQ12;
gaindeltaQ12 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(gaindeltaQ12,DivFactor,15);
curGainQ12 = oldGainQ12;
oldLagQ7 = lagsQ7[k];
oldGainQ12 = gainsQ12[k];
for (n=0;n<PITCH_SUBFRAME_LEN;n++) {
if (cnt == 0) { /* Update parameters */
curGainQ12 += gaindeltaQ12;
curLagQ7 += lagdeltaQ7;
indW16 = (WebRtc_Word16)CalcLrIntQ(curLagQ7,7);
tmpW16 = WEBRTC_SPL_LSHIFT_W16(indW16,7);
tmpW16 -= curLagQ7;
frcQQ = WEBRTC_SPL_RSHIFT_W16(tmpW16,4);
frcQQ += 4;
if(frcQQ==PITCH_FRACS)
frcQQ=0;
fracoeffQQ = kIntrpCoef[frcQQ];
cnt=12;
}
/* shift low pass filter state */
for (m=PITCH_DAMPORDER-1;m>0;m--)
inystateQQ[m] = inystateQQ[m-1];
/* Filter to get fractional pitch */
pos = ind + PITCH_BUFFSIZE;
pos2 = pos - (indW16 + 2);
tmpW32=0;
for (m=0;m<PITCH_FRACORDER;m++)
tmpW32 += WEBRTC_SPL_MUL_16_16(ubufQQ[pos2+m], fracoeffQQ[m]);
/* Saturate to avoid overflow in tmpW16 */
tmpW32 = WEBRTC_SPL_SAT(536862719, tmpW32, -536879104);
tmpW32 += 8192;
tmpW16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmpW32,14);
inystateQQ[0] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(curGainQ12, tmpW16,12); /* Multiply with gain */
/* Low pass filter */
tmpW32=0;
for (m=0;m<PITCH_DAMPORDER;m++)
tmpW32 += WEBRTC_SPL_MUL_16_16(inystateQQ[m], kDampFilter[m]);
/* Saturate to avoid overflow in tmpW16 */
tmpW32 = WEBRTC_SPL_SAT(1073725439, tmpW32, -1073758208);
tmpW32 += 16384;
tmpW16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmpW32,15);
/* Subtract from input and update buffer */
tmpW32 = indatQQ[ind] - WEBRTC_SPL_MUL_16_16(sign, tmpW16);
outdatQQ[ind] = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(tmpW32);
tmpW32 = indatQQ[ind] + (WebRtc_Word32)outdatQQ[ind];
ubufQQ[pos] = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(tmpW32);
ind++;
cnt--;
}
}
/* Export buffer and states */
memcpy(pfp->ubufQQ, ubufQQ+PITCH_FRAME_LEN, WEBRTC_SPL_MUL_16_16(sizeof(WebRtc_Word16), PITCH_BUFFSIZE));
memcpy(pfp->ystateQQ, inystateQQ, WEBRTC_SPL_MUL_16_16(sizeof(WebRtc_Word16), PITCH_DAMPORDER));
pfp->oldlagQ7 = oldLagQ7;
pfp->oldgainQ12 = oldGainQ12;
if (type==2) {
/* Filter look-ahead segment */
for (n=0;n<QLOOKAHEAD;n++) {
/* shift low pass filter state */
for (m=PITCH_DAMPORDER-1;m>0;m--)
inystateQQ[m] = inystateQQ[m-1];
/* Filter to get fractional pitch */
pos = ind + PITCH_BUFFSIZE;
pos2= pos - (indW16 + 2);
tmpW32=0;
for (m=0;m<PITCH_FRACORDER;m++)
tmpW32 += WEBRTC_SPL_MUL_16_16(ubufQQ[pos2+m], fracoeffQQ[m]);
if (tmpW32<536862720) {//536870912)
tmpW32 += 8192;
tmpW16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmpW32,14);
} else
tmpW16= 32767;
inystateQQ[0] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(curGainQ12, tmpW16,12); /* Multiply with gain */
/* Low pass filter */
tmpW32=0;
for (m=0;m<PITCH_DAMPORDER;m++)
tmpW32 += WEBRTC_SPL_MUL_16_16(inystateQQ[m], kDampFilter[m]);
if (tmpW32<1073725440) { //1073741824)
tmpW32 += 16384;
tmpW16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmpW32,15);
} else
tmpW16 = 32767;
/* Subtract from input and update buffer */
tmpW32 = indatQQ[ind] - (WebRtc_Word32)tmpW16;
outdatQQ[ind] = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(tmpW32);
tmpW32 = indatQQ[ind] + (WebRtc_Word32)outdatQQ[ind];
ubufQQ[pos] = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(tmpW32);
ind++;
}
}
}
void WebRtcIsacfix_PitchFilterGains(const WebRtc_Word16 *indatQ0,
PitchFiltstr *pfp,
WebRtc_Word16 *lagsQ7,
WebRtc_Word16 *gainsQ12)
{
int k, n, m, ind;
WebRtc_Word16 ubufQQ[PITCH_INTBUFFSIZE];
WebRtc_Word16 oldLagQ7,lagdeltaQ7, curLagQ7;
WebRtc_Word16 DivFactor = 6553;
const WebRtc_Word16 *fracoeffQQ = NULL;
WebRtc_Word16 scale;
WebRtc_Word16 cnt=0, pos, pos3QQ, frcQQ, indW16 = 0, tmpW16;
WebRtc_Word32 tmpW32, tmp2W32, csum1QQ, esumxQQ;
/* Set up buffer and states */
memcpy(ubufQQ, pfp->ubufQQ, WEBRTC_SPL_MUL_16_16(sizeof(WebRtc_Word16), PITCH_BUFFSIZE));
oldLagQ7 = pfp->oldlagQ7;
/* No interpolation if pitch lag step is big */
if ((WEBRTC_SPL_RSHIFT_W16(WEBRTC_SPL_MUL_16_16(lagsQ7[0], 3), 1) < oldLagQ7) ||
(lagsQ7[0] > WEBRTC_SPL_RSHIFT_W16(WEBRTC_SPL_MUL_16_16(oldLagQ7, 3), 1))) {
oldLagQ7 = lagsQ7[0];
}
ind=0;
scale=0;
for (k=0;k<PITCH_SUBFRAMES;k++) {
/* Calculate interpolation steps */
lagdeltaQ7 = lagsQ7[k]-oldLagQ7;
lagdeltaQ7 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(lagdeltaQ7,DivFactor,15);
curLagQ7 = oldLagQ7;
oldLagQ7 = lagsQ7[k];
csum1QQ=1;
esumxQQ=1;
for (n=0;n<PITCH_SUBFRAME_LEN;n++) {
if (cnt == 0) { /* Update parameters */
curLagQ7 += lagdeltaQ7;
indW16 = (WebRtc_Word16)CalcLrIntQ(curLagQ7,7);
tmpW16 = WEBRTC_SPL_LSHIFT_W16(indW16,7);
tmpW16 -= curLagQ7;
frcQQ = WEBRTC_SPL_RSHIFT_W16(tmpW16,4);
frcQQ += 4;
if(frcQQ==PITCH_FRACS)
frcQQ=0;
fracoeffQQ = kIntrpCoef[frcQQ];
cnt=12;
}
/* Filter to get fractional pitch */
pos = ind + PITCH_BUFFSIZE;
pos3QQ = pos - (indW16 + 4);
tmpW32=0;
for (m=0;m<PITCH_FRACORDER;m++){
tmpW32 += WEBRTC_SPL_MUL_16_16(ubufQQ[pos3QQ+m], fracoeffQQ[m]);
}
/* Subtract from input and update buffer */
ubufQQ[pos] = indatQ0[ind];
tmp2W32 = WEBRTC_SPL_MUL_16_32_RSFT14(indatQ0[ind], tmpW32);
tmpW32 += 8192;
tmpW16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmpW32,14);
tmpW32 = WEBRTC_SPL_MUL_16_16(tmpW16, tmpW16);
if ((tmp2W32>1073700000) || (csum1QQ>1073700000) || (tmpW32>1073700000) || (esumxQQ>1073700000)) {//2^30
scale++;
csum1QQ = WEBRTC_SPL_RSHIFT_W32(csum1QQ,1);
esumxQQ = WEBRTC_SPL_RSHIFT_W32(esumxQQ,1);
}
tmp2W32 = WEBRTC_SPL_RSHIFT_W32(tmp2W32,scale);
csum1QQ += tmp2W32;
tmpW32 = WEBRTC_SPL_RSHIFT_W32(tmpW32,scale);
esumxQQ += tmpW32;
ind++;
cnt--;
}
if (csum1QQ<esumxQQ) {
tmp2W32=WebRtcSpl_DivResultInQ31(csum1QQ,esumxQQ);
/* Gain should be half the correlation */
tmpW32=WEBRTC_SPL_RSHIFT_W32(tmp2W32,20);
} else
tmpW32=4096;
gainsQ12[k]=(WebRtc_Word16)WEBRTC_SPL_SAT(PITCH_MAX_GAIN_Q12, tmpW32, 0);
}
/* Export buffer and states */
memcpy(pfp->ubufQQ, ubufQQ+PITCH_FRAME_LEN, WEBRTC_SPL_MUL_16_16(sizeof(WebRtc_Word16), PITCH_BUFFSIZE));
pfp->oldlagQ7 = lagsQ7[PITCH_SUBFRAMES-1];
pfp->oldgainQ12 = gainsQ12[PITCH_SUBFRAMES-1];
}