]> git.sesse.net Git - pitch/blobdiff - pitch.cpp
Separate the Linux audio functions into a separate file.
[pitch] / pitch.cpp
index 933fef9aacc97896dc108dd2466ecbb85f23f8e3..1ab4696c5b9794c8c24dc1bc0a4e077eeec7c90c 100644 (file)
--- a/pitch.cpp
+++ b/pitch.cpp
@@ -1,16 +1,12 @@
 #include <stdio.h>
+#include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <fcntl.h>
-#include <complex>
-#include <cassert>
-#include <algorithm>
-#include <fftw3.h>
-#include <sys/ioctl.h>
-#include <linux/soundcard.h>
 
+#include "linux_audio.h"
 #include "pitchdetector.h"
 
+#define BASE_PITCH      440.0
 #define SAMPLE_RATE     22050
 #define FFT_LENGTH      4096     /* in samples */
 #define PAD_FACTOR      2        /* 1/pf of the FFT samples are real samples, the rest are padding */
 
 #define TUNING WELL_TEMPERED_GUITAR
 
-int get_dsp_fd();
-void read_chunk(int fd, short *in, unsigned num_samples);
 void print_spectrogram(double freq, double amp);
 void write_sine(int dsp_fd, double freq, unsigned num_samples);
 
 int main()
 {
        PitchDetector pd(SAMPLE_RATE, FFT_LENGTH, PAD_FACTOR, OVERLAP);
-       
-       int fd = get_dsp_fd();
+       int fd = get_dsp_fd(SAMPLE_RATE, FFT_LENGTH, OVERLAP);
        for ( ;; ) {
                short buf[FFT_LENGTH / PAD_FACTOR / OVERLAP];
 
@@ -52,81 +45,10 @@ int main()
        }
 }
 
-int get_dsp_fd()
-{
-       int fd = open("/dev/dsp", O_RDWR);
-       if (fd == -1) {
-               perror("/dev/dsp");
-               exit(1);
-       }
-       
-       ioctl(3, SNDCTL_DSP_RESET, 0);
-       
-       int fmt = AFMT_S16_LE;   // FIXME
-       ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
-
-       int chan = 1;
-       ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &chan);
-       
-       int rate = SAMPLE_RATE;
-       ioctl(fd, SOUND_PCM_WRITE_RATE, &rate);
-
-       int max_fragments = 2;
-       int frag_shift = ffs(FFT_LENGTH / OVERLAP) - 1;
-       int fragments = (max_fragments << 16) | frag_shift;
-        ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
-       
-       ioctl(3, SNDCTL_DSP_SYNC, 0);
-       
-       return fd;
-}
-
-#if 1
-void read_chunk(int fd, short *in, unsigned num_samples)
-{
-       int ret;
-
-       ret = read(fd, in, num_samples * sizeof(short));
-       if (ret == 0) {
-               printf("EOF\n");
-               exit(0);
-       }
-
-       if (ret != int(num_samples * sizeof(short))) {
-               // blah
-               perror("read");
-               exit(1);
-       }
-}
-#else
-// make a pure 440hz sine for testing
-void read_chunk(int fd, short *in, unsigned num_samples)
-{
-       static double theta = 0.0;
-       for (unsigned i = 0; i < num_samples; ++i) {
-               in[i] = 32768.0 * cos(theta);
-               theta += 2.0 * M_PI * 440.0 / double(SAMPLE_RATE);
-       }
-}
-#endif
-
-void write_sine(int dsp_fd, double freq, unsigned num_samples) 
-{
-       static double theta = 0.0;
-       short buf[num_samples];
-       
-       for (unsigned i = 0; i < num_samples; ++i) {
-               buf[i] = short(cos(theta) * 16384.0);
-               theta += 2.0 * M_PI * freq / double(SAMPLE_RATE);
-       }
-
-       write(dsp_fd, buf, num_samples * sizeof(short));
-}
-
 std::string freq_to_tonename(double freq)
 {
        std::string notenames[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
-       double half_notes_away = 12.0 * log2(freq / 440.0) - 3.0;
+       double half_notes_away = 12.0 * log2(freq / BASE_PITCH) - 3.0;
        int hnai = int(floor(half_notes_away + 0.5));
        int octave = (hnai + 48) / 12;
 
@@ -139,7 +61,7 @@ std::string freq_to_tonename(double freq)
 void print_spectrogram(double freq, double amp)
 {
        std::string notenames[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
-       double half_notes_away = 12.0 * log2(freq / 440.0) - 3.0;
+       double half_notes_away = 12.0 * log2(freq / BASE_PITCH) - 3.0;
        int hnai = int(floor(half_notes_away + 0.5));
        int octave = (hnai + 48) / 12;
 
@@ -173,12 +95,12 @@ struct note {
        double freq;
 };
 static note notes[] = {
-       { "E-3", 110.0 * (3.0/4.0) },
-       { "A-3", 110.0 },
-       { "D-4", 110.0 * (4.0/3.0) },
-       { "G-4", 110.0 * (4.0/3.0)*(4.0/3.0) },
-       { "B-4", 440.0 * (3.0/4.0)*(3.0/4.0) },
-       { "E-5", 440.0 * (3.0/4.0) }
+       { "E-3", BASE_PITCH/4.0 * (3.0/4.0) },
+       { "A-3", BASE_PITCH/4.0 },
+       { "D-4", BASE_PITCH/4.0 * (4.0/3.0) },
+       { "G-4", BASE_PITCH/4.0 * (4.0/3.0)*(4.0/3.0) },
+       { "B-4", BASE_PITCH * (3.0/4.0)*(3.0/4.0) },
+       { "E-5", BASE_PITCH * (3.0/4.0) }
 };
 
 void print_spectrogram(double freq, double amp)
@@ -202,6 +124,7 @@ void print_spectrogram(double freq, double amp)
 
        printf(" (%s %+.2f, %5.2fHz) [%5.2fdB]  [", notes[best_away_ind].notename, best_away, freq, amp);
 
+       // coarse tuning
        for (int i = -10; i <= 10; ++i) {
                if (best_away >= (i-0.5) * 0.05 && best_away < (i+0.5) * 0.05) {
                        printf("#");
@@ -213,6 +136,20 @@ void print_spectrogram(double freq, double amp)
                        }
                }
        }
+       printf("]  [");
+       
+       // fine tuning
+       for (int i = -10; i <= 10; ++i) {
+               if (best_away >= (i-0.5) * 0.01 && best_away < (i+0.5) * 0.01) {
+                       printf("#");
+               } else {
+                       if (i == 0) {
+                               printf("|");
+                       } else {
+                               printf("-");
+                       }
+               }
+       }
        printf("]\n");
 }
 #endif