# Help with a 4 band parametric eq

#### jvphotog

##### Active member
Can anyone please help me make an adjustable 4 band parametric eq. Ive looked through all the examples in the Teensy library, the open audio library, as well as other people's projects, and I just can't make anything work. Im very new to programming. I can make a high or low pass filter work using a biquad filter, but nothing with adjustable frequency, gain, and Q. Any help is appreciated!

Take a look at doing it with FIR filtering.
The size of the FIR relates to the relative frequency width of the narrowest band in the equalizer.
Traditional hardware and some DSP implementations used biquad or similar IIR filtering. The Teensy handles the load of the FIR approach with ease, and to me seems a better choice.

The link above shows both I16 and F32 equalizers and I suspect thaey will be fine with T4.1 (they were tested on T3.6).

Bob

Yes using FIR is good idea, but if you want to go IIR way a simple biquad structure implements all kinds of filters (LP, HP, BP, BR, halving, etc), you can use calculator here to find out coefficients needed

And C++ source code, including controls over freq, gain and Q is here:

Last edited:
Thanks for replying guys. Haha Ive had some time to work on this! I found a IIR filter in a project from 6 years ago called TeensyDist, made by jcugnoni, works great for my needs. https://github.com/jcugnoni/TeensyDist

This is has been a major learning experience. I knew nothing about any of this. But I now have a tft screen that you can navigate via an encoder and update values in real time and save to eeprom and a live VU meter. I have two channels right now, each with their own HPF (doubled up to increase the slope), 3 peaking filters, MarkzP's Dynamics processor, and Pio's stereo plate reverb shared. Everything is in F32, except the reverb. I couldn't get that to work in F32 land. So I have the reverb send converting to 16 and it goes through the reverb and then back out to get converted into the main mixer.

Right now im working on the mic and guitar preamp, voltage protection and power. One thing I could never fix is screen flicker. Idk what Im doing wrong but man this screen is not stable! About a month ago I switched from the ili9341_t3 library to the ili9341_t3n library but no go, but like I said. I don't know what Im doing!

Typically flickering is because you first erase content and then you draw. Between erase and new draw there is nothing on screen and that causes flicker. To avoid that you should "never paint the same pixel twice". Don't erase the content of screen then draw, but draw the new content over existing (old) content by setting both foreground and background pixels in one run and minimize screen updates to only areas that actually changed.

