1 /*
2 * pitchrecog.c
3 Hacked from aubionotes.c for denemo by Richard Shann (c) 2007
4 Copyright (C) 2003 Paul Brossier
5
6 This program 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 2 of the License, or
9 (at your option) any later version.
10
11 This program 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 this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "audio/audio.h"
22
23 #ifdef _WITH_AUBIO_3_
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <getopt.h>
28 #include <unistd.h>
29 #include <math.h>
30 #include <glib.h>
31 #include <aubio/aubio.h>
32 #include "audio/pitchrecog.h"
33
34 #ifdef HAVE_C99_VARARGS_MACROS
35 #define debug(...) if (verbose) fprintf (stderr, __VA_ARGS__)
36 #define errmsg(...) fprintf (stderr, __VA_ARGS__)
37 #define outmsg(...) fprintf (stdout, __VA_ARGS__)
38 #else
39 #define debug(format, args...) if (verbose) fprintf(stderr, format , ##args)
40 #define errmsg(format, args...) fprintf(stderr, format , ##args)
41 #define outmsg(format, args...) fprintf(stdout, format , ##args)
42 #endif
43
44
45
46
47
48
49 typedef int (*aubio_process_func_t) (smpl_t ** input, smpl_t ** output, int nframes);
50
51
52
53 static void send_noteon (smpl_t pitch, int velo);
54
55
56
57
58
59
60 #define MAX_PITCHES (20)
61
62 static smpl_t pitches[MAX_PITCHES];
63
64 static int usejack = 1;
65 static int usedoubled = 1;
66
67
68 /* energy,specdiff,hfc,complexdomain,phase */
69 static aubio_onsetdetection_type type_onset = aubio_onset_kl;
70 static aubio_onsetdetection_type type_onset2 = aubio_onset_complex;
71 static smpl_t threshold = 0.3;
72 static smpl_t silence = -90.;
73 static uint_t buffer_size = 1024; //512; //1024;
74 static uint_t overlap_size = 512; //256; //512;
75 static uint_t channels = 1;
76 static uint_t samplerate = 44100;
77
78 static aubio_pvoc_t *pv;
79 static fvec_t *ibuf;
80 static fvec_t *obuf;
81 static cvec_t *fftgrain;
82
83 static aubio_onsetdetection_t *o;
84 static aubio_onsetdetection_t *o2;
85 static fvec_t *onset;
86 static fvec_t *onset2;
87 static int isonset = 0;
88 static aubio_pickpeak_t *parms;
89
90
91 /* pitch objects */
92 static smpl_t pitch = 0.;
93 static aubio_pitchdetection_t *pitchdet;
94 static aubio_pitchdetection_type type_pitch = aubio_pitch_yinfft; // aubio_pitch_mcomb
95 static aubio_pitchdetection_mode mode_pitch = aubio_pitchm_freq;
96 static uint_t median = 6;
97
98 static fvec_t *note_buffer = NULL;
99 static fvec_t *note_buffer2 = NULL;
100 static smpl_t curlevel = 0.;
101
102
103
104 static smpl_t curnote = 0.; // should not be global
105 //smpl_t newnote = 0.;
106 static uint_t isready = 0; // should not be global, is static within pitchrecog()
107
108
109 static aubio_onsetdetection_type onset_types[] = { aubio_onset_energy,
110 aubio_onset_specdiff,
111 aubio_onset_hfc,
112 aubio_onset_complex,
113 aubio_onset_complex,
114 aubio_onset_phase,
115 aubio_onset_mkl,
116 aubio_onset_kl
117 };
118
119
120
121
122
123 static void
init_aubio(void)124 init_aubio (void)
125 {
126
127 ibuf = new_fvec (overlap_size, channels);
128 obuf = new_fvec (overlap_size, channels);
129 fftgrain = new_cvec (buffer_size, channels);
130
131 {
132 pitchdet = new_aubio_pitchdetection (buffer_size * 4, overlap_size, channels, samplerate, type_pitch, mode_pitch);
133 aubio_pitchdetection_set_yinthresh (pitchdet, 0.7);
134
135 if (median)
136 {
137 note_buffer = new_fvec (median, 1);
138 note_buffer2 = new_fvec (median, 1);
139 }
140 }
141 /* phase vocoder */
142 pv = new_aubio_pvoc (buffer_size, overlap_size, channels);
143 /* onsets */
144 parms = new_aubio_peakpicker (threshold);
145 o = new_aubio_onsetdetection (type_onset, buffer_size, channels);
146 onset = new_fvec (1, channels);
147 if (usedoubled)
148 {
149 o2 = new_aubio_onsetdetection (type_onset2, buffer_size, channels);
150 onset2 = new_fvec (1, channels);
151 }
152
153 }
154
155
156 static void
aubio_finish(void)157 aubio_finish (void)
158 {
159 {
160 send_noteon (curnote, 0);
161 del_aubio_pitchdetection (pitchdet);
162 if (median)
163 {
164 del_fvec (note_buffer);
165 del_fvec (note_buffer2);
166 }
167 }
168 if (usedoubled)
169 {
170 del_aubio_onsetdetection (o2);
171 del_fvec (onset2);
172 }
173 del_aubio_onsetdetection (o);
174 del_aubio_peakpicker (parms);
175 del_aubio_pvoc (pv);
176 del_fvec (obuf);
177 del_fvec (ibuf);
178 del_cvec (fftgrain);
179 del_fvec (onset);
180 aubio_cleanup ();
181 }
182
183 static volatile int count;
184
185
186 static void
send_noteon(smpl_t pitch,int velo)187 send_noteon (smpl_t pitch, int velo)
188 {
189 if (velo)
190 if (++count < MAX_PITCHES)
191 pitches[count] = pitch;
192 }
193
194
195 /** append new note candidate to the note_buffer and return filtered value. we
196 * need to copy the input array as vec_median destroy its input data.*/
197 static void
note_append(fvec_t * note_buffer,smpl_t anote)198 note_append (fvec_t * note_buffer, smpl_t anote)
199 {
200 uint_t i = 0;
201 for (i = 0; i < note_buffer->length - 1; i++)
202 {
203 note_buffer->data[0][i] = note_buffer->data[0][i + 1];
204 }
205 note_buffer->data[0][note_buffer->length - 1] = anote;
206 return;
207 }
208
209 static uint_t
get_note(fvec_t * note_buffer,fvec_t * note_buffer2)210 get_note (fvec_t * note_buffer, fvec_t * note_buffer2)
211 {
212 uint_t i = 0;
213 for (i = 0; i < note_buffer->length; i++)
214 {
215 note_buffer2->data[0][i] = note_buffer->data[0][i];
216 }
217 return vec_median (note_buffer2);
218 }
219
220
221 static int calls;
222
223
224 static int Stop;
225
226 int
pitchrecog(float ** input,float ** output,int nframes)227 pitchrecog (float **input, float **output, int nframes)
228 {
229 unsigned int pos = 0; /*frames%dspblocksize */
230 unsigned int i; /*channels */
231 unsigned int j; /*frames */
232 calls++;
233 if (Stop)
234 return Stop;
235 for (j = 0; j < (unsigned) nframes; j++)
236 {
237 if (usejack)
238 {
239 for (i = 0; i < channels; i++)
240 {
241 DENEMO_SAMPLE_TYPE *in = (DENEMO_SAMPLE_TYPE *) * input;
242 ibuf->data[i][pos] = *(in + j); /* need threshold higher - say 0.5 to avoid repeated note detection when using this higher precision data */
243 }
244 }
245 /*when pos reaches overlap size it is time for fft to look for a note */
246 if (pos == overlap_size - 1)
247 {
248 /* block loop */
249 aubio_pvoc_do (pv, ibuf, fftgrain);
250 aubio_onsetdetection (o, fftgrain, onset);
251 if (usedoubled)
252 {
253 aubio_onsetdetection (o2, fftgrain, onset2);
254 onset->data[0][0] *= onset2->data[0][0];
255 }
256 isonset = aubio_peakpick_pimrt (onset, parms);
257
258 pitch = aubio_pitchdetection (pitchdet, ibuf);
259
260 if (median)
261 {
262 note_append (note_buffer, pitch);
263 }
264
265 /* curlevel is negatif or 1 if silence */
266 curlevel = aubio_level_detection (ibuf, silence);
267
268 if (isonset)
269 {
270 /* test for silence */
271 #ifndef SUSPICIOUS_CODE
272 if (curlevel == 1.)
273 {
274 #else
275 //if (curlevel <= 1.) {
276
277 #endif
278
279 isonset = 0;
280 if (median)
281 isready = 0;
282 /* send note off */
283 send_noteon (curnote, 0);
284 }
285 else
286 { // not silent
287 if (median)
288 {
289 isready = 1;
290 }
291 else
292 {
293 /* kill old note */
294 send_noteon (curnote, 0);
295 /* get and send new one */
296 send_noteon (pitch, 1);
297 curnote = pitch;
298 }
299
300
301 }
302 }
303 else
304 { //not onset
305 if (median)
306 {
307 if (isready > 0)
308 isready++;
309 if (isready == median)
310 {
311 /* kill old note */
312 send_noteon (curnote, 0);
313
314 curnote = get_note (note_buffer, note_buffer2);
315 /* get and send new one */
316 if (curnote > 45)
317 { //FIXME
318 send_noteon (curnote, 1);
319 }
320 }
321 } // if median
322
323 }
324 /* end of block loop */
325 pos = -1; /* so it will be zero next j loop */
326 } /* end of if pos==overlap_size-1 */
327 pos++;
328 }
329
330 return Stop;
331 }
332
333 #ifdef _HAVE_PORTAUDIO_
334 extern int pa_main (aubio_process_func_t process_func);
335 #else
336 int
pa_main(AubioCallback * fn)337 pa_main (AubioCallback * fn)
338 {
339 fprintf (stderr, "portaudio support not compiled\n");
340 return -1;
341
342 }
343 #endif
344
345
346 #define START init_aubio();return pa_main(pitchrecog);
347 #define STOP (void)pa_main(NULL);aubio_finish();
348
349 int
set_silence(double shh)350 set_silence (double shh)
351 {
352 silence = shh;
353 return 0;
354 }
355
356 int
set_threshold(double thresh)357 set_threshold (double thresh)
358 { /* threshold requires memory allocation */
359 STOP threshold = thresh;
360 START}
361
362 int
set_smoothing(double smooth)363 set_smoothing (double smooth)
364 { /* median requires memory allocation */
365 STOP median = (unsigned) smooth;
366 START}
367
368 /* FIXME consider controlling usedoubled parameter as well*/
369 int
set_onset_type(unsigned onset)370 set_onset_type (unsigned onset)
371 {
372 /* changing onset type requires memory allocation */
373 if (onset >= sizeof (onset_types) / sizeof (aubio_onsetdetection_type))
374 return 0;
375 STOP type_onset = onset_types[onset];
376 START}
377
378 int
initialize_pitch_recognition(void)379 initialize_pitch_recognition (void)
380 {
381 Stop = 0;
382 init_aubio ();
383 return pa_main (pitchrecog);
384 }
385
386
387 int
terminate_pitch_recognition(void)388 terminate_pitch_recognition (void)
389 {
390 g_message ("Terminating portaudio and aubio");
391 (void) pa_main (NULL);
392 aubio_finish ();
393 return 0;
394 }
395
396 double
get_pitch(void)397 get_pitch (void)
398 {
399 double ret = 0.0;
400 if (count)
401 {
402 //printf("count is %d\n", count);
403 ret = pitches[count];
404 count = 0;
405 }
406
407 return ret;
408 }
409
410 void
store_pitch(double pitch)411 store_pitch (double pitch)
412 {
413 send_noteon (pitch, 1);
414 // return count<MAX_PITCHES; no point in returning the status, look at it outside of interrupts.
415 }
416
417
418 //END OF AUBIO 3
419 #else
420 //START AUBIO 4
421
422 /*
423 * pitchrecog.c
424 * upgraded to AUBIO 4 Paul Brossier 2014
425 Hacked from aubionotes.c for denemo by Richard Shann (c) 2007
426 Copyright (C) 2003 Paul Brossier
427
428 This program is free software; you can redistribute it and/or modify
429 it under the terms of the GNU General Public License as published by
430 the Free Software Foundation; either version 2 of the License, or
431 (at your option) any later version.
432
433 This program is distributed in the hope that it will be useful,
434 but WITHOUT ANY WARRANTY; without even the implied warranty of
435 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
436 GNU General Public License for more details.
437
438 You should have received a copy of the GNU General Public License
439 along with this program; if not, write to the Free Software
440 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
441 */
442
443
444 #ifdef _HAVE_PORTAUDIO_
445 #include <stdio.h>
446 #include <stdlib.h>
447 #include <stdarg.h>
448 #include <getopt.h>
449 #include <unistd.h>
450 #include <math.h>
451 #define AUBIO_UNSTABLE 1
452 #include <aubio/aubio.h>
453 #include <glib.h>
454 #include "audio/pitchrecog.h"
455
456 typedef int (*aubio_process_func_t) (smpl_t ** input, smpl_t ** output, int nframes);
457
458
459
460 static void send_noteon (smpl_t pitch, int velo);
461
462
463
464
465
466
467 #define MAX_PITCHES (20)
468
469 static smpl_t pitches[MAX_PITCHES];
470
471 static int usejack = 1;
472 static int usedoubled = 1;
473
474
475 /* energy,specdiff,hfc,complexdomain,phase */
476 static smpl_t threshold = 0.3;
477 static smpl_t silence = -90.;
478 static uint_t buffer_size = 1024; //512; //1024;
479 static uint_t overlap_size = 512; //256; //512;
480 static uint_t samplerate = 44100;
481
482 static fvec_t *ibuf;
483
484 static aubio_onset_t *o;
485 static fvec_t *onset;
486 static uint_t isonset;
487
488 /* pitch objects */
489 static aubio_pitch_t *p;
490 static fvec_t *pitch;
491 static uint_t median = 6;
492
493 static fvec_t *note_buffer = NULL;
494 static fvec_t *note_buffer2 = NULL;
495 static smpl_t curlevel = 0.;
496
497
498
499 static smpl_t curnote = 0.; // should not be global
500 //smpl_t newnote = 0.;
501 static uint_t isready = 0; // should not be global, is static within pitchrecog()
502
503 static void
init_aubio(void)504 init_aubio (void)
505 {
506
507 ibuf = new_fvec (overlap_size);
508
509 {
510 p = new_aubio_pitch ("default", buffer_size * 4, overlap_size, samplerate);
511 aubio_pitch_set_tolerance (p, 0.7);
512 aubio_pitch_set_unit (p, "freq");
513
514 if (median)
515 {
516 note_buffer = new_fvec (median);
517 note_buffer2 = new_fvec (median);
518 }
519 }
520 o = new_aubio_onset ("default", buffer_size, overlap_size, samplerate);
521 onset = new_fvec (2);
522 pitch = new_fvec (1);
523
524 }
525
526
527 static void
aubio_finish(void)528 aubio_finish (void)
529 {
530 {
531 send_noteon (curnote, 0);
532 if (median)
533 {
534 if (note_buffer) del_fvec (note_buffer);
535 if (note_buffer2) del_fvec (note_buffer2);
536 }
537 }
538 if (o) del_aubio_onset (o);
539 if (p) del_aubio_pitch (p);
540 if (onset) del_fvec (onset);
541 if (pitch) del_fvec (pitch);
542 aubio_cleanup ();
543 }
544
545 static volatile int count;
546
547
548 static void
send_noteon(smpl_t pitch,int velo)549 send_noteon (smpl_t pitch, int velo)
550 {
551 if (velo)
552 if (++count < MAX_PITCHES)
553 pitches[count] = pitch;
554 }
555
556
557 /** append new note candidate to the note_buffer and return filtered value. we
558 * need to copy the input array as fvec_median destroy its input data.*/
559 static void
note_append(fvec_t * note_buffer,smpl_t anote)560 note_append (fvec_t * note_buffer, smpl_t anote)
561 {
562 uint_t i = 0;
563 for (i = 0; i < note_buffer->length - 1; i++)
564 {
565 note_buffer->data[i] = note_buffer->data[i + 1];
566 }
567 note_buffer->data[note_buffer->length - 1] = anote;
568 return;
569 }
570
571 static uint_t
get_note(fvec_t * note_buffer,fvec_t * note_buffer2)572 get_note (fvec_t * note_buffer, fvec_t * note_buffer2)
573 {
574 fvec_copy(note_buffer, note_buffer2);
575 return fvec_median (note_buffer2);
576 }
577
578
579 static int Stop;
580
581 int
pitchrecog(float ** input,float ** output,int nframes)582 pitchrecog (float **input, float **output, int nframes)
583 {
584 unsigned int pos = 0; /*frames%dspblocksize */
585 unsigned int j; /*frames */
586 if (Stop)
587 return Stop;
588 for (j = 0; j < (unsigned) nframes; j++)
589 {
590 if (usejack)
591 {
592 DENEMO_SAMPLE_TYPE *in = (DENEMO_SAMPLE_TYPE *) * input;
593 ibuf->data[pos] = *(in + j); /* need threshold higher - say 0.5 to avoid repeated note detection when using this higher precision data */
594 }
595 /*when pos reaches overlap size it is time for fft to look for a note */
596 if (pos == overlap_size - 1)
597 {
598 /* block loop */
599 aubio_onset_do (o, ibuf, onset);
600 aubio_pitch_do (p, ibuf, pitch);
601
602 isonset = onset->data[0];
603
604 if (median)
605 {
606 note_append (note_buffer, pitch->data[0]);
607 }
608
609 /* curlevel is negatif or 1 if silence */
610 curlevel = aubio_level_detection (ibuf, silence);
611
612 if (isonset)
613 {
614 if (curlevel == 1)
615 {
616 isonset = 0;
617 if (median)
618 isready = 0;
619 /* send note off */
620 send_noteon (curnote, 0);
621 }
622 else
623 { // not silent
624 if (median)
625 {
626 isready = 1;
627 }
628 else
629 {
630 /* kill old note */
631 send_noteon (curnote, 0);
632 /* get and send new one */
633 curnote = pitch->data[0];
634 send_noteon (curnote, 1);
635 }
636
637
638 }
639 }
640 else
641 { //not onset
642 if (median)
643 {
644 if (isready > 0)
645 isready++;
646 if (isready == median)
647 {
648 /* kill old note */
649 send_noteon (curnote, 0);
650
651 curnote = get_note (note_buffer, note_buffer2);
652 /* get and send new one */
653 if (curnote > 45)
654 { //FIXME
655 send_noteon (curnote, 1);
656 }
657 }
658 } // if median
659
660 }
661 /* end of block loop */
662 pos = -1; /* so it will be zero next j loop */
663
664 }
665 pos++;
666 }
667
668 return Stop;
669 }
670
671 extern int pa_main (aubio_process_func_t process_func);
672
673
674 #define START init_aubio();return pa_main(pitchrecog);
675 #define STOP (void)pa_main(NULL);aubio_finish();
676
677 int
set_silence(double shh)678 set_silence (double shh)
679 {
680 silence = shh;
681 return 0;
682 }
683
684 int
set_threshold(double thresh)685 set_threshold (double thresh)
686 { /* threshold requires memory allocation */
687 STOP threshold = thresh;
688 START}
689
690 int
set_smoothing(double smooth)691 set_smoothing (double smooth)
692 { /* median requires memory allocation */
693 STOP median = (unsigned) smooth;
694 START}
695
696 int
set_onset_type(unsigned onset)697 set_onset_type (unsigned onset)
698 {
699 /* changing onset type requires memory allocation */
700 #if 0
701 if (onset >= sizeof (onset_types) / sizeof (aubio_onsetdetection_type))
702 return 0;
703 STOP type_onset = onset_types[onset];
704 #endif
705 START}
706
707 int
initialize_pitch_recognition(void)708 initialize_pitch_recognition (void)
709 {
710 Stop = 0;
711 init_aubio ();
712 return pa_main (pitchrecog);
713 }
714
715
716 int
terminate_pitch_recognition(void)717 terminate_pitch_recognition (void)
718 {
719 g_print ("Terminating portaudio and aubio\n");
720 (void) pa_main (NULL);
721 aubio_finish ();
722 return 0;
723 }
724
725 double
get_pitch(void)726 get_pitch (void)
727 {
728 double ret = 0.0;
729 if (count)
730 {
731 //printf("count is %d\n", count);
732 ret = pitches[count];
733 count = 0;
734 }
735
736 return ret;
737 }
738
739 void
store_pitch(double pitch)740 store_pitch (double pitch)
741 {
742 send_noteon (pitch, 1);
743 // return count<MAX_PITCHES; no point in returning the status, look at it outside of interrupts.
744 }
745 #endif
746
747 #endif //AUBIO_4_
748