Adapted code from original GT_Tuner code (by Andrew Durand) for a school project by Tapton School.

Dependencies:   mbed

main.cpp

Committer:
mptapton
Date:
2017-02-06
Revision:
2:c242fd25e7e2
Parent:
1:c8ec50d75f80

File content as of revision 2:c242fd25e7e2:

//    Guitar Tuner and Chord Learning Tool using Goertzel's Algorithm     //
//    Based on original code created by: Andrew Durand                   //
//    Adjusted and modified by Tapton School EDS Project Team            //

#include "TextLCD.h"
#include "mbed.h"
#include "adc.h"
#include <math.h>
#define PI 3.1415
#define SAMPLE_RATE 24000

Serial pc(USBTX, USBRX); // tx, rx

DigitalOut intune(p22);
DigitalOut toohigh(p23);
DigitalOut toolow(p24);
DigitalOut state(p25);
DigitalOut led_low(LED1);
DigitalOut led_ok(LED2);
DigitalOut led_high(LED4);
InterruptIn button1(p6); //mosi

DigitalIn myInputPin (p21); //select tuner or chord learning mode

Serial device(p28, p27);  // tx, rx to connect to mbed 2

/* This code uses libraries created for 4-bit LCD's based on the HD44780. This 
program was designed for a similar product (Winstar's WH1602B 2x16 LC) working 
into an Mbed LPC1768. 
LCD pins: Pin 1(VSS) to Mbed Gnd, Pin 2(VDD) to Mbed 5v USB output, Pin 3(Vo- contrast)
to Mbed Gnd (via a 4k7 resistor), Pin 5(R/W) to Mbed Gnd, Pin 15(A)to Mbed 5v USB output, Pin 16(B) to 
MBed Gnd,  Pins 4(RS),20(E) and the 4 data bits (DB4 [11] through to DB7 [14])
go to the Mbed pins described below: */   
TextLCD lcd(p10, p12, p15, p16, p29, p30); // rs, e, d4-d7

int intunetrig=2; //set max times in tune for before triggering intune to mbed2
int txcountmax=4;//set max times before determining in tune or not {set to even number as used later in divide by 2  
int txcounttrig=2; // set threshold for triggering success or not
int txcounter=0; //set counter to control transmit message timing to mbed2 
int intunecounter=0;//set counter to capture how many times in tune during txcounter time
int string_select = 0;
int chord_select = 0;
float high, high1, in_tune, in_tune1, in_tune2, in_tune3,
low, low1, note, low_mod, high_mod;
char* key;
char* chordkey;
int Counter = 0;
int Buffer[6000];

float goertzelFilter(int samples[], float freq, int N) {
    float s_prev = 0.0;
    float s_prev2 = 0.0;
    float coeff,normalizedfreq,power,s;
    int i;
    normalizedfreq = freq / SAMPLE_RATE;
    coeff = 2*cos(2*PI*normalizedfreq);
    for (i=0; i<N; i++) {
        s = samples[i] + coeff * s_prev - s_prev2;
        s_prev2 = s_prev;
        s_prev = s;
    }
    power = s_prev2*s_prev2+s_prev*s_prev-coeff*s_prev*s_prev2;
    return power;
}

ADC adc(SAMPLE_RATE, 1);

void sample_audio(int chan, uint32_t value) {
    Buffer[Counter] = adc.read(p20);
    Counter += 1;
}

void button1_pressed() {
    string_select++;
    chord_select++;
    if (string_select > 5) string_select = 0;
    if (chord_select > 6) chord_select = 0;//change for number of chords supported
    intune=0; //clear all pins to mbed2 
    toohigh=0; 
    toolow=0;
    state=0;
    txcounter=0; //set counter to control transmit message timing to mbed2 
    intunecounter=0;//set counter to capture how many times in tune during txcounter time
}

