]> git.sesse.net Git - pitch/blob - glpitch.cpp
Port from OSS to ALSA, as OSS is pretty much dying these days.
[pitch] / glpitch.cpp
1 #include <SDL.h>
2 #include <GL/gl.h>
3
4 #include "config.h"
5 #include "linux_audio.h"
6 #include "notes.h"
7 #include "pitchdetector.h"
8
9 #define MIN_X -40
10 #define MAX_X 5
11
12 double find_linear_pos(double freq)
13 {
14         return 12.0 * log2(freq / BASE_PITCH) - 3.0;
15 }
16
17 #if COMPRESS_PITCH_DISPLAY
18 // bend the scale a bit to get more precision around the interesting points
19 double magnifying_glass(double x)
20 {
21         double sigma = PITCH_COMPRESSION_SIGMA;
22         double div = 1.0 / sqrt(2.0 * sigma * sigma);
23         return
24                 erf((x - find_linear_pos(notes[0].freq)) * div) +
25                 erf((x - find_linear_pos(notes[1].freq)) * div) +
26                 erf((x - find_linear_pos(notes[2].freq)) * div) +
27                 erf((x - find_linear_pos(notes[3].freq)) * div) +
28                 erf((x - find_linear_pos(notes[4].freq)) * div) +
29                 erf((x - find_linear_pos(notes[5].freq)) * div);
30 }
31
32 // like nonlinear_func, but f(MIN_X) = MIN_X and f(MAX_X) = MAX_X
33 double normalized_magnifying_glass(double x)
34 {
35         double y = magnifying_glass(x);
36         double min_y = magnifying_glass(MIN_X);
37         double max_y = magnifying_glass(MAX_X);
38         return (y - min_y) * (MAX_X - MIN_X) / (max_y - min_y) + MIN_X;
39 }
40 #endif /* COMPRESS_PITCH_DISPLAY */
41
42 double find_display_pos(double freq)
43 {
44         double linear_pos = find_linear_pos(freq);
45 #if COMPRESS_PITCH_DISPLAY
46         return normalized_magnifying_glass(linear_pos);
47 #else
48         return linear_pos;
49 #endif
50 }
51
52 int main(void)
53 {
54         PitchDetector pd(SAMPLE_RATE, FFT_LENGTH, PAD_FACTOR, OVERLAP);
55         snd_pcm_t *pcm = get_dsp_handle(SAMPLE_RATE);
56
57         SDL_Init(SDL_INIT_VIDEO);
58         SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
59         SDL_SetVideoMode(1024, 200, 32, SDL_OPENGL);
60
61         glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
62         glClear(GL_COLOR_BUFFER_BIT);
63         glDisable(GL_DEPTH_TEST);
64
65         for ( ;; ) {
66                 SDL_Event event;
67                 while (SDL_PollEvent(&event)) {
68                         switch (event.type) {
69                         case SDL_KEYUP:
70                                 if (event.key.keysym.sym == SDLK_ESCAPE) {
71                                         exit(0);
72                                 }
73                                 break;
74                         case SDL_QUIT:
75                                 exit(0);
76                         }
77                 }
78
79                 short buf[FFT_LENGTH / PAD_FACTOR / OVERLAP];
80                 read_chunk(pcm, buf, FFT_LENGTH / PAD_FACTOR / OVERLAP);
81                 std::pair<double, double> peak = pd.detect_pitch(buf);
82
83                 glMatrixMode(GL_PROJECTION);
84                 glLoadIdentity();
85                 glOrtho(MIN_X, MAX_X, 1.0f, 0.0f, 0.0f, 1.0f);
86
87                 glMatrixMode(GL_MODELVIEW);
88                 glLoadIdentity();
89
90                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
91                 glEnable(GL_BLEND); 
92
93                 glBegin(GL_QUADS);      
94                 glColor4f(0.0, 0.0f, 0.0f, 0.05f);
95                 glVertex2f(MIN_X, 0.0f);
96                 glVertex2f(MIN_X, 1.0f);
97                 glVertex2f(MAX_X, 1.0f);
98                 glVertex2f(MAX_X, 0.0f);
99                 glEnd();
100
101                 if (peak.second - log10(FFT_LENGTH) >= 0.0) {
102                         double peak_pos = find_display_pos(peak.first);
103                         double strength = peak.second / 40.0f;
104
105                         glEnable(GL_POLYGON_SMOOTH);
106                         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
107                         glEnable(GL_POLYGON_SMOOTH);
108
109                         glBegin(GL_QUADS);      
110                         glColor4f(0.0f, strength, 1.0 - strength, 0.2f);
111                         glVertex2f(peak_pos - 0.1, 0.0f);
112                         glVertex2f(peak_pos - 0.1, 1.0f);
113                         glVertex2f(peak_pos + 0.1, 1.0f);
114                         glVertex2f(peak_pos + 0.1, 0.0f);
115                         glEnd();
116
117                         glDisable(GL_POLYGON_SMOOTH);
118                 }
119
120                 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
121                 glBegin(GL_LINES);
122
123                 for (int i = 0; i < 6; ++i) {
124                         double pos = find_display_pos(notes[i].freq);
125                         glVertex2f(pos, 0.0f);
126                         glVertex2f(pos, 1.0f);
127                 }
128                 glEnd();
129
130                 SDL_GL_SwapBuffers();
131         }
132 }