#include <LiquidCrystal_I2C.h>
#include "fix_fft.h"

#define LCHAN A1

int load;
int decaytest = 1;
int x = 0, y = 0, z = 0;
int i = 0, val;
char im[64], data[64];
char data_avgs[32];
float peaks[32];
const int channels = 1;
const int gain = 3;
const int yres = 8;

// VU METER CHARACTERS
byte v1[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F};
byte v2[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F};
byte v3[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F};
byte v4[8] = {0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F};
byte v5[8] = {0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};
byte v6[8] = {0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};
byte v7[8] = {0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};
byte v8[8] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};

LiquidCrystal_I2C   lcd(0x27, 16, 2);

void setup()
{
  lcd.init();
  lcd.backlight();

  lcd.createChar(1, v1);
  lcd.createChar(2, v2);
  lcd.createChar(3, v3);
  lcd.createChar(4, v4);
  lcd.createChar(5, v5);
  lcd.createChar(6, v6);
  lcd.createChar(7, v7);
  lcd.createChar(8, v8);

  lcd.setCursor(0, 0);
  lcd.print("  FM  91.9 MHz ");
}

void loop()
{
  mono();
}

void vu()
{
  for (i = 0; i < 64; i++)
  {
    val = ((analogRead(LCHAN) / 4 ) - 128);  // 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]);// + data[i*2+1]);// + data[i*3 + 2]);// + data[i*4 + 3]);  // 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 Vu

void decay(int decayrate)
{
  // reduce the values of the last peaks by 1
  if (decaytest == decayrate)
  {
    for (x = 0; x < 32; x++)
    {
      peaks[x] = peaks[x] - 1;  // subtract 1 from each column peaks
      decaytest = 0;
    }
  }
  decaytest++;
}

void mono()
{
  vu();
  decay(1);

  // repeat for each column of the display horizontal resolution
  for (x = 1; x < 15; x++)
  {
    y = data_avgs[x];  // get current column value
    z = peaks[x];
    if (y > z)
    {
      peaks[x] = y;
    }
    y = peaks[x];

    if (y <= 8)
    {
      lcd.setCursor(x, 1); // draw second row
      if (y == 0)
      {
        lcd.print(" "); // save a glyph
      }
      else
      {
        lcd.write(y);
      }
    }
    else
    {
      lcd.setCursor(x, 1);
      lcd.write(8);
    } // end display
  } // end xres
}