Guitar Tuner Project Report - EE 6th Sem
Guitar Tuner Project Report - EE 6th Sem
In order to play beautiful music, a musician needs to have perfectly tuned instruments. If it is not tuned properly, it will not sound good, even if you are playing everything correctly. As any novice musician knows, one of the most frustrating parts of learning how to play guitar is tuning the instrument which can be difficult for the untrained ear. This is where electronic tuners come in. These small devices allow guitarists to perfectly tune their instruments. The tuner is designed using the filtering, measuring and analyzing capabilities of the Arduino. Compared to tuning by ear, where a certain amount of guess work is involved in deciding how much to tighten/loosen a string, the Arduino based tuner is able to give accurate instructions so that tuning can be achieved quicker.
1|Page
ACKNOWLEDGEMENT:
On the very outset of this project, we would like to extend our sincere and heartfelt gratitude towards our guide Mr. Shankar Banwasi for his constant support throughout the course of this venture. We are ineffably indebted to Mrs Abha Tripathi for her conscientious guidance and encouragement to accomplish this assignment. We are extremely thankful and express our earnest gratitude to the faculty members of electrical and electronics department of PESIT for providing us with valuable information in our endeavour. We would also like to show our appreciation for our HOD Dr.B Keshavan and our principal Dr K.N.B Murthy, for providing us with the opportunity to take this task upon ourselves.
2|Page
TABLE OF CONTENTS
Chapter 1: Introduction 1.0: Electric Guitar Theory 1.1: Working of an Electric Guitar Chapter 2: Design 2.0: Block Diagram Representation 2.1: Choice of Components and Cost Analysis 2.1.1: Op-Amp 2.1.2: Digital Signal Processing 2.1.3: LCD Display 2.2: External Circuit 2.3: Selection of Algorithm 2.3.1:Auto-Correlation 2.3.2:Measuring Zero Crossing with Positive Slope Chapter 3: Implementation 3.0: External Circuit 3.0.1: Simulation Results 3.1: Implementation of Algorithm 3.1.1: Measuring Zero Crossing with Positive Slope 3.1.2: Auto-Correlation 3.2: Pitch Calculation 3.3: Output Display 3.4: Bread Board View Chapter 4: Result and Conclusion Chapter 5: Future Enhancements Bibliography 4 5
6 6 7 7 8 9 10
12 12 13 14 15 15 16 17 18
Appendix A1: Source code for Auto-Correlation 19 A2: Source Code for measuring Zero Crossing with Positive Slope 31
3|Page
CHAPTER 1
INTRODUCTION
1.0 ELECTRIC GUITAR THEORY
A guitar is a six stringed musical instrument. It primarily consists of a neck and a body. The six strings are strung along the neck to the bridge on the body. The thickness of each string is different. Along the neck of the guitar are frets. Pressing the strings down onto the fret board changes the length of the string, which changes the note being played. As the stings of the guitar are of a particular length and tension, when played, each string corresponds to a particular note and thus can be tuned to a particular note. Each musical note corresponds to a particular frequency of sound. In western music there are 12 notes, A A# B C C# D D# E F F# G G# The set of these 12 notes make an octave. Given below is the standard tuning of the guitars six strings along with the frequencies, from the thickest to the thinnest string: E: 82.41Hz A: 110.00Hz D: 146.83Hz G: 196.00Hz B: 246.94Hz E: 329.63Hz When the guitar goes out of tune, the frequency of the string does not correspond to that of the expected note. A tuner detects the pitch of the notes played and gives visual feedback, to show how far away the note is from the desired frequency. A guitar note is not made up of a single frequency. It consists of a number of harmonics as well. The difference in the harmonics is what makes a guitar and a violin sound different even while playing the same note. Once a sample note is played on the guitar, its fundamental frequency has to be calculated. A major part of the project is dedicated towards recovering the fundamental frequency from the frequency spectrum of the sample note played on a guitar. Once recovered, it can be compared with the standard to determine if the guitar is in tune.
4|Page
5|Page
CHAPTER 2
DESIGN
2.0 BLOCK DIAGRAM REPRESENTATION
a) Amplifier stage Amplifier stage contains a simple op-amp based audio amplifier, which amplifies the electrical input obtained from the pickups b) Analog to Digital converter The ADC converts the analog input to a digital signal. The digital signal must have suitable resolution and sampling frequency. c) Digital Signal Processor The DSP stage is used to estimate the fundamental frequency of the incoming signal using suitable algorithms. d) LCD Display The LCD display is used to display how close the signal frequency is to the fixed standards. If the signal frequency matches the standards exactly, the display reflects the note in tune. If the note is a little too high or low relative to the fixed standards, the tuner will show the note as being little sharp or flat respectively.
6|Page
2.1.2 DIGITAL SIGNAL PROCESSOR The microcontroller is the ADC and DSP stage. Our choice was between: a) Arduino b) MSP430 Launchpad
Parameters Microcontroller Data Bus Speed Storage RAM Digital I/O Analog I/O IDE Language Kit Cost
MSP430 Launchpad TI M430G2553 16 bit 16MHz 16KB 512B 8 Channels 8 Channels Code Composer Studio Embedded C Rs.500
Arduino ATMega328 8 bit 16Mhz 32KB 2KB 14 Channels 6 Channels Arduino v1.0.1 IDE Arduino C Rs.1200
Arduino is open source and its community support is unmatched compared to the Launchpad. We chose the Arduino as it is easier to prototype on and it has larger RAM space compared to the Launchpad; however the MSP430 is superior to the Arduino in terms of pricing and versatility. Thus as the aim was to prototype, we chose the Arduino. However if we intend to mass produce our tuners, we would use the MSP430. 2.1.3 LCD DISPLAY We use the D6711 7 segment LCD display, for displaying the note. 7 segment displays are used to indicate decimal numerals or alphabets. Once the guitar is tuned, the display will show the alphabet corresponding to the note being played. If the frequency of the played note is too high or too low, this will be indicated by three LEDs one to indicate the note is in tune, and the other two to indicate if the note is higher or lower than the desired note.
7|Page
8|Page
In the above equation, is the time lag of the second signal. Consider a composite signal with most of its energy in one frequency, called the fundamental frequency. It also contains a small fraction of the energy within the harmonics of that fundamental frequency. This kind of a spectrum is native to most musical instrument sounds. The timbre of the instrument is characterized by the specific levels of these harmonics and is usually the result of the materials and physical characteristics of the instrument. Either way, the fundamental frequency of the signal is the same regardless of what instrument is played. Consider a composite signal like so.
The magnitude of the autocorrelation function plot with respect to the time lag would result in a graph like so.
9|Page
Since the autocorrelation function works by inducing a time lag to one of the signals, in effect, it compares the phase shifted version of the signal to the original signal. Most of the energy of the signal lies in the fundamental frequency of the signal. Hence, when the phase shift of the signal equals 180o of the fundamental frequency, this results in the cancellation of the fundamental frequency due to the superposition theory. This results in a very low energy at this time lag, thereby resulting in a minimum point in the autocorrelation function. If we measure the time lag (in samples) at this minimum point, it must, more or less be equal to the time lag for 180o phase shift of the fundamental frequency. If the sampling frequency is known, the actual time can be calculated for this lag. The time period of the fundamental would simply by twice the time lag. If sampling frequency is Fs and time lag is tl, then the fundamental frequency F is given by:
This fundamental frequency is then compared to the standard pitches of the musical notes. 2.3.2 MEASURING ZERO CROSSING WITH POSITIVE SLOPE The Arduino has an internal ADC (analog to digital converter) that uses 8 bits for digital encoding. The maximum voltage that can be read by the arduino is 5V, thus this will be read as 255 by it after digital conversion. The reference of 2.5V will be read as 127. We also know that the ADC is setup such that it updates the analog signal at the rate of 38,462Hz. In order to determine the frequency of the input signal, the number of positive slopes encountered is counted. We use interrupts to count the positive slopes. Timer interrupts allow the user to perform a task at very specifically timed intervals regardless of what else is going on in your code. Interrupts are
10 | P a g e
useful for measuring an incoming signal at equally spaced intervals at constant sampling frequency. The following figure should help illustrate this algorithm. The yellow signal is the audio signal. The blue signals spikes indicate the time at which the audio signal crosses the reference with a positive slope. The time between two consecutive spikes will give the time period of the fundamental frequency.
11 | P a g e
CHAPTER 3
IMPLEMENTATION
3.0 EXTERNAL CIRCUIT
3.0.1 SIMULATION RESULTS The following graphs represent the output of the external circuit. - The blue waveform represents the direct output of the guitar. The orange waveform represents the output of the non inverting amplifier. The grey waveform represents the waveform after the DC offset.
Simulation Parameters: - Simulation Tool: www.circuitlab.com - Input: 400mV peak to peak sinusoidal voltage source.
//if increasing and crossing midpoint period = timer; //get period timer = 0; //reset timer } timer++; } Since we know the sampling rate of the ADC, we can use it to calculate the fundamental frequency using the following formula. frequency = 38462/period;//timer-rate/period
3.1.2 AUTOCORRELATION ALGORITHM The following function computes the fundamental frequency using autocorrelation. The array buffer of size N is used as a buffer to store a stream of converted analog values. The array corr stores the result of the autocorrelation of the values stored in buffer. The minIndex variable is used to store the index of the minimum value of the autocorrelation. void compute(void){ //Autocorrelate and find minimum point minIndex=0; for(i=0; i<=N-1; i++){ corr[i] = 0; for(j=0; j<=N-1; j++){ s = j+i; if((j+i)>(N-1)) s = (j+i) - (N-1); corr[i] = corr[i] + (int)buffer[j]*buffer[s]; } if(corr[i]<corr[minIndex]) minIndex = i; } //Calculate Frequency Freq = sampleF/(minIndex*2); } This minimum index is used to find the fundamental frequency using the above formula. Since minIndex corresponds to a 180o phase shift of the fundamental frequency, it must be multiplied by two to obtain the time period.
13 | P a g e
14 | P a g e
15 | P a g e
CHAPTER 4
16 | P a g e
CHAPTER 5
FUTURE ENHANCEMENTS
This project can be extended to include automatic tuning of the guitar strings by using a motor to turn the tuning pegs. These motors can be controlled by a voltage proportional to the amount of turn required. We may estimate the frequency using the same algorithms. We intended to implement the YIN algorithm [1] entirely but we used only the autocorrelation portion of this algorithm as it sufficed our application. The YIN algorithm further uses a cumulative mean normalized difference function along with parabolic interpolation to reduce the error by nearly three times.
17 | P a g e
BIBILIOGRAPHY
[1] Alain de Cheveigne, Hideki Kawahara. YIN, a fundamental frequency estimator for speech and music, 2002. Acoustical Society of America [2] Arduino Frequency Detection by amandaghassaei http://www.instructables.com/id/Arduino-Frequency-Detection/ [3] TL072 Datasheet [4] D6711 Datasheet
18 | P a g e
APPENDIX
A1.SOURCE CODE FOR AUTOCORRELATION ALGORITHM
/******************************************************************************** PESIT EEE 6th Sem Mini Project May 2013 ELECTRONIC GUITAR TUNER Tested on: Arduino Uno Main Algorithm Used: Autocorrelation (for fundamental frequency) Software version: 1.0.1 Test Parameters: INPUT: Emulated Acoustic guitar sound from Guitar Pro V5 (for windows) SIGNAL FLOW: Computer Audio out->Operational Amplifier->Arduino Uno->7 Segment Display USNs: 1PI10EE009 1PI10EE026 1PI10EE019 Source Code: http://pastebin.com/XiU7QHdk ********************************************************************************/ /***************************************************************************** DECLARATIONS ******************************************************************************/ #define N 200 //Buffer Size #define sampleF 38500//Hz #define display_time 5000//ms byte incomingAudio, bIndex=N-1; int buffer[N]; long int corr[N], corrMin; long int t_old, t_new = millis(); int i, j, minIndex,s; int Freq=0; boolean clipping = 0, flag = 0; const int A = 110, //These are the standard note frequencies As = 116, //At the lowest octave B = 123, C = 131, Cs = 139, D = 147, Ds = 156, E = 165, F = 171, Fs = 185, G = 196, Gs = 208; int note = A; int deviation = 0; bool dev; //Higher or lower from the correct note bool correct; //To show that the guitar is in tune
19 | P a g e
/***************************************************************************** FUNCTION TO COMPUTE FUNDAMENTAL FREQUENCY ******************************************************************************/ void compute(void){ //Autocorrelate and find minimum point minIndex=0; for(i=0; i<=N-1; i++){ corr[i] = 0; for(j=0; j<=N-1; j++){ s = j+i; if((j+i)>(N-1)) s = (j+i) - (N-1); corr[i] = corr[i] + (int)buffer[j]*buffer[s]; } if(corr[i]<corr[minIndex]) minIndex = i; } //Calculate Frequency Freq = sampleF/(minIndex*2); } /***************************************************************************** PITCH DETECTION FUNCTION ******************************************************************************/ void pitch(void){ /* This function is used to find the pitch after finding frequency and display the outputs on the 7 segment display and the LEDs */ const float t = 0.035; //tolerance band for note const float t2 = 0.01; //tolerance band for correct note int octave = 1; //FIND OCTAVE if(Freq > Gs*1) octave = 2; if(Freq > Gs*2) octave =4; if(Freq > Gs*4) octave = 8; /*FIND PITCH The following portion is equivalent to checking if 'Freq' lies within a certain band around the given note. The width of this band is set by 't' (a percentage value) Check if: (input_note) lies within required_note +/(percentage*required_note) */ if( Freq > (A*octave)*(1-t) && Freq < (A*octave)*(1+t) ){ note = A;
20 | P a g e
//Signal the 7 seg display with the letter in each of these if statements. seven_seg_A(); } else if( Freq > (As*octave)*(1-t) && Freq < (As*octave)*(1+t) ){ note = As; seven_seg_As(); } else if( Freq > (B*octave)*(1-t) && Freq < (B*octave)*(1+t) ){ note = B; seven_seg_B(); } else if( Freq > (C*octave)*(1-t) && Freq < (C*octave)*(1+t) ){ note = C; seven_seg_C(); } else if( Freq > (Cs*octave)*(1-t) && Freq < (Cs*octave)*(1+t) ){ note = Cs; seven_seg_Cs(); } else if( Freq > (D*octave)*(1-t) && Freq < (D*octave)*(1+t) ){ note = D; seven_seg_D(); } else if( Freq > (Ds*octave)*(1-t) && Freq < (Ds*octave)*(1+t) ){ note = Ds; seven_seg_Ds(); } else if( Freq > (E*octave)*(1-t) && Freq < (E*octave)*(1+t) ){ note = E; seven_seg_E(); } else if( Freq > (F*octave)*(1-t) && Freq < (F*octave)*(1+t) ){ note = F; seven_seg_F(); } else if( Freq > (Fs*octave)*(1-t) && Freq < (Fs*octave)*(1+t) ){ note = Fs; seven_seg_Fs(); } else if( Freq > (G*octave)*(1-t) && Freq < (G*octave)*(1+t) ){ note = G; seven_seg_G(); } else if( Freq > (Gs*octave)*(1-t) && Freq < (Gs*octave)*(1+t) ){ note = Gs; seven_seg_Gs(); } //DISPLAY deviation = Freq - note*octave; if (abs(deviation) < t2*note){ correct = 1; //in tune //Serial.print(" "); //Serial.println("Correct"); } else{ correct = 0; //not in tune if((deviation)>0){ //Serial.print(" "); //Serial.println("Note = deviated HIGH");
21 | P a g e
dev = HIGH; } else { // Serial.print(" "); //Serial.println("Deviated Low"); dev = LOW; } } } /***************END OF PITCH DETECTION FUNCTION****************/ /****************************************************************************** FUNCTIONS FOR 7 SEGMENT DISPLAY *******************************************************************************/ //These are used to display the specific note on the 7 segment display void seven_seg_A(void){ digitalWrite(9, LOW); digitalWrite(8, LOW); digitalWrite(7, LOW); digitalWrite(6, HIGH); digitalWrite(5, LOW); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, HIGH); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_As(void){ digitalWrite(9, LOW); digitalWrite(8, LOW); digitalWrite(7, LOW); digitalWrite(6, HIGH); digitalWrite(5, LOW); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, LOW); if(correct == 1) { digitalWrite(12,LOW);
22 | P a g e
digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_B(void){ digitalWrite(9, HIGH); digitalWrite(8, HIGH); digitalWrite(7, LOW); digitalWrite(6, LOW); digitalWrite(5, LOW); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, HIGH); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_C(void){ digitalWrite(9, HIGH); digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, LOW); digitalWrite(5, LOW); digitalWrite(4, HIGH); digitalWrite(3, LOW); digitalWrite(2, HIGH);
23 | P a g e
if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_Cs(void){ digitalWrite(9, HIGH); digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, LOW); digitalWrite(5, LOW); digitalWrite(4, HIGH); digitalWrite(3, LOW); digitalWrite(2, LOW); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_D(void){ digitalWrite(9, HIGH); digitalWrite(8, LOW); digitalWrite(7, LOW); digitalWrite(6, LOW); digitalWrite(5, LOW);
24 | P a g e
digitalWrite(4, HIGH); digitalWrite(3, LOW); digitalWrite(2, HIGH); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_Ds(void){ digitalWrite(9, HIGH); digitalWrite(8, LOW); digitalWrite(7, LOW); digitalWrite(6, LOW); digitalWrite(5, LOW); digitalWrite(4, HIGH); digitalWrite(3, LOW); digitalWrite(2, LOW); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_E(void){ digitalWrite(9, LOW); digitalWrite(8, HIGH);
25 | P a g e
digitalWrite(7, HIGH); digitalWrite(6, LOW); digitalWrite(5, LOW); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, HIGH); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_F(void){ digitalWrite(9, LOW); digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, HIGH); digitalWrite(5, LOW); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, HIGH); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } }
26 | P a g e
void seven_seg_Fs(void){ digitalWrite(9, LOW); digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, HIGH); digitalWrite(5, LOW); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, LOW); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_G(void){ digitalWrite(9, LOW); digitalWrite(8, LOW); digitalWrite(7, LOW); digitalWrite(6, LOW); digitalWrite(5, HIGH); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, HIGH); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); }
27 | P a g e
} } void seven_seg_Gs(void){ digitalWrite(9, LOW); digitalWrite(8, LOW); digitalWrite(7, LOW); digitalWrite(6, LOW); digitalWrite(5, HIGH); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, LOW); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void blank(void){ //Blanks out the 7 Segment display digitalWrite(10, LOW); digitalWrite(11, LOW); digitalWrite(12, LOW); digitalWrite(9, HIGH); digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, HIGH); digitalWrite(5, HIGH); digitalWrite(4, HIGH); digitalWrite(3, HIGH); digitalWrite(2, HIGH); } void test(void){ //To test the 7 Segment display seven_seg_A(); delay(500); seven_seg_As(); delay(500); seven_seg_B(); delay(500); seven_seg_C(); delay(500); seven_seg_Cs();
28 | P a g e
delay(500); seven_seg_D(); delay(500); seven_seg_Ds(); delay(500); seven_seg_E(); delay(500); seven_seg_F(); delay(500); seven_seg_Fs(); delay(500); seven_seg_G(); delay(500); seven_seg_Gs(); delay(500); blank(); } /***************END OF 7 SEG FUNCTIONS****************/ /***************************************************************************** SETUP ******************************************************************************/ void setup(){ pinMode(13,OUTPUT);//led clipping indicator pin cli(); //disable interrupts //set up continuous sampling of analog pin 0 ADCSRA = 0; //clear ADCSRA and ADCSRB registers ADCSRB = 0; ADMUX |= (1 << REFS0); //set reference voltage ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only ADCSRA |= (1 << ADPS2) | (1 << ADPS0); //set ADC clock with 32 prescaler16mHz/32=500kHz //ADCSRA |= (1 << ADPS2) | (0 << ADPS1) | (0 << ADPS0); ADCSRA |= (1 << ADATE); //enabble auto trigger ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete ADCSRA |= (1 << ADEN); //enable ADC ADCSRA |= (1 << ADSC); //start ADC measurements sei();//enable interrupts Serial.begin(9600); } /***************************************************************************** INTERRUPT SERVICE ROUTINE ******************************************************************************/ ISR(ADC_vect) {//when new ADC value ready incomingAudio = ADCH;//store 8 bit value from analog pin 0 //t_new = millis(); if (incomingAudio == 0 || incomingAudio == 255){//if clipping digitalWrite(13,HIGH);//set pin 13 high clipping = 1;//currently clipping } //Store in buffer //Works
29 | P a g e
if(bIndex!=N-1){ buffer[bIndex] = incomingAudio; bIndex++; } else{ bIndex = 0; //flag = 1; } } /***************END OF INTERRUPT SERVICE ROUTINE**************/ /***************************************************************************** LOOP ******************************************************************************/ void loop(){ if (clipping){//if currently clipping clipping = 0;// digitalWrite(13,LOW);//turn off clipping led indicator (pin 13) } cli(); compute(); //To print results on serial monitor //Serial.print(Freq); //Serial.println(" hz"); sei(); } /***************END OF LOOP**************/
30 | P a g e
/***************************************************************************** DECLARATIONS ****************************************************************************** / byte incomingAudio; int Freq=0; boolean clipping = 0, flag = 0; const int A = 110, //These are the standard note frequencies As = 116, //At the lowest octave B = 123, C = 131, Cs = 139, D = 147, Ds = 156, E = 165, F = 171, Fs = 185, G = 196, Gs = 208; int note = A; int deviation = 0; bool dev; //Higher or lower from the correct note bool correct; //To show that the guitar is in tune //data storage variables byte newData = 0; byte prevData = 0; unsigned int time = 0; //keeps time and sends vales to store in timer[] occasionally int timer[10]; //sstorage for timing of events int slope[10]; //storage for slope of events unsigned int totalTimer;//used to calculate period
31 | P a g e
unsigned int period; //storage for period of wave byte index = 0; //current storage index float frequency; //storage for frequency calculations int maxSlope = 0; //used to calculate max slope as trigger point int newSlope; //storage for incoming slope data //variables for decided whether you have a match byte noMatch = 0; //counts how many non-matches you've received to reset variables if it's been too long byte slopeTol = 3; //slope tolerance- adjust this if you need int timerTol = 10; //timer tolerance- adjust this if you need //variables for amp detection unsigned int ampTimer = 0; byte maxAmp = 0; byte checkMaxAmp; byte ampThreshold = 30; //raise if you have a very noisy signal /***************END OF INITIAL DECLARATIONS****************/ /***************************************************************************** PITCH DETECTION FUNCTION ****************************************************************************** / void pitch(void){ /* This function is used to find the pitch after finding frequency and display the outputs on the 7 segment display and the LEDs */ const float t = 0.035; //tolerance band for note const float t2 = 0.01; //tolerance band for correct note int octave = 1; //FIND OCTAVE if(Freq > Gs*1){ //Serial.print(" "); //Serial.print("Once Octave"); octave = 2;} if(Freq > Gs*2){ //Serial.print(" "); //Serial.print("twice Octave"); octave =4;} if(Freq > Gs*4) octave = 8; /*FIND PITCH The following portion is equivalent to checking if 'Freq' lies within a certain band around the given note. The width of this band is set by 't' (a percentage value) Check if: (input_note) lies within required_note +/(percentage*required_note) */ if( Freq > (A*octave)*(1-t) && Freq < (A*octave)*(1+t) ){ note = A; //Signal the 7 seg display with the letter in each of these if statements.
32 | P a g e
seven_seg_A(); } else if( Freq > (As*octave)*(1-t) && Freq < (As*octave)*(1+t) ){ note = As; seven_seg_As(); } else if( Freq > (B*octave)*(1-t) && Freq < (B*octave)*(1+t) ){ note = B; seven_seg_B(); } else if( Freq > (C*octave)*(1-t) && Freq < (C*octave)*(1+t) ){ note = C; seven_seg_C(); } else if( Freq > (Cs*octave)*(1-t) && Freq < (Cs*octave)*(1+t) ){ note = Cs; seven_seg_Cs(); } else if( Freq > (D*octave)*(1-t) && Freq < (D*octave)*(1+t) ){ note = D; seven_seg_D(); } else if( Freq > (Ds*octave)*(1-t) && Freq < (Ds*octave)*(1+t) ){ note = Ds; seven_seg_Ds(); } else if( Freq > (E*octave)*(1-t) && Freq < (E*octave)*(1+t) ){ note = E; seven_seg_E(); } else if( Freq > (F*octave)*(1-t) && Freq < (F*octave)*(1+t) ){ note = F; seven_seg_F(); } else if( Freq > (Fs*octave)*(1-t) && Freq < (Fs*octave)*(1+t) ){ note = Fs; seven_seg_Fs(); } else if( Freq > (G*octave)*(1-t) && Freq < (G*octave)*(1+t) ){ note = G; seven_seg_G(); } else if( Freq > (Gs*octave)*(1-t) && Freq < (Gs*octave)*(1+t) ){ note = Gs; seven_seg_Gs(); } //DISPLAY deviation = Freq - note*octave; if (abs(deviation) < t2*note){ correct = 1; //in tune //Serial.print(" "); //Serial.println("Correct"); } else{ correct = 0; //not in tune if((deviation)>0){ //Serial.print(" "); //Serial.println("Note = deviated HIGH"); dev = HIGH; }
33 | P a g e
else { // Serial.print(" "); //Serial.println("Deviated Low"); dev = LOW; } } } /***************END OF PITCH DETECTION FUNCTION****************/ /***************************************************************************** * FUNCTIONS FOR 7 SEGMENT DISPLAY ****************************************************************************** */ //These are used to display the specific note on the 7 segment display void seven_seg_A(void){ digitalWrite(9, LOW); digitalWrite(8, LOW); digitalWrite(7, LOW); digitalWrite(6, HIGH); digitalWrite(5, LOW); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, HIGH); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_As(void){ digitalWrite(9, LOW); digitalWrite(8, LOW); digitalWrite(7, LOW); digitalWrite(6, HIGH); digitalWrite(5, LOW); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, LOW); if(correct == 1) { digitalWrite(12,LOW);
34 | P a g e
digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_B(void){ digitalWrite(9, HIGH); digitalWrite(8, HIGH); digitalWrite(7, LOW); digitalWrite(6, LOW); digitalWrite(5, LOW); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, HIGH); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_C(void){ digitalWrite(9, HIGH); digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, LOW); digitalWrite(5, LOW); digitalWrite(4, HIGH); digitalWrite(3, LOW); digitalWrite(2, HIGH);
35 | P a g e
if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_Cs(void){ digitalWrite(9, HIGH); digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, LOW); digitalWrite(5, LOW); digitalWrite(4, HIGH); digitalWrite(3, LOW); digitalWrite(2, LOW); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_D(void){ digitalWrite(9, HIGH); digitalWrite(8, LOW); digitalWrite(7, LOW); digitalWrite(6, LOW); digitalWrite(5, LOW);
36 | P a g e
digitalWrite(4, HIGH); digitalWrite(3, LOW); digitalWrite(2, HIGH); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_Ds(void){ digitalWrite(9, HIGH); digitalWrite(8, LOW); digitalWrite(7, LOW); digitalWrite(6, LOW); digitalWrite(5, LOW); digitalWrite(4, HIGH); digitalWrite(3, LOW); digitalWrite(2, LOW); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_E(void){ digitalWrite(9, LOW); digitalWrite(8, HIGH);
37 | P a g e
digitalWrite(7, HIGH); digitalWrite(6, LOW); digitalWrite(5, LOW); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, HIGH); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_F(void){ digitalWrite(9, LOW); digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, HIGH); digitalWrite(5, LOW); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, HIGH); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } }
38 | P a g e
void seven_seg_Fs(void){ digitalWrite(9, LOW); digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, HIGH); digitalWrite(5, LOW); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, LOW); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void seven_seg_G(void){ digitalWrite(9, LOW); digitalWrite(8, LOW); digitalWrite(7, LOW); digitalWrite(6, LOW); digitalWrite(5, HIGH); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, HIGH); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); }
39 | P a g e
} } void seven_seg_Gs(void){ digitalWrite(9, LOW); digitalWrite(8, LOW); digitalWrite(7, LOW); digitalWrite(6, LOW); digitalWrite(5, HIGH); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, LOW); if(correct == 1) { digitalWrite(12,LOW); digitalWrite(11,HIGH); digitalWrite(10,LOW); } else if(correct == 0) { if(dev == HIGH) { digitalWrite(12,LOW); digitalWrite(11,LOW); digitalWrite(10,HIGH); } else if(dev == LOW) { digitalWrite(12,HIGH); digitalWrite(11,LOW); digitalWrite(10,LOW); } } } void blank(void){ //Blanks out the 7 Segment display digitalWrite(10, LOW); digitalWrite(11, LOW); digitalWrite(12, LOW); digitalWrite(9, HIGH); digitalWrite(8, HIGH); digitalWrite(7, HIGH); digitalWrite(6, HIGH); digitalWrite(5, HIGH); digitalWrite(4, HIGH); digitalWrite(3, HIGH); digitalWrite(2, HIGH); } void test(void){ //To test the 7 Segment display seven_seg_A(); delay(500); seven_seg_As(); delay(500); seven_seg_B(); delay(500); seven_seg_C(); delay(500); seven_seg_Cs();
40 | P a g e
delay(500); seven_seg_D(); delay(500); seven_seg_Ds(); delay(500); seven_seg_E(); delay(500); seven_seg_F(); delay(500); seven_seg_Fs(); delay(500); seven_seg_G(); delay(500); seven_seg_Gs(); delay(500); blank(); } /***************END OF 7 SEG FUNCTIONS****************/ /***************************************************************************** INTERRUPT SERVICE ROUTINE ****************************************************************************** / ISR(ADC_vect) {//when new ADC value ready PORTB &= B11101111;//set pin 12 low prevData = newData;//store previous value newData = ADCH;//get value from A0 if (prevData < 127 && newData >=127){//if increasing and crossing midpoint newSlope = newData - prevData;//calculate slope if (abs(newSlope-maxSlope)<slopeTol){//if slopes are == //record new data and reset time slope[index] = newSlope; timer[index] = time; time = 0; if (index == 0){//new max slope just reset PORTB |= B00010000;//set pin 12 high noMatch = 0; index++;//increment index } else if (abs(timer[0]-timer[index])<timerTol && abs(slope[0]newSlope)<slopeTol){//if timer duration and slopes match //sum timer values totalTimer = 0; for (byte i=0;i<index;i++){ totalTimer+=timer[i]; } period = totalTimer;//set period //reset new zero index values to compare with timer[0] = timer[index]; slope[0] = slope[index]; index = 1;//set index to 1 PORTB |= B00010000;//set pin 12 high noMatch = 0; } else{//crossing midpoint but not match index++;//increment index if (index > 9){ reset(); }
41 | P a g e
} } else if (newSlope>maxSlope){//if new slope is much larger than max slope maxSlope = newSlope; time = 0;//reset clock noMatch = 0; index = 0;//reset index } else{//slope not steep enough noMatch++;//increment no match counter if (noMatch>9){ reset(); } } } if (newData == 0 || newData == 1023){//if clipping PORTB |= B00100000;//set pin 13 high- turn on clipping indicator led clipping = 1;//currently clipping } time++;//increment timer at rate of 38.5kHz ampTimer++;//increment amplitude timer if (abs(127-ADCH)>maxAmp){ maxAmp = abs(127-ADCH); } if (ampTimer==1000){ ampTimer = 0; checkMaxAmp = maxAmp; maxAmp = 0; } } void reset(){//clea out some variables index = 0;//reset index noMatch = 0;//reset match couner maxSlope = 0;//reset slope } void checkClipping(){//manage clipping indicator LED if (clipping){//if currently clipping PORTB &= B11011111;//turn off clipping indicator led clipping = 0; } } /***************END OF INTERRUPT SERVICE ROUTINE**************/ /***************************************************************************** SETUP ****************************************************************************** / void setup(){ Serial.begin(9600); pinMode(13,OUTPUT);//led indicator pin
42 | P a g e
pinMode(12,OUTPUT);//output pin cli();//diable interrupts //set up continuous sampling of analog pin 0 at 38.5kHz //clear ADCSRA and ADCSRB registers ADCSRA = 0; ADCSRB = 0; ADMUX |= (1 << REFS0); //set reference voltage ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only ADCSRA |= (1 << 16mHz/32=500kHz ADCSRA |= (1 << ADCSRA |= (1 << ADCSRA |= (1 << ADCSRA |= (1 << ADPS2) | (1 << ADPS0); //set ADC clock with 32 prescalerADATE); //enabble auto trigger ADIE); //enable interrupts when measurement complete ADEN); //enable ADC ADSC); //start ADC measurements
sei();//enable interrupts pinMode(13,OUTPUT);//led indicator pin pinMode(12, OUTPUT); pinMode(11, OUTPUT); pinMode(10, OUTPUT); pinMode(9, OUTPUT); pinMode(8, OUTPUT); pinMode(7, OUTPUT); pinMode(6, OUTPUT); pinMode(5, OUTPUT); pinMode(4, OUTPUT); pinMode(3, OUTPUT); pinMode(2, OUTPUT); blank(); //test(); } /***************END OF SETUP**************/ /***************************************************************************** LOOP ****************************************************************************** / void loop(){ checkClipping(); if (checkMaxAmp>ampThreshold){ //calculate frequency timer rate/period Freq = 38462/float(period); //To print results on serial monitor //Serial.print(Freq); //Serial.println(" hz"); } //Detect and display the pitch pitch(); }
43 | P a g e
/***************END OF LOOP**************/
44 | P a g e