Make the ALSA reader handle and recover from underruns.
[pitch] / pitch.cpp
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5
6 #include "config.h"
7 #include "notes.h"
8 #include "linux_audio.h"
9 #include "pitchdetector.h"
10
11 void print_spectrogram(double freq, double amp);
12
13 int main()
14 {
15         PitchDetector pd(SAMPLE_RATE, FFT_LENGTH, PAD_FACTOR, OVERLAP);
16         snd_pcm_t *pcm = get_dsp_handle(SAMPLE_RATE);
17         for ( ;; ) {
18                 short buf[FFT_LENGTH / PAD_FACTOR / OVERLAP];
19
20                 read_chunk(pcm, buf, FFT_LENGTH / PAD_FACTOR / OVERLAP);
21                 std::pair<double, double> peak = pd.detect_pitch(buf);
22
23                 if (peak.first < 50.0 || peak.second - log10(FFT_LENGTH) < 0.0) {
24 #if TUNING == WELL_TEMPERED_GUITAR
25                         printf("......\n");
26 #else           
27                         printf("............\n");
28 #endif
29                 } else {
30                         print_spectrogram(peak.first, peak.second - log10(FFT_LENGTH));
31                 }
32         }
33 }
34
35 std::string freq_to_tonename(double freq)
36 {
37         std::string notenames[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
38         double half_notes_away = 12.0 * log2(freq / BASE_PITCH) - 3.0;
39         int hnai = int(floor(half_notes_away + 0.5));
40         int octave = (hnai + 48) / 12;
41
42         char buf[256];
43         sprintf(buf, "%s%d + %.2f [%d]", notenames[((hnai % 12) + 12) % 12].c_str(), octave, half_notes_away - hnai, hnai);
44         return buf;
45 }
46
47 #if TUNING == EQUAL_TEMPERAMENT
48 void print_spectrogram(double freq, double amp)
49 {
50         std::string notenames[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
51         double half_notes_away = 12.0 * log2(freq / BASE_PITCH) - 3.0;
52         int hnai = int(floor(half_notes_away + 0.5));
53         int octave = (hnai + 48) / 12;
54
55         for (int i = 0; i < 12; ++i)
56                 if (i == ((hnai % 12) + 12) % 12)
57                         printf("#");
58                 else
59                         printf(".");
60
61         printf(" (%-2s%d %+.2f, %5.2fHz) [%5.2fdB]  [", notenames[((hnai % 12) + 12) % 12].c_str(), octave, half_notes_away - hnai,
62                 freq, amp);
63
64         double off = half_notes_away - hnai;
65         for (int i = -10; i <= 10; ++i) {
66                 if (off >= (i-0.5) * 0.05 && off < (i+0.5) * 0.05) {
67                         printf("#");
68                 } else {
69                         if (i == 0) {
70                                 printf("|");
71                         } else {
72                                 printf("-");
73                         }
74                 }
75         }
76         printf("]\n");
77
78 }
79 #else
80 void print_spectrogram(double freq, double amp)
81 {
82         double best_away = 999999999.9;
83         unsigned best_away_ind = 0;
84         
85         for (unsigned i = 0; i < sizeof(notes)/sizeof(note); ++i) {
86                 double half_notes_away = 12.0 * log2(freq / notes[i].freq);
87                 if (fabs(half_notes_away) < fabs(best_away)) {
88                         best_away = half_notes_away;
89                         best_away_ind = i;
90                 }
91         }
92         
93         for (unsigned i = 0; i < sizeof(notes)/sizeof(note); ++i)
94                 if (i == best_away_ind)
95                         printf("#");
96                 else
97                         printf(".");
98
99         printf(" (%s %+.2f, %5.2fHz) [%5.2fdB]  [", notes[best_away_ind].notename, best_away, freq, amp);
100
101         // coarse tuning
102         for (int i = -10; i <= 10; ++i) {
103                 if (best_away >= (i-0.5) * 0.05 && best_away < (i+0.5) * 0.05) {
104                         printf("#");
105                 } else {
106                         if (i == 0) {
107                                 printf("|");
108                         } else {
109                                 printf("-");
110                         }
111                 }
112         }
113         printf("]  [");
114         
115         // fine tuning
116         for (int i = -10; i <= 10; ++i) {
117                 if (best_away >= (i-0.5) * 0.01 && best_away < (i+0.5) * 0.01) {
118                         printf("#");
119                 } else {
120                         if (i == 0) {
121                                 printf("|");
122                         } else {
123                                 printf("-");
124                         }
125                 }
126         }
127         printf("]\n");
128 }
129 #endif