#include <LiquidCrystal_I2C.h>
#include "fix_fft.h"
#define LCHAN 1
const int yres = 8;
const int gain = 3;
int i = 0, val;
int lmax[2];                  // level max memory
int dly[2];                   // delay & speed for peak return
char im[64], data[64];
char data_avgs[32];
// VU METER CHARACTERS
byte v1[8] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};
byte sp[8] = {0x03, 0x05, 0x19, 0x11, 0x11, 0x19, 0x05, 0x03};
LiquidCrystal_I2C lcd(0x27, 16, 2); //saves 5 pwm pins for servos, leds, etc
void setup()
{
  lcd.init();
  lcd.backlight();
  lcd.createChar(0, sp);
  lcd.createChar(1, v1);
  lcd.setCursor(2, 0);
  lcd.print("FM  99.9 MHz");
}
// the loop routine runs over and over again forever;
void loop()
{
  bars();
}
void vu()
{
  for (i = 0; i < 64; i++)
  {
    val = ((analogRead(LCHAN)) - 96);  // chose how to interpret the data from analog in
    data[i] = val;
    im[i] = 0;
  }
  fix_fft(data, im, 6, 0); // Send the data through fft
  // get the absolute value of the values in the array, so we're only dealing with positive numbers
  for (i = 0; i < 32 ; i++)
  {
    data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);
  }
  // todo: average as many or as little dynamically based on yres
  for (i = 0; i < 32; i++)
  {
    data_avgs[i] = (data[i]);                               // add 3 samples to be averaged, use 4 when yres < 16
    data_avgs[i] = constrain(data_avgs[i], 0, 9 - gain);    //data samples * range (0-9) = 9
    data_avgs[i] = map(data_avgs[i], 0, 9 - gain, 0, yres); // remap averaged values
  }
} // end loop
void bars()
{
  vu();
  int anL = map((data_avgs[18]), 0, 11, 0, 80); // sqrt to have non linear scale (better was log)
  bar(1, anL);
}
void  bar(int rows, int levs)
{
#define T_REFRESH    100              // msec bar refresh rate
#define T_PEAKHOLD   5 * T_REFRESH    // msec peak hold time before return
  lcd.setCursor(0, rows);
  lcd.write(0);
  lcd.setCursor(2, rows);
  for (int i = 1 ; i < 16 ; i++)
  {
    int f = constrain(levs       - i * 5, 0, 5);
    int p = constrain(lmax[rows] - i * 5, 0, 6);
    if (f)
      lcd.write(1);
    else
      lcd.write(' ');
  }
  if (levs > lmax[rows])
  {
    lmax[rows] = levs;
    dly[rows]  = -(T_PEAKHOLD) / T_REFRESH;              // Starting delay value. Negative=peak don't move
  }
  else
  {
    if (dly[rows] > 0)
      lmax[rows] -= dly[rows];
    if (lmax[rows] < 0)
      lmax[rows] = 0;
    else
      dly[rows]++;
  }
}