1
/* ------------------------------------------------------------------
3
libofa -- the Open Fingerprint Architecture library
5
Copyright (C) 2006 MusicIP Corporation
8
-------------------------------------------------------------------*/
9
// FILE: "frametracker_op.cpp"
10
// MODULE: Implementation for class FrameTracker
11
// AUTHOR: Stephen Pope, Frode Holm
12
// DATE CREATED: 01/12/06
15
#include "frametracker_op.h"
16
#include "trackdata_op.h"
20
FrameTracker_op::FrameTracker_op(float peakT, float fThresh, float lenT, int maxTrax)
22
PeakThreshold = peakT;
23
FreqThreshold = fThresh;
24
LengthThreshold = lenT;
26
PeakWidth = 2; // width of peak interval (on one side)
32
FrameTracker_op::~FrameTracker_op()
39
FrameTracker_op::Compute(FFT_op& spectra)
41
double sdur = spectra.GetStepDur();
43
int numFrames = spectra.GetNumFrames();
45
// Detect the peaks in each frame
46
for (int i = 0; i < numFrames; i++)
48
float realTime = (float)(i * sdur);
49
TrackFrame_op* thePeaks = new TrackFrame_op(realTime);
51
FindPeaks(spectra, i, thePeaks);
52
Tracks.Add(thePeaks); // add the frame to the track list
55
TrackPeaks(); // Track the peaks between frames
56
ContinuePeaks(); // Try to extend the tracks
59
// Find the peaks in a single frame;
60
// use local-max detection over the min threshold
62
FrameTracker_op::FindPeaks(FFT_op& data, int frameNum, TrackFrame_op* thePeaks)
65
int numBins = data.GetNumBins();
66
float* frame = data.GetFrame(frameNum);
68
double realTime = frameNum * data.GetStepDur();
69
TrackData_op* prevP = 0;
70
float prevPV = * frame++; // previous previous sample
71
float prevV = * frame++; // previous sample
72
float thisV = * frame++; // this sample
73
float nextV = * frame++; // next sample
74
for (int i = 4; i < (numBins - 2); i++)
76
float nextNV = * frame++; // next next sample
78
// check for peak relatively > PeakThreshold
79
bool found = (thisV > PeakThreshold) && (thisV > prevV) && (thisV > nextV);
81
if (found && (PeakWidth > 1)) // if using wide peaks, compare prevPV and nextNV
82
found = found && (thisV > prevPV) && (thisV > nextNV);
86
// If peak detected, do cubic interpolation for index, // freq, and magnitude -- first calculate "real" index
87
double realIndex = ((prevV - nextV) * 0.5) / (prevV - (2.0 * thisV) + nextV);
88
// then interpolate the real magnitude and frequency
89
double realPeak = thisV - ((prevV - nextV) * 0.25 * realIndex);
90
double realFreq = data.GetFreqStep() * (float)(i-2);
91
// Add the new peak to the list and link it in
92
TrackData_op* thisP = new TrackData_op((float)realTime, (float)realFreq, (float)realPeak, (float)data.GetStepDur());
94
prevP->linkHigher(thisP);
99
prevPV = prevV; // step the values to the next freq. bin
106
// Answer the best match for the given frequency in the given frame
108
FrameTracker_op::GetBestMatch(float pitch, TrackFrame_op* frame)
110
TrackData_op* match = frame->getTrackNearestFreq(pitch);
111
if (match != 0) { // If it's within the freq. range FreqThreshold
112
double frqDiff = fabs(log(match->getPitch()) - log(pitch));
113
if (frqDiff < FreqThreshold)
119
// Track and group peaks in the given data set;
120
// do a running forward/backward comparison of all peaks in a track
123
FrameTracker_op::TrackPeaks()
126
TrackFrame_op* prevFr = Tracks.getBaseFrame();
127
TrackFrame_op* thisFr = prevFr->getNext();
128
TrackFrame_op* nextFr = thisFr->getNext();
129
TrackFrame_op* lastFr = nextFr->getNext();
130
while (thisFr != 0) { // Iterate over the frames trying to track peaks
131
TrackData_op* baseTr = prevFr->getBaseTrack();
132
// Try to track the previous frame's peaks into this frame
133
while (baseTr != 0) { // Find the best freq. match between track and current pks
134
float baseP = baseTr->getPitch();
135
TrackData_op* match = GetBestMatch(baseP, thisFr);
137
baseTr->linkTo(match); // create double links
139
baseTr = baseTr->getHigher();
140
} // end of current frame
145
lastFr = lastFr->getNext();
146
} // end of all tracks
149
// Continue track groups, and gather track statistics
152
FrameTracker_op::ContinuePeaks()
155
TrackFrame_op* base = Tracks.getBaseFrame();
156
while (base != 0) { // Iterate over all frames
157
TrackData_op* td = base->getBaseTrack();
158
while (td != 0) { // Iterate over peaks in a frame
160
float am = td->getAmplitude();
161
float pc = td->getPitch();
165
TrackData_op* tl = td->getNext();
166
while (tl != 0) { // Iterate forward over peaks in a track
167
am = tl->getAmplitude();
175
td->setAvgAmplitude(avgA / (float) i);
176
td->setAvgPitch(avgP / (float) i);
178
td = td->getHigher(); // go to next peak in frame
180
base = base->getNext(); // go to next frame