Mike Pollock
/
GT_Tuner3
Adapted code from original GT_Tuner code (by Andrew Durand) for a school project by Tapton School.
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(' '); } } } }