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