File: frametracker_op.cpp

package info (click to toggle)
libofa 0.9.3-3.1
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 1,936 kB
  • ctags: 460
  • sloc: cpp: 24,470; sh: 8,366; makefile: 45; ansic: 14
file content (183 lines) | stat: -rw-r--r-- 5,605 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/* ------------------------------------------------------------------

   libofa -- the Open Fingerprint Architecture library

   Copyright (C) 2006 MusicIP Corporation
   All rights reserved.

-------------------------------------------------------------------*/
// FILE: "frametracker_op.cpp"
// MODULE: Implementation for class FrameTracker
// AUTHOR: Stephen Pope, Frode Holm
// DATE CREATED: 01/12/06

#include <math.h>
#include "frametracker_op.h"
#include "trackdata_op.h"

// Constructor

FrameTracker_op::FrameTracker_op(float peakT, float fThresh, float lenT, int maxTrax)
{
	PeakThreshold = peakT;
	FreqThreshold = fThresh;
	LengthThreshold = lenT;
	MaxTracks = maxTrax;
	PeakWidth = 2;		// width of peak interval (on one side)
	BaseFr = 0;
}

// Destructor

FrameTracker_op::~FrameTracker_op() 
{ 
	BaseFr = 0;
}


void 
FrameTracker_op::Compute(FFT_op& spectra) 
{
	double sdur = spectra.GetStepDur();

	int numFrames = spectra.GetNumFrames();

	// Detect the peaks in each frame
	for (int i = 0; i < numFrames; i++) 
	{		
		float realTime = (float)(i * sdur);
		TrackFrame_op* thePeaks = new TrackFrame_op(realTime);

		FindPeaks(spectra, i, thePeaks);
		Tracks.Add(thePeaks);				// add the frame to the track list
	}
					
	TrackPeaks();							// Track the peaks between frames
	ContinuePeaks();						// Try to extend the tracks
}

// Find the peaks in a single frame;
// use local-max detection over the min threshold
void 
FrameTracker_op::FindPeaks(FFT_op& data, int frameNum, TrackFrame_op* thePeaks) 
{

	int numBins = data.GetNumBins();
	float* frame = data.GetFrame(frameNum);
	int npeak = 0;
	double realTime = frameNum * data.GetStepDur();
	TrackData_op* prevP = 0;
	float prevPV = * frame++;			// previous previous sample
	float prevV = * frame++;			// previous sample
	float thisV = * frame++;			// this sample
	float nextV = * frame++;			// next sample
	for (int i = 4; i < (numBins - 2); i++) 
	{
		float nextNV = * frame++;		// next next sample

									// check for peak relatively > PeakThreshold
		bool found = (thisV > PeakThreshold) && (thisV > prevV) && (thisV > nextV);

		if (found && (PeakWidth > 1))	// if using wide peaks, compare prevPV and nextNV
			found = found && (thisV > prevPV) && (thisV > nextNV);

		if (found) 
		{
									// If peak detected, do cubic interpolation for index, 									// freq, and magnitude -- first calculate "real" index
			double realIndex = ((prevV - nextV) * 0.5) / (prevV - (2.0 * thisV) + nextV);
									// then interpolate the real magnitude and frequency
			double realPeak = thisV - ((prevV - nextV) * 0.25 * realIndex);
			double realFreq = data.GetFreqStep() * (float)(i-2);
									// Add the new peak to the list and link it in
			TrackData_op* thisP = new TrackData_op((float)realTime, (float)realFreq, (float)realPeak, (float)data.GetStepDur());
			if (prevP != 0)
				prevP->linkHigher(thisP);
			prevP = thisP;
			thePeaks->Add(thisP);
			npeak++;
		}
		prevPV = prevV;				// step the values to the next freq. bin
		prevV = thisV;
		thisV = nextV;
		nextV = nextNV;
	}
}

// Answer the best match for the given frequency in the given frame
TrackData_op* 
FrameTracker_op::GetBestMatch(float pitch, TrackFrame_op* frame) 
{
	TrackData_op* match =  frame->getTrackNearestFreq(pitch);
	if (match != 0) {				// If it's within the freq. range FreqThreshold
		double frqDiff = fabs(log(match->getPitch()) - log(pitch));
		if (frqDiff < FreqThreshold)
			return match;
	}
	return 0;
}

// Track and group peaks in the given data set;
// do a running forward/backward comparison of all peaks in a track

void 
FrameTracker_op::TrackPeaks() 
{

	TrackFrame_op* prevFr = Tracks.getBaseFrame();
	TrackFrame_op* thisFr = prevFr->getNext();
	TrackFrame_op* nextFr = thisFr->getNext();
	TrackFrame_op* lastFr = nextFr->getNext();
	while (thisFr != 0) {				// Iterate over the frames trying to track peaks
		TrackData_op* baseTr = prevFr->getBaseTrack();
										// Try to track the previous frame's peaks into this frame
		while (baseTr != 0) {			// Find the best freq. match between track and current pks
			float baseP = baseTr->getPitch();
			TrackData_op* match =  GetBestMatch(baseP, thisFr);
			if (match != 0) {
				baseTr->linkTo(match);					// create double links
			} 
			baseTr = baseTr->getHigher();
		}								 // end of current frame
		prevFr = thisFr;
		thisFr = nextFr;
		nextFr = lastFr;
		if (lastFr != 0)
			lastFr = lastFr->getNext();
	}									// end of all tracks
}

// Continue track groups, and gather track statistics

void 
FrameTracker_op::ContinuePeaks() 
{

	TrackFrame_op* base = Tracks.getBaseFrame();
	while (base != 0) {			// Iterate over all frames
		TrackData_op* td = base->getBaseTrack();
		while (td != 0) {		// Iterate over peaks in a frame
			if (td->isHead()) {
				float am = td->getAmplitude();
				float pc = td->getPitch();
				float avgA = am;
				float avgP = pc;
				int i = 1;
				TrackData_op* tl = td->getNext();
				while (tl != 0) {		// Iterate forward over peaks in a track
					am = tl->getAmplitude();
					pc = tl->getPitch();
					avgA += am;
					avgP += pc;
					td->setEndPitch(pc);
					tl = tl->getNext();
					i++;
				}		// end of links
				td->setAvgAmplitude(avgA / (float) i);
				td->setAvgPitch(avgP / (float) i);
			}			// end of track
			td = td->getHigher();			// go to next peak in frame
		}				// end of frame
		base = base->getNext();				// go to next frame
	}
}