Mercurial > hg > pyin
comparison YinVamp.cpp @ 35:8e50e88417e6 tony
rename VampYin to YinVamp
author | matthiasm |
---|---|
date | Sun, 26 Jan 2014 14:24:49 +0000 |
parents | VampYin.cpp@24943b76a109 |
children | 4db418fafb6d |
comparison
equal
deleted
inserted
replaced
34:5d43ce0eeeb8 | 35:8e50e88417e6 |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 pYIN - A fundamental frequency estimator for monophonic audio | |
5 Centre for Digital Music, Queen Mary, University of London. | |
6 | |
7 This program is free software; you can redistribute it and/or | |
8 modify it under the terms of the GNU General Public License as | |
9 published by the Free Software Foundation; either version 2 of the | |
10 License, or (at your option) any later version. See the file | |
11 COPYING included with this distribution for more information. | |
12 */ | |
13 | |
14 #include "YinVamp.h" | |
15 #include "MonoNote.h" | |
16 | |
17 #include "vamp-sdk/FFT.h" | |
18 | |
19 #include <vector> | |
20 #include <algorithm> | |
21 | |
22 #include <cstdio> | |
23 #include <cmath> | |
24 #include <complex> | |
25 | |
26 using std::string; | |
27 using std::vector; | |
28 using Vamp::RealTime; | |
29 | |
30 | |
31 YinVamp::YinVamp(float inputSampleRate) : | |
32 Plugin(inputSampleRate), | |
33 m_channels(0), | |
34 m_stepSize(256), | |
35 m_blockSize(2048), | |
36 m_fmin(40), | |
37 m_fmax(1000), | |
38 m_yin(2048, inputSampleRate, 0.0), | |
39 m_outNoF0(0), | |
40 m_outNoPeriodicity(0), | |
41 m_outNoRms(0), | |
42 m_outNoSalience(0), | |
43 m_yinParameter(0.15f), | |
44 m_outputUnvoiced(2.0f) | |
45 { | |
46 } | |
47 | |
48 YinVamp::~YinVamp() | |
49 { | |
50 } | |
51 | |
52 string | |
53 YinVamp::getIdentifier() const | |
54 { | |
55 return "yin"; | |
56 } | |
57 | |
58 string | |
59 YinVamp::getName() const | |
60 { | |
61 return "Yin"; | |
62 } | |
63 | |
64 string | |
65 YinVamp::getDescription() const | |
66 { | |
67 return "A vamp implementation of the Yin algorithm for monophonic frequency estimation."; | |
68 } | |
69 | |
70 string | |
71 YinVamp::getMaker() const | |
72 { | |
73 return "Matthias Mauch"; | |
74 } | |
75 | |
76 int | |
77 YinVamp::getPluginVersion() const | |
78 { | |
79 // Increment this each time you release a version that behaves | |
80 // differently from the previous one | |
81 return 1; | |
82 } | |
83 | |
84 string | |
85 YinVamp::getCopyright() const | |
86 { | |
87 return "GPL"; | |
88 } | |
89 | |
90 YinVamp::InputDomain | |
91 YinVamp::getInputDomain() const | |
92 { | |
93 return TimeDomain; | |
94 } | |
95 | |
96 size_t | |
97 YinVamp::getPreferredBlockSize() const | |
98 { | |
99 return 2048; | |
100 } | |
101 | |
102 size_t | |
103 YinVamp::getPreferredStepSize() const | |
104 { | |
105 return 256; | |
106 } | |
107 | |
108 size_t | |
109 YinVamp::getMinChannelCount() const | |
110 { | |
111 return 1; | |
112 } | |
113 | |
114 size_t | |
115 YinVamp::getMaxChannelCount() const | |
116 { | |
117 return 1; | |
118 } | |
119 | |
120 YinVamp::ParameterList | |
121 YinVamp::getParameterDescriptors() const | |
122 { | |
123 ParameterList list; | |
124 | |
125 ParameterDescriptor d; | |
126 d.identifier = "yinThreshold"; | |
127 d.name = "Yin threshold"; | |
128 d.description = "The greedy Yin search for a low value difference function is done once a dip lower than this threshold is reached."; | |
129 d.unit = ""; | |
130 d.minValue = 0.025f; | |
131 d.maxValue = 1.0f; | |
132 d.defaultValue = 0.15f; | |
133 d.isQuantized = true; | |
134 d.quantizeStep = 0.025f; | |
135 | |
136 list.push_back(d); | |
137 | |
138 // d.identifier = "removeunvoiced"; | |
139 // d.name = "Remove pitches classified as unvoiced."; | |
140 // d.description = "If ticked, then the pitch estimator will return the most likely pitch, even if it 'thinks' there isn't any."; | |
141 // d.unit = ""; | |
142 // d.minValue = 0.0f; | |
143 // d.maxValue = 1.0f; | |
144 // d.defaultValue = 0.0f; | |
145 // d.isQuantized = true; | |
146 // d.quantizeStep = 1.0f; | |
147 // d.valueNames.clear(); | |
148 // list.push_back(d); | |
149 | |
150 d.identifier = "outputunvoiced"; | |
151 d.valueNames.clear(); | |
152 d.name = "Output estimates classified as unvoiced?"; | |
153 d.description = "."; | |
154 d.unit = ""; | |
155 d.minValue = 0.0f; | |
156 d.maxValue = 2.0f; | |
157 d.defaultValue = 2.0f; | |
158 d.isQuantized = true; | |
159 d.quantizeStep = 1.0f; | |
160 d.valueNames.push_back("No"); | |
161 d.valueNames.push_back("Yes"); | |
162 d.valueNames.push_back("Yes, as negative frequencies"); | |
163 list.push_back(d); | |
164 | |
165 return list; | |
166 } | |
167 | |
168 float | |
169 YinVamp::getParameter(string identifier) const | |
170 { | |
171 if (identifier == "yinThreshold") { | |
172 return m_yinParameter; | |
173 } | |
174 if (identifier == "outputunvoiced") { | |
175 return m_outputUnvoiced; | |
176 } | |
177 return 0.f; | |
178 } | |
179 | |
180 void | |
181 YinVamp::setParameter(string identifier, float value) | |
182 { | |
183 if (identifier == "yinThreshold") | |
184 { | |
185 m_yinParameter = value; | |
186 } | |
187 if (identifier == "outputunvoiced") | |
188 { | |
189 m_outputUnvoiced = value; | |
190 } | |
191 } | |
192 | |
193 YinVamp::ProgramList | |
194 YinVamp::getPrograms() const | |
195 { | |
196 ProgramList list; | |
197 return list; | |
198 } | |
199 | |
200 string | |
201 YinVamp::getCurrentProgram() const | |
202 { | |
203 return ""; // no programs | |
204 } | |
205 | |
206 void | |
207 YinVamp::selectProgram(string name) | |
208 { | |
209 } | |
210 | |
211 YinVamp::OutputList | |
212 YinVamp::getOutputDescriptors() const | |
213 { | |
214 OutputList outputs; | |
215 | |
216 OutputDescriptor d; | |
217 | |
218 int outputNumber = 0; | |
219 | |
220 d.identifier = "f0"; | |
221 d.name = "Estimated f0"; | |
222 d.description = "Estimated fundamental frequency"; | |
223 d.unit = "Hz"; | |
224 d.hasFixedBinCount = true; | |
225 d.binCount = 1; | |
226 d.hasKnownExtents = true; | |
227 d.minValue = m_fmin; | |
228 d.maxValue = 500; | |
229 d.isQuantized = false; | |
230 d.sampleType = OutputDescriptor::FixedSampleRate; | |
231 d.sampleRate = (m_inputSampleRate / m_stepSize); | |
232 d.hasDuration = false; | |
233 outputs.push_back(d); | |
234 m_outNoF0 = outputNumber++; | |
235 | |
236 d.identifier = "periodicity"; | |
237 d.name = "Periodicity"; | |
238 d.description = "by-product of Yin f0 estimation"; | |
239 d.unit = ""; | |
240 d.hasFixedBinCount = true; | |
241 d.binCount = 1; | |
242 d.hasKnownExtents = true; | |
243 d.minValue = 0; | |
244 d.maxValue = 1; | |
245 d.isQuantized = false; | |
246 d.sampleType = OutputDescriptor::FixedSampleRate; | |
247 d.sampleRate = (m_inputSampleRate / m_stepSize); | |
248 d.hasDuration = false; | |
249 outputs.push_back(d); | |
250 m_outNoPeriodicity = outputNumber++; | |
251 | |
252 d.identifier = "rms"; | |
253 d.name = "Root mean square"; | |
254 d.description = "Root mean square of the waveform."; | |
255 d.unit = ""; | |
256 d.hasFixedBinCount = true; | |
257 d.binCount = 1; | |
258 d.hasKnownExtents = true; | |
259 d.minValue = 0; | |
260 d.maxValue = 1; | |
261 d.isQuantized = false; | |
262 d.sampleType = OutputDescriptor::FixedSampleRate; | |
263 d.sampleRate = (m_inputSampleRate / m_stepSize); | |
264 d.hasDuration = false; | |
265 outputs.push_back(d); | |
266 m_outNoRms = outputNumber++; | |
267 | |
268 d.identifier = "salience"; | |
269 d.name = "Salience"; | |
270 d.description = "Yin Salience"; | |
271 d.hasFixedBinCount = true; | |
272 d.binCount = m_blockSize / 2; | |
273 d.hasKnownExtents = true; | |
274 d.minValue = 0; | |
275 d.maxValue = 1; | |
276 d.isQuantized = false; | |
277 d.sampleType = OutputDescriptor::FixedSampleRate; | |
278 d.sampleRate = (m_inputSampleRate / m_stepSize); | |
279 d.hasDuration = false; | |
280 outputs.push_back(d); | |
281 m_outNoSalience = outputNumber++; | |
282 | |
283 return outputs; | |
284 } | |
285 | |
286 bool | |
287 YinVamp::initialise(size_t channels, size_t stepSize, size_t blockSize) | |
288 { | |
289 if (channels < getMinChannelCount() || | |
290 channels > getMaxChannelCount()) return false; | |
291 | |
292 /* | |
293 std::cerr << "YinVamp::initialise: channels = " << channels | |
294 << ", stepSize = " << stepSize << ", blockSize = " << blockSize | |
295 << std::endl; | |
296 */ | |
297 m_channels = channels; | |
298 m_stepSize = stepSize; | |
299 m_blockSize = blockSize; | |
300 | |
301 reset(); | |
302 | |
303 return true; | |
304 } | |
305 | |
306 void | |
307 YinVamp::reset() | |
308 { | |
309 m_yin.setThreshold(m_yinParameter); | |
310 m_yin.setFrameSize(m_blockSize); | |
311 /* | |
312 std::cerr << "YinVamp::reset: yin threshold set to " << (m_yinParameter) | |
313 << ", blockSize = " << m_blockSize | |
314 << std::endl; | |
315 */ | |
316 } | |
317 | |
318 YinVamp::FeatureSet | |
319 YinVamp::process(const float *const *inputBuffers, RealTime timestamp) | |
320 { | |
321 timestamp = timestamp + Vamp::RealTime::frame2RealTime(m_blockSize/4, lrintf(m_inputSampleRate)); | |
322 FeatureSet fs; | |
323 | |
324 double *dInputBuffers = new double[m_blockSize]; | |
325 for (size_t i = 0; i < m_blockSize; ++i) dInputBuffers[i] = inputBuffers[0][i]; | |
326 | |
327 Yin::YinOutput yo = m_yin.process(dInputBuffers); | |
328 // std::cerr << "f0 in YinVamp: " << yo.f0 << std::endl; | |
329 Feature f; | |
330 f.hasTimestamp = true; | |
331 f.timestamp = timestamp; | |
332 if (m_outputUnvoiced == 0.0f) | |
333 { | |
334 // std::cerr << "f0 in YinVamp: " << yo.f0 << std::endl; | |
335 if (yo.f0 > 0 && yo.f0 < m_fmax && yo.f0 > m_fmin) { | |
336 f.values.push_back(yo.f0); | |
337 fs[m_outNoF0].push_back(f); | |
338 } | |
339 } else if (m_outputUnvoiced == 1.0f) | |
340 { | |
341 if (fabs(yo.f0) < m_fmax && fabs(yo.f0) > m_fmin) { | |
342 f.values.push_back(fabs(yo.f0)); | |
343 fs[m_outNoF0].push_back(f); | |
344 } | |
345 } else | |
346 { | |
347 if (fabs(yo.f0) < m_fmax && fabs(yo.f0) > m_fmin) { | |
348 f.values.push_back(yo.f0); | |
349 fs[m_outNoF0].push_back(f); | |
350 } | |
351 } | |
352 | |
353 f.values.clear(); | |
354 f.values.push_back(yo.rms); | |
355 fs[m_outNoRms].push_back(f); | |
356 | |
357 f.values.clear(); | |
358 for (size_t iBin = 0; iBin < yo.salience.size(); ++iBin) | |
359 { | |
360 f.values.push_back(yo.salience[iBin]); | |
361 } | |
362 fs[m_outNoSalience].push_back(f); | |
363 | |
364 f.values.clear(); | |
365 // f.values[0] = yo.periodicity; | |
366 f.values.push_back(yo.periodicity); | |
367 fs[m_outNoPeriodicity].push_back(f); | |
368 | |
369 delete [] dInputBuffers; | |
370 | |
371 return fs; | |
372 } | |
373 | |
374 YinVamp::FeatureSet | |
375 YinVamp::getRemainingFeatures() | |
376 { | |
377 FeatureSet fs; | |
378 return fs; | |
379 } |