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