]> git.sesse.net Git - pitch/blob - pitch.cpp
Separate the Linux audio functions into a separate file.
[pitch] / pitch.cpp
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5
6 #include "linux_audio.h"
7 #include "pitchdetector.h"
8
9 #define BASE_PITCH      440.0
10 #define SAMPLE_RATE     22050
11 #define FFT_LENGTH      4096     /* in samples */
12 #define PAD_FACTOR      2        /* 1/pf of the FFT samples are real samples, the rest are padding */
13 #define OVERLAP         4        /* 1/ol samples will be replaced in the buffer every frame. Should be
14                                   * a multiple of 2 for the Hamming window (see
15                                   * http://www-ccrma.stanford.edu/~jos/parshl/Choice_Hop_Size.html).
16                                   */
17
18 #define EQUAL_TEMPERAMENT     0
19 #define WELL_TEMPERED_GUITAR  1
20
21 #define TUNING WELL_TEMPERED_GUITAR
22
23 void print_spectrogram(double freq, double amp);
24 void write_sine(int dsp_fd, double freq, unsigned num_samples);
25
26 int main()
27 {
28         PitchDetector pd(SAMPLE_RATE, FFT_LENGTH, PAD_FACTOR, OVERLAP);
29         int fd = get_dsp_fd(SAMPLE_RATE, FFT_LENGTH, OVERLAP);
30         for ( ;; ) {
31                 short buf[FFT_LENGTH / PAD_FACTOR / OVERLAP];
32
33                 read_chunk(fd, buf, FFT_LENGTH / PAD_FACTOR / OVERLAP);
34                 std::pair<double, double> peak = pd.detect_pitch(buf);
35
36                 if (peak.first < 50.0 || peak.second - log10(FFT_LENGTH) < 0.0) {
37 #if TUNING == WELL_TEMPERED_GUITAR
38                         printf("......\n");
39 #else           
40                         printf("............\n");
41 #endif
42                 } else {
43                         print_spectrogram(peak.first, peak.second - log10(FFT_LENGTH));
44                 }
45         }
46 }
47
48 std::string freq_to_tonename(double freq)
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         char buf[256];
56         sprintf(buf, "%s%d + %.2f [%d]", notenames[((hnai % 12) + 12) % 12].c_str(), octave, half_notes_away - hnai, hnai);
57         return buf;
58 }
59
60 #if TUNING == EQUAL_TEMPERAMENT
61 void print_spectrogram(double freq, double amp)
62 {
63         std::string notenames[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
64         double half_notes_away = 12.0 * log2(freq / BASE_PITCH) - 3.0;
65         int hnai = int(floor(half_notes_away + 0.5));
66         int octave = (hnai + 48) / 12;
67
68         for (int i = 0; i < 12; ++i)
69                 if (i == ((hnai % 12) + 12) % 12)
70                         printf("#");
71                 else
72                         printf(".");
73
74         printf(" (%-2s%d %+.2f, %5.2fHz) [%5.2fdB]  [", notenames[((hnai % 12) + 12) % 12].c_str(), octave, half_notes_away - hnai,
75                 freq, amp);
76
77         double off = half_notes_away - hnai;
78         for (int i = -10; i <= 10; ++i) {
79                 if (off >= (i-0.5) * 0.05 && off < (i+0.5) * 0.05) {
80                         printf("#");
81                 } else {
82                         if (i == 0) {
83                                 printf("|");
84                         } else {
85                                 printf("-");
86                         }
87                 }
88         }
89         printf("]\n");
90
91 }
92 #else
93 struct note {
94         char notename[16];
95         double freq;
96 };
97 static note notes[] = {
98         { "E-3", BASE_PITCH/4.0 * (3.0/4.0) },
99         { "A-3", BASE_PITCH/4.0 },
100         { "D-4", BASE_PITCH/4.0 * (4.0/3.0) },
101         { "G-4", BASE_PITCH/4.0 * (4.0/3.0)*(4.0/3.0) },
102         { "B-4", BASE_PITCH * (3.0/4.0)*(3.0/4.0) },
103         { "E-5", BASE_PITCH * (3.0/4.0) }
104 };
105
106 void print_spectrogram(double freq, double amp)
107 {
108         double best_away = 999999999.9;
109         unsigned best_away_ind = 0;
110         
111         for (unsigned i = 0; i < sizeof(notes)/sizeof(note); ++i) {
112                 double half_notes_away = 12.0 * log2(freq / notes[i].freq);
113                 if (fabs(half_notes_away) < fabs(best_away)) {
114                         best_away = half_notes_away;
115                         best_away_ind = i;
116                 }
117         }
118         
119         for (unsigned i = 0; i < sizeof(notes)/sizeof(note); ++i)
120                 if (i == best_away_ind)
121                         printf("#");
122                 else
123                         printf(".");
124
125         printf(" (%s %+.2f, %5.2fHz) [%5.2fdB]  [", notes[best_away_ind].notename, best_away, freq, amp);
126
127         // coarse tuning
128         for (int i = -10; i <= 10; ++i) {
129                 if (best_away >= (i-0.5) * 0.05 && best_away < (i+0.5) * 0.05) {
130                         printf("#");
131                 } else {
132                         if (i == 0) {
133                                 printf("|");
134                         } else {
135                                 printf("-");
136                         }
137                 }
138         }
139         printf("]  [");
140         
141         // fine tuning
142         for (int i = -10; i <= 10; ++i) {
143                 if (best_away >= (i-0.5) * 0.01 && best_away < (i+0.5) * 0.01) {
144                         printf("#");
145                 } else {
146                         if (i == 0) {
147                                 printf("|");
148                         } else {
149                                 printf("-");
150                         }
151                 }
152         }
153         printf("]\n");
154 }
155 #endif