Improve robustness by combining AKF and AMDF
This commit is contained in:
1 parent
980644108e
commit
6ad9f6a1ef
3 files changed
+23
-13
No files matched your search
@@ -11,12 +11,13 @@ AnalyzerExt::~AnalyzerExt(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
int AnalyzerExt::GetNoteFast(double* maxVolume, float* weights){
|
int AnalyzerExt::GetNoteFast(double* maxVolume, float* weights){
|
||||||
|
float AnaylsisBuf[m_SampleCt];
|
||||||
size_t size = m_fastAnalysisBuf.size();
|
size_t size = m_fastAnalysisBuf.size();
|
||||||
if(size > m_SampleCt)
|
if(size > m_SampleCt)
|
||||||
m_fastAnalysisBuf.pop(size - m_SampleCt);
|
m_fastAnalysisBuf.pop(size - m_SampleCt);
|
||||||
if(!m_fastAnalysisBuf.read(m_AnalysisBuf, m_AnalysisBuf + m_SampleCt))
|
if(!m_fastAnalysisBuf.read(AnaylsisBuf, AnaylsisBuf + m_SampleCt))
|
||||||
return -1;
|
return -1;
|
||||||
return PitchTracker::GetTone(m_AnalysisBuf, m_SampleCt, maxVolume, weights);
|
return PitchTracker::GetTone(AnaylsisBuf, m_SampleCt, maxVolume, weights);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PtFast_Init(double baseToneFrequency, int minHalfTone, int maxHalfTone){
|
void PtFast_Init(double baseToneFrequency, int minHalfTone, int maxHalfTone){
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
constexpr static size_t m_SampleCt = 4096;
|
constexpr static size_t m_SampleCt = 4096;
|
||||||
RingBuffer<m_SampleCt * 2> m_fastAnalysisBuf; // Buffer used for fast analysis instead of FFT
|
RingBuffer<m_SampleCt * 2> m_fastAnalysisBuf; // Buffer used for fast analysis instead of FFT
|
||||||
float m_AnalysisBuf[4096];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DllExport void PtFast_Init(double baseToneFrequency, int minHalfTone, int maxHalfTone);
|
DllExport void PtFast_Init(double baseToneFrequency, int minHalfTone, int maxHalfTone);
|
||||||
|
|||||||
@@ -66,26 +66,35 @@ namespace PitchTracker{
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static T _AnalyzeToneFunc(T *samples, int sampleCt, int toneIndex){
|
static T _AnalyzeToneFunc(T *samples, int sampleCt, int toneIndex, bool scale){
|
||||||
|
// Use method by Kobayashi and Shimamura (1995): Combine AKF and AMDF to a new f(z)=AKF(z)/(AMDF(z)+k) with k=1
|
||||||
double samplesPerPeriodD = SamplesPerPeriodPerTone[toneIndex]; // samples in one period
|
double samplesPerPeriodD = SamplesPerPeriodPerTone[toneIndex]; // samples in one period
|
||||||
int samplesPerPeriod = static_cast<int>(samplesPerPeriodD);
|
int samplesPerPeriod = static_cast<int>(samplesPerPeriodD);
|
||||||
T fHigh = static_cast<T>(samplesPerPeriodD - samplesPerPeriod);
|
T fHigh = static_cast<T>(samplesPerPeriodD - samplesPerPeriod);
|
||||||
T fLow = static_cast<T>(1.0 - fHigh);
|
T fLow = static_cast<T>(1.0 - fHigh);
|
||||||
|
|
||||||
T accumDist = 0; // accumulated distances
|
T accumDistAKF = 0; // accumulated distances
|
||||||
|
T accumDistAMDF = 0; // accumulated distances
|
||||||
|
|
||||||
// compare correlating samples
|
// compare correlating samples
|
||||||
int sampleIndex = 0; // index of sample to analyze
|
int sampleIndex = 0; // index of sample to analyze
|
||||||
// Start value= index of sample one period ahead
|
// Start value= index of sample one period ahead
|
||||||
for (int correlatingSampleIndex = sampleIndex + samplesPerPeriod; correlatingSampleIndex + 1 < sampleCt; correlatingSampleIndex++, sampleIndex++)
|
for (int correlatingSampleIndex = sampleIndex + samplesPerPeriod; correlatingSampleIndex + 1 < sampleCt; correlatingSampleIndex++, sampleIndex++)
|
||||||
{
|
{
|
||||||
// calc distance to corresponding sample in next period (lower means more distant)
|
// calc distance to corresponding sample in next period
|
||||||
T dist = samples[sampleIndex] * (samples[correlatingSampleIndex] * fLow + samples[correlatingSampleIndex + 1] * fHigh);
|
T xn = samples[sampleIndex];
|
||||||
accumDist += dist;
|
T xnt = samples[correlatingSampleIndex] * fLow + samples[correlatingSampleIndex + 1] * fHigh;
|
||||||
|
accumDistAKF += xn * xnt;
|
||||||
|
accumDistAMDF += abs(xn - xnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Using sampleCt here makes it return correct values among all analyzed frequencies
|
accumDistAKF /= sampleCt;
|
||||||
return accumDist / sampleCt;
|
accumDistAMDF /= sampleIndex;
|
||||||
|
|
||||||
|
if(scale)
|
||||||
|
return accumDistAKF / (accumDistAMDF * 32767.f + 32767.f); // Need to scale AKF by MAX^2 and AMDF by MAX, so do some maths to divide only once
|
||||||
|
else
|
||||||
|
return accumDistAKF / (accumDistAMDF + 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -98,15 +107,16 @@ namespace PitchTracker{
|
|||||||
if(vol > maxVolumeL)
|
if(vol > maxVolumeL)
|
||||||
maxVolumeL = vol;
|
maxVolumeL = vol;
|
||||||
}
|
}
|
||||||
|
if(scale)
|
||||||
|
maxVolumeL /= 32767.;
|
||||||
*maxVolume = maxVolumeL;
|
*maxVolume = maxVolumeL;
|
||||||
|
|
||||||
T maxWeight = -1;
|
T maxWeight = -1;
|
||||||
T minWeight = 1;
|
T minWeight = 1;
|
||||||
int maxTone = -1;
|
int maxTone = -1;
|
||||||
for (int toneIndex = MinHalfTone; toneIndex <= MaxHalfTone; toneIndex++)
|
for (int toneIndex = MinHalfTone; toneIndex <= MaxHalfTone; toneIndex++)
|
||||||
{
|
{
|
||||||
T curWeight = _AnalyzeToneFunc<T>(samples, sampleCt, toneIndex) / maxVolumeL;
|
T curWeight = _AnalyzeToneFunc<T>(samples, sampleCt, toneIndex, scale);
|
||||||
if(scale)
|
|
||||||
curWeight /= 32768.0; //maximum abs value of a short, would actually need to scale by MaxValue^2 but we already scaled by maxVolume
|
|
||||||
|
|
||||||
if (curWeight > maxWeight)
|
if (curWeight > maxWeight)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user