#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 "config.h"
+#include "notes.h"
+#include "linux_audio.h"
#include "pitchdetector.h"
-#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 OVERLAP 4 /* 1/ol samples will be replaced in the buffer every frame. Should be
- * a multiple of 2 for the Hamming window (see
- * http://www-ccrma.stanford.edu/~jos/parshl/Choice_Hop_Size.html).
- */
-
-#define EQUAL_TEMPERAMENT 0
-#define WELL_TEMPERED_GUITAR 1
-
-#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];
}
}
-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;
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;
}
#else
-struct note {
- char notename[16];
- 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) }
-};
-
void print_spectrogram(double freq, double amp)
{
double best_away = 999999999.9;