matthiasm@32
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
matthiasm@32
|
2
|
matthiasm@32
|
3 /*
|
matthiasm@32
|
4 pYIN - A fundamental frequency estimator for monophonic audio
|
matthiasm@32
|
5 Centre for Digital Music, Queen Mary, University of London.
|
matthiasm@32
|
6
|
matthiasm@32
|
7 This program is free software; you can redistribute it and/or
|
matthiasm@32
|
8 modify it under the terms of the GNU General Public License as
|
matthiasm@32
|
9 published by the Free Software Foundation; either version 2 of the
|
matthiasm@32
|
10 License, or (at your option) any later version. See the file
|
matthiasm@32
|
11 COLocalCandidatePYING included with this distribution for more information.
|
matthiasm@32
|
12 */
|
matthiasm@32
|
13
|
matthiasm@32
|
14 #include "LocalCandidatePYIN.h"
|
matthiasm@32
|
15 #include "MonoPitch.h"
|
matthiasm@32
|
16 #include "YinUtil.h"
|
matthiasm@32
|
17
|
matthiasm@32
|
18 #include "vamp-sdk/FFT.h"
|
matthiasm@32
|
19
|
matthiasm@32
|
20 #include <vector>
|
matthiasm@32
|
21 #include <algorithm>
|
matthiasm@32
|
22
|
matthiasm@32
|
23 #include <cstdio>
|
matthiasm@32
|
24 #include <sstream>
|
matthiasm@32
|
25 // #include <iostream>
|
matthiasm@32
|
26 #include <cmath>
|
matthiasm@32
|
27 #include <complex>
|
matthiasm@32
|
28
|
matthiasm@32
|
29 using std::string;
|
matthiasm@32
|
30 using std::vector;
|
matthiasm@32
|
31 using Vamp::RealTime;
|
matthiasm@32
|
32
|
matthiasm@32
|
33
|
matthiasm@32
|
34 LocalCandidatePYIN::LocalCandidatePYIN(float inputSampleRate) :
|
matthiasm@32
|
35 Plugin(inputSampleRate),
|
matthiasm@32
|
36 m_channels(0),
|
matthiasm@32
|
37 m_stepSize(256),
|
matthiasm@32
|
38 m_blockSize(2048),
|
matthiasm@32
|
39 m_fmin(40),
|
matthiasm@32
|
40 m_fmax(700),
|
matthiasm@32
|
41 m_yin(2048, inputSampleRate, 0.0),
|
matthiasm@32
|
42 m_oPitchTrackCandidates(0),
|
matthiasm@32
|
43 m_threshDistr(2.0f),
|
matthiasm@32
|
44 m_outputUnvoiced(0.0f),
|
matthiasm@32
|
45 m_pitchProb(0),
|
matthiasm@32
|
46 m_timestamp(0),
|
matthiasm@32
|
47 m_nCandidate(20)
|
matthiasm@32
|
48 {
|
matthiasm@32
|
49 }
|
matthiasm@32
|
50
|
matthiasm@32
|
51 LocalCandidatePYIN::~LocalCandidatePYIN()
|
matthiasm@32
|
52 {
|
matthiasm@32
|
53 }
|
matthiasm@32
|
54
|
matthiasm@32
|
55 string
|
matthiasm@32
|
56 LocalCandidatePYIN::getIdentifier() const
|
matthiasm@32
|
57 {
|
matthiasm@32
|
58 return "localcandidatepyin";
|
matthiasm@32
|
59 }
|
matthiasm@32
|
60
|
matthiasm@32
|
61 string
|
matthiasm@32
|
62 LocalCandidatePYIN::getName() const
|
matthiasm@32
|
63 {
|
matthiasm@32
|
64 return "Local Candidate PYIN";
|
matthiasm@32
|
65 }
|
matthiasm@32
|
66
|
matthiasm@32
|
67 string
|
matthiasm@32
|
68 LocalCandidatePYIN::getDescription() const
|
matthiasm@32
|
69 {
|
matthiasm@32
|
70 return "Monophonic pitch and note tracking based on a probabilistic Yin extension.";
|
matthiasm@32
|
71 }
|
matthiasm@32
|
72
|
matthiasm@32
|
73 string
|
matthiasm@32
|
74 LocalCandidatePYIN::getMaker() const
|
matthiasm@32
|
75 {
|
matthiasm@32
|
76 return "Matthias Mauch";
|
matthiasm@32
|
77 }
|
matthiasm@32
|
78
|
matthiasm@32
|
79 int
|
matthiasm@32
|
80 LocalCandidatePYIN::getPluginVersion() const
|
matthiasm@32
|
81 {
|
matthiasm@32
|
82 // Increment this each time you release a version that behaves
|
matthiasm@32
|
83 // differently from the previous one
|
matthiasm@32
|
84 return 1;
|
matthiasm@32
|
85 }
|
matthiasm@32
|
86
|
matthiasm@32
|
87 string
|
matthiasm@32
|
88 LocalCandidatePYIN::getCopyright() const
|
matthiasm@32
|
89 {
|
matthiasm@32
|
90 return "GPL";
|
matthiasm@32
|
91 }
|
matthiasm@32
|
92
|
matthiasm@32
|
93 LocalCandidatePYIN::InputDomain
|
matthiasm@32
|
94 LocalCandidatePYIN::getInputDomain() const
|
matthiasm@32
|
95 {
|
matthiasm@32
|
96 return TimeDomain;
|
matthiasm@32
|
97 }
|
matthiasm@32
|
98
|
matthiasm@32
|
99 size_t
|
matthiasm@32
|
100 LocalCandidatePYIN::getPreferredBlockSize() const
|
matthiasm@32
|
101 {
|
matthiasm@32
|
102 return 2048;
|
matthiasm@32
|
103 }
|
matthiasm@32
|
104
|
matthiasm@32
|
105 size_t
|
matthiasm@32
|
106 LocalCandidatePYIN::getPreferredStepSize() const
|
matthiasm@32
|
107 {
|
matthiasm@32
|
108 return 256;
|
matthiasm@32
|
109 }
|
matthiasm@32
|
110
|
matthiasm@32
|
111 size_t
|
matthiasm@32
|
112 LocalCandidatePYIN::getMinChannelCount() const
|
matthiasm@32
|
113 {
|
matthiasm@32
|
114 return 1;
|
matthiasm@32
|
115 }
|
matthiasm@32
|
116
|
matthiasm@32
|
117 size_t
|
matthiasm@32
|
118 LocalCandidatePYIN::getMaxChannelCount() const
|
matthiasm@32
|
119 {
|
matthiasm@32
|
120 return 1;
|
matthiasm@32
|
121 }
|
matthiasm@32
|
122
|
matthiasm@32
|
123 LocalCandidatePYIN::ParameterList
|
matthiasm@32
|
124 LocalCandidatePYIN::getParameterDescriptors() const
|
matthiasm@32
|
125 {
|
matthiasm@32
|
126 ParameterList list;
|
matthiasm@32
|
127
|
matthiasm@32
|
128 ParameterDescriptor d;
|
matthiasm@32
|
129
|
matthiasm@32
|
130 d.identifier = "threshdistr";
|
matthiasm@32
|
131 d.name = "Yin threshold distribution";
|
matthiasm@32
|
132 d.description = ".";
|
matthiasm@32
|
133 d.unit = "";
|
matthiasm@32
|
134 d.minValue = 0.0f;
|
matthiasm@32
|
135 d.maxValue = 7.0f;
|
matthiasm@32
|
136 d.defaultValue = 2.0f;
|
matthiasm@32
|
137 d.isQuantized = true;
|
matthiasm@32
|
138 d.quantizeStep = 1.0f;
|
matthiasm@32
|
139 d.valueNames.push_back("Uniform");
|
matthiasm@32
|
140 d.valueNames.push_back("Beta (mean 0.10)");
|
matthiasm@32
|
141 d.valueNames.push_back("Beta (mean 0.15)");
|
matthiasm@32
|
142 d.valueNames.push_back("Beta (mean 0.20)");
|
matthiasm@32
|
143 d.valueNames.push_back("Beta (mean 0.30)");
|
matthiasm@32
|
144 d.valueNames.push_back("Single Value 0.10");
|
matthiasm@32
|
145 d.valueNames.push_back("Single Value 0.15");
|
matthiasm@32
|
146 d.valueNames.push_back("Single Value 0.20");
|
matthiasm@32
|
147 list.push_back(d);
|
matthiasm@32
|
148
|
matthiasm@32
|
149 d.identifier = "outputunvoiced";
|
matthiasm@32
|
150 d.valueNames.clear();
|
matthiasm@32
|
151 d.name = "Output estimates classified as unvoiced?";
|
matthiasm@32
|
152 d.description = ".";
|
matthiasm@32
|
153 d.unit = "";
|
matthiasm@32
|
154 d.minValue = 0.0f;
|
matthiasm@32
|
155 d.maxValue = 2.0f;
|
matthiasm@32
|
156 d.defaultValue = 0.0f;
|
matthiasm@32
|
157 d.isQuantized = true;
|
matthiasm@32
|
158 d.quantizeStep = 1.0f;
|
matthiasm@32
|
159 d.valueNames.push_back("No");
|
matthiasm@32
|
160 d.valueNames.push_back("Yes");
|
matthiasm@32
|
161 d.valueNames.push_back("Yes, as negative frequencies");
|
matthiasm@32
|
162 list.push_back(d);
|
matthiasm@32
|
163
|
matthiasm@32
|
164 return list;
|
matthiasm@32
|
165 }
|
matthiasm@32
|
166
|
matthiasm@32
|
167 float
|
matthiasm@32
|
168 LocalCandidatePYIN::getParameter(string identifier) const
|
matthiasm@32
|
169 {
|
matthiasm@32
|
170 if (identifier == "threshdistr") {
|
matthiasm@32
|
171 return m_threshDistr;
|
matthiasm@32
|
172 }
|
matthiasm@32
|
173 if (identifier == "outputunvoiced") {
|
matthiasm@32
|
174 return m_outputUnvoiced;
|
matthiasm@32
|
175 }
|
matthiasm@32
|
176 return 0.f;
|
matthiasm@32
|
177 }
|
matthiasm@32
|
178
|
matthiasm@32
|
179 void
|
matthiasm@32
|
180 LocalCandidatePYIN::setParameter(string identifier, float value)
|
matthiasm@32
|
181 {
|
matthiasm@32
|
182 if (identifier == "threshdistr")
|
matthiasm@32
|
183 {
|
matthiasm@32
|
184 m_threshDistr = value;
|
matthiasm@32
|
185 }
|
matthiasm@32
|
186 if (identifier == "outputunvoiced")
|
matthiasm@32
|
187 {
|
matthiasm@32
|
188 m_outputUnvoiced = value;
|
matthiasm@32
|
189 }
|
matthiasm@32
|
190
|
matthiasm@32
|
191 }
|
matthiasm@32
|
192
|
matthiasm@32
|
193 LocalCandidatePYIN::ProgramList
|
matthiasm@32
|
194 LocalCandidatePYIN::getPrograms() const
|
matthiasm@32
|
195 {
|
matthiasm@32
|
196 ProgramList list;
|
matthiasm@32
|
197 return list;
|
matthiasm@32
|
198 }
|
matthiasm@32
|
199
|
matthiasm@32
|
200 string
|
matthiasm@32
|
201 LocalCandidatePYIN::getCurrentProgram() const
|
matthiasm@32
|
202 {
|
matthiasm@32
|
203 return ""; // no programs
|
matthiasm@32
|
204 }
|
matthiasm@32
|
205
|
matthiasm@32
|
206 void
|
matthiasm@32
|
207 LocalCandidatePYIN::selectProgram(string name)
|
matthiasm@32
|
208 {
|
matthiasm@32
|
209 }
|
matthiasm@32
|
210
|
matthiasm@32
|
211 LocalCandidatePYIN::OutputList
|
matthiasm@32
|
212 LocalCandidatePYIN::getOutputDescriptors() const
|
matthiasm@32
|
213 {
|
matthiasm@32
|
214 OutputList outputs;
|
matthiasm@32
|
215
|
matthiasm@32
|
216 OutputDescriptor d;
|
matthiasm@32
|
217
|
matthiasm@32
|
218 int outputNumber = 0;
|
matthiasm@32
|
219
|
matthiasm@32
|
220 d.identifier = "pitchtrackcandidates";
|
matthiasm@32
|
221 d.name = "Pitch track candidates";
|
matthiasm@32
|
222 d.description = "Multiple candidate pitch tracks.";
|
matthiasm@32
|
223 d.unit = "Hz";
|
matthiasm@32
|
224 d.hasFixedBinCount = false;
|
matthiasm@32
|
225 // d.binCount = 1;
|
matthiasm@32
|
226 d.hasKnownExtents = true;
|
matthiasm@32
|
227 d.minValue = m_fmin;
|
matthiasm@32
|
228 d.maxValue = 500;
|
matthiasm@32
|
229 d.isQuantized = false;
|
matthiasm@32
|
230 d.sampleType = OutputDescriptor::FixedSampleRate;
|
matthiasm@32
|
231 d.sampleRate = (m_inputSampleRate / m_stepSize);
|
matthiasm@32
|
232 d.hasDuration = false;
|
matthiasm@32
|
233 outputs.push_back(d);
|
matthiasm@32
|
234 // m_oPitchTrackCandidates = outputNumber++;
|
matthiasm@32
|
235
|
matthiasm@32
|
236 return outputs;
|
matthiasm@32
|
237 }
|
matthiasm@32
|
238
|
matthiasm@32
|
239 bool
|
matthiasm@32
|
240 LocalCandidatePYIN::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
matthiasm@32
|
241 {
|
matthiasm@32
|
242 if (channels < getMinChannelCount() ||
|
matthiasm@32
|
243 channels > getMaxChannelCount()) return false;
|
matthiasm@32
|
244
|
matthiasm@32
|
245 /*
|
matthiasm@32
|
246 std::cerr << "LocalCandidatePYIN::initialise: channels = " << channels
|
matthiasm@32
|
247 << ", stepSize = " << stepSize << ", blockSize = " << blockSize
|
matthiasm@32
|
248 << std::endl;
|
matthiasm@32
|
249 */
|
matthiasm@32
|
250 m_channels = channels;
|
matthiasm@32
|
251 m_stepSize = stepSize;
|
matthiasm@32
|
252 m_blockSize = blockSize;
|
matthiasm@32
|
253
|
matthiasm@32
|
254 reset();
|
matthiasm@32
|
255
|
matthiasm@32
|
256 return true;
|
matthiasm@32
|
257 }
|
matthiasm@32
|
258
|
matthiasm@32
|
259 void
|
matthiasm@32
|
260 LocalCandidatePYIN::reset()
|
matthiasm@32
|
261 {
|
matthiasm@32
|
262 m_yin.setThresholdDistr(m_threshDistr);
|
matthiasm@32
|
263 m_yin.setFrameSize(m_blockSize);
|
matthiasm@32
|
264
|
matthiasm@32
|
265 m_pitchProb.clear();
|
matthiasm@32
|
266 for (size_t iCandidate = 0; iCandidate < m_nCandidate; ++iCandidate)
|
matthiasm@32
|
267 {
|
matthiasm@32
|
268 m_pitchProb.push_back(vector<vector<pair<double, double> > >());
|
matthiasm@32
|
269 }
|
matthiasm@32
|
270 m_timestamp.clear();
|
matthiasm@32
|
271 /*
|
matthiasm@32
|
272 std::cerr << "LocalCandidatePYIN::reset"
|
matthiasm@32
|
273 << ", blockSize = " << m_blockSize
|
matthiasm@32
|
274 << std::endl;
|
matthiasm@32
|
275 */
|
matthiasm@32
|
276 }
|
matthiasm@32
|
277
|
matthiasm@32
|
278 LocalCandidatePYIN::FeatureSet
|
matthiasm@32
|
279 LocalCandidatePYIN::process(const float *const *inputBuffers, RealTime timestamp)
|
matthiasm@32
|
280 {
|
matthiasm@32
|
281 timestamp = timestamp + Vamp::RealTime::frame2RealTime(m_blockSize/4, lrintf(m_inputSampleRate));
|
matthiasm@32
|
282 FeatureSet fs;
|
matthiasm@32
|
283
|
matthiasm@32
|
284 double *dInputBuffers = new double[m_blockSize];
|
matthiasm@32
|
285 for (size_t i = 0; i < m_blockSize; ++i) dInputBuffers[i] = inputBuffers[0][i];
|
matthiasm@32
|
286
|
matthiasm@32
|
287 size_t yinBufferSize = m_blockSize/2;
|
matthiasm@32
|
288 double* yinBuffer = new double[yinBufferSize];
|
matthiasm@32
|
289 YinUtil::fastDifference(dInputBuffers, yinBuffer, yinBufferSize);
|
matthiasm@32
|
290
|
matthiasm@32
|
291 delete [] dInputBuffers;
|
matthiasm@32
|
292
|
matthiasm@32
|
293 YinUtil::cumulativeDifference(yinBuffer, yinBufferSize);
|
matthiasm@32
|
294
|
matthiasm@32
|
295 for (size_t iCandidate = 0; iCandidate < m_nCandidate; ++iCandidate)
|
matthiasm@32
|
296 {
|
matthiasm@32
|
297 float minFrequency = m_fmin * std::pow(2,(3.0*iCandidate)/12);
|
matthiasm@32
|
298 float maxFrequency = m_fmin * std::pow(2,(3.0*iCandidate+9)/12);
|
matthiasm@34
|
299 vector<double> peakProbability = YinUtil::yinProb(yinBuffer,
|
matthiasm@34
|
300 m_threshDistr,
|
matthiasm@34
|
301 yinBufferSize,
|
matthiasm@34
|
302 m_inputSampleRate/maxFrequency,
|
matthiasm@34
|
303 m_inputSampleRate/minFrequency);
|
matthiasm@32
|
304
|
matthiasm@32
|
305 vector<pair<double, double> > tempPitchProb;
|
matthiasm@32
|
306 for (size_t iBuf = 0; iBuf < yinBufferSize; ++iBuf)
|
matthiasm@32
|
307 {
|
matthiasm@32
|
308 if (peakProbability[iBuf] > 0)
|
matthiasm@32
|
309 {
|
matthiasm@32
|
310 double currentF0 =
|
matthiasm@32
|
311 m_inputSampleRate * (1.0 /
|
matthiasm@32
|
312 YinUtil::parabolicInterpolation(yinBuffer, iBuf, yinBufferSize));
|
matthiasm@32
|
313 double tempPitch = 12 * std::log(currentF0/440)/std::log(2.) + 69;
|
matthiasm@32
|
314 tempPitchProb.push_back(pair<double, double>(tempPitch, peakProbability[iBuf]));
|
matthiasm@32
|
315 }
|
matthiasm@32
|
316 }
|
matthiasm@32
|
317 m_pitchProb[iCandidate].push_back(tempPitchProb);
|
matthiasm@32
|
318 }
|
matthiasm@32
|
319 m_timestamp.push_back(timestamp);
|
matthiasm@32
|
320
|
matthiasm@32
|
321 return fs;
|
matthiasm@32
|
322 }
|
matthiasm@32
|
323
|
matthiasm@32
|
324 LocalCandidatePYIN::FeatureSet
|
matthiasm@32
|
325 LocalCandidatePYIN::getRemainingFeatures()
|
matthiasm@32
|
326 {
|
matthiasm@32
|
327 FeatureSet fs;
|
matthiasm@32
|
328 Feature f;
|
matthiasm@32
|
329 f.hasTimestamp = true;
|
matthiasm@32
|
330 f.hasDuration = false;
|
matthiasm@32
|
331 f.values.push_back(0);
|
matthiasm@32
|
332
|
matthiasm@32
|
333 std::cerr << "in remaining features" << std::endl;
|
matthiasm@32
|
334
|
matthiasm@32
|
335 if (m_pitchProb.empty()) {
|
matthiasm@32
|
336 return fs;
|
matthiasm@32
|
337 }
|
matthiasm@32
|
338
|
matthiasm@32
|
339 // MONO-PITCH STUFF
|
matthiasm@32
|
340 MonoPitch mp;
|
matthiasm@32
|
341 size_t nFrame = m_timestamp.size();
|
matthiasm@32
|
342 vector<vector<float> > pitchTracks;
|
matthiasm@32
|
343 vector<float> freqSum = vector<float>(m_nCandidate);
|
matthiasm@32
|
344 vector<float> freqNumber = vector<float>(m_nCandidate);
|
matthiasm@32
|
345 vector<float> freqMean = vector<float>(m_nCandidate);
|
matthiasm@32
|
346
|
matthiasm@32
|
347 for (size_t iCandidate = 0; iCandidate < m_nCandidate; ++iCandidate)
|
matthiasm@32
|
348 {
|
matthiasm@32
|
349 pitchTracks.push_back(vector<float>(nFrame));
|
matthiasm@32
|
350 vector<float> mpOut = mp.process(m_pitchProb[iCandidate]);
|
matthiasm@32
|
351 for (size_t iFrame = 0; iFrame < nFrame; ++iFrame)
|
matthiasm@32
|
352 {
|
matthiasm@32
|
353 if (mpOut[iFrame] > 0) {
|
matthiasm@32
|
354 pitchTracks[iCandidate][iFrame] = mpOut[iFrame];
|
matthiasm@32
|
355 freqSum[iCandidate] += mpOut[iFrame];
|
matthiasm@32
|
356 freqNumber[iCandidate]++;
|
matthiasm@32
|
357 }
|
matthiasm@32
|
358 }
|
matthiasm@32
|
359 freqMean[iCandidate] = freqSum[iCandidate]*1.0/freqNumber[iCandidate];
|
matthiasm@32
|
360 }
|
matthiasm@32
|
361
|
matthiasm@34
|
362 vector<size_t> duplicates;
|
matthiasm@34
|
363 for (size_t iCandidate = 0; iCandidate < m_nCandidate; ++iCandidate) {
|
matthiasm@34
|
364 for (size_t jCandidate = iCandidate+1; jCandidate < m_nCandidate; ++jCandidate) {
|
matthiasm@34
|
365 size_t countEqual = 0;
|
matthiasm@34
|
366 for (size_t iFrame = 0; iFrame < nFrame; ++iFrame)
|
matthiasm@34
|
367 {
|
matthiasm@34
|
368 if (fabs(pitchTracks[iCandidate][iFrame]/pitchTracks[jCandidate][iFrame]-1)<0.01)
|
matthiasm@34
|
369 countEqual++;
|
matthiasm@34
|
370 }
|
matthiasm@34
|
371 if (countEqual * 1.0 / nFrame > 0.8) {
|
matthiasm@34
|
372 if (freqNumber[iCandidate] > freqNumber[jCandidate]) {
|
matthiasm@34
|
373 duplicates.push_back(jCandidate);
|
matthiasm@34
|
374 } else {
|
matthiasm@34
|
375 duplicates.push_back(iCandidate);
|
matthiasm@34
|
376 }
|
matthiasm@34
|
377 }
|
matthiasm@34
|
378 }
|
matthiasm@34
|
379 }
|
matthiasm@34
|
380
|
matthiasm@32
|
381 int actualCandidateNumber = 0;
|
matthiasm@32
|
382 for (size_t iCandidate = 0; iCandidate < m_nCandidate; ++iCandidate) {
|
matthiasm@34
|
383 bool isDuplicate = false;
|
matthiasm@34
|
384 for (size_t i = 0; i < duplicates.size(); ++i) {
|
matthiasm@34
|
385 std::cerr << duplicates[i] << std::endl;
|
matthiasm@34
|
386 if (duplicates[i] == iCandidate) {
|
matthiasm@34
|
387 isDuplicate = true;
|
matthiasm@34
|
388 break;
|
matthiasm@34
|
389 }
|
matthiasm@34
|
390 }
|
matthiasm@34
|
391 if (!isDuplicate && freqNumber[iCandidate] > 0.8*nFrame)
|
matthiasm@32
|
392 {
|
matthiasm@32
|
393 std::ostringstream convert;
|
matthiasm@32
|
394 convert << actualCandidateNumber++;
|
matthiasm@32
|
395 f.label = convert.str();
|
matthiasm@32
|
396 std::cerr << freqNumber[iCandidate] << " " << freqMean[iCandidate] << std::endl;
|
matthiasm@32
|
397 for (size_t iFrame = 0; iFrame < nFrame; ++iFrame)
|
matthiasm@32
|
398 {
|
matthiasm@32
|
399 if (pitchTracks[iCandidate][iFrame] > 0)
|
matthiasm@32
|
400 {
|
matthiasm@32
|
401 f.values[0] = pitchTracks[iCandidate][iFrame];
|
matthiasm@32
|
402 f.timestamp = m_timestamp[iFrame];
|
matthiasm@32
|
403 fs[m_oPitchTrackCandidates].push_back(f);
|
matthiasm@32
|
404 }
|
matthiasm@32
|
405 }
|
matthiasm@32
|
406 }
|
matthiasm@32
|
407 // std::cerr << freqNumber[iCandidate] << " " << (freqSum[iCandidate]*1.0/freqNumber[iCandidate]) << std::endl;
|
matthiasm@32
|
408 }
|
matthiasm@32
|
409
|
matthiasm@32
|
410 // only retain those that are close to their means
|
matthiasm@32
|
411
|
matthiasm@32
|
412 return fs;
|
matthiasm@32
|
413 }
|