// Spectrum Analyzer using a Teensy 3.2 & the Adafruit 1.8" TFT module w/ ST7735S chip
// Test microphone is connected to A3
// Adding some FastLED code to test interaction
//*********************************************************************************** INIT
//
#define TFT_SCLK 14 // SCLK can also use pin 13
#define TFT_MOSI 7 // MOSI can also use pin 11
#define TFT_CS 10 // CS & DC can use pins 2, 6, 9, 10, 15, 20, 21, 22, 23
#define TFT_DC 20 // but certain pairs must NOT be used: 2+10, 6+9, 20+23, 21+22
#define TFT_RST 8 // RST can use any pin
#define SD_CS 4 // CS for SD card, can use any pin
#define MIC_GAIN 2 // multiplier for the specific mic
#include <Adafruit_GFX.h> // Core graphics library
#include <ST7735_t3.h> // Hardware-specific library for the ST7735 LCD controller
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SerialFlash.h>
#include "FastLED.h"
// create the LCD object
ST7735_t3 tft = ST7735_t3(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
// Assign human-readable names to some common 16-bit color values:
#define WHITE 0xFFFF
#define BLACK 0x0000
#define GREEN 0x07E0
//Set-up the audio library functions
AudioInputAnalog adc1(A3); //default for adc1 is A2
AudioAnalyzeFFT1024 fft1024_1;
AudioConnection patchCord1(adc1, fft1024_1);
// An array to hold the 16 frequency bands
float level[16];
// How many leds are in the strip?
#define NUM_LEDS 45
// Data pin that led data will be written out over
#define DATA_PIN 2
// Clock pin only needed for SPI based chipsets when not using hardware SPI
//#define CLOCK_PIN 8
// This is an array of leds. One item for each led in your strip.
CRGB leds[NUM_LEDS];
#define LEDBRIGHTNESS 64 // display brightness
byte colorMap = 160; // the offset position for the color map
byte colorScale = 2; // the variation in the color map - 0=one color, 4=full spectrum
//*********************************************************************************** SETUP
void setup() {
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab
tft.fillScreen(ST7735_BLACK);
tft.setRotation(1); // 1=270
tft.setTextColor(WHITE);
tft.setTextSize(1);
tft.print("TFT Spectrum Analyzer ");
// Audio connections require memory to work.
AudioMemory(12);
// Configure the window algorithm to use
fft1024_1.windowFunction(AudioWindowHanning1024);
}
//*********************************************************************************** LOOP
void loop() {
byte pColor; // a color map position
byte Channel; // specific frequency channel
byte Red1; // temporary Red value
byte Green1; // temporary Green value
byte Blue1; // temporary Blue value
//****************************************************************************** INPUT
if (fft1024_1.available()) {
// each time new FFT data is available, bin it into 16 channels
// Note- response doesn't seem flat so each is normalized <experimenting!
// Note- these calculations go very fast!!
level[0] = fft1024_1.read(0) * 1.21 * MIC_GAIN;
level[1] = fft1024_1.read(1) * 1.18 * MIC_GAIN;
level[2] = fft1024_1.read(2, 3) * 1.15 * MIC_GAIN;
level[3] = fft1024_1.read(4, 6) * 1.12 * MIC_GAIN;
level[4] = fft1024_1.read(7, 10) * 1.09 * MIC_GAIN;
level[5] = fft1024_1.read(11, 15) * 1.06 * MIC_GAIN;
level[6] = fft1024_1.read(16, 22) * 1.03 * MIC_GAIN;
level[7] = fft1024_1.read(23, 32) * 1.00 * MIC_GAIN;
level[8] = fft1024_1.read(33, 46) * 0.96 * MIC_GAIN;
level[9] = fft1024_1.read(47, 66) * 0.93 * MIC_GAIN;
level[10] = fft1024_1.read(67, 93) * 0.90 * MIC_GAIN;
level[11] = fft1024_1.read(94, 131) * 0.87 * MIC_GAIN;
level[12] = fft1024_1.read(132, 184) * 0.84 * MIC_GAIN;
level[13] = fft1024_1.read(185, 257) * 0.81 * MIC_GAIN;
level[14] = fft1024_1.read(258, 359) * 0.78 * MIC_GAIN;
level[15] = fft1024_1.read(360, 511) * 0.75 * MIC_GAIN;
//****************************************************************************** LED OUTPUT
for (int i = 0; i < NUM_LEDS; i++){ // cycle through all the LEDs
pColor = i * colorScale * 4 + colorMap; // this results in a color map position
Channel = i/3 ; // there are 16 frequency bands - not perfect - needs better math
Red1 = (WheelR(pColor) * level[Channel]) ; // brightness proportionally to the loudness
Green1 = (WheelG(pColor) * level[Channel]) ; // of the individual channel
Blue1 = (WheelB(pColor) * level[Channel]) ;
leds[i].setRGB( Red1, Green1, Blue1);
}
FastLED.show(); //show the new strip colors - FYI - takes rough 4.66 milliseconds on the Uno
//****************************************************************************** LCD OUTPUT
for (byte i = 0; i < 16; i++){ // cycle through the 16 channels
// takes about 1.66msec on a Teensy 3.2 to draw two fillRect 9-pixels wide - one
// black to erase any old information and one for the new data
// takes about 190usec per line on a Teensy 3.2 to draw the two drawFastVLines
// needed to erase the old information and draw a new line
int line1 = level[i] * 100;
if (line1 > 100){
line1 = 100;
}
tft.fillRect( i*10, 10, 10, 128-line1, BLACK); //erase old information
tft.drawRect( i*10, 128-line1, 10, line1, WHITE); //paint new bar
for (byte j = 1; j < 9; j++){ // draw muliple lines to create the bar
//tft.drawFastVLine( i*10 + j, 10, 128-line1, BLACK);
tft.drawFastVLine( i*10 + j, 128-line1, line1, Wheel565(i * 15 + 60));
}
}
}
}
//*******************************************************************************************/
// Wheel565: standard color look-up routine - Input a value 0 to 255 to get an RGB color value.
// NOTE: The colors are a transition Green (0) to Red (85) to Blue (170) back to Green
// RGB565 format!!
// R4-R3-R2-R1-R0-G5-G4-G3-G2-G1-G0-B4-B3-B2-B1-B0 Bits
// |-----------|-----------|-----------|-----------| Bytes
//*******************************************************************************************/
long Wheel565(byte WheelPos) {
if(WheelPos < 85) {
return ((((WheelPos * 3) / 8) * 0x0800) + ((63 - ((WheelPos * 3) / 4)) * 0x0020));
} else if(WheelPos < 170) {
WheelPos -= 85;
return (((31 - ((WheelPos * 3) / 8)) * 0x0800) + (0 * 0x0020) + (WheelPos * 3 / 8));
} else {
WheelPos -= 170;
return ((((WheelPos * 3) / 4) * 0x0020) + (31 - ((WheelPos * 3) / 8)));
}
}
//******************************************************************************************/
// WheelR: Neopixel RGB color wheel - returns the Red byte (not the entire RGB word)
byte WheelR(byte WheelPos) {
if(WheelPos < 85) {
return WheelPos * 3;
}
else if(WheelPos < 170) {
WheelPos -= 85;
return 255 - WheelPos * 3;
} else {
return 0;
}
}
//*******************************************************************************************/
// WheelG: same as above but just returns the Green byte
byte WheelG(byte WheelPos) {
if(WheelPos < 85) {
return 255 - WheelPos * 3;
} else if(WheelPos < 170) {
return 0;
} else {
WheelPos -= 170;
return WheelPos * 3;
}
}
//*******************************************************************************************/
// WheelB: same as above but just returns the Blue byte
byte WheelB(byte WheelPos) {
if(WheelPos < 85) {
return 0;
} else if(WheelPos < 170) {
WheelPos -= 85;
return WheelPos * 3;
} else {
WheelPos -= 170;
return 255 - WheelPos * 3;
}
}