Finally managed to have my Arduino Uno ‘spectrualize’ audio on a 1.3″ monochrome 128×64 oled screen. These small oled screens are amazingly fast!
Sound quality of the video is limited because the music (“Golden Brown” by The Stranglers) was picked up from a small laptop speaker.
The upper part of the screen shows a peak level indicator.
The sketch uses a FastĀ Fourier Transformation library that I found on Internet. It translates the signal from the time domain to the frequency domain. [Some comments are in Dutch]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
/* Arduino Spectrum Analyzer */ #include <fix_fft.h> //library to perfom the Fast Fourier Transform //#include <SPI.h> //SPI library #include <Wire.h> //I2C library for OLED #include <Adafruit_GFX.h> //graphics library for OLED #include <Adafruit_SH1106.h> //OLED driver #define OLED_RESET 4 //OLED reset, not hooked up but required by library Adafruit_SH1106 display(OLED_RESET); //declare instance of OLED library called display char im[64], data[64]; //variables for the FFT char x = 0, ylim = 60; //variables for drawing the graphics int i = 0, val; //counters int dropMax = 0; int curMax; void setup() { // Serial.begin(9600); //serial comms for debuging display.begin(SH1106_SWITCHCAPVCC,0x3C); //begin OLED @ hex addy 0x3C display.setTextSize(1); //set OLED text size to 1 (1-6) display.setTextColor(WHITE); //set text color to white display.clearDisplay(); //clear display //analogReference(DEFAULT); // Use default aref voltage (5V op UNO). analogReference(EXTERNAL); // voeding naar microphone breakout ook met AREF verbinden }; void loop() { int min=1024, max=0; //set minumum & maximum ADC values for (i = 0; i < 64; i++) { //take 64 samples val = analogRead(A0); //get audio from Analog 0 data[i] = val / 4 - 128; //each element of array is val/4-128 im[i] = 0; if(val>max) max=val; //capture maximum level if(val<min) min=val; //capture minimum level }; // Serial.println(max-min); // blijkt tussen 0 en 512 te liggen // data bevat reeel en im imaginair deel van de meting; im hier op 0 gesteld // 3-de parameter m, dan zijn er 2^m 'bins'; als m=7 dan dus 128; alleen de eerste helft (64) bevatten de bruikbare waarden fix_fft(data, im, 6, 0); //perform the FFT on data display.clearDisplay(); //clear display // de eerste 32 array elementen bevatten na fix_fft de reeele waarden for (i = 1; i < 32; i++) { // In the current design, 60Hz and noise int dat = sqrt(data[i] * data[i] + im[i] * im[i]);//filter out noise and hum // vermenigvuldigingsfactor zorgt dat het er met het microfoonbordje dan beter uitziet (loopt af van 2 tot 1) dat = (2-dat/60)*dat; // de +5 zorgt dat de achtergrondruis over de volle breedte onzichtbaar wordt display.drawLine(0,63,128,63,WHITE); // baseline display.fillRect(i*4 + x, ylim-dat+5, 2, 63-ylim+dat, WHITE); // draw bar graphics for freqs above 500Hz to buffer }; display.setCursor(0,0); //set cursor to top of screen // gewogen gemiddelde tussen nieuwe en oude waarde; deelfactor 4 omdat max-min in range 0-512 zit; -12 is compensatie curMax=(dropMax+2*min((max-min)/4-12,128))/3; display.fillRect(0,0,curMax,3,WHITE); if (dropMax>curMax+4) { dropMax=dropMax-3; display.fillRect(dropMax-4,0,3,3,WHITE); } else { dropMax=curMax; } display.display(); //show the buffer }; |