20189fcfccc7f9cc189a8ed3654d3cf1c1cc0bd5
[vamp-aubio-plugins.git] / plugins / Pitch.cpp
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2
3 /*
4     Vamp feature extraction plugins using Paul Brossier's Aubio library.
5
6     Centre for Digital Music, Queen Mary, University of London.
7     This file copyright 2006 Chris Cannam.
8     
9     This program is free software; you can redistribute it and/or
10     modify it under the terms of the GNU General Public License as
11     published by the Free Software Foundation; either version 2 of the
12     License, or (at your option) any later version.  See the file
13     COPYING included with this distribution for more information.
14
15 */
16
17 #include <math.h>
18 #include "Pitch.h"
19
20 using std::string;
21 using std::vector;
22 using std::cerr;
23 using std::endl;
24
25 Pitch::Pitch(float inputSampleRate) :
26     Plugin(inputSampleRate),
27     m_ibuf(0),
28     m_obuf(0),
29     m_pitchdet(0),
30     m_pitchtype(PitchYinFFT),
31     m_minfreq(aubio_miditofreq(32)),
32     m_maxfreq(aubio_miditofreq(95)),
33     m_silence(-90),
34     m_wrapRange(false),
35     m_stepSize(0),
36     m_blockSize(0)
37 {
38 }
39
40 Pitch::~Pitch()
41 {
42     if (m_pitchdet) del_aubio_pitch(m_pitchdet);
43     if (m_ibuf) del_fvec(m_ibuf);
44     if (m_obuf) del_fvec(m_obuf);
45 }
46
47 string
48 Pitch::getIdentifier() const
49 {
50     return "aubiopitch";
51 }
52
53 string
54 Pitch::getName() const
55 {
56     return "Aubio Pitch Detector";
57 }
58
59 string
60 Pitch::getDescription() const
61 {
62     return "Track estimated note pitches";
63 }
64
65 string
66 Pitch::getMaker() const
67 {
68     return "Paul Brossier (plugin by Chris Cannam)";
69 }
70
71 int
72 Pitch::getPluginVersion() const
73 {
74     return 3;
75 }
76
77 string
78 Pitch::getCopyright() const
79 {
80     return "GPL";
81 }
82
83 bool
84 Pitch::initialise(size_t channels, size_t stepSize, size_t blockSize)
85 {
86     if (channels != 1) {
87         std::cerr << "Pitch::initialise: channels must be 1" << std::endl;
88         return false;
89     }
90
91     m_stepSize = stepSize;
92     m_blockSize = blockSize;
93
94     m_ibuf = new_fvec(stepSize);
95     m_obuf = new_fvec(1);
96
97     reset();
98
99     return true;
100 }
101
102 void
103 Pitch::reset()
104 {
105     if (m_pitchdet) del_aubio_pitch(m_pitchdet);
106
107     m_pitchdet = new_aubio_pitch
108         (const_cast<char *>(getAubioNameForPitchType(m_pitchtype)),
109          m_blockSize,
110          m_stepSize,
111          lrintf(m_inputSampleRate));
112
113     aubio_pitch_set_unit(m_pitchdet, const_cast<char *>("freq"));
114 }
115
116 size_t
117 Pitch::getPreferredStepSize() const
118 {
119     return 512;
120 }
121
122 size_t
123 Pitch::getPreferredBlockSize() const
124 {
125     return 2048;
126 }
127
128 Pitch::ParameterList
129 Pitch::getParameterDescriptors() const
130 {
131     ParameterList list;
132     
133     ParameterDescriptor desc;
134     desc.identifier = "pitchtype";
135     desc.name = "Pitch Detection Function Type";
136     desc.description = "Type of pitch detection function to use";
137     desc.minValue = 0;
138     desc.maxValue = 4;
139     desc.defaultValue = (int)PitchYinFFT;
140     desc.isQuantized = true;
141     desc.quantizeStep = 1;
142     desc.valueNames.push_back("YIN Frequency Estimator");
143     desc.valueNames.push_back("Spectral Comb");
144     desc.valueNames.push_back("Schmitt");
145     desc.valueNames.push_back("Fast Harmonic Comb");
146     desc.valueNames.push_back("YIN with FFT");
147     list.push_back(desc);
148
149     desc = ParameterDescriptor();
150     desc.identifier = "minfreq";
151     desc.name = "Minimum Fundamental Frequency";
152     desc.description = "Lower frequency to look for";
153     desc.minValue = 1;
154     desc.maxValue = m_inputSampleRate/2;
155     desc.defaultValue = aubio_miditofreq(32);
156     desc.unit = "Hz";
157     desc.isQuantized = false;
158     list.push_back(desc);
159
160     desc = ParameterDescriptor();
161     desc.identifier = "maxfreq";
162     desc.name = "Maximum Fundamental Frequency";
163     desc.description = "Highest frequency to look for";
164     desc.minValue = 1;
165     desc.maxValue = m_inputSampleRate/2;
166     desc.defaultValue = aubio_miditofreq(95);
167     desc.unit = "Hz";
168     desc.isQuantized = false;
169     list.push_back(desc);
170
171     desc = ParameterDescriptor();
172     desc.identifier = "wraprange";
173     desc.name = "Fold Higher or Lower Frequencies into Range";
174     desc.description = "Frequencies detected outside the range will be transposed to higher or lower octaves";
175     desc.minValue = 0;
176     desc.maxValue = 1;
177     desc.defaultValue = 0;
178     desc.isQuantized = true;
179     desc.quantizeStep = 1;
180     list.push_back(desc);
181
182     desc = ParameterDescriptor();
183     desc.identifier = "silencethreshold";
184     desc.name = "Silence Threshold";
185     desc.description = "Silence threshold, the higher the least detection";
186     desc.minValue = -120;
187     desc.maxValue = 0;
188     desc.defaultValue = -90;
189     desc.unit = "dB";
190     desc.isQuantized = false;
191     list.push_back(desc);
192
193     return list;
194 }
195
196 float
197 Pitch::getParameter(std::string param) const
198 {
199     if (param == "pitchtype") {
200         return m_pitchtype;
201     } else if (param == "minfreq") {
202         return m_minfreq;
203     } else if (param == "maxfreq") {
204         return m_maxfreq;
205     } else if (param == "wraprange") {
206         return m_wrapRange ? 1.0 : 0.0;
207     } else if (param == "silencethreshold") {
208         return m_silence;
209     } else {
210         return 0.0;
211     }
212 }
213
214 void
215 Pitch::setParameter(std::string param, float value)
216 {
217     if (param == "pitchtype") {
218         switch (lrintf(value)) {
219         case 0: m_pitchtype = PitchYin; break;
220         case 1: m_pitchtype = PitchMComb; break;
221         case 2: m_pitchtype = PitchSchmitt; break;
222         case 3: m_pitchtype = PitchFComb; break;
223         case 4: m_pitchtype = PitchYinFFT; break;
224         }
225     } else if (param == "minfreq") {
226         m_minfreq = value;
227     } else if (param == "maxfreq") {
228         m_maxfreq = value;
229     } else if (param == "wraprange") {
230         m_wrapRange = (value > 0.5);
231     } else if (param == "silencethreshold") {
232         m_silence = value;
233     }
234 }
235
236 Pitch::OutputList
237 Pitch::getOutputDescriptors() const
238 {
239     OutputList list;
240
241     OutputDescriptor d;
242     d.identifier = "frequency";
243     d.name = "Fundamental Frequency";
244     d.description = "List of detected frequencies";
245     d.unit = "Hz";
246     d.hasFixedBinCount = true;
247     d.binCount = 1;
248     d.hasKnownExtents = false;
249     d.isQuantized = false;
250     d.sampleType = OutputDescriptor::VariableSampleRate;
251     d.sampleRate = 0;
252     if (m_stepSize != 0) {
253         d.sampleRate = m_inputSampleRate / m_stepSize;
254     }
255     list.push_back(d);
256
257     return list;
258 }
259
260 Pitch::FeatureSet
261 Pitch::process(const float *const *inputBuffers,
262                Vamp::RealTime timestamp)
263 {
264     FeatureSet returnFeatures;
265
266     if (m_stepSize == 0) {
267         std::cerr << "Pitch::process: Pitch plugin not initialised" << std::endl;
268         return returnFeatures;
269     }
270
271     for (size_t i = 0; i < m_stepSize; ++i) {
272         fvec_set_sample(m_ibuf, inputBuffers[0][i], i);
273     }
274
275     aubio_pitch_do(m_pitchdet, m_ibuf, m_obuf);
276     
277     float freq = m_obuf->data[0];
278
279     bool silent = aubio_silence_detection(m_ibuf, m_silence);
280     if (silent) {
281 //        std::cerr << "(silent)" << std::endl;
282         return returnFeatures;
283     }
284
285     if (m_wrapRange) {
286         while (freq > 0 && freq < m_minfreq) {
287             freq = freq * 2.0;
288         }
289         while (freq > m_maxfreq) {
290             freq = freq / 2.0;
291         }
292     }
293
294     if (freq < m_minfreq || freq > m_maxfreq) {
295         return returnFeatures;
296     }
297
298     Feature feature;
299     feature.hasTimestamp = true;
300     feature.timestamp = timestamp;
301     feature.values.push_back(freq);
302
303     returnFeatures[0].push_back(feature);
304     return returnFeatures;
305 }
306
307 Pitch::FeatureSet
308 Pitch::getRemainingFeatures()
309 {
310     return FeatureSet();
311 }
312