ECE 4180 Tuner Spring 2019

Team Members

Trent Hobbs
Adar Leibovitch
Collin Rusch
Gabriel Trevino Santos

Project Overview

The goal of this project is to build an instrument tuner which will read in a note being played and return the frequency. The frequency of the note is calculated using an FFT algorithm sampling at 4 kHz. The sampled note is then displayed on the LCD screen along with a graph to show the user how close to the desired frequency they are. The current note being tuned can also be played through a speaker so the user can tune their instrument by ear. Pushbuttons add functionality to select what note the user is trying to tune. The current code will correctly calculate frequencies up to 2 kHz and play any notes from A0 to B8.

Parts List

  1. mbed LPC1768 https://os.mbed.com/platforms/mbed-LPC1768/
  2. Electret Microphone Amplifier - MAX4466 with Adjustable Gain https://os.mbed.com/components/Electret-Microphone-MAX4466-Amplifier/
  3. uLCD-144-G2 128 by 128 Smart Color LCD https://os.mbed.com/users/4180_1/notebook/ulcd-144-g2-128-by-128-color-lcd/
  4. TPA2005D1 Class D Audio Amp https://os.mbed.com/users/4180_1/notebook/tpa2005d1-class-d-audio-amp/
  5. Speaker - PCB Mount https://www.sparkfun.com/products/11089
  6. x5 Pushbuttons https://os.mbed.com/users/4180_1/notebook/pushbuttons/

Schematic

/media/uploads/gabots/schematic.png

Libraries Used

mbed - https://os.mbed.com/users/mbed_official/code/mbed/
MAX4466 - https://os.mbed.com/users/mgolino/code/MAX4466/
FFT - https://os.mbed.com/users/zchen78/code/FFT/
mbed-rtos - https://os.mbed.com/teams/ST/code/mbed-rtos/
4DGL-uLCD-SE - https://os.mbed.com/users/4180_1/code/4DGL-uLCD-SE/
Pin Detect - https://os.mbed.com/users/AjK/code/PinDetect/

Source Code

main.cpp

#include "mbed.h"
#include "MAX4466.h"
#include "FFT.h"
#include "rtos.h"
#include "uLCD_4DGL.h"
#include "PinDetect.h"
#include <string>
#include <math.h>

PinDetect pb1(p6);
PinDetect pb2(p7);
PinDetect pb3(p8);
PinDetect pb4(p9);
DigitalIn pb5 (p10);
MAX4466 mic(p15);
PwmOut speaker(p21);
uLCD_4DGL uLCD(p28,p27,p30);
Timer tim;

#define MAX_NOTE 11
#define MAX_OCT 8
std::string notes[] = {"C","C#/Db","D","D#/Eb","E","F","F#/Gb","G","G#/Ab","A","A#/Bb","B"};
float notefreqs[] = {16.35,17.32,18.35,19.45,20.60,21.93,23.12,24.50,25.96,27.50,29.14,30.87};

volatile float readfreq = 0.00;
volatile int octave = 0;
volatile int indx = 0;

void pb1_note_down(void) {
    if(!pb1) {
        indx -= 1;
        if (indx < 0) {
            indx = MAX_NOTE; 
        }
    }
}

void pb2_note_up (void) {
    if(!pb2) {
        indx += 1;
        if (indx > MAX_NOTE) {
            indx = 0; 
        }
    }
}

void pb3_oct_down (void) {
   if(!pb3) {
        octave -= 1;
        if (octave < 0) {
            octave = MAX_OCT; 
        }
    }
}

