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