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