/* this is the non-GTK version of gstring
 * String - Yet another Guitar Tuning Application
 * Copyright (C) 1998-1999 Sam Tannous
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * You should have received a copy of the GNU General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
  
#include <stdio.h>
#include <math.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <sys/ioctl.h>
#include <sys/soundcard.h>

// in version 2.0 of FFTW, the following line was rfftw.h
//    this changed in version 2.1 because of the new RPM 
//    I was using.
#include <rfftw.h>

static int    cross=0, max1 = 0, max2 = 0;

int fd;

// Your frequecy resolution (smallest frequecy difference we can
//    detect), is simply   f = sampling rate/number of samples
// N is the number of samples we take each time we sample.
//    increasing this value will improve your freq resolution.
//    but if you make it too large, it takes longer to get each
//    sample.
#define N 16384

//  sampleing_rate is the sampling frequecy of the microphone...in Hz
//  lowering this value will lower f and improve your resolution.
//  But it will also limit the highest frequency you can detect...
//  ...remember the Nyquist rate:  you must sample at twice the
//  highest frequency in order to prevent aliasing...
int sampling_frequency = 22050;

//int arg = 0x0002000a;
int channels = 0;   // mono=0, stereo = 1

int M = N/2;
int N2 = N*N;
 
// this is the default 8 bit format
// you must use unsigned char for the data read (in[N])
int format = AFMT_S8;  

// this is for 16 bit samples.  here, you must use
// signed short
//int format = AFMT_S16_LE;  
//signed short in[N];

int i;
int a440 = 440;

// f is the frequency resolution in Hz.  It is commented and calculated
//  below.  mycosine is just an array of cosine values used to improve
//  performance.
float f, mycosine[N];

// delta is how far off we can be from a given note (changes with octaves)
//   before we say it is sharp or flat..
float delta;


unsigned char in[N];
fftw_real freq,maxi,max, temp, in2[N], out[N];
rfftw_plan p;


// this routing actually gets data from /dev/dsp...
void get_data(void)
{
  read(fd,in,N);
  for(i=0;i<N;i++)  {

    /* for 8 bit uncomment the following line */
    in2[i]=((float)in[i]-128.0)*(.54 - .46 * mycosine[i]);

    /* for 16 bit, uncomment the following line */
    //    in2[i]=((float)in[i])*(.54 - .46 * cos(2.0 * M_PI * (float)i/(N-1)));

  }
  //  printf("get_data: \n");

  //  p = rfftw_create_plan(N, FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE);
  rfftw_one(p, in2, out);
  //  rfftw_destroy_plan(p);
  
  //  power_spectrum[0] = out[0]*out[0];  /* DC component */
  // for (k = 1; k < N/2; ++k)  /* (k < N/2 rounded up) */
  //    power_spectrum[k] = out[k]*out[k] + out[N-k]*out[N-k];
  // if (N % 2 == 0) /* N is even */
  //  power_spectrum[N/2] = out[N/2]*out[N/2];  /* Nyquist freq. */

  maxi = 0;
  max = 0;
  max1 = 0;
  max2 = 0;
  cross = 0;
  
  for (i = 2; i < N/16; i++ ) {
    temp = out[i]*out[i] + out[N-i]*out[N-i];//power_spectrum[i];
    if (temp > max) {
      max = temp;
      maxi = i;// * f;
    }
  }
  return;
}