void pb4_oct_up (void) {
   if(!pb4) {
        octave += 1;
        if (octave > MAX_OCT) {
            octave = 0; 
        }
    }
}
//Plays speaker at desired frequency selected by user
void playspeaker(void const *arguments) {
   while (1) {
        speaker.period(1.0/(notefreqs[indx] * pow(2.0f,octave)));
        speaker = 0.0;
        while(!pb5) {
            speaker = 0.5;
        }
        speaker = 0.0;
        Thread::wait(100);
    }
}
//Print frequencies of notes, detected freq, and circle display graphic to LCD
void ulcd(void const *arguments) {
    int cx;
    int old_i = 0;
    int old_oct= 0;
    int i;
    int oct;
    while(1) {
        i = indx;
        oct = octave;
        if (old_oct != oct) {
            old_oct = oct;
            uLCD.locate(1,7);
            uLCD.printf("           ");
        }
        if (old_i != i) {
            old_i = i;
            uLCD.locate(1,7);
            uLCD.printf("           ");
            uLCD.locate(1,3);
            uLCD.printf("           ");
        }
        uLCD.locate(1,3);
        uLCD.printf("%s%D", notes[i], oct);
        uLCD.locate(1,7);
        uLCD.printf("%.2f Hz.", notefreqs[i] * pow(2.0f,oct));
        uLCD.locate(1,14);
        uLCD.printf("%.2f Hz.", readfreq);
        uLCD.filled_circle(108, cx, 5, BLACK);
        if (readfreq <= (notefreqs[i] * pow(2.0f,oct))+ 5 && readfreq >= (notefreqs[i] * pow(2.0f,oct)) - 5) {
            cx = 64;
            uLCD.line(88, 64, 128, 64, GREEN);
            uLCD.filled_circle(108, cx, 5, GREEN);
        } else {
            cx = 64 + (notefreqs[i] * pow(2.0f,oct)) - readfreq;
            if (cx < 0) {
                cx = 0; 
            } else if (cx > 128) {
                cx = 128;    
            }
            uLCD.line(88, 64, 128, 64, RED);
            uLCD.filled_circle(108, cx, 5, RED);
        }
        Thread::wait(10);
    }
}

int main() {
    //set up pindetect
    pb1.mode(PullUp);
    pb2.mode(PullUp);
    pb3.mode(PullUp);
    pb4.mode(PullUp);
    pb5.mode(PullUp);
    wait(0.01);
    pb1.attach_deasserted(&pb1_note_down);
    pb2.attach_deasserted(&pb2_note_up);
    pb3.attach_deasserted(&pb3_oct_down);
    pb4.attach_deasserted(&pb4_oct_up);
    pb1.setSampleFrequency();
    pb2.setSampleFrequency();
    pb3.setSampleFrequency();
    pb4.setSampleFrequency();
    //set intial lcd values
    uLCD.background_color(BLACK);
    uLCD.baudrate(3000000);
    uLCD.line(88, 0, 88, 128, WHITE);
    uLCD.color(WHITE);
    uLCD.locate(1,1);
    uLCD.printf("Note:");
    uLCD.locate(1,5);
    uLCD.printf("Note Freq:");
    uLCD.locate(1,12);
    uLCD.printf("Read Freq:");
    //launch threads
    Thread ulcd_thread(&ulcd);
    Thread speaker_thread(&playspeaker);
    //set up main thread
    int samples = 1024;
    float arr [samples+1];
    arr[0] = 0;
    float max = 0;
    float loc = 0;
    float freq;
    osThreadSetPriority(osThreadGetId(), osPriorityHigh);
    //Loop and constantly be finding frequency of signal
    while (1) { 
        tim.reset();
        tim.start();
        for (int i = 1; i<=samples; i++){
            arr[i] = mic.instantlevel(); //Sample microphone at ~4 Khz
            wait(.00025);
            }
        tim.stop();
        freq = samples/tim.read(); 
        //Turn sampled array into its fourier transform
        vRealFFT(arr,samples); 
        
        //Loop through and find most apparent frequency of sampled signal 
        for(int i = 2; i<=samples; i++){ 
            arr[i] *= arr[i];
            if(max<arr[i]){
                loc = freq/samples * i/2; //determine frequency by using sample rate,index in array
                max = arr[i];
                }
            }
        readfreq = loc; 
        max=0;
        wait(0.25);
        Thread::wait(100);
    }  
}

Import Program

Import program4180_Tuner

1.0

Photos

/media/uploads/gabots/img_7163.jpg /media/uploads/gabots/img_7164.jpg /media/uploads/gabots/img_7165.jpg

Videos


Please log in to post comments.