5fd37301aab179389c2a828ad00ade1d63e4cedb
[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 static float
26 getFrequencyForMIDIPitch(int midiPitch)
27 {
28     return 440.f * powf(2.0, (float(midiPitch) - 69.0) / 12.0);
29 }
30
31 Pitch::Pitch(float inputSampleRate) :
32     Plugin(inputSampleRate),
33     m_ibuf(0),
34     m_obuf(0),
35     m_pitchdet(0),
36     m_pitchtype(PitchYinFFT),
37     m_minfreq(getFrequencyForMIDIPitch(32)),
38     m_maxfreq(getFrequencyForMIDIPitch(95)),
39     m_silence(-90),
40     m_wrapRange(false),
41     m_stepSize(0),
42     m_blockSize(0)
43 {
44 }
45
46 Pitch::~Pitch()
47 {
48     if (m_pitchdet) del_aubio_pitch(m_pitchdet);
49     if (m_ibuf) del_fvec(m_ibuf);
50     if (m_obuf) del_fvec(m_obuf);
51 }
52
53 string
54 Pitch::getIdentifier() const
55 {
56     return "aubiopitch";
57 }
58
59 string
60 Pitch::getName() const
61 {
62     return "Aubio Pitch Detector";
63 }
64
65 string
66 Pitch::getDescription() const
67 {
68     return "Track estimated note pitches";
69 }
70
71 string
72 Pitch::getMaker() const
73 {
74     return "Paul Brossier (plugin by Chris Cannam)";
75 }
76
77 int
78 Pitch::getPluginVersion() const
79 {
80     return 3;
81 }
82
83 string
84 Pitch::getCopyright() const
85 {
86     return "GPL";
87 }
88
89 bool
90 Pitch::initialise(size_t channels, size_t stepSize, size_t blockSize)
91 {
92     if (channels != 1) {
93         std::cerr << "Pitch::initialise: channels must be 1" << std::endl;
94         return false;
95     }
96
97     m_stepSize = stepSize;
98     m_blockSize = blockSize;
99
100     m_ibuf = new_fvec(stepSize);
101     m_obuf = new_fvec(1);
102
103     reset();
104
105     return true;
106 }
107
108 void
109 Pitch::reset()
110 {
111     if (m_pitchdet) del_aubio_pitch(m_pitchdet);
112
113     m_pitchdet = new_aubio_pitch
114         (const_cast<char *>(getAubioNameForPitchType(m_pitchtype)),
115          m_blockSize,
116          m_stepSize,
117          lrintf(m_inputSampleRate));
118
119     aubio_pitch_set_unit(m_pitchdet, const_cast<char *>("freq"));
120 }
121
122 size_t
123 Pitch::getPreferredStepSize() const
124 {
125     return 512;
126 }
127
128 size_t
129 Pitch::getPreferredBlockSize() const
130 {
131     return 2048;
132 }
133
134 Pitch::ParameterList
135 Pitch::getParameterDescriptors() const
136 {
137     ParameterList list;
138     
139     ParameterDescriptor desc;
140     desc.identifier = "pitchtype";
141     desc.name = "Pitch Detection Function Type";
142     desc.minValue = 0;
143     desc.maxValue = 4;
144     desc.defaultValue = (int)PitchYinFFT;
145     desc.isQuantized = true;
146     desc.quantizeStep = 1;
147     desc.valueNames.push_back("YIN Frequency Estimator");
148     desc.valueNames.push_back("Spectral Comb");
149     desc.valueNames.push_back("Schmitt");
150     desc.valueNames.push_back("Fast Harmonic Comb");
151     desc.valueNames.push_back("YIN with FFT");
152     list.push_back(desc);
153
154     desc = ParameterDescriptor();
155     desc.identifier = "minfreq";
156     desc.name = "Minimum Fundamental Frequency";
157     desc.minValue = 1;
158     desc.maxValue = m_inputSampleRate/2;
159     desc.defaultValue = getFrequencyForMIDIPitch(32);
160     desc.unit = "Hz";
161     desc.isQuantized = false;
162     list.push_back(desc);
163
164     desc = ParameterDescriptor();
165     desc.identifier = "maxfreq";
166     desc.name = "Maximum Fundamental Frequency";
167     desc.minValue = 1;
168     desc.maxValue = m_inputSampleRate/2;
169     desc.defaultValue = getFrequencyForMIDIPitch(95);
170     desc.unit = "Hz";
171     desc.isQuantized = false;
172     list.push_back(desc);
173
174     desc = ParameterDescriptor();
175     desc.identifier = "wraprange";
176     desc.name = "Fold Higher or Lower Frequencies into Range";
177     desc.minValue = 0;
178     desc.maxValue = 1;
179     desc.defaultValue = 0;
180     desc.isQuantized = true;
181     desc.quantizeStep = 1;
182     list.push_back(desc);
183
184     desc = ParameterDescriptor();
185     desc.identifier = "silencethreshold";
186     desc.name = "Silence Threshold";
187     desc.minValue = -120;
188     desc.maxValue = 0;
189     desc.defaultValue = -90;
190     desc.unit = "dB";
191     desc.isQuantized = false;
192     list.push_back(desc);
193
194     return list;
195 }
196
197 float
198 Pitch::getParameter(std::string param) const
199 {
200     if (param == "pitchtype") {
201         return m_pitchtype;
202     } else if (param == "minfreq") {
203         return m_minfreq;
204     } else if (param == "maxfreq") {
205         return m_maxfreq;
206     } else if (param == "wraprange") {
207         return m_wrapRange ? 1.0 : 0.0;
208     } else if (param == "silencethreshold") {
209         return m_silence;
210     } else {
211         return 0.0;
212     }
213 }
214
215 void
216 Pitch::setParameter(std::string param, float value)
217 {
218     if (param == "pitchtype") {
219         switch (lrintf(value)) {
220         case 0: m_pitchtype = PitchYin; break;
221         case 1: m_pitchtype = PitchMComb; break;
222         case 2: m_pitchtype = PitchSchmitt; break;
223         case 3: m_pitchtype = PitchFComb; break;
224         case 4: m_pitchtype = PitchYinFFT; break;
225         }
226     } else if (param == "minfreq") {
227         m_minfreq = value;
228     } else if (param == "maxfreq") {
229         m_maxfreq = value;
230     } else if (param == "wraprange") {
231         m_wrapRange = (value > 0.5);
232     } else if (param == "silencethreshold") {
233         m_silence = value;
234     }
235 }
236
237 Pitch::OutputList
238 Pitch::getOutputDescriptors() const
239 {
240     OutputList list;
241
242     OutputDescriptor d;
243     d.identifier = "frequency";
244     d.name = "Fundamental Frequency";
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_write_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