void string_loop(void)
{
  char label[128];
 
  struct {
    char *label;
    float  freq;
  } notes[] =      
    {
      {"C ",65.406},
      {"C ",130.81},
      {"C ",261.63},
      {"C ",523.25},
      {"C ",1046.5},
      {"C#",69.296},
      {"C#",138.59},
      {"C#",277.18},
      {"C#",554.37},
      {"C#",1108.7},
      {"D ",73.416},
      {"D ",146.83},
      {"D ",293.66},
      {"D ",587.33},
      {"D ",1174.7},
      {"D#",77.782},
      {"D#",155.56},
      {"D#",311.13},
      {"D#",622.25},
      {"D#",1244.5},
      {"E ",82.407},
      {"E ",164.81},
      {"E ",329.63},
      {"E ",659.26},
      {"E ",1318.5},
      {"F ",87.307},
      {"F ",174.61},
      {"F ",349.23},
      {"F ",698.46},
      {"F ",1396.9},
      {"F#",92.499},
      {"F#",185.00},
      {"F#",369.99},
      {"F#",739.99},
      {"F#",1480.0},
      {"G ",97.999},
      {"G ",196.00},
      {"G ",392.00},
      {"G ",783.99},
      {"G ",1568.0},
      {"G#",103.83},
      {"G#",207.65},
      {"G#",415.30},
      {"G#",830.61},
      {"G#",1661.2},
      {"A ",55},
      {"A ",110},
      {"A ",220},
      {"A ",440},
      {"A ",880},
      {"A ",1760},
      {"A#",58.270},
      {"A#",116.54},
      {"A#",233.08},
      {"A#",466.16},
      {"A#",932.33},
      {"A#",1864.7},
      {"B ",61.735},
      {"B ",123.47},
      {"B ",246.94},
      {"B ",493.88},
      {"B ",987.77}
    };
  /*
 
STANDARD FREQUENCIES (Hz) OF MUSICAL NOTES FOR INSTRUMENTS EXCEPT PIANO

OCT
 #     C         C#        D        D#       E        F       F#      G      G#       A      A#       B
 1   32.703   34.648     36.708   38.891   41.203   43.654  46.249  48.999  51.913  55.000  58.270  61.735
 2   65.406   69.296     73.416   77.782   82.407   87.307  92.499  97.999 103.83  110.00  116.54  123.47
 3  130.81   138.59     146.83   155.56   164.81   174.61  185.00  196.00  207.65  220.00  233.08  246.94
 4  261.63   277.18     293.66   311.13   329.63   349.23  369.99  392.00  415.30  440.00  466.16  493.88
 5  523.25   554.37     587.33   622.25   659.26   698.46  739.99  783.99  830.61  880.00  932.33  987.77
 6 1046.5   1108.7     1174.7    1244.5   1318.5  1396.9  1480.0  1568.0  1661.2  1760.0  1864.7  1975.5
 7 2093.0   2217.5     2349.3    2489.0   2637.0  2793.8  2960.0  3136.0  3322.4  3520.0  3729.3  3951.1
 8 4186.0   4434.9     4698.6    4978.0   5274.0  5587.7  5919.9  6271.9  6644.9  7040.0  7458.6  7902.1

          MIDDLE C IS C4 AT 261.63Hz, CONCERT PITCH IS A4 AT 440Hz.



 PITCH     1        2        3        4         5        6          7         8

    G#  51.913  103.826   207.652  415.305  830.609   1661.219  3322.437
    G   48.999            195.998  391.995  783.991   1567.982  3135.437
    F#  46.249  97.999    184.997  369.994  739.989   1479.978  2959.955
    F   43.654            174.614  349.228  698.456   1396.913  2793.826
    E   41.203  92.499    164.814  329.629  659.255   1318.520  2637.020
    D#  38.891            155.563  311.127  622.254   1244.598  2489.016
    D   36.708  87.307    146.832  293.665  587.330   1174.659  2439.318
    C#  34.648            138.591  277.183  554.365   1108.731  2217.461
    C   32.703  82.407    130.813  261.626  523.251   1046.502  2093.004
    B   30.868            123.471  246.942  493.883             1975.533
    A#  29.135  77.782    116.541  233.082  466.164   987.767   1864.655
    A   27.500            110.000  220.000  440.000             1760.000
                73.416                                932.328

                69.296                                880.000

                65.406

                61.735
                                                                          4186.009
                58.270                                                    3951.066
                                                                          3729.310
                55.000                                                    3520.000

   */
  
  int num_notes = sizeof (notes) / sizeof (notes[0]);
  //  printf("string loop: \n");

  get_data();

  freq = maxi*f;
  sprintf(label,"i = %.0f   freq = %.3f Hz",maxi,freq);

  /* change the delta as the freqency increases */
  if (freq > 31   && freq < 63) delta = 2;
  if (freq > 63   && freq < 128) delta = 4;
  if (freq > 128  && freq < 192) delta = 8;
  if (freq > 192  && freq < 256) delta = 12;
  if (freq > 256  && freq < 384) delta = 16;
  if (freq > 384  && freq < 512) delta = 24;
  if (freq > 512  && freq < 1024) delta = 32;
  if (freq > 1024 && freq < 2048) delta = 64;
  if (freq > 2048 && freq < 4096) delta = 128;
  if (freq > 4096 && freq < 8100) delta = 256;

  for (i=0; i < num_notes; i++) {
    if (abs(notes[i].freq - freq) < delta/2) {
      if (abs(notes[i].freq - freq) < (f/2.0) )  
	sprintf(label,"i = %.0f  reference freq = %.3f Hz  actual freq = %.3f Hz  note =    %s",
		maxi,notes[i].freq,freq,notes[i].label);
      else if (notes[i].freq < freq) 
	sprintf(label,"i = %.0f  reference freq = %.3f Hz  actual freq = %.3f Hz  note = <--%s",
		maxi,notes[i].freq,freq,notes[i].label);
      else if (notes[i].freq > freq) 
	sprintf(label,"i = %.0f  reference freq = %.3f Hz  actual freq = %.3f Hz  note =    %s-->",
		maxi,notes[i].freq,freq,notes[i].label);
    }
  }

  if (max > 10000000000) {
    printf("%s\n",label);
    //    printf("max = %f  temp = %f\n",max,temp);
  }
  return;  
}

int main(int argc, char *argv[])
{

  // save these values so we don't keep recalculating them for each sample
  // if an A440 does not really give you 440 Hz, then you probably
  // need to change the following line a little.  Run the program
  // and use an A440 Hz tuning fork.  The program will tell you what
  // value 'i' is on the line.  f = 440.0/i;
  f = (float) sampling_frequency/N;

  // we store an array of cosine values to improve preformance.
  for(i=0;i<N;i++)  {
    mycosine[i]=cos(2.0 * M_PI * (float)i/N);
  }

  fd = open("/dev/dsp",O_RDONLY);

  p = rfftw_create_plan(N, FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE);

  if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels)==-1) {
    perror("bad channels setting.");
    exit(2); 
  } 

  if (ioctl(fd, SNDCTL_DSP_SETFMT, &format)==-1) {
    perror("bad sound format.");
    exit(2); 
  } 

  if (ioctl(fd, SNDCTL_DSP_SPEED, &sampling_frequency) == -1) {
    perror("bad sampling rate.");
    exit(2); 
  }


  /*
  if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg)) perror("Frag!");
  ioctl(fd, SNDCTL_DSP_SPEED, &sampling_frequency);
  */
  //  printf("main: \n");
  while (1) {
    //    printf("main: loop\n");
    string_loop();
  }
  return 0;
}