Typically flickering is because you first erase content and then you draw. Between erase and new draw there is nothing on screen and that causes flicker. To avoid that you should "never paint the same pixel twice". Don't erase the content of screen then draw, but draw the new content over existing (old) content by setting both foreground and background pixels in one run and minimize screen updates to only areas that actually changed.
Thank you tomas. I think I understand, but I cant get it to work. It seems that any time a "fillrect" is called anywhere on the screen, it causes the screen to flicker a bit, no matter where the rect is filling? . I commented out the fillrect and added the background color to my main menu but every encoder turn still flickers. It's not awful, just a bit annoying I couldn't get it to stop.
Code:
``````void displayMenu(Menu* menu, int selectedIndex) {
tft.setFont(Arial_13);
int itemsPerPage = maxDisplayItems;
int currentPage = selectedIndex / itemsPerPage;
static int previousPage = -1;

// Determine if we need to switch pages
if (currentPage != previousPage) {
// Clear the screen for the new page
tft.fillRect(0, 32, 200, tft.height() -32, ILI9341_BLACK);  //around 200
previousPage = currentPage;
}

int startItem = currentPage * itemsPerPage;
int endItem = min(startItem + itemsPerPage, menu->itemCount);

// Define and set the clipping rectangle
//tft.setClipRect(7, 0, tft.width(), tft.height());

for (int i = startItem; i < endItem; ++i) {
int drawIndex = i - startItem;
//int itemY = 35 + 21 * drawIndex; // Y position of the menu item
tft.setCursor(10, 35 + 21 * drawIndex);
tft.setTextColor(i == selectedIndex ? ILI9341_BLUE : ILI9341_WHITE);

{
for (int i = 0; i < 4; ++i) {
int valueY = 35 + 21 * i;  // Y position of each value
// Clear the area before redrawing the value?
//tft.fillRect(160, valueY, 50, 21, ILI9341_BLACK);
tft.setCursor(160, valueY);
tft.setTextColor(i == selectedItemIndex && editMode ? ILI9341_BLUE : ILI9341_WHITE, ILI9341_BLACK);
// Display the values
switch (i) {
case 0: tft.print(micVolume * 100, 0); break;
case 1: tft.print(guitarVolume * 100, 0); break;
case 2: tft.print(micReverb * 100, 0); break;
case 3: tft.print(guitarReverb * 100, 0); break;
}
}

It's hard to say without seeing the flicker on the video, but sometimes display may be having problems with keeping up with reliable transfer at high SPI clocks or the wires that you are using to connect to display are too long to transmit high frequency SPI clock. You can try lowering SPI clock or using shorter wires.

It's hard to say without seeing the flicker on the video, but sometimes display may be having problems with keeping up with reliable transfer at high SPI clocks or the wires that you are using to connect to display are too long to transmit high frequency SPI clock. You can try lowering SPI clock or using shorter wires.
Thank you, I'll try shorter wires and monkeying around with the connections. The bread board connections aren't the best.
Im a little confused about the correct connections listed on the prjc.com touch display page. I have my Teensy 4.1 plugged directly onto the audio board, and im using pins 9,10,11,12, and 13 for the TFT display. Is that fine, or should I be using alternate pins?
*Im also powering the display from the Teensy.

Edit: I moved some wires around and that actually seemed to make things better, so thank you for that!

The VU meter bar is still a little glitchy. Ive tried refresh rates from 33 milliseconds to 333. I get these weird diagonal scan lines in it. The slower I set the updates, the lower the peak read will be - which isnt helpful!

I think Ive tried drawing fast vertical lines as well as the rect.
Code:
``````void updateVUMeter(int channel, float level) {
int barWidth = VU_METER_WIDTH - 2; // Adjusted to ensure border visibility
int x = (channel == 0) ? VU_METER_X + 1 : VU_METER_X + VU_METER_WIDTH + VU_METER_GAP + 1; // Adjusted for border
int y = 36; // Adjusted for border
int height = VU_METER_HEIGHT - 2; // Adjusted for border

// Calculate the filled height
int filledHeight = (int)(level * height);

// Clear the previous state - fill only the non-border area
tft.fillRect(x, y, barWidth, height, ILI9341_BLACK);

// Draw the filled part using fillRect
int filledY = y + height - filledHeight;
uint16_t color = ILI9341_GREEN;
if (level > 0.7) color = ILI9341_YELLOW;
if (level > 0.85) color = ILI9341_RED;

tft.fillRect(x, filledY, barWidth, filledHeight, color);

if (channel == 0) {
if (level > peakLevel1) {
peakLevel1 = level;
lastPeakUpdateTime1 = millis();
}
if (millis() - lastPeakUpdateTime1 > peakHoldTime) peakLevel1 = 0;

// Calculate Y position for peak level and draw peak bar, added -1 to move it up
int peakHeight = peakLevel1 * height;
int peakY = y + height - peakHeight;
tft.fillRect(x, peakY - 1, barWidth, 2, ILI9341_WHITE);
} else if (channel == 1) {
if (level > peakLevel2) {
peakLevel2 = level;
lastPeakUpdateTime2 = millis();
}
if (millis() - lastPeakUpdateTime2 > peakHoldTime) peakLevel2 = 0;

// Calculate Y position for peak level and draw peak bar, added -1 to move it up
int peakHeight = peakLevel2 * height;
int peakY = y + height - peakHeight;
tft.fillRect(x, peakY - 1, barWidth, 2, ILI9341_WHITE);
}
}``````

Last edited:
Been trying to play around with DMA and frame buffering but Im not sure Im doing it correctly. This will make the VU meter display much nicer but my menu system will freak out with a lot of lines through it if I scroll using the encoder. How do people make their UI's work with multiple menus and live meters/spectrum analyzers, etc? Is there a standard practice on how to display both static and dynamic screen items or a way to use DMA on only a section? Thank you for the help, I appreciate it!

Code:
``````tft.useFrameBuffer(true);

if (!tft.asyncUpdateActive()) {
}``````

Here's the method that I use (not DMA specific): in general, keep track of the values from both the current update & the previous update. When it's time for an update, first redraw the "previous_value" using the background color, then draw the "current_value" using the desired color, then store the "current_value" into the "previous_value" for use in the next update. This approach results in an update to a much smaller area, which is thus less likely to flicker.

Mark J Culross
KD5RXT

Here's the method that I use (not DMA specific): in general, keep track of the values from both the current update & the previous update. When it's time for an update, first redraw the "previous_value" using the background color, then draw the "current_value" using the desired color, then store the "current_value" into the "previous_value" for use in the next update. This approach results in an update to a much smaller area, which is thus less likely to flicker.

Mark J Culross
KD5RXT
Thank you, that makes sense. Overwriting first with the background color would definitely be less redrawn pixels! What do you do for dynamic visuals that constantly move?
Thanks!

I did something similar. I have a mic processor that has an eq for adujusting sound levels and a spectrum display to see the processed mic results.

It's been several years since I looked at this code but maybe it will give you a head start

Code:
``````/*

This program is a microphone montitor for a DSLR, it will sit between a mic and DSLR input
so the user can control the mic levels and see the levels.

compile 96 mhz, debug or fastest

rev   data          Description               author
1.0   4/8/2018      initial creation          Kasprzak
3.0   5/12/2018     added 30 band FFT         Kasprzak
4.0   5/20/2018     added cute splash screen  Kasprzak
5.0   6/2/2018      added mic level reminder  Kasprzak

connection map

Teensy 3.2     Display

0              Touch pin
1              Touch pin
2              Touch pin
3              Touch pin
4              Touch pin
5              LED pin (PWM to control brightness)
6
7              MOSI
8
9
10
11
12             MISO
13
14             SCK
A1
A2
A3
A4
A5
A6             Chip Select
A7             DC
A8
A9

*/

// #define Debug

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <ILI9341_t3.h>
#include <Colors.h>
#include "UTouch.h"
#include <font_ArialBold.h>   // custom fonts that ships with ILI9341_t3.h
#include <font_ArialBlack.h>  // custom fonts that ships with ILI9341_t3.h
#include <font_Arial.h>       // custom fonts that ships with ILI9341_t3.h
#include <EEPROM.h>
#include <ILI9341_t3_Controls.h>  // custom control define file
#include <FlickerFreePrint.h>     // library to draw w/o flicker
// some audio defines and pin defines
#define FILTER_Q      .5
#define MIC_BAR_GAIN  100.0
#define LED_PIN       5
#define DC_PIN        21
#define BAT_PIN       16
#define CS_PIN        20
#define PIN_RST       255  // 255 = unused, connect to 3.3V
#define MO_PIN        7
#define Display_SCLK  14
#define MI_PIN        12
#define WIDTH         7
#define OFFSET        25
#define HIGHPASS      60
#define LOWPASS       8000

#define BAND1 40
#define BAND2 100
#define BAND3 160
#define BAND4 220
#define BAND5 280

// variables for the locations of the keypad buttons
#define BUTTON_X 100
#define BUTTON_Y 80
#define BUTTON_W 60
#define BUTTON_H 30
#define BUTTON_SPACING_X 10
#define BUTTON_SPACING_Y 10
#define BUTTON_TEXTSIZE 2
#define BUTTON_CORNER 4
#define SLIDER_COLOR C_LTBLUE
#define HANDLE_SIZE 20

#define BAR_THICKNESS 8

#define FONT_BANNER Arial_16 //ArialBlack_40
#define FONT_LBUTTON Arial_16
#define FONT_TEXT Arial_14
#define FONT_SMALLTEXT Arial_10
#define FONT_BUTTONTEXT Arial_14 //Arial_12_Bold

// GUItool: automatically generated code from
// https://www.pjrc.com/teensy/gui/index.html

AudioInputI2S            i2s1;
AudioMixer4              mixer1;
AudioAnalyzeFFT1024      fft1024_1;
AudioOutputI2S           i2s2;
AudioConnection          patchCord1(i2s1, 0, mixer1, 0);
AudioConnection          patchCord2(i2s1, 1, mixer1, 1);
AudioControlSGTL5000     sgtl5000_1;

// create the display object
// note I've modifed the library to accept the screen size, that way I can drive different size displays
// from the same lib--i just pass in the size

ILI9341_t3 Display = ILI9341_t3(CS_PIN, DC_PIN, 240, 320, PIN_RST, MO_PIN, Display_SCLK, MI_PIN);

// some more varibales
int left,   top, wide, high;
unsigned long curtime, pretime;

int TempNum;
int HighPassF = 0;
int LowPassF = 0;
int MicGain = 5;
float BatVolts = 0.0;
byte ShowHistory = 0;
byte Background = 0;
byte Brightness = 255;
byte HighPass = 0;
byte LowPass = 0;
uint16_t BackColor = C_BLACK; // i have a custom "Colors.h" that lists all the colors i use
uint16_t ForeColor = C_WHITE;
unsigned long Showit;
char str[20];
float Band1 = 0.0;
float Band2 = 0.0;
float Band3 = 0.0;
float Band4 = 0.0;
float Band5 = 0.0;

char FilterText[2][5] = {"Off", "On" };
char HistoryText[2][5] = {"No", "Yes" };

char KeyPadBtnText[12][5] = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "Done", "0", "Clr" };
uint16_t KeyPadBtnColor[12] = {SLIDER_COLOR, SLIDER_COLOR, SLIDER_COLOR,
SLIDER_COLOR, SLIDER_COLOR, SLIDER_COLOR,
SLIDER_COLOR, SLIDER_COLOR, SLIDER_COLOR,
C_GREEN, SLIDER_COLOR, C_RED
};
byte Qty, j, i, row, col, b;
int x, y, h, w, loval, hival, Count;
int line1;

volatile float MixerGain;
// An array to hold the 32 frequency bands
volatile float level[32];
volatile float Max[32];
float BatLevel;

// create the touch object
UTouch  Touch( 0, 1, 2, 3, 4);

// create the slider objects
SliderV sBand1(&Display);
SliderV sBand2(&Display);
SliderV sBand3(&Display);
SliderV sBand4(&Display);
SliderV sBand5(&Display);
SliderV sMicGain(&Display);

SliderH shMicGain(&Display);

Button SetupBtn(&Display);
Button MicGainBtn(&Display);
Button HighPassFBtn(&Display);
Button LowPassFBtn(&Display);
Button DoneBtn(&Display);
Button OKBtn(&Display);
Button EQBtn(&Display);

CheckBox cbHistory(&Display);
CheckBox cbHighPass(&Display);
CheckBox cbLowPass(&Display);
CheckBox cbBackground(&Display);
FlickerFreePrint<ILI9341_t3> MicGainText(&Display, C_WHITE, C_BLACK);
void setup() {

// Serial.begin(9600);

AudioMemory(60);
pinMode(BAT_PIN, INPUT);
Display.begin();
Display.fillScreen(C_BLACK);
Display.setRotation(3);

// I save basic parameters, like background color and filter values to the EEPROM
GetParameters();

if (Background == 0) {
BackColor = C_BLACK;
ForeColor = C_WHITE;
}
else {
BackColor = C_WHITE;
ForeColor = C_BLACK;
}

// show a cute little splash screen
// SplashScreen();

// set the display background brightness
analogWrite(LED_PIN, Brightness);
Display.fillScreen(BackColor);

// start setting the audio board parameters
// i really have no idea if these are the optimal settings
// after days of trial and error, they seem to be the best
sgtl5000_1.enable();
sgtl5000_1.inputSelect(AUDIO_INPUT_LINEIN);
sgtl5000_1.volume(0.8);
sgtl5000_1.lineInLevel(MicGain);
sgtl5000_1.lineOutLevel(31);

sgtl5000_1.audioPreProcessorEnable();
sgtl5000_1.audioPostProcessorEnable();
sgtl5000_1.enhanceBassEnable();
sgtl5000_1.eqSelect(3);

// setup the FFT
fft1024_1.windowFunction(AudioWindowHanning1024);

// initilize the touch screen
Touch.InitTouch();
Touch.setPrecision(PREC_EXTREME);

// create all the buttons
SetupBtn.init(289, 18, 60, 29, C_WHITE, C_DKGREY, C_LTGREY, C_BLACK, "Setup", -10, -7, FONT_BUTTONTEXT );
OKBtn.init(   280, 18, 80, 29, C_WHITE, C_DKGREY, C_LTGREY, C_BLACK, "OK", -10, -7, FONT_BUTTONTEXT );
DoneBtn.init( 270, 18, 80, 29, C_WHITE, C_DKGREY, C_LTGREY, C_BLACK, "Done", -10, -7, FONT_BUTTONTEXT );
MicGainBtn.init(  205, 100, 50, 25, C_DKGREY, C_GREY, C_BLACK, C_BLACK, "Set", -10, -7, FONT_BUTTONTEXT );
HighPassFBtn.init(260, 130, 100, 25, C_DKGREY, C_GREY, C_BLACK, C_BLACK, "Set", -20, -7, FONT_BUTTONTEXT );
LowPassFBtn.init( 260, 160, 100, 25, C_DKGREY, C_GREY, C_BLACK, C_BLACK, "Set", -20, -7, FONT_BUTTONTEXT );
EQBtn.init(       205, 220, 50, 25, C_DKGREY, C_GREY, C_BLACK, C_BLACK, "Set",  -10, -7, FONT_BUTTONTEXT );
for (row = 0; row < 4; row++) {
for (col = 0; col < 3; col++) {
KeyPadBtn[col + row * 3].init(BUTTON_X + col * (BUTTON_W + BUTTON_SPACING_X),
BUTTON_Y + row * (BUTTON_H + BUTTON_SPACING_Y),
BUTTON_W, BUTTON_H, C_WHITE, KeyPadBtnColor[col + row * 3], C_BLACK, C_WHITE,
KeyPadBtnText[col + row * 3],  -5, -7, FONT_BUTTONTEXT );
}
}
cbHistory.init(180, 60, C_WHITE, SLIDER_COLOR, C_GREY, C_WHITE, C_BLACK, 20, 5, "", FONT_BUTTONTEXT );
cbHighPass.init(180, 120, C_WHITE, SLIDER_COLOR, C_GREY, C_WHITE, C_BLACK, 20, 5, "", FONT_BUTTONTEXT );
cbLowPass.init(180, 150, C_WHITE, SLIDER_COLOR, C_GREY, C_WHITE, C_BLACK, 20, 5, "", FONT_BUTTONTEXT );
cbBackground.init(180, 180, C_WHITE, SLIDER_COLOR, C_GREY, C_WHITE, C_BLACK, 20, 5, "", FONT_BUTTONTEXT );

MixerGain = 0.5;

// initialize the sliders
sBand1.init(BAND1, 45, 160, -1, 1, 1, 0, C_WHITE, C_BLACK, SLIDER_COLOR);
sBand2.init(BAND2, 45, 160, -1, 1, 1, 0, C_WHITE, C_BLACK, SLIDER_COLOR);
sBand3.init(BAND3, 45, 160, -1, 1, 1, 0, C_WHITE, C_BLACK, SLIDER_COLOR);
sBand4.init(BAND4, 45, 160, -1, 1, 1, 0, C_WHITE, C_BLACK, SLIDER_COLOR);
sBand5.init(BAND5, 45, 160, -1, 1, 1, 0, C_WHITE, C_BLACK, SLIDER_COLOR);

sMicGain.init( 290, 55, 160, 0, 2.0, 0, 0, C_WHITE, C_BLACK, SLIDER_COLOR);

shMicGain.init( 185, 100, 120, 0, 15.0, 0, 1, C_WHITE, C_BLACK, SLIDER_COLOR);
shMicGain.setBarThickness(3);
shMicGain.setHandleShape(HANDLE_RECTANGLE);
shMicGain.setHandleSize(24, 10);

sBand1.setBarThickness(BAR_THICKNESS);
sBand2.setBarThickness(BAR_THICKNESS);
sBand3.setBarThickness(BAR_THICKNESS);
sBand4.setBarThickness(BAR_THICKNESS);
sBand5.setBarThickness(BAR_THICKNESS);

sBand1.setHandleSize(HANDLE_SIZE);
sBand2.setHandleSize(HANDLE_SIZE);
sBand3.setHandleSize(HANDLE_SIZE);
sBand4.setHandleSize(HANDLE_SIZE);
sBand5.setHandleSize(HANDLE_SIZE);

sMicGain.setBarThickness(BAR_THICKNESS);
sMicGain.setHandleSize(40, 16);
sMicGain.setHandleShape(HANDLE_RECTANGLE);

// turn off the mixers / till boot up
mixer1.gain(0, 0.0);
mixer1.gain(1, 0.0);
mixer1.gain(2, 0.0);
mixer1.gain(3, 0.0);

sgtl5000_1.eqBands(Band1, Band2, Band3, Band4, Band5);

// remind the user to set the mic input level very low
DSLRSetupScreen();

Display.fillScreen(BackColor);

// draw the main screen
DrawMainScreen();

ActivateFilters();

curtime = 70000;
pretime = 0;
ShowBattery();

mixer1.gain(0, MixerGain);
mixer1.gain(1, MixerGain);
mixer1.gain(2, 0.0);
mixer1.gain(3, 0.0);

}

void loop() {

// I have everything in the fft read loop, so far no issues, but i should have some catch code outside that if

if (fft1024_1.available()) {
curtime = millis();
// read the batter level every minute
if (curtime - pretime > 60000) {
pretime = curtime;
ShowBattery();
}

// anyone touch anything?
if (Touch.dataAvailable()) {

ProcessTouch();

if (PressIt(SetupBtn) == true) {
SetupScreen();
}

else if (x > 250) {
sMicGain.slide(x, y);
MixerGain = sMicGain.value;
mixer1.gain(0, MixerGain);
mixer1.gain(1, MixerGain);
mixer1.gain(2, 0);
mixer1.gain(3, 0);
}

else if (( x > 24 + (0 * WIDTH)) & (x < 24 + (6 * WIDTH))) {
// eq band 1
Band1 = MapFloat(y, 50.0, 230.0, 1.0, -1.0);
if (Band1 > 1.0) {
Band1 = 1.0;
}
if (Band1 < -1.0) {
Band1 = -1.0;
}
sgtl5000_1.eqBands(Band1, Band2, Band3, Band4, Band5);

}
else if (( x > 24 + (6 * WIDTH)) & (x < 24 + (12 * WIDTH))) {
// eq band 1
Band2 = MapFloat(y, 50.0, 230.0, 1.0, -1.0);
if (Band2 > 1.0) {
Band2 = 1.0;
}
if (Band2 < -1.0) {
Band2 = -1.0;
}
sgtl5000_1.eqBands(Band1, Band2, Band3, Band4, Band5);

}
else if (( x > 24 + (12 * WIDTH)) & (x < 24 + (18 * WIDTH))) {
// eq band 1
Band3 = MapFloat(y, 50.0, 230.0, 1.0, -1.0);
if (Band3 > 1.0) {
Band3 = 1.0;
}
if (Band3 < -1.0) {
Band3 = -1.0;
}
sgtl5000_1.eqBands(Band1, Band2, Band3, Band4, Band5);

}
else if (( x > 24 + (18 * WIDTH)) & (x < 24 + (24 * WIDTH))) {
// eq band 1
Band4 = MapFloat(y, 50.0, 230.0, 1.0, -1.0);
if (Band4 > 1.0) {
Band4 = 1.0;
}
if (Band4 < -1.0) {
Band4 = -1.0;
}
sgtl5000_1.eqBands(Band1, Band2, Band3, Band4, Band5);

}
else if (( x > 24 + (24 * WIDTH)) & (x < 24 + (31 * WIDTH))) {
// eq band 1
Band5 = MapFloat(y, 50.0, 230.0, 1.0, -1.0);
if (Band5 > 1.0) {
Band5 = 1.0;
}
if (Band5 < -1.0) {
Band5 = -1.0;
}
sgtl5000_1.eqBands(Band1, Band2, Band3, Band4, Band5);

}
//else if (( x > 10) & (x < 200)) {
//  Brightness = map(y, 0, 240, 255, 5);
//  analogWrite(LED_PIN, Brightness);
//}
}

// process the fft spectrum
level[0] = fft1024_1.read(0, 1) * 1.000 * MIC_BAR_GAIN;
level[1] = fft1024_1.read(2, 3) * 1.179 * MIC_BAR_GAIN;
level[2] = fft1024_1.read(4, 5) * 1.273 * MIC_BAR_GAIN;
level[3] = fft1024_1.read(6, 7) * 1.339 * MIC_BAR_GAIN;
level[4] = fft1024_1.read(8, 9) * 1.390 * MIC_BAR_GAIN;
level[5] = fft1024_1.read(10, 12) * 1.452 * MIC_BAR_GAIN;
level[6] = fft1024_1.read(13, 15) * 1.501 * MIC_BAR_GAIN;
level[7] = fft1024_1.read(16, 18) * 1.543 * MIC_BAR_GAIN;
level[8] = fft1024_1.read(19, 22) * 1.590 * MIC_BAR_GAIN;
level[9] = fft1024_1.read(23, 26) * 1.630 * MIC_BAR_GAIN;
level[10] = fft1024_1.read(27, 30) * 1.666 * MIC_BAR_GAIN;
level[11] = fft1024_1.read(31, 35) * 1.705 * MIC_BAR_GAIN;
level[12] = fft1024_1.read(36, 40) * 1.739 * MIC_BAR_GAIN;
level[13] = fft1024_1.read(41, 46) * 1.776 * MIC_BAR_GAIN;
level[14] = fft1024_1.read(47, 53) * 1.814 * MIC_BAR_GAIN;
level[15] = fft1024_1.read(54, 61) * 1.853 * MIC_BAR_GAIN;
level[16] = fft1024_1.read(62, 69) * 1.887 * MIC_BAR_GAIN;
level[17] = fft1024_1.read(70, 79) * 1.926 * MIC_BAR_GAIN;
level[18] = fft1024_1.read(80, 90) * 1.964 * MIC_BAR_GAIN;
level[19] = fft1024_1.read(91, 102) * 2.001 * MIC_BAR_GAIN;
level[20] = fft1024_1.read(103, 116) * 2.040 * MIC_BAR_GAIN;
level[21] = fft1024_1.read(117, 131) * 2.078 * MIC_BAR_GAIN;
level[22] = fft1024_1.read(132, 148) * 2.116 * MIC_BAR_GAIN;
level[23] = fft1024_1.read(149, 167) * 2.155 * MIC_BAR_GAIN;
level[24] = fft1024_1.read(168, 189) * 2.195 * MIC_BAR_GAIN;
level[25] = fft1024_1.read(190, 213) * 2.235 * MIC_BAR_GAIN;
level[26] = fft1024_1.read(214, 241) * 2.277 * MIC_BAR_GAIN;
level[27] = fft1024_1.read(242, 272) * 2.318 * MIC_BAR_GAIN;
level[28] = fft1024_1.read(273, 307) * 2.361 * MIC_BAR_GAIN;
level[29] = fft1024_1.read(308, 347) * 2.405 * MIC_BAR_GAIN;
level[30] = fft1024_1.read(348, 392) * 2.449 * MIC_BAR_GAIN;

for (i = 0; i < 31; i++) {  // cycle through the 32 channels

// scale the level to the bar height and clamp if exceed max
line1 = level[i] * 170;
if (line1 > 170) {
line1 = 170;
}
// now it's just a matter of displaying some little boxes for each bar in a certian color
// get number of bars
Qty = line1 / 10;
for (j = Qty; j < 18; j++) {
Display.fillRect(  (i * WIDTH) + OFFSET, 210 - (j * 10), WIDTH - 1, 9, BackColor);
}
if (ShowHistory) {
if (Qty > Max[i]) {
Max[i] = Qty - 1;
}
if ((millis() - Showit ) > 2000) {
Showit = millis();
for (byte k = 0; k < 32; k++) {
Display.fillRect((i * WIDTH) + OFFSET, 210 - (Max[k] * 10), WIDTH - 1, 9, BackColor);
Max[k] = 0;
}
}
else {
if (Max[i] < 11) {
Display.fillRect( (i * WIDTH) + OFFSET, 210 - (Max[i] * 10), WIDTH - 1, 9, C_GREEN);
}
else if (Max[i] < 16) {
Display.fillRect( (i * WIDTH) + OFFSET, 210 - (Max[i] * 10), WIDTH - 1, 9, C_YELLOW);
}
else {
Display.fillRect( (i * WIDTH) + OFFSET, 210 - (Max[i] * 10), WIDTH - 1, 9, C_RED);
}
}
}
for ( j = 0; j < Qty; j++) {
if (j < 11) {
Display.fillRect(  (i * WIDTH) + OFFSET, 210 - (j * 10), WIDTH - 1, 9, C_GREEN);
}
else if (j < 16) {
Display.fillRect(  (i * WIDTH) + OFFSET, 210 - (j * 10), WIDTH - 1, 9, C_YELLOW);
}
else {
Display.fillRect(  (i * WIDTH) + OFFSET, 210 - (j * 10), WIDTH - 1, 9, C_RED);
}
}
}
}
}

void ActivateFilters() {

if (HighPass == 1) {
}
else if (HighPass == 0) {
}

if (LowPass == 1) {
}
else if (LowPass == 0) {
}
}

void DrawMainScreen() {

sMicGain.setColors(ForeColor, BackColor, SLIDER_COLOR);
sMicGain.drawSliderColor(true);
sMicGain.draw(MixerGain);

Display.fillRect(0, 0, 320, 35, C_LTGREY);

Display.setTextColor(C_BLACK, BackColor);
Display.setCursor(78, 5);
Display.print(F("Monitoring"));

Display.setFont(FONT_TEXT);
SetupBtn.draw();

Display.setFont(FONT_BUTTONTEXT);
Display.setTextColor(ForeColor, BackColor);

Display.setCursor(2, 220);
Display.print(F("-o")) ;
Display.setCursor(16, 220);
Display.print(F("o")) ;

Display.setCursor(2, 75);
Display.print(F("-6")) ;;

Display.setCursor(2, 45);
Display.print(F("0")) ;;

Display.drawFastHLine( 24, 220, 218, C_GREY);
Display.drawFastHLine( 24, 79, 218, C_GREY);
Display.drawFastHLine( 24, 49, 218, C_GREY);

Display.drawFastVLine( 24, 49, 171, C_GREY);

Display.drawFastVLine( 24 + (6 * WIDTH), 49, 171, C_DKGREY);
Display.drawFastVLine( 24 + (12 * WIDTH), 49, 171, C_DKGREY);
Display.drawFastVLine( 24 + (18 * WIDTH), 49, 171, C_DKGREY);
Display.drawFastVLine( 24 + (24 * WIDTH), 49, 171, C_DKGREY);
Display.drawFastVLine( 24 + (31 * WIDTH), 49, 171, C_GREY);

Display.setCursor(30, 225);
Display.print(F("100")) ;;

Display.setCursor(95, 225);
Display.print(F("1000")) ;;
Display.setCursor(195, 225);
Display.print(F("10000")) ;;

}

void SetupScreen() {

bool KeepIn = true;
bool s = false;
DrawSetupScreen();

while (KeepIn) {

if (Touch.dataAvailable()) {

ProcessTouch() ;

s = shMicGain.slide(x, y);
if (cbHistory.press(x, y)) {
ShowHistory = cbHistory.value;
}

if (s) {
MicGain = shMicGain.value;
sgtl5000_1.lineInLevel(MicGain);
sprintf(str, "Gain %d", MicGain );
Display.setCursor(10 , 95);
MicGainText.setTextColor(ForeColor, BackColor);
MicGainText.print(str);

}

/*
if (PressIt(MicGainBtn) == true) {
sgtl5000_1.lineInLevel(MicGain);
sprintf(str, "%d", MicGain );
MicGainBtn.setText(str);
MicGainBtn.draw();
}
*/
if (cbHighPass.press(x, y)) {
HighPass = cbHighPass.value;
if (HighPass == 1) {
sprintf(str, "%d hZ", HighPassF );
HighPassFBtn.setText(str);
HighPassFBtn.enable();
HighPassFBtn.draw();
}
else {
strcpy(str, "Off");
HighPassFBtn.setText(str);
HighPassFBtn.disable();
HighPassFBtn.draw();
}
ActivateFilters();
}
if (PressIt(HighPassFBtn) == true) {
ActivateFilters();
sprintf(str, "%d hz", HighPassF );
HighPassFBtn.setText(str);
HighPassFBtn.enable();
HighPassFBtn.draw();
// DrawSetupScreen();
}

if (cbLowPass.press(x, y)) {
LowPass = cbLowPass.value;
if (LowPass == 1) {
sprintf(str, "%d hz", LowPassF );
LowPassFBtn.setText(str);
LowPassFBtn.enable();
LowPassFBtn.draw();
}
else {
strcpy(str, "Off");
LowPassFBtn.setText(str);
LowPassFBtn.disable();
LowPassFBtn.draw();
}
ActivateFilters();
}
if (PressIt(LowPassFBtn) == true) {
ActivateFilters();
sprintf(str, "%d hZ", LowPassF );
LowPassFBtn.setText(str);
LowPassFBtn.enable();
LowPassFBtn.draw();
// DrawSetupScreen();
}

if (cbBackground.press(x, y)) {
Background = cbBackground.value;
if (Background == 1) {
BackColor = C_WHITE;
ForeColor = C_BLACK;
DrawSetupScreen();
}
else {
BackColor = C_BLACK;
ForeColor = C_WHITE;
DrawSetupScreen();
}
}

if (PressIt(EQBtn) == true) {
Equalizer();
}
if (PressIt(DoneBtn) == true) {
KeepIn = false;
}

}
}

// save data and exit
EEPROM.put(10, ShowHistory);
EEPROM.put(20, Background);
EEPROM.put(30, MicGain);
EEPROM.put(40, HighPass);
EEPROM.put(50, LowPass);
EEPROM.put(60, HighPassF);
EEPROM.put(70, LowPassF);

Display.fillScreen(BackColor);
curtime = 70000;
pretime = 0;
DrawMainScreen();

}

void DrawSetupScreen() {

Display.fillScreen(BackColor);
Display.fillRect(0, 0, 320, 35, C_LTGREY);
Display.setTextColor(C_BLACK, BackColor);
Display.setCursor(5, 7);

Display.print(F("Setup"))  ;
Display.setTextColor(ForeColor, BackColor);
Display.setFont(FONT_BUTTONTEXT);
cbHistory.draw(ShowHistory);

//sprintf(str, "%d", MicGain );
//MicGainBtn.setText(str);
//MicGainBtn.draw();
shMicGain.setColors(ForeColor, BackColor, SLIDER_COLOR);
shMicGain.draw(MicGain);
cbHighPass.draw(HighPass);
cbLowPass.draw(LowPass);

if (HighPass) {
sprintf(str, "%d hz", HighPassF );
HighPassFBtn.setText(str);
HighPassFBtn.enable();
HighPassFBtn.draw();
}
else {
strcpy(str, "Off");
HighPassFBtn.setText(str);
HighPassFBtn.disable();
HighPassFBtn.draw();
}

if (LowPass) {
sprintf(str, "%d hz", LowPassF );
LowPassFBtn.setText(str);
LowPassFBtn.enable();
LowPassFBtn.draw();
}
else {
strcpy(str, "Off");
LowPassFBtn.setText(str);
LowPassFBtn.disable();
LowPassFBtn.draw();
}

cbBackground.draw(Background);

EQBtn.draw();

Display.setFont(FONT_TEXT);
DoneBtn.draw();

Display.setTextColor(ForeColor, BackColor);
Display.setFont(FONT_TEXT);
Display.setCursor(10 , 65);
Display.print(F("Hold spectrum"));
Display.setCursor(10 , 95);

sprintf(str, "Gain %d", MicGain );
Display.setCursor(10 , 95);
MicGainText.setTextColor(ForeColor, BackColor);
MicGainText.print(str);
Display.setTextColor(ForeColor, BackColor);
Display.setCursor(10 , 125);
Display.print(F("High pass filter"));
Display.setCursor(10 , 155);
Display.print(F("Low pass filter"));
Display.setCursor(10 , 185);
Display.print(F("White background"));
Display.setCursor(10 , 215);
Display.print(F("Graphic equalizer"));

}

void KeyPad(int & TheNumber, int MinVal, int MaxVal) {

Display.setFont(FONT_TEXT);

left = BUTTON_X - (BUTTON_W);
top = BUTTON_Y - (2 * BUTTON_H);
wide = (3 * BUTTON_W ) + (8 * BUTTON_SPACING_X);
high = 5 * (BUTTON_H +  BUTTON_SPACING_Y);

// prevent any button press misfires
x = 0, y = y;

TempNum = 0;

bool KeepIn = true;

Display.fillRect(left, top, wide , high, C_DKGREY);
Display.drawRect(left, top, wide , high, C_LTGREY);

Display.fillRect(left + 10, top + 10, wide - 20 , 30, C_GREY);
Display.drawRect(left + 10, top + 10, wide - 20 , 30, C_WHITE);

Display.setCursor(left  + 110 , top + 18);
Display.setTextColor(C_BLACK, 80);
Display.print(F("(") + String(MinVal) + F(" - ") + String(MaxVal) + F(")"));

Display.setCursor(left  + 20 , top + 18);
Display.setTextColor(C_BLACK, C_GREY);
Display.print(TheNumber);

for (row = 0; row < 4; row++) {
for (col = 0; col < 3; col++) {
}
}

while (KeepIn) {
// get the touch point
if (Touch.dataAvailable()) {
ProcessTouch() ;

// go thru all the KeyPadBtn, checking if they were pressed
for (b = 0; b < 12; b++) {
if ((b < 9) || (b == 10)) {
TempNum *= 10;
if (TempNum == 0) {
Display.fillRect(left + 10 - 1, top + 10 + 1, 80 - 2 , 30 - 2, C_GREY);
}
if (b != 10) {
TempNum += (b + 1);
}
if (TempNum > MaxVal) {
Display.fillRect(left + 10 - 1, top + 10 + 1, 80 - 2 , 30 - 2, C_GREY);
TempNum = 0;
Serial.println("here");
}
}
// clr button! delete char
if (b == 11) {
Display.fillRect(left + 10 - 1, top + 10 + 1, 80 - 2 , 30 - 2, C_GREY);
TempNum = 0;
}
if (b == 9) {
if (TempNum == 0) {
TempNum = TheNumber;
}
if ((TempNum >= MinVal) && (TempNum <= MaxVal)) {
KeepIn = false;
}
}

Display.setFont(FONT_TEXT);
Display.setCursor(left  + 20 , top + 18);
Display.setTextColor(C_BLACK, C_GREY);
Display.print(TempNum);

}
}
}

}

TheNumber = TempNum;
DrawSetupScreen();

}

void GetParameters() {

byte i, test;

EEPROM.get(0, test);
if (test == 255) {
// new programmer reset the whole thing
for (i = 0; i < 255; i++) {
EEPROM.put(i, 0);
}
// set some defaulTouch
// and populate the eeprom

ShowHistory = 0;
EEPROM.get(10, ShowHistory);
Background = 0;
EEPROM.put(20, Background);
MicGain = 5;
EEPROM.put(30, MicGain);
HighPass = 0;
EEPROM.put(40, HighPass);
LowPass = 0;
EEPROM.put(50, LowPass);
HighPassF = 4000;
EEPROM.put(60, HighPassF);
LowPassF = 40;
EEPROM.put(70, LowPassF);
Band1 = 0;
EEPROM.put(80, Band1);
Band2 = 0;
EEPROM.put(90, Band2);
Band3 = 0;
EEPROM.put(100, Band3);
Band4 = 0;
EEPROM.put(110, Band4);
Band5 = 0;
EEPROM.put(120, Band5);

}

EEPROM.get(10, ShowHistory);
EEPROM.get(20, Background);
EEPROM.get(30, MicGain);
EEPROM.get(40, HighPass);
EEPROM.get(50, LowPass);
EEPROM.get(60, HighPassF);
EEPROM.get(70, LowPassF);
EEPROM.get(80, Band1);
EEPROM.get(90, Band2);
EEPROM.get(100, Band3);
EEPROM.get(110, Band4);
EEPROM.get(120, Band5);

}

bool PressIt(Button TheButton) {

if (TheButton.press(x, y)) {

TheButton.draw(B_PRESSED);
while (Touch.dataAvailable()) {
if (TheButton.press(x, y)) {
TheButton.draw(B_PRESSED);
}
else {
TheButton.draw(B_RELEASED);
return false;
}
ProcessTouch();
}

TheButton.draw(B_RELEASED);
return true;
}
return false;
}

void DSLRSetupScreen() {

unsigned long LastTime = 0;
bool KeepIn = true;
bool LastColor = true;

analogWrite(LED_PIN, 255);

Display.fillScreen(C_BLACK);
OKBtn.draw();
Display.setTextColor(C_WHITE, C_BLACK);

Display.setCursor(10, 50);
Display.print(F("Set the CAMERA mic level to 17%"));

Display.fillRect(60, 80, 200 , 20, C_DKRED);
Display.setCursor(65, 85);
Display.print(F("Sound Recording"));
Display.setFont(FONT_SMALLTEXT);
Display.setCursor(65, 115);
Display.print(F("Sound Rec."));
Display.setCursor(160, 115);
Display.print(F("Manual"));

Display.setCursor(65, 147);
Display.print(F("Rec. level"));

Display.fillRect(155, 150, 100 , 2, C_WHITE);

Display.fillRect(155, 145, 2 , 10, C_WHITE);
Display.fillRect(155 + 25, 145, 2 , 10, C_WHITE);
Display.fillRect(155 + 50, 145, 2 , 10, C_WHITE);
Display.fillRect(155 + 75, 145, 2 , 10, C_WHITE);
Display.fillRect(155 + 100, 145, 2 , 10, C_WHITE);

Display.fillRect(60, 175, 200 , 60, C_DKGREY);

Display.setCursor(65, 180);
Display.print(F("-dB 40"));
Display.setCursor(180, 180);
Display.print(F("12"));
Display.setCursor(240, 180);
Display.print(F("0"));

Display.setCursor(65, 200);
Display.print(F("L"));

Display.setCursor(65, 220);
Display.print(F("R"));

for (int i = 80; i < 248; i += 12) {

if (i < 188) {
Display.fillRect(i, 200, 10 , 10, C_WHITE);
Display.fillRect(i, 220, 10 , 10, C_WHITE);
}
else if (i < 212) {
Display.fillRect(i, 200, 10 , 10, C_YELLOW);
Display.fillRect(i, 220, 10 , 10, C_YELLOW);
}
else {
Display.fillRect(i, 200, 10 , 10, C_MDGREY);
Display.fillRect(i, 220, 10 , 10, C_MDGREY);
}
}

Display.drawRect (60, 80, 200, 155, C_GREY);

while (KeepIn) {

if ((millis() - LastTime) > 200) {
LastTime = millis();

if (LastColor == true) {
LastColor = false;
Display.fillTriangle (155 - 4 + 16, 135, 155 + 4 + 16, 135, 155 + 16, 148, C_RED);

}
else {
LastColor = true;
Display.fillTriangle (155 - 4 + 16, 135, 155 + 4 + 16, 135, 155 + 16, 148, C_GREEN);

}
}

if (Touch.dataAvailable()) {

ProcessTouch();

delay(100);

if ((PressIt(OKBtn) == true)) {
KeepIn = false;
}
}
}
}

void SplashScreen() {

analogWrite(LED_PIN, 255);

Display.fillScreen(C_BLACK);
delay(500);
for (int i = 0; i < 320; i += 2) {
Display.setTextColor(C_RED, C_BLACK);
Display.setFont(FONT_BANNER);
Display.setCursor(11, 40);
Display.print(F("Canon 7D"));

Display.setTextColor(C_WHITE, C_BLACK);
Display.setCursor(30, 120);
Display.print(F("Microphone Monitor"));

Display.setCursor(40, 180);
Display.print(F("v 2.5 Kasprzak (c)"));
Display.setScroll(i);
}

delay(2000);

}

float MapFloat(float x, float in_min, float in_max, float out_min, float out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

void Equalizer() {

bool KeepIn = true;

Display.fillScreen(BackColor);

Display.fillRect(0, 0, 320, 35, C_LTGREY);
Display.setTextColor(C_BLACK, BackColor);
Display.setCursor(5, 7);

Display.print(F("Equalizer"));

Display.setFont(FONT_TEXT);
Display.setTextColor(ForeColor, BackColor);

Display.setCursor(BAND1 - 20, 223);
Display.print("115");
Display.setCursor(BAND2 - 20, 223);
Display.print("330");
Display.setCursor(BAND3 - 20, 223);
Display.print("990");
Display.setCursor(BAND4 - 20, 223);
Display.print("3K");
Display.setCursor(BAND5 - 20, 223);
Display.print("9.9K");

Display.setTextColor(C_WHITE, BackColor);

sBand1.setColors(ForeColor, BackColor, SLIDER_COLOR);
sBand2.setColors(ForeColor, BackColor, SLIDER_COLOR);
sBand3.setColors(ForeColor, BackColor, SLIDER_COLOR);
sBand4.setColors(ForeColor, BackColor, SLIDER_COLOR);
sBand5.setColors(ForeColor, BackColor, SLIDER_COLOR);

sBand1.drawSliderColor(true);
sBand2.drawSliderColor(true);
sBand3.drawSliderColor(true);
sBand4.drawSliderColor(true);
sBand5.drawSliderColor(true);

sBand1.draw(Band1);
sBand2.draw(Band2);
sBand3.draw(Band3);
sBand4.draw(Band4);
sBand5.draw(Band5);

analogWrite(LED_PIN, 255);

Display.setFont(FONT_TEXT);
DoneBtn.draw();
Display.setFont(FONT_TEXT);
Display.setTextColor(C_WHITE, BackColor);

while (KeepIn) {

if (Touch.dataAvailable()) {

ProcessTouch() ;
if (PressIt(DoneBtn) == true) {
KeepIn = false;
}

sBand1.slide(x, y);
sBand2.slide(x, y);
sBand3.slide(x, y);
sBand4.slide(x, y);
sBand5.slide(x, y);

Band1 = sBand1.value;
Band2 = sBand2.value;
Band3 = sBand3.value;
Band4 = sBand4.value;
Band5 = sBand5.value;

sgtl5000_1.eqBands(Band1, Band2, Band3, Band4, Band5);
/*
if (sBand1.changed()) {
sgtl5000_1.eqBand(1, Band1);
}
if (sBand2.changed()) {
sgtl5000_1.eqBand(2, Band2);
}
if (sBand3.changed()) {
sgtl5000_1.eqBand(3, Band3);
}
if (sBand4.changed()) {
sgtl5000_1.eqBand(4, Band4);
}
if (sBand5.changed()) {
// sgtl5000_1.eqBand(5, Band5);
}
*/
}
}
x = 0, y = 0; // keep from previous menuu from mis firign.
EEPROM.put(80, Band1);
EEPROM.put(90, Band2);
EEPROM.put(100, Band3);
EEPROM.put(110, Band4);
EEPROM.put(120, Band5);

Display.fillScreen(BackColor);
DrawSetupScreen();

}

void ShowBattery() {

loval = 0;
hival = 100.0;

BatVolts = 0.0;
for (i = 0; i < 100; i++) {
}
BatVolts = BatVolts / 100.0;

BatVolts = BatVolts * (3.3 / 1024.0);
BatVolts = (BatVolts * (1000.0 + 4700.0)) / 1000.0;
BatVolts  = (map(BatVolts * 10, 70, 90, 0, 1000)) / 10.0;
if (BatVolts > 100.0) {
BatVolts = 100.0;
}
if (BatVolts < 0.0) {
BatVolts = 0.0;
}
Display.drawRect(5, 8, 60, 15, ForeColor);
Display.setTextColor(ForeColor, BackColor);
BatLevel = (60 * (((BatVolts - loval) / (hival - loval))));
if (BatLevel < 25.0) {
Display.fillRect(5 + BatLevel, 9, 58 - BatLevel, 13,  C_DKRED);
Display.fillRect(6, 9, BatLevel,  13, C_RED);
}
else {
Display.fillRect(6 + BatLevel, 9, 58 - BatLevel, 13,  C_DKGREEN);
Display.fillRect(6, 9, BatLevel - 0,  13, C_GREEN);
}
}

void ProcessTouch() {

y = Touch.getX();
x = Touch.getY();
#ifdef debug
Serial.print(x);
Serial.print(" - ");
Serial.print(y);
Serial.print(", ");
#endif
x  = map(x, 0, 234, 310, 0);
y  = map(y, 379, 0, 240, 0);
#ifdef debug
Serial.print(x);
Serial.print(" - ");
Serial.println(y);
Display.drawPixel(x, y, C_GREEN);
#endif
}

/////////////////////////////////////////////////////////``````

Hope this helps.

See the spectrum in action here:

Updating the 31 frequency channels is very fast and did not need any frame buffering. After getting the fft data, I simply cycle through each of the 31 channels and draw a colored rectangle based on the level. The code has a 2 second "hold" option to show the max val for each frequency. Don't laugh at my fft scaling to get a level. I guessed at some values that made the display look reasonable

Code:
``````for (i = 0; i < 31; i++) {  // cycle through the 32 channels

// scale the level to the bar height and clamp if exceed max
line1 = level[i] * 170;
if (line1 > 170) {
line1 = 170;
}
// now it's just a matter of displaying some little boxes for each bar in a certian color
// get number of bars
Qty = line1 / 10;
for (j = Qty; j < 18; j++) {
Display.fillRect(  (i * WIDTH) + OFFSET, 210 - (j * 10), WIDTH - 1, 9, BackColor);
}
if (ShowHistory) {
if (Qty > Max[i]) {
Max[i] = Qty - 1;
}
if ((millis() - Showit ) > 2000) {
Showit = millis();
for (byte k = 0; k < 32; k++) {
Display.fillRect((i * WIDTH) + OFFSET, 210 - (Max[k] * 10), WIDTH - 1, 9, BackColor);
Max[k] = 0;
}
}
else {
if (Max[i] < 11) {
Display.fillRect( (i * WIDTH) + OFFSET, 210 - (Max[i] * 10), WIDTH - 1, 9, C_GREEN);
}
else if (Max[i] < 16) {
Display.fillRect( (i * WIDTH) + OFFSET, 210 - (Max[i] * 10), WIDTH - 1, 9, C_YELLOW);
}
else {
Display.fillRect( (i * WIDTH) + OFFSET, 210 - (Max[i] * 10), WIDTH - 1, 9, C_RED);
}
}
}
for ( j = 0; j < Qty; j++) {
if (j < 11) {
Display.fillRect(  (i * WIDTH) + OFFSET, 210 - (j * 10), WIDTH - 1, 9, C_GREEN);
}
else if (j < 16) {
Display.fillRect(  (i * WIDTH) + OFFSET, 210 - (j * 10), WIDTH - 1, 9, C_YELLOW);
}
else {
Display.fillRect(  (i * WIDTH) + OFFSET, 210 - (j * 10), WIDTH - 1, 9, C_RED);
}
}
}``````

More....

Want a touch-slider controls for an EQ? Example and code link here:

Wanna draw text w/o flickering? Code and example here:

Wanna menu system? Code and example here:

Need custom fonts? Code and example here:

I did something similar. I have a mic processor that has an eq for adujusting sound levels and a spectrum display to see the processed mic results...
Holy moly batman! That is really impressive, and thank you for the resources. Your FFT seems like it's drawing extremely well. And it looks like you're just using fill rect just like me... however you're using an include called flicker free? Is that why it's drawing nicely or am I missing something else? Thanks!

Flicker free is just for keeping text from flickering. Nothing to do with drawing graphics.

I saw this line of code above

// Clear the previous state - fill only the non-border area
tft.fillRect(x, y, barWidth, height, ILI9341_BLACK);

And is probably the culprit, you are erasing the entire box then redrawing. Only erase what changed. If you are using a bar graph type display (as opposed to my individual boxes).
1. get the height of the bar, draw a fill rec with that height
2. draw a blank out fill rect starting at that height

I have a lib that draw simple bar charts, like the one shown above. It uses the above notion to eliminate flicker

There is sample code to get you up and running.

Flicker free is just for keeping text from flickering. Nothing to do with drawing graphics.
Ah! Thank you KrisKasprzak, I'll look at your controls code and play around with it.
Thanks!

Im trying to separate the audio shield and the Teensy so i can isolate the grounds and Im having a bit of trouble getting it to work. I have a separate 3.3v source to power the audio shield, and im getting correct voltage, confirmed by the top of the audio shield's 3.3v pin/hole. I have 7 connections to the Teensy, and I have the 2 ground connections connected on either side of the audio shield. Is there anything else I could be missing that is obvious? If I plug the shield straight into the teensy, it works, so it must be some connection Im missing. Thank you

I think my issues might be related to my amazon bread board. I got it working for a bit on a solder less breadboard.

What's the best way to isolate digital noise and analog noise? Can I just use isolation transformers? Should power to the shield and all analog preamps be separate from the teensy's 5v? Thank you