Craig Evans
/
AudioIn
Reads in audio signal on ADC, performs FFT and displays spectrum on Nokia 5110 LCD display.
main.cpp
- Committer:
- eencae
- Date:
- 2014-07-22
- Revision:
- 2:8da22b498051
- Parent:
- 1:7c6c1f98b8f5
- Child:
- 3:0df6485bc3ec
File content as of revision 2:8da22b498051:
#include "mbed.h" #include "N5110.h" extern "C" void fftR4(short *y, short *x, int N); float magnitude(short y1, short y2); void updateSamples(); void doFFT(); void printSpectrum(); void printSamples(); void ledBarGraph(); void rgbDance(); void lcdEqualiser(); int calcPeakFrequency(); AnalogIn audio(p17); // ADC pin must be biased at Vcc/2 using coupling capacitor and potential divider BusOut leds(LED1,LED2,LED3,LED4); LocalFileSystem local("local"); // Create the local filesystem under the name "local" Serial serial(USBTX,USBRX); // VCC,SCE,RST,D/C,MOSI,SCLK,LED N5110 lcd(p7,p8,p9,p10,p11,p13,p21); PwmOut red(p23); // RGB LEDs (same connections as app board) PwmOut green(p24); PwmOut blue(p25); #define BUF_LEN 1024 #define SAMP_FREQ 30000 short samples[BUF_LEN]; // store the values read from ADC short mx[BUF_LEN*2]; // input data 16 bit, 4 byte aligned x0r,x0i,x1r,x1i,.... short my[BUF_LEN*2]; // output data 16 bit,4 byte aligned y0r,y0i,y1r,y1i,.... float spectrum[BUF_LEN/2]; // frequency spectrum char buffer[14]; // screen buffer int main() { // initialise LCD and display welcomes message lcd.init(); lcd.printString("Audio FFT",14,0); lcd.printString("Analyser",20,1); lcd.printString("Craig A. Evans",0,4); serial.baud(115200); red.period(1e-4); // 10 kHz period for starters // setting one PWM channel sets them all as they share the same frequency leds = 15; wait(2.0); // short pause to allow coupling capacitor to charge leds = 0; lcd.clear(); while(1) { //red = 1.0,green=1.0,blue=1.0; updateSamples(); // read in new analog values doFFT(); // calc FFT ledBarGraph(); // display amplitude bar graph on LEDs from sample values lcdEqualiser(); // plot spectrum on LCD rgbDance(); //printSpectrum(); //printSamples(); //int tone = calcPeakFrequency(); // calculate peak frequcny and send over serial for debug //serial.printf("f = %u\n",tone); wait_ms(10); // update display 100 ms } } void ledBarGraph() { float rms = 0.0; // initialse array for (int i = 0; i < BUF_LEN; i++) { rms+= samples[i]*samples[i]; } // calc the sum of the squares rms/=BUF_LEN; // get the mean rms = sqrt(rms); // and root to get the RMS rms/= 16384.0; // scale according to 16-bit signed maximum value // check value and update LEDs to show amplitude if (rms > 0.8) { leds = 15; } else if (rms > 0.6) { leds = 7; } else if (rms > 0.4) { leds = 3; } else if (rms > 0.2) { leds = 1; } else { leds = 0; } //serial.printf("RMS = %f\n",rms); } float magnitude(short y1, short y2) { return sqrt(float(y1*y1+y2*y2)); // pythagoras } void updateSamples() { for (int i = 0; i < BUF_LEN; i++) { samples[i] = (short) (audio.read_u16() - 0x8000); // read unsigned 16-bit and convert to signed 16-bit (subtract 32768) wait_us(1e6/SAMP_FREQ); // wait for sampling frequency, should really implement with tickers } } void doFFT() { // clear buffers for (int i=0; i<2*BUF_LEN; i++) { my[i] = 0; mx[i] = 0; } for (int i=0; i<BUF_LEN; i++) { // load samples in array (skip imaginary input values) mx[i*2]=samples[i]; } fftR4(my, mx, BUF_LEN); // call FFT routine int j = 0; for (int i = 0; i < BUF_LEN; i+=2) { spectrum[j] = magnitude(my[i],my[i+1]); // get magnitude of FFT output to get spectrum data j++; } } void printSpectrum() { FILE *fp = fopen("/local/fft.csv","w"); //now write a CSV file to filesytem of frequency vs amplitude int j = 0; for (int i = 0; i < BUF_LEN; i+=2) { int frequency = int(SAMP_FREQ/BUF_LEN/2*i); // calculate value of frequency bin fprintf(fp, "%d,%f\n", frequency, spectrum[j]); j++; } fclose(fp); } void printSamples() { FILE *fp = fopen("/local/samples.csv","w"); //now write a CSV file to filesytem of frequency vs amplitude for (int i = 0; i < BUF_LEN; i++) { fprintf(fp, "%d\n", samples[i]); } fclose(fp); } int calcPeakFrequency() { float max = 0.0; int frequency = 0; int j = 0; for (int i=0; i<BUF_LEN; i+=2) { // loop through spectrum and look for maximum value if (spectrum[j] > max) { max = spectrum[j]; frequency = int(SAMP_FREQ/BUF_LEN/2*i); } j++; } //serial.printf("Max = %f\n",max); return frequency; } void lcdEqualiser() { // spectrum has BUF_LEN/2 values = 512 // screen has 84 pixel, giving 6 spectrum points per pixel float max = 0.0; // used for normalisation later float pixelValue[84]; for (int i=0; i<84; i++) { // loop through array pixelValue[i] = 0.0; for (int y=0; y<6; y++) { pixelValue[i] += spectrum[i*6+y]; // sum the 6 values in the spectrum } pixelValue[i]/=6; // calc. average for that pixel if (pixelValue[i] > max) // check for biggest value max = pixelValue[i]; } for (int i=0; i<84; i++) { // loop through array pixelValue[i]/=max; // normalise to 1.0 } lcd.clear(); for (int i=0; i<84; i++) { // loop through array for (int j=0; j<= 47 - int(pixelValue[i]*47.0); j++) { // loop through array lcd.setPixel(i,j); // draw bar graphs for spectrum bins } } lcd.refresh(); } void rgbDance() { // spectrum has BUF_LEN/2 values = 512 // split into 3 bins for R, G and B gives 170 bins per colour float ledColour[3]; float total = 0.0; for (int i=0; i<60; i++) { ledColour[0] += spectrum[i]; // sum the 6 values in the spectrum } total += ledColour[0]; for (int i=60; i<200; i++) { ledColour[1] += spectrum[i]; // sum the 6 values in the spectrum } total += ledColour[1]; for (int i=200; i<512; i++) { ledColour[2] += spectrum[i]; // sum the 6 values in the spectrum } total += ledColour[2]; float r = ledColour[0]/total; float g = ledColour[1]/total; float b = ledColour[2]/total; serial.printf("RGB = %f , %f , %f (%f)\n",r,g,b,r+g+b); r = 1.0 - r; // common anode, smaller value is brighter g = 1.0 - g; // bigger value is duller b = 1.0 - b; if (r > 1.0) r = 1.0; else if (r < 0.0) r = 0.0; if (g > 1.0) g = 1.0; else if (g < 0.0) g = 0.0; if (b > 1.0) b = 1.0; else if (b < 0.0) b = 0.0; red.write(r); // set duty cycles green.write(g); blue.write(b); }