int main() {
  pc.baud(115200);
  device.baud(19200); //mbed to mbed serial communication speed
  txcounter=0;
  intunecounter=0;
  intune=0; //clear all pins to mbed2 
  toohigh=0; 
  toolow=0;
  state=0;
  int chordkeyint=0;
  setbuf(stdout, NULL);
  
  while (1) {
     myInputPin.mode(PullUp);  //set the mbed to use a pullup resistor
     if (myInputPin) { //select guitar tuner or chord teaching
        lcd.cls (); // Guitar Tuner Section based on p21 being +3v
     
        //Interupt for Switching Strings
        button1.mode(PullDown);
        button1.rise(&button1_pressed);

        while (1) {

              switch (string_select) {
              case 0:
                note = 82;
                key= "E"; //E2
                break;
              case 1:
                note = 110;
                key= "A";//A2
                break;
              case 2:
                note = 147;
                key= "D";//D3
                break;
              case 3:
                note = 196;
                key= "G";//G3
                break;
              case 4:
                note = 247;
                key= "B";//B3
                break;
              case 5:
                note = 330;
                key= "E";//E4
                break;
              }

           //Prepare for burst mode on all ADC pins and set up interrupt handler (using ADC library from Simon Blandford
           adc.append(sample_audio);
           adc.startmode(0,0);
           adc.burst(1);
           adc.setup(p20,1);

           //start the interrupt and wait for about 4096 samples
          adc.interrupt_state(p20,1);
          wait(.2);

          //Finsh up - Unset pin 20
          adc.interrupt_state(p20,0);
          adc.setup(p20,0);
          int actual_rate = adc.actual_sample_rate();

          //for debugging tell the terminal sample rate and how many samples we took
          //printf("Requested max sample rate is %u, actual max sample rate is %u.\n",
          //     SAMPLE_RATE, actual_rate);
          // printf("We did %i samples\n",Counter);

          high = 0;
          low = 0;
          for (int i=3; i<46; i+=3) {
             high1 = goertzelFilter(Buffer, (note + i ), Counter);
             if (high1 > high) high=high1;
             }
          for (int i=3; i<46; i+=3) {
             low1 = goertzelFilter(Buffer, (note - i ), Counter);
             if (low1 > low) low=low1;
             }
           in_tune1 =  goertzelFilter(Buffer, (note+1), Counter);
           in_tune2 =  goertzelFilter(Buffer, note, Counter);
           in_tune3 =  goertzelFilter(Buffer, (note-1), Counter);
        
          if ((in_tune1 > in_tune2) && (in_tune1 > in_tune3)) in_tune = in_tune1;
          else if ((in_tune2 > in_tune1) && (in_tune2 > in_tune3)) in_tune = in_tune2;
          else in_tune = in_tune3;
 
          if ((in_tune > high) && (in_tune > low)) {
            led_high = 0;
            led_ok = 1;
            led_low = 0;
           } else if (high > in_tune) {
            led_high = 1;
            led_ok = 0;
            led_low = 0;
             } else if (low > in_tune) {
               led_high = 0;
               led_ok = 0;
               led_low = 1;
               } else {
                 led_high = 0;
                 led_ok = 0;
                 led_low = 0;
                 }
        
        int pintwenty = adc.read(p20); //read pin 20
        lcd.locate(0,1);
        lcd.printf("%s %iHz %d\n",key, (int) note, pintwenty);
        if (led_ok) {
                     lcd.printf("Tuner- In Tune");
                //     device.printf("%s", key);// send to mbed 2
                     }
        else if (led_low) {
                      lcd.printf("Tuner- 2Low   ");
               //       device.printf("%s", key);// send to mbed 2
                      }
        else if (led_high){ 
                      lcd.printf("Tuner- 2High  ");
               //       device.printf("%s", key);// send to mbed 2
                      }
         Counter = 0;
        } //inner tuner while (1)loop

      } else {  //if myinputpin Chord or Tuner mode = Chord mode selected
      
                // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                // ..............CHORD MODE.........................
                  
      lcd.cls (); //Chord Tutor Section based on p21 being 0v 
     
    //Interupt for Switching chord selection
    button1.mode(PullDown);
    button1.rise(&button1_pressed);

    while (1) {

        switch (chord_select) {
            case 0:
                note = 82;
                chordkey= "E";//E2 send E chord white LED pattern
                chordkeyint=69; //E in ASCII
                break;
            case 1:
                note = 110;
                chordkey= "A";//A chord
                chordkeyint=65; //A in ASCII
                break;
            case 2:
                note = 147;
                chordkey= "D";//D3 chord
                chordkeyint=68; //D in ASCII                
                break;
            case 3:
                note = 196;
                chordkey= "G";//G3 chord 
                chordkeyint=71; //G in ASCII               
                break;
            case 4:
                note = 247;
                chordkey= "B";//B3 chord   
                chordkeyint=66; //B in ASCII             
                break;
            case 5:
                note = 131;
                chordkey= "C";//C3 chord    
                chordkeyint=67; //C in ASCII            
                break;
            case 6:
                note = 87;
                chordkey= "F";//F2 chord    
                chordkeyint=70; //F in ASCII           
                break;
                }
                
        //Prepare for burst mode on all ADC pins and set up interrupt handler (using ADC library from Simon Blandford
        adc.append(sample_audio);
        adc.startmode(0,0);
        adc.burst(1);
        adc.setup(p20,1);

        //start the interrupt and wait for about 4096 samples
        adc.interrupt_state(p20,1);
        wait(.2);

        //Finsh up - Unset pin 20
        adc.interrupt_state(p20,0);
        adc.setup(p20,0);
        int actual_rate = adc.actual_sample_rate();

        //for debugging tell the terminal sample rate and how many samples we took
        //printf("Requested max sample rate is %u, actual max sample rate is %u.\n",
         //      SAMPLE_RATE, actual_rate);
        //printf("We did %i samples\n",Counter);

high = 0;
low = 0;
for (int i=3; i<46; i+=3) {
    high1 = goertzelFilter(Buffer, (note + i ), Counter);
    if (high1 > high) high=high1;
}
for (int i=3; i<46; i+=3) {
    low1 = goertzelFilter(Buffer, (note - i ), Counter);
    if (low1 > low) low=low1;
}
        in_tune1 =  goertzelFilter(Buffer, (note+1), Counter);
        in_tune2 =  goertzelFilter(Buffer, note, Counter);
        in_tune3 =  goertzelFilter(Buffer, (note-1), Counter);
        
        if ((in_tune1 > in_tune2) && (in_tune1 > in_tune3)) in_tune = in_tune1;
        else if ((in_tune2 > in_tune1) && (in_tune2 > in_tune3)) in_tune = in_tune2;
        else in_tune = in_tune3;
        if ((in_tune > high) && (in_tune > low)) {
            led_high = 0;
            led_ok = 1; // <<IN TUNE>>
            led_low = 0;
        //    toohigh=0;
        //    toolow=0;
        //    intune=1;
            intunecounter++; // increment the intune counter
        } else if (high > in_tune) {
            led_high = 1;  // <<TOO HIGH>>
            led_ok = 0;
            led_low = 0;
        //    toohigh=1;
        //    toolow=0;
        //    intune=0;
        } else if (low > in_tune) {
            led_high = 0;
            led_ok = 0;
            led_low = 1;  // <<TOO LOW>>
       //     toohigh=0;
       //     toolow=1;
       //     intune=0;
        } else {
            led_high = 0; // not sure if we ever get here
            led_ok = 0;
            led_low = 0;
         //   toohigh=0;
         //   toolow=0;
         //   intune=0;
        }
        
    int pintwenty = adc.read(p20); //read pin 20
        lcd.locate(0,1);
        lcd.printf("%s ",chordkey);
        lcd.locate(4,1);// need to deal with lcd screen changes to length of frequencies
        lcd.printf("       ");
        lcd.locate(4,1);
        lcd.printf("%iHz",(int) note); 
        lcd.locate(11,1);
        lcd.printf("%4d\n",pintwenty); //need to deal with lcd screen changes to restrict input decimal range to 4sf
        txcounter++; //increment transmit counter acting as a timer before sending chord value to mbed2
     //   if (txcounter>txcountmax+20){txcounter=0;}//if there is a counter overrun fix it here
        lcd.printf("Play %s         ",chordkey); //send initial message to LCD screen

        if (txcounter == 1)// First time around
           {
           device.putc(chordkeyint); //SEND INITIAL CHORD LETTER  TO MBED2 (ONLY ONCE)per button press or txcounter
                 pc.putc('1');
               pc.putc(chordkeyint);
            //   intune=0; //reset status pins to mbed2
            //   toohigh=0;
            //   toolow=0;
            //   state=0;
            }
    //        else 
    //        {
            //pc.putc('z');
    //        }
        if (txcounter == txcounttrig) //if more than txcounttrig of sample time then set the corrrect outputs to mbed2
           {                          //for more lengthy intune/out tune notification
            state=1;                  // ONLY SET THIS THRESHOLD CONDITION TO mbed 2 ONCE till button press r txcounter max 
            pc.putc('2');
            if ((led_ok)||(intunecounter >1 )) 
            {
                intune=1; //its intune OR BEEN in tune so hold this until
                toohigh=0;
                toolow=0;
                pc.putc('3');
                }
            else if ((led_high)||(led_low))
                 {
                 pc.putc('4');
                 intune=0;
                 toohigh=1;// out of tune so set both output pins to mbed2
                 toolow=1;
                 }
            }
            
        if (led_ok) //          <<IN TUNE>>
           {
           lcd.locate(0,0);
           lcd.printf("Play %s->In Tune",chordkey); //to LCD screen
    pc.putc('5'); // dont use printf as buffering issues
           if ((txcounter>=txcountmax)&& (intunecounter>=intunetrig))
              {  //keep going until time to decide if intune or not
           pc.putc('6'); // send to pc usb- dont use printf as buffering issues
               //  IN TUNE FOR LONG ENOUGH AND TEST TIME ENDEDif (intunecounter >= intunetrig)
               //  attempt has been IN TUNE for suffcient time to be deemed overall intune
               //  pc.putc('4');// send to pc usb- dont use printf as buffering issues
                    intune=0; //clear all pins to mbed2 
                    toohigh=0; 
                    toolow=0;
                    state=0;
                    intunecounter=0; //reset for next test
                    txcounter=0; // reset for next test
              }
            if (txcounter>=txcountmax)
              {     //IN TUNE, TEST TME UP BUT NOT IN TUNE LONG ENOUGH
            pc.putc('7');  // attempt time is up attempt was NOT in tune long enough
                    intune=0; //clear all pins to mbed2 
                    toohigh=0; 
                    toolow=0;
                    state=0;
                    intunecounter=0; //reset for next test
                    txcounter=0; // reset for next test
              }     
        }        
        if ((led_high)||(led_low))
           {       //    <<OUT of TUNE>> either too high or 2 low    
           lcd.locate(0,0);
           lcd.printf("Play %s -> Nope  ",chordkey);
        pc.putc('8');// send to pc usb- dont use printf as buffering issues
            //   Counter = 0; //reset number of samples counter used in algorithm
            if ((txcounter>=txcountmax)&& (intunecounter>=intunetrig))
               {  // OUT OF TUNE, TEST TIME UP, BUT BEEN INTUNE FOR LONG ENOUGH 
                  // if (txcounter<=txcountmax) //keep going until time to decide if intune or not
                  //    {
                  //     device.printf("%s", chordkey);// send chord letter to mbed 2
             pc.putc('9'); // send to pc usb- dont use printf as buffering issues
                  //     if (intunecounter >=intunetrig)
                  //        {                // attempt has been IN TUNE for suffcient time to be deemed overall intune
                  //        pc.putc('7'); // even though its currently out of tune
                intune=0; //clear output pins to mbed2
                toohigh=0;   
                toolow=0;
                state=0;
                intunecounter=0; //reset for next test
                txcounter=0; // reset for next test
                }
             if (txcounter>=txcountmax)
                { //OUT OF TUNE, TEST TME UP BUT NOT IN TUNE LONG ENOUGH    
           pc.putc('a');// send to pc usb- dont use printf as buffering issues
                intune=0;     //set intune pin to 0 for mbed2 to read
                toohigh=0;    // set out of tune pins to 1 for mbed2 to read
                toolow=0;
                state=0;
                intunecounter=0; //reset for next test
                txcounter=0; // reset for next test
                } 
           } 
      Counter=0;
    pc.printf("(%i %i)\n", txcounter, intunecounter); //ok to use printf here as uses \n to clear buffer 
    //  pc.putc(txcounter);
    //  pc.putc(' ');
      }  

  }
  }
  }