40c310eff3e98f91381f9119b24138453199c7d0
[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_pitchdet(0),
35     m_pitchtype(PitchYinFFT),
36     m_minfreq(getFrequencyForMIDIPitch(32)),
37     m_maxfreq(getFrequencyForMIDIPitch(95)),
38     m_silence(-90),
39     m_wrapRange(false),
40     m_stepSize(0),
41     m_blockSize(0)
42 {
43 }
44
45 Pitch::~Pitch()
46 {
47     if (m_pitchdet) del_aubio_pitch(m_pitchdet);
48     if (m_ibuf) del_fvec(m_ibuf);
49 }
50
51 string
52 Pitch::getIdentifier() const
53 {
54     return "aubiopitch";
55 }
56
57 string
58 Pitch::getName() const
59 {
60     return "Aubio Pitch Detector";
61 }
62
63 string
64 Pitch::getDescription() const
65 {
66     return "Track estimated note pitches";
67 }
68
69 string
70 Pitch::getMaker() const
71 {
72     return "Paul Brossier (plugin by Chris Cannam)";
73 }
74
75 int
76 Pitch::getPluginVersion() const
77 {
78     return 3;
79 }
80
81 string
82 Pitch::getCopyright() const
83 {
84     return "GPL";
85 }
86
87 bool
88 Pitch::initialise(size_t channels, size_t stepSize, size_t blockSize)
89 {
90     if (channels != 1) {
91         std::cerr << "Pitch::initialise: channels must be 1" << std::endl;
92         return false;
93     }
94
95     m_stepSize = stepSize;
96     m_blockSize = blockSize;
97
98     m_ibuf = new_fvec(stepSize);
99
100     m_pitchdet = new_aubio_pitchdetection(blockSize,
101                                           stepSize,
102                                           channels,
103                                           lrintf(m_inputSampleRate),
104                                           m_pitchtype,
105                                           m_pitchmode);
106
107     return true;
108 }
109
110 void
111 Pitch::reset()
112 {
113 }
114
115 size_t
116 Pitch::getPreferredStepSize() const
117 {
118     return 512;
119 }
120
121 size_t
122 Pitch::getPreferredBlockSize() const
123 {
124     return 2048;
125 }
126
127 Pitch::ParameterList
128 Pitch::getParameterDescriptors() const
129 {
130     ParameterList list;
131     
132     ParameterDescriptor desc;
133     desc.identifier = "pitchtype";
134     desc.name = "Pitch Detection Function Type";
135     desc.minValue = 0;
136     desc.maxValue = 4;
137     desc.defaultValue = (int)aubio_pitch_yinfft;
138     desc.isQuantized = true;
139     desc.quantizeStep = 1;
140     desc.valueNames.push_back("YIN Frequency Estimator");
141     desc.valueNames.push_back("Spectral Comb");
142     desc.valueNames.push_back("Schmitt");
143     desc.valueNames.push_back("Fast Harmonic Comb");
144     desc.valueNames.push_back("YIN with FFT");
145     list.push_back(desc);
146
147     desc = ParameterDescriptor();
148     desc.identifier = "minfreq";
149     desc.name = "Minimum Fundamental Frequency";
150     desc.minValue = 1;
151     desc.maxValue = m_inputSampleRate/2;
152     desc.defaultValue = getFrequencyForMIDIPitch(32);
153     desc.unit = "Hz";
154     desc.isQuantized = false;
155     list.push_back(desc);
156
157     desc = ParameterDescriptor();
158     desc.identifier = "maxfreq";
159     desc.name = "Maximum Fundamental Frequency";
160     desc.minValue = 1;
161     desc.maxValue = m_inputSampleRate/2;
162     desc.defaultValue = getFrequencyForMIDIPitch(95);
163     desc.unit = "Hz";
164     desc.isQuantized = false;
165     list.push_back(desc);
166
167     desc = ParameterDescriptor();
168     desc.identifier = "wraprange";
169     desc.name = "Fold Higher or Lower Frequencies into Range";
170     desc.minValue = 0;
171     desc.maxValue = 1;
172     desc.defaultValue = 0;
173     desc.isQuantized = true;
174     desc.quantizeStep = 1;
175     list.push_back(desc);
176
177     desc = ParameterDescriptor();
178     desc.identifier = "silencethreshold";
179     desc.name = "Silence Threshold";
180     desc.minValue = -120;
181     desc.maxValue = 0;
182     desc.defaultValue = -90;
183     desc.unit = "dB";
184     desc.isQuantized = false;
185     list.push_back(desc);
186
187     return list;
188 }
189
190 float
191 Pitch::getParameter(std::string param) const
192 {
193     if (param == "pitchtype") {
194         return m_pitchtype;
195     } else if (param == "minfreq") {
196         return m_minfreq;
197     } else if (param == "maxfreq") {
198         return m_maxfreq;
199     } else if (param == "wraprange") {
200         return m_wrapRange ? 1.0 : 0.0;
201     } else if (param == "silencethreshold") {
202         return m_silence;
203     } else {
204         return 0.0;
205     }
206 }
207
208 void
209 Pitch::setParameter(std::string param, float value)
210 {
211     if (param == "pitchtype") {
212         switch (lrintf(value)) {
213         case 0: m_pitchtype = aubio_pitch_yin; break;
214         case 1: m_pitchtype = aubio_pitch_mcomb; break;
215         case 2: m_pitchtype = aubio_pitch_schmitt; break;
216         case 3: m_pitchtype = aubio_pitch_fcomb; break;
217         case 4: m_pitchtype = aubio_pitch_yinfft; break;
218         }
219     } else if (param == "minfreq") {
220         m_minfreq = value;
221     } else if (param == "maxfreq") {
222         m_maxfreq = value;
223     } else if (param == "wraprange") {
224         m_wrapRange = (value > 0.5);
225     } else if (param == "silencethreshold") {
226         m_silence = value;
227     }
228 }
229
230 Pitch::OutputList
231 Pitch::getOutputDescriptors() const
232 {
233     OutputList list;
234
235     OutputDescriptor d;
236     d.identifier = "frequency";
237     d.name = "Fundamental Frequency";
238     d.unit = "Hz";
239     d.hasFixedBinCount = true;
240     d.binCount = 1;
241     d.hasKnownExtents = false;
242     d.isQuantized = false;
243     d.sampleType = OutputDescriptor::VariableSampleRate;
244     d.sampleRate = 0;
245     if (m_stepSize != 0) {
246         d.sampleRate = m_inputSampleRate / m_stepSize;
247     }
248     list.push_back(d);
249
250     return list;
251 }
252
253 Pitch::FeatureSet
254 Pitch::process(const float *const *inputBuffers,
255                Vamp::RealTime timestamp)
256 {
257     FeatureSet returnFeatures;
258
259     if (m_stepSize == 0) {
260         std::cerr << "Pitch::process: Pitch plugin not initialised" << std::endl;
261         return returnFeatures;
262     }
263
264     for (size_t i = 0; i < m_stepSize; ++i) {
265         for (size_t j = 0; j < m_channelCount; ++j) {
266             fvec_write_sample(m_ibuf, inputBuffers[j][i], j, i);
267         }
268     }
269
270     float freq = aubio_pitchdetection(m_pitchdet, m_ibuf);
271
272     bool silent = aubio_silence_detection(m_ibuf, m_silence);
273     if (silent) {
274 //        std::cerr << "(silent)" << std::endl;
275         return returnFeatures;
276     }
277
278     if (m_wrapRange) {
279         while (freq > 0 && freq < m_minfreq) {
280             freq = freq * 2.0;
281         }
282         while (freq > m_maxfreq) {
283             freq = freq / 2.0;
284         }
285     }
286
287     if (freq < m_minfreq || freq > m_maxfreq) {
288         return returnFeatures;
289     }
290
291     Feature feature;
292     feature.hasTimestamp = true;
293     feature.timestamp = timestamp;
294     feature.values.push_back(freq);
295
296     returnFeatures[0].push_back(feature);
297     return returnFeatures;
298 }
299
300 Pitch::FeatureSet
301 Pitch::getRemainingFeatures()
302 {
303     return FeatureSet();
304 }
305