blob: bcd603847641238d3bba4279949c8543c78c5aea [file] [log] [blame]
/*
* Copyright (c) 2012 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.
*/
#include "webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.h"
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
#include "webrtc/modules/audio_coding/codecs/isac/fix/source/settings.h"
#include "webrtc/modules/audio_coding/codecs/isac/fix/source/structs.h"
#include "webrtc/rtc_base/compile_assert_c.h"
// Number of segments in a pitch subframe.
static const int kSegments = 5;
// A division factor of 1/5 in Q15.
static const int16_t kDivFactor = 6553;
// Interpolation coefficients; generated by design_pitch_filter.m.
// Coefficients are stored in Q14.
static const int16_t 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 size_t CalcLrIntQ(int16_t fixVal,
int16_t qDomain) {
int32_t roundVal = 1 << (qDomain - 1);
return (fixVal + roundVal) >> qDomain;
}
void WebRtcIsacfix_PitchFilter(int16_t* indatQQ, // Q10 if type is 1 or 4,
// Q0 if type is 2.
int16_t* outdatQQ,
PitchFiltstr* pfp,
int16_t* lagsQ7,
int16_t* gainsQ12,
int16_t type) {
int k, ind, cnt;
int16_t sign = 1;
int16_t inystateQQ[PITCH_DAMPORDER];
int16_t ubufQQ[PITCH_INTBUFFSIZE + QLOOKAHEAD];
const int16_t Gain = 21299; // 1.3 in Q14
int16_t oldLagQ7;
int16_t oldGainQ12, lagdeltaQ7, curLagQ7, gaindeltaQ12, curGainQ12;
size_t indW32 = 0, frcQQ = 0;
const int16_t* fracoeffQQ = NULL;
// Assumptions in ARM assembly for WebRtcIsacfix_PitchFilterCoreARM().
RTC_COMPILE_ASSERT(PITCH_FRACORDER == 9);
RTC_COMPILE_ASSERT(PITCH_DAMPORDER == 5);
// Set up buffer and states.
memcpy(ubufQQ, pfp->ubufQQ, sizeof(pfp->ubufQQ));
memcpy(inystateQQ, pfp->ystateQQ, sizeof(inystateQQ));
// Get old lag and gain value from memory.
oldLagQ7 = pfp->oldlagQ7;
oldGainQ12 = pfp->oldgainQ12;
if (type == 4) {
sign = -1;
// Make output more periodic.
for (k = 0; k < PITCH_SUBFRAMES; k++) {
gainsQ12[k] = (int16_t)(gainsQ12[k] * Gain >> 14);
}
}
// No interpolation if pitch lag step is big.
if (((lagsQ7[0] * 3 >> 1) < oldLagQ7) || (lagsQ7[0] > (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 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
lagdeltaQ7, kDivFactor, 15);
curLagQ7 = oldLagQ7;
gaindeltaQ12 = gainsQ12[k] - oldGainQ12;
gaindeltaQ12 = (int16_t)(gaindeltaQ12 * kDivFactor >> 15);
curGainQ12 = oldGainQ12;
oldLagQ7 = lagsQ7[k];
oldGainQ12 = gainsQ12[k];
// Each frame has 4 60-sample pitch subframes, and each subframe has 5
// 12-sample segments. Each segment need to be processed with
// newly-updated parameters, so we break the pitch filtering into
// two for-loops (5 x 12) below. It's also why kDivFactor = 0.2 (in Q15).
for (cnt = 0; cnt < kSegments; cnt++) {
// Update parameters for each segment.
curGainQ12 += gaindeltaQ12;
curLagQ7 += lagdeltaQ7;
indW32 = CalcLrIntQ(curLagQ7, 7);
if (indW32 < PITCH_FRACORDER - 2) {
// WebRtcIsacfix_PitchFilterCore requires indW32 >= PITCH_FRACORDER -
// 2; otherwise, it will read from entries of ubufQQ that haven't been
// written yet. (This problem has only been seen in fuzzer tests, not
// in real life.) See Chromium bug 581901.
indW32 = PITCH_FRACORDER - 2;
}
frcQQ = ((indW32 << 7) + 64 - curLagQ7) >> 4;
if (frcQQ >= PITCH_FRACS) {
frcQQ = 0;
}
fracoeffQQ = kIntrpCoef[frcQQ];
// Pitch filtering.
WebRtcIsacfix_PitchFilterCore(PITCH_SUBFRAME_LEN / kSegments, curGainQ12,
indW32, sign, inystateQQ, ubufQQ, fracoeffQQ, indatQQ, outdatQQ, &ind);
}
}
// Export buffer and states.
memcpy(pfp->ubufQQ, ubufQQ + PITCH_FRAME_LEN, sizeof(pfp->ubufQQ));
memcpy(pfp->ystateQQ, inystateQQ, sizeof(pfp->ystateQQ));
pfp->oldlagQ7 = oldLagQ7;
pfp->oldgainQ12 = oldGainQ12;
if (type == 2) {
// Filter look-ahead segment.
WebRtcIsacfix_PitchFilterCore(QLOOKAHEAD, curGainQ12, indW32, 1, inystateQQ,
ubufQQ, fracoeffQQ, indatQQ, outdatQQ, &ind);
}
}
void WebRtcIsacfix_PitchFilterGains(const int16_t* indatQ0,
PitchFiltstr* pfp,
int16_t* lagsQ7,
int16_t* gainsQ12) {
int k, n, m;
size_t ind, pos, pos3QQ;
int16_t ubufQQ[PITCH_INTBUFFSIZE];
int16_t oldLagQ7, lagdeltaQ7, curLagQ7;
const int16_t* fracoeffQQ = NULL;
int16_t scale;
int16_t cnt = 0, tmpW16;
size_t frcQQ, indW16 = 0;
int32_t tmpW32, tmp2W32, csum1QQ, esumxQQ;
// Set up buffer and states.
memcpy(ubufQQ, pfp->ubufQQ, sizeof(pfp->ubufQQ));
oldLagQ7 = pfp->oldlagQ7;
// No interpolation if pitch lag step is big.
if (((lagsQ7[0] * 3 >> 1) < oldLagQ7) || (lagsQ7[0] > (oldLagQ7 * 3 >> 1))) {
oldLagQ7 = lagsQ7[0];
}
ind = 0;
pos = ind + PITCH_BUFFSIZE;
scale = 0;
for (k = 0; k < PITCH_SUBFRAMES; k++) {
// Calculate interpolation steps.
lagdeltaQ7 = lagsQ7[k] - oldLagQ7;
lagdeltaQ7 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
lagdeltaQ7, kDivFactor, 15);
curLagQ7 = oldLagQ7;
oldLagQ7 = lagsQ7[k];
csum1QQ = 1;
esumxQQ = 1;
// Same as function WebRtcIsacfix_PitchFilter(), we break the pitch
// filtering into two for-loops (5 x 12) below.
for (cnt = 0; cnt < kSegments; cnt++) {
// Update parameters for each segment.
curLagQ7 += lagdeltaQ7;
indW16 = CalcLrIntQ(curLagQ7, 7);
frcQQ = ((indW16 << 7) + 64 - curLagQ7) >> 4;
if (frcQQ >= PITCH_FRACS) {
frcQQ = 0;
}
fracoeffQQ = kIntrpCoef[frcQQ];
pos3QQ = pos - (indW16 + 4);
for (n = 0; n < PITCH_SUBFRAME_LEN / kSegments; n++) {
// Filter to get fractional pitch.
tmpW32 = 0;
for (m = 0; m < PITCH_FRACORDER; m++) {
tmpW32 += 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 = tmpW32 >> 14;
tmpW32 = tmpW16 * tmpW16;
if ((tmp2W32 > 1073700000) || (csum1QQ > 1073700000) ||
(tmpW32 > 1073700000) || (esumxQQ > 1073700000)) { // 2^30
scale++;
csum1QQ >>= 1;
esumxQQ >>= 1;
}
csum1QQ += tmp2W32 >> scale;
esumxQQ += tmpW32 >> scale;
ind++;
pos++;
pos3QQ++;
}
}
if (csum1QQ < esumxQQ) {
tmp2W32 = WebRtcSpl_DivResultInQ31(csum1QQ, esumxQQ);
// Gain should be half the correlation.
tmpW32 = tmp2W32 >> 20;
} else {
tmpW32 = 4096;
}
gainsQ12[k] = (int16_t)WEBRTC_SPL_SAT(PITCH_MAX_GAIN_Q12, tmpW32, 0);
}
// Export buffer and states.
memcpy(pfp->ubufQQ, ubufQQ + PITCH_FRAME_LEN, sizeof(pfp->ubufQQ));
pfp->oldlagQ7 = lagsQ7[PITCH_SUBFRAMES - 1];
pfp->oldgainQ12 = gainsQ12[PITCH_SUBFRAMES - 1];
}