// Copyright (C) 1999 Jean-Marc Valin
#include "BufferedNode.h"
#include "Buffer.h"
#include "Vector.h"
#include <stdlib.h>
#include <math.h>
#ifdef HAVE_FLOAT_H
#include <float.h>
#endif
using namespace std;
namespace FD {
class LTP;
DECLARE_NODE(LTP)
/*Node
*
* @name LTP
* @category DSP:Adaptive
* @description Long-term predictor, finds best correlation (pitch) within (START <= sample delay <= END)
*
* @input_name INPUT
* @input_type Vector<float>
* @input_description Input frame
*
* @output_name OUTPUT
* @output_type Vector<float>
* @output_description [pitch gain, pitch period]
*
* @parameter_name START
* @parameter_type int
* @parameter_description Smallest pitch allowed
*
* @parameter_name END
* @parameter_type int
* @parameter_description Largest pitch allowed
*
END*/
class LTP : public BufferedNode {
int inputID;
int outputID;
int start;
int end;
public:
LTP(string nodeName, ParameterSet params)
: BufferedNode(nodeName, params)
{
inputID = addInput("INPUT");
outputID = addOutput("OUTPUT");
start = dereference_cast<int> (parameters.get("START"));
end = dereference_cast<int> (parameters.get("END"));
inputsCache[inputID].lookBack=1;
}
void calculate(int output_id, int count, Buffer &out)
{
ObjectRef inputValue = getInput(inputID, count);
const Vector<float> &in = object_cast<Vector<float> > (inputValue);
int inputLength = in.size();
Vector<float> &output = *Vector<float>::alloc(2);
out[count] = &output;
const Vector<float> *past;
bool can_look_back = false;
if (count > 0)
{
ObjectRef pastInputValue = getInput(inputID, count-1);
can_look_back=true;
past = &object_cast<Vector<float> > (pastInputValue);
}
float best=-FLT_MAX;
float best_gain=0;
int best_T=0;
//float scores[end+1];
//float gains[end+1];
DYN_VEC(float, end+1, scores);
DYN_VEC(float, end+1, gains);
/*static float old_scores[2000];
static bool init=false;
if (!init)
{
for (int i=0;i<2000;i++)
old_scores[i]=0;
init=true;
}*/
for (int i=0;i<start;i++)
scores[i]=0;
for (int lag=start;lag<=end;lag++)
{
float corr=0;
float energy=0;
for (int i=lag;i<inputLength;i++)
{
corr += in[i]*in[i-lag];
energy += in[i-lag]*in[i-lag];
}
if (can_look_back)
for (int i=0;i<lag;i++)
{
corr += in[i] * (*past)[inputLength+i-lag];
energy += (*past)[inputLength+i-lag] * (*past)[inputLength+i-lag];
}
float gain = corr/(energy+.000000001);
float score = corr*corr/(energy+.000000001);
scores[lag]=score;
gains[lag]=gain;
//cout << corr/energy << " ";
if (score > best)
{
//prevents period doubling
if (1 || score/best > 1.6 || abs(lag-2*best_T) > 5)
{
best = score;
best_T = lag;
best_gain = corr/(energy+.00000001);
} //else {cerr << "doubling\n";}
}
}
//cout << endl;
/*
for (int i=start;i<=end;i++)
{
scores[i] += .6*old_scores[i];
old_scores[i]=scores[i];
cout << scores[i] << " ";
}
cout << endl;
*/
for (int i=4;i>=2;i--)
{
int div = best_T/i;
float max_score = 0;
float max_gain = 0;
int max_T=0;
for (int j=div-2; j <= div+2 ; j++)
{
if (scores[j]>max_score)
{
max_score = scores[j];
max_gain = gains[j];
max_T = j;
}
}
if (max_score*2 > best || max_gain > .3)
{
if (i==2)
{
int div2 = best_T+max_T;
float max_score2 = 0;
float max_gain2 = 0;
int max_T2=0;
for (int j=div2-2; j <= div2+2 && j<end; j++)
{
if (scores[j]>max_score2)
{
max_score2 = scores[j];
max_gain2 = gains[j];
max_T2 = j;
}
}
if (!(max_score2*2 > best || max_gain > .2))
continue;
}
best_T = max_T;
best_gain = max_gain;
break;
}
}
//cout << endl;
if (best_gain > 1.2)
best_gain = 1.2;
if (best_gain < -.2)
best_gain = -.2;
//cout << endl;
output[0] = best_gain;
output[1] = best_T;
//cout << output[0] << " " << output[1] << endl;
}
};
}//namespace FD
syntax highlighted by Code2HTML, v. 0.9.1