Merge aubio.org:/git/aubio/aubio
[aubio.git] / src / pitch / pitch.c
1 /*
2   Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
3
4   This file is part of aubio.
5
6   aubio is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   aubio is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with aubio.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #include "aubio_priv.h"
22 #include "fvec.h"
23 #include "cvec.h"
24 #include "lvec.h"
25 #include "mathutils.h"
26 #include "musicutils.h"
27 #include "spectral/phasevoc.h"
28 #include "temporal/filter.h"
29 #include "temporal/c_weighting.h"
30 #include "pitch/pitchmcomb.h"
31 #include "pitch/pitchyin.h"
32 #include "pitch/pitchfcomb.h"
33 #include "pitch/pitchschmitt.h"
34 #include "pitch/pitchyinfft.h"
35 #include "pitch/pitch.h"
36
37 /** pitch detection algorithm */
38 typedef enum
39 {
40   aubio_pitcht_yin,     /**< YIN algorithm */
41   aubio_pitcht_mcomb,   /**< Multi-comb filter */
42   aubio_pitcht_schmitt, /**< Schmitt trigger */
43   aubio_pitcht_fcomb,   /**< Fast comb filter */
44   aubio_pitcht_yinfft,   /**< Spectral YIN */
45   aubio_pitcht_default = aubio_pitcht_yinfft, /**< the one used when "default" is asked */
46 } aubio_pitch_type;
47
48 /** pitch detection output mode */
49 typedef enum
50 {
51   aubio_pitchm_freq,   /**< Frequency (Hz) */
52   aubio_pitchm_midi,   /**< MIDI note (0.,127) */
53   aubio_pitchm_cent,   /**< Cent */
54   aubio_pitchm_bin,    /**< Frequency bin (0,bufsize) */
55   aubio_pitchm_default = aubio_pitchm_freq, /**< the one used when "default" is asked */
56 } aubio_pitch_mode;
57
58 typedef void (*aubio_pitch_func_t)
59   (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf);
60 typedef smpl_t (*aubio_pitch_conv_t)
61   (smpl_t value, uint_t srate, uint_t bufsize);
62
63 void aubio_pitch_slideblock (aubio_pitch_t * p, fvec_t * ibuf);
64
65 void aubio_pitch_do_mcomb (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf);
66 void aubio_pitch_do_yin (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf);
67 void aubio_pitch_do_schmitt (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf);
68 void aubio_pitch_do_fcomb (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf);
69 void aubio_pitch_do_yinfft (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf);
70
71 /** generic pitch detection structure */
72 struct _aubio_pitch_t
73 {
74   aubio_pitch_type type; /**< pitch detection mode */
75   aubio_pitch_mode mode; /**< pitch detection output mode */
76   uint_t srate;                   /**< samplerate */
77   uint_t bufsize;                 /**< buffer size */
78   aubio_pitchmcomb_t *mcomb;      /**< mcomb object */
79   aubio_pitchfcomb_t *fcomb;      /**< fcomb object */
80   aubio_pitchschmitt_t *schmitt;  /**< schmitt object */
81   aubio_pitchyinfft_t *yinfft;    /**< yinfft object */
82   aubio_pitchyin_t *yin;    /**< yinfft object */
83   aubio_filter_t *filter;         /**< filter */
84   aubio_pvoc_t *pv;               /**< phase vocoder for mcomb */
85   cvec_t *fftgrain;               /**< spectral frame for mcomb */
86   fvec_t *buf;                    /**< temporary buffer for yin */
87   aubio_pitch_func_t callback; /**< pointer to current pitch detection method */
88   aubio_pitch_conv_t freqconv; /**< pointer to current pitch conversion method */
89 };
90
91 /* convenience wrapper function for frequency unit conversions 
92  * should probably be rewritten with #defines */
93 smpl_t freqconvbin (smpl_t f, uint_t srate, uint_t bufsize);
94 smpl_t
95 freqconvbin (smpl_t f, uint_t srate, uint_t bufsize)
96 {
97   return aubio_freqtobin (f, srate, bufsize);
98 }
99
100 smpl_t freqconvmidi (smpl_t f, uint_t srate, uint_t bufsize);
101 smpl_t
102 freqconvmidi (smpl_t f, uint_t srate UNUSED, uint_t bufsize UNUSED)
103 {
104   return aubio_freqtomidi (f);
105 }
106
107 smpl_t freqconvpass (smpl_t f, uint_t srate, uint_t bufsize);
108 smpl_t
109 freqconvpass (smpl_t f, uint_t srate UNUSED, uint_t bufsize UNUSED)
110 {
111   return f;
112 }
113
114 aubio_pitch_t *
115 new_aubio_pitch (char_t * pitch_mode,
116     uint_t bufsize, uint_t hopsize, uint_t samplerate)
117 {
118   aubio_pitch_t *p = AUBIO_NEW (aubio_pitch_t);
119   aubio_pitch_type pitch_type;
120   if (strcmp (pitch_mode, "mcomb") == 0)
121     pitch_type = aubio_pitcht_mcomb;
122   else if (strcmp (pitch_mode, "yinfft") == 0)
123     pitch_type = aubio_pitcht_yin;
124   else if (strcmp (pitch_mode, "yin") == 0)
125     pitch_type = aubio_pitcht_yin;
126   else if (strcmp (pitch_mode, "schmitt") == 0)
127     pitch_type = aubio_pitcht_schmitt;
128   else if (strcmp (pitch_mode, "fcomb") == 0)
129     pitch_type = aubio_pitcht_fcomb;
130   else if (strcmp (pitch_mode, "default") == 0)
131     pitch_type = aubio_pitcht_default;
132   else {
133     AUBIO_ERR ("unknown pitch detection method %s, using default.\n",
134         pitch_mode);
135     pitch_type = aubio_pitcht_default;
136   }
137   p->srate = samplerate;
138   p->type = pitch_type;
139   aubio_pitch_set_unit (p, "default");
140   p->bufsize = bufsize;
141   switch (p->type) {
142     case aubio_pitcht_yin:
143       p->buf = new_fvec (bufsize);
144       p->yin = new_aubio_pitchyin (bufsize);
145       p->callback = aubio_pitch_do_yin;
146       aubio_pitchyin_set_tolerance (p->yin, 0.15);
147       break;
148     case aubio_pitcht_mcomb:
149       p->pv = new_aubio_pvoc (bufsize, hopsize);
150       p->fftgrain = new_cvec (bufsize);
151       p->mcomb = new_aubio_pitchmcomb (bufsize, hopsize);
152       p->filter = new_aubio_filter_c_weighting (samplerate);
153       p->callback = aubio_pitch_do_mcomb;
154       break;
155     case aubio_pitcht_fcomb:
156       p->buf = new_fvec (bufsize);
157       p->fcomb = new_aubio_pitchfcomb (bufsize, hopsize);
158       p->callback = aubio_pitch_do_fcomb;
159       break;
160     case aubio_pitcht_schmitt:
161       p->buf = new_fvec (bufsize);
162       p->schmitt = new_aubio_pitchschmitt (bufsize);
163       p->callback = aubio_pitch_do_schmitt;
164       break;
165     case aubio_pitcht_yinfft:
166       p->buf = new_fvec (bufsize);
167       p->yinfft = new_aubio_pitchyinfft (bufsize);
168       p->callback = aubio_pitch_do_yinfft;
169       aubio_pitchyinfft_set_tolerance (p->yinfft, 0.85);
170       break;
171     default:
172       break;
173   }
174   return p;
175 }
176
177 void
178 del_aubio_pitch (aubio_pitch_t * p)
179 {
180   switch (p->type) {
181     case aubio_pitcht_yin:
182       del_fvec (p->buf);
183       del_aubio_pitchyin (p->yin);
184       break;
185     case aubio_pitcht_mcomb:
186       del_aubio_pvoc (p->pv);
187       del_cvec (p->fftgrain);
188       del_aubio_filter (p->filter);
189       del_aubio_pitchmcomb (p->mcomb);
190       break;
191     case aubio_pitcht_schmitt:
192       del_fvec (p->buf);
193       del_aubio_pitchschmitt (p->schmitt);
194       break;
195     case aubio_pitcht_fcomb:
196       del_fvec (p->buf);
197       del_aubio_pitchfcomb (p->fcomb);
198       break;
199     case aubio_pitcht_yinfft:
200       del_fvec (p->buf);
201       del_aubio_pitchyinfft (p->yinfft);
202       break;
203     default:
204       break;
205   }
206   AUBIO_FREE (p);
207 }
208
209 void
210 aubio_pitch_slideblock (aubio_pitch_t * p, fvec_t * ibuf)
211 {
212   uint_t j = 0, overlap_size = 0;
213   overlap_size = p->buf->length - ibuf->length;
214   for (j = 0; j < overlap_size; j++) {
215     p->buf->data[j] = p->buf->data[j + ibuf->length];
216   }
217   for (j = 0; j < ibuf->length; j++) {
218     p->buf->data[j + overlap_size] = ibuf->data[j];
219   }
220 }
221
222 uint_t
223 aubio_pitch_set_unit (aubio_pitch_t * p, char_t * pitch_unit)
224 {
225   aubio_pitch_mode pitch_mode;
226   if (strcmp (pitch_unit, "freq") == 0)
227     pitch_mode = aubio_pitchm_freq;
228   else if (strcmp (pitch_unit, "midi") == 0)
229     pitch_mode = aubio_pitchm_midi;
230   else if (strcmp (pitch_unit, "cent") == 0)
231     pitch_mode = aubio_pitchm_cent;
232   else if (strcmp (pitch_unit, "bin") == 0)
233     pitch_mode = aubio_pitchm_bin;
234   else if (strcmp (pitch_unit, "default") == 0)
235     pitch_mode = aubio_pitchm_default;
236   else {
237     AUBIO_ERR ("unknown pitch detection unit %s, using default\n", pitch_unit);
238     pitch_mode = aubio_pitchm_default;
239   }
240   p->mode = pitch_mode;
241   switch (p->mode) {
242     case aubio_pitchm_freq:
243       p->freqconv = freqconvpass;
244       break;
245     case aubio_pitchm_midi:
246       p->freqconv = freqconvmidi;
247       break;
248     case aubio_pitchm_cent:
249       /* bug: not implemented */
250       p->freqconv = freqconvmidi;
251       break;
252     case aubio_pitchm_bin:
253       p->freqconv = freqconvbin;
254       break;
255     default:
256       break;
257   }
258   return AUBIO_OK;
259 }
260
261 uint_t
262 aubio_pitch_set_tolerance (aubio_pitch_t * p, smpl_t tol)
263 {
264   switch (p->type) {
265     case aubio_pitcht_yin:
266       aubio_pitchyin_set_tolerance (p->yin, tol);
267       break;
268     case aubio_pitcht_yinfft:
269       aubio_pitchyinfft_set_tolerance (p->yinfft, tol);
270       break;
271     default:
272       break;
273   }
274   return AUBIO_OK;
275 }
276
277 void
278 aubio_pitch_do (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf)
279 {
280   p->callback (p, ibuf, obuf);
281   obuf->data[0] = p->freqconv (obuf->data[0], p->srate, p->bufsize);
282 }
283
284 void
285 aubio_pitch_do_mcomb (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf)
286 {
287   aubio_filter_do (p->filter, ibuf);
288   aubio_pvoc_do (p->pv, ibuf, p->fftgrain);
289   aubio_pitchmcomb_do (p->mcomb, p->fftgrain, obuf);
290   obuf->data[0] = aubio_bintofreq (obuf->data[0], p->srate, p->bufsize);
291 }
292
293 void
294 aubio_pitch_do_yin (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf)
295 {
296   smpl_t pitch = 0.;
297   aubio_pitch_slideblock (p, ibuf);
298   aubio_pitchyin_do (p->yin, p->buf, obuf);
299   pitch = obuf->data[0];
300   if (pitch > 0) {
301     pitch = p->srate / (pitch + 0.);
302   } else {
303     pitch = 0.;
304   }
305   obuf->data[0] = pitch;
306 }
307
308
309 void
310 aubio_pitch_do_yinfft (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * obuf)
311 {
312   smpl_t pitch = 0.;
313   aubio_pitch_slideblock (p, ibuf);
314   aubio_pitchyinfft_do (p->yinfft, p->buf, obuf);
315   pitch = obuf->data[0];
316   if (pitch > 0) {
317     pitch = p->srate / (pitch + 0.);
318   } else {
319     pitch = 0.;
320   }
321   obuf->data[0] = pitch;
322 }
323
324 void
325 aubio_pitch_do_fcomb (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * out)
326 {
327   aubio_pitch_slideblock (p, ibuf);
328   aubio_pitchfcomb_do (p->fcomb, p->buf, out);
329   out->data[0] = aubio_bintofreq (out->data[0], p->srate, p->bufsize);
330 }
331
332 void
333 aubio_pitch_do_schmitt (aubio_pitch_t * p, fvec_t * ibuf, fvec_t * out)
334 {
335   smpl_t period, pitch = 0.;
336   aubio_pitch_slideblock (p, ibuf);
337   aubio_pitchschmitt_do (p->schmitt, p->buf, out);
338   period = out->data[0];
339   if (period > 0) {
340     pitch = p->srate / period;
341   } else {
342     pitch = 0.;
343   }
344   out->data[0] = pitch;
345 }