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