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