text: /*===============================================================================================
   Pitch detection example.
   Copyright (c), Firelight Technologies Pty, Ltd 2004-2016.
  
   This example combines recording with spectrum analysis to determine the pitch of the sound 
   being recorded.
  ===============================================================================================*/
  #include "../../api/inc/fmod.hpp"
  #include "../../api/inc/fmod_errors.h"
  #include "../common/wincompat.h"
  
  #include <math.h>
  #include <string.h>
  
  
  void ERRCHECK(FMOD_RESULT result)
  {
      if (result != FMOD_OK)
      {
          printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
          exit(-1);
      }
  }
  
  static const char *note[120] =
  {
      "C 0", "C#0", "D 0", "D#0", "E 0", "F 0", "F#0", "G 0", "G#0", "A 0", "A#0", "B 0",  
      "C 1", "C#1", "D 1", "D#1", "E 1", "F 1", "F#1", "G 1", "G#1", "A 1", "A#1", "B 1",  
      "C 2", "C#2", "D 2", "D#2", "E 2", "F 2", "F#2", "G 2", "G#2", "A 2", "A#2", "B 2",  
      "C 3", "C#3", "D 3", "D#3", "E 3", "F 3", "F#3", "G 3", "G#3", "A 3", "A#3", "B 3",  
      "C 4", "C#4", "D 4", "D#4", "E 4", "F 4", "F#4", "G 4", "G#4", "A 4", "A#4", "B 4",  
      "C 5", "C#5", "D 5", "D#5", "E 5", "F 5", "F#5", "G 5", "G#5", "A 5", "A#5", "B 5",  
      "C 6", "C#6", "D 6", "D#6", "E 6", "F 6", "F#6", "G 6", "G#6", "A 6", "A#6", "B 6",  
      "C 7", "C#7", "D 7", "D#7", "E 7", "F 7", "F#7", "G 7", "G#7", "A 7", "A#7", "B 7",  
      "C 8", "C#8", "D 8", "D#8", "E 8", "F 8", "F#8", "G 8", "G#8", "A 8", "A#8", "B 8",  
      "C 9", "C#9", "D 9", "D#9", "E 9", "F 9", "F#9", "G 9", "G#9", "A 9", "A#9", "B 9"
  };
  
  static const float notefreq[120] =
  {
        16.35f,   17.32f,   18.35f,   19.45f,    20.60f,    21.83f,    23.12f,    24.50f,    25.96f,    27.50f,    29.14f,    30.87f, 
        32.70f,   34.65f,   36.71f,   38.89f,    41.20f,    43.65f,    46.25f,    49.00f,    51.91f,    55.00f,    58.27f,    61.74f, 
        65.41f,   69.30f,   73.42f,   77.78f,    82.41f,    87.31f,    92.50f,    98.00f,   103.83f,   110.00f,   116.54f,   123.47f, 
       130.81f,  138.59f,  146.83f,  155.56f,   164.81f,   174.61f,   185.00f,   196.00f,   207.65f,   220.00f,   233.08f,   246.94f, 
       261.63f,  277.18f,  293.66f,  311.13f,   329.63f,   349.23f,   369.99f,   392.00f,   415.30f,   440.00f,   466.16f,   493.88f, 
       523.25f,  554.37f,  587.33f,  622.25f,   659.26f,   698.46f,   739.99f,   783.99f,   830.61f,   880.00f,   932.33f,   987.77f, 
      1046.50f, 1108.73f, 1174.66f, 1244.51f,  1318.51f,  1396.91f,  1479.98f,  1567.98f,  1661.22f,  1760.00f,  1864.66f,  1975.53f, 
      2093.00f, 2217.46f, 2349.32f, 2489.02f,  2637.02f,  2793.83f,  2959.96f,  3135.96f,  3322.44f,  3520.00f,  3729.31f,  3951.07f, 
      4186.01f, 4434.92f, 4698.64f, 4978.03f,  5274.04f,  5587.65f,  5919.91f,  6271.92f,  6644.87f,  7040.00f,  7458.62f,  7902.13f, 
      8372.01f, 8869.84f, 9397.27f, 9956.06f, 10548.08f, 11175.30f, 11839.82f, 12543.85f, 13289.75f, 14080.00f, 14917.24f, 15804.26f
  };
  
  #define OUTPUTRATE          48000
  #define SPECTRUMSIZE        8192
  #define SPECTRUMRANGE       ((float)OUTPUTRATE / 2.0f)      /* 0 to nyquist */
  
  #define BINSIZE      (SPECTRUMRANGE / (float)SPECTRUMSIZE)
  
  int main(int argc, char *argv[])
  {
      FMOD::System          *system  = 0;
      FMOD::Sound           *sound   = 0;
      FMOD::Channel         *channel = 0;
      FMOD_RESULT            result;
      FMOD_CREATESOUNDEXINFO exinfo;
      int                    key, driver, recorddriver, numdrivers, count, outputfreq, bin;
      unsigned int           version;    
  
      /*
          Create a System object and initialize.
      */
      result = FMOD::System_Create(&system);
      ERRCHECK(result);
  
      result = system->getVersion(&version);
      ERRCHECK(result);
  
      if (version < FMOD_VERSION)
      {
          printf("Error!  You are using an old version of FMOD %08x.  This program requires %08x\n", version, FMOD_VERSION);
          return 0;
      }
  
      /* 
          System initialization
      */
      printf("---------------------------------------------------------\n");    
      printf("Select OUTPUT type\n");    
      printf("---------------------------------------------------------\n");    
      printf("1 :  OSS        - Open Sound System\n");
      printf("2 :  ALSA       - Advanced Linux Sound Architecture\n");
      printf("3 :  ESD        - Enlightenment Sound Daemon\n");
      printf("4 :  PULSEAUDIO - Pulse Audio Sound Server\n");
      printf("---------------------------------------------------------\n");
      printf("Press a corresponding number or ESC to quit\n");
  
      do
      {
          key = getch();
      } while (key != 27 && key < '1' && key > '5');
      
      switch (key)
      {
          case '1' :  result = system->setOutput(FMOD_OUTPUTTYPE_OSS);
                      break;
          case '2' :  result = system->setOutput(FMOD_OUTPUTTYPE_ALSA);
                      break;
          case '3' :  result = system->setOutput(FMOD_OUTPUTTYPE_ESD);
                      break;
          case '4' :  result = system->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO);
                      break;                   
          default  :  return 1; 
      }  
      ERRCHECK(result);
      
      /*
          Enumerate playback devices
      */
  
      result = system->getNumDrivers(&numdrivers);
      ERRCHECK(result);
  
      printf("---------------------------------------------------------\n");    
      printf("Choose a PLAYBACK driver\n");
      printf("---------------------------------------------------------\n");    
      for (count=0; count < numdrivers; count++)
      {
          char name[256];
  
          result = system->getDriverInfo(count, name, 256, 0);
          ERRCHECK(result);
  
          printf("%d : %s\n", count + 1, name);
      }
      printf("---------------------------------------------------------\n");
      printf("Press a corresponding number or ESC to quit\n");
  
      do
      {
          key = getch();
          if (key == 27)
          {
              return 0;
          }
          driver = key - '1';
      } while (driver < 0 || driver >= numdrivers);
  
      result = system->setDriver(driver);
      ERRCHECK(result);
  
      /*
          Enumerate record devices
      */
  
      result = system->getRecordNumDrivers(&numdrivers);
      ERRCHECK(result);
  
      printf("---------------------------------------------------------\n");    
      printf("Choose a RECORD driver\n");
      printf("---------------------------------------------------------\n");    
      for (count=0; count < numdrivers; count++)
      {
          char name[256];
  
          result = system->getRecordDriverInfo(count, name, 256, 0);
          ERRCHECK(result);
  
          printf("%d : %s\n", count + 1, name);
      }
      printf("---------------------------------------------------------\n");
      printf("Press a corresponding number or ESC to quit\n");
  
      recorddriver = 0;
      do
      {
          key = getch();
          if (key == 27)
          {
              return 0;
          }
          recorddriver = key - '1';
      } while (recorddriver < 0 || recorddriver >= numdrivers);
  
      printf("\n");
   
      result = system->setSoftwareFormat(OUTPUTRATE, FMOD_SOUND_FORMAT_PCM16, 1, 0, FMOD_DSP_RESAMPLER_LINEAR);
      ERRCHECK(result);
  
      result = system->init(32, FMOD_INIT_NORMAL, 0);
      ERRCHECK(result);
  
      system->getSoftwareFormat(&outputfreq, 0, 0, 0, 0, 0);
      ERRCHECK(result);
  
      /*
          Create a sound to record to.
      */
      memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
  
      exinfo.cbsize           = sizeof(FMOD_CREATESOUNDEXINFO);
      exinfo.numchannels      = 1;
      exinfo.format           = FMOD_SOUND_FORMAT_PCM16;
      exinfo.defaultfrequency = OUTPUTRATE;
      exinfo.length           = exinfo.defaultfrequency * sizeof(short) * exinfo.numchannels * 5;
      
      result = system->createSound(0, FMOD_2D | FMOD_SOFTWARE | FMOD_LOOP_NORMAL | FMOD_OPENUSER, &exinfo, &sound);
      ERRCHECK(result);
  
      /*
          Start the interface
      */
      printf("=========================================================================\n");
      printf("Pitch detection example.  Copyright (c) Firelight Technologies 2004-2016.\n");
      printf("=========================================================================\n");
      printf("\n");
      printf("Record something through the selected recording device and FMOD will\n");
      printf("Determine the pitch.  Sustain the tone for at least a second to get an\n");
      printf("accurate reading.\n");
      printf("Press 'Esc' to quit\n");
      printf("\n");
  
      result = system->recordStart(recorddriver, sound, true);
      ERRCHECK(result);
      
      Sleep(200);      /* Give it some time to record something */
      
      result = system->playSound(FMOD_CHANNEL_REUSE, sound, false, &channel);
      ERRCHECK(result);
  
      /* Dont hear what is being recorded otherwise it will feedback.  Spectrum analysis is done before volume scaling in the DSP chain */
      result = channel->setVolume(0);
      ERRCHECK(result);
  
      bin = 0;
  
      /*
          Main loop.
      */
      do
      {
          static float spectrum[SPECTRUMSIZE];
          float        dominanthz = 0;
          float        max;
          int          dominantnote = 0;
          float        binsize = BINSIZE;
  
          if (kbhit())
          {
              key = getch();
          }
  
          result = channel->getSpectrum(spectrum, SPECTRUMSIZE, 0, FMOD_DSP_FFT_WINDOW_TRIANGLE);
          ERRCHECK(result);
  
          max = 0;
  
          for (count = 0; count < SPECTRUMSIZE; count++)
          {
              if (spectrum[count] > 0.01f && spectrum[count] > max)
              {
                  max = spectrum[count];
                  bin = count;
              }
          }        
  
          dominanthz  = (float)bin * BINSIZE;       /* dominant frequency min */
  
          dominantnote = 0;
          for (count = 0; count < 120; count++)
          {
               if (dominanthz >= notefreq[count] && dominanthz < notefreq[count + 1])
               {
                  /* which is it closer to.  This note or the next note */
                  if (fabs(dominanthz - notefreq[count]) < fabs(dominanthz - notefreq[count+1]))
                  {
                      dominantnote = count;
                  }
                  else
                  {
                      dominantnote = count + 1;
                  }
                  break;
               }
          }
  
          printf("Detected rate : %7.1f -> %7.1f hz.  Detected musical note. %-3s (%7.1f hz)\r", dominanthz, ((float)bin + 0.99f) * BINSIZE, note[dominantnote], notefreq[dominantnote]);
          fflush(stdout);
  
          system->update();
  
          Sleep(10);
  
      } while (key != 27);
  
      printf("\n");
  
      /*
          Shut down
      */
      result = sound->release();
      ERRCHECK(result);
  
      result = system->release();
      ERRCHECK(result);
  
      return 0;
  }
  
  
  