#include <LiquidCrystal_I2C.h>
#define IN_LEFT     A1  // analog input for left channel
#define T_REFRESH   25
#define T_PEAKHOLD  (50 * T_REFRESH)
byte  fill[6] = {0x20, 0x00, 0x01, 0x02, 0x03, 0xFF};
byte  peak[7] = {0x20, 0x00, 0x04, 0x05, 0x06, 0x07, 0x20};
byte block[8][8] =
{
  {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10},
  {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
  {0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C},
  {0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E},
  {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08},
  {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04},
  {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02},
  {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
};
int lmax[2];
int dly[2];
long lastT = 0;
LiquidCrystal_I2C  lcd(0x27, 16, 2 );
void  setup()
{
  lcd.init();
  lcd.backlight();
 
  for (int j = 0; j < 8; j++)
    lcd.createChar(j, block[j]); 
}
void  loop() {
  if (millis() < lastT)
    return;
  lastT += T_REFRESH;
  int anL = map(sqrt(analogRead(IN_LEFT) * 16), 0, 128, 0, 100);
  bar(1, anL);
}
void  bar(int row, int lev)
{
  lcd.setCursor(0, row);
  lcd.write('L');
  for (int i = 1; i < 16; i++)
  {
    int f = constrain(lev - i * 5, 0, 5);
    int p = constrain(lmax[row] - i * 5, 0, 6);
    if (f)
      lcd.write(fill[f]);
    else
      lcd.write(peak[p]);
  }
  if (lev > lmax[row])
  {
    lmax[row] = lev;
    dly[row]  = -(T_PEAKHOLD) / T_REFRESH;
  }
  else
  {
    if (dly[row] > 0)
      lmax[row] -= dly[row];
    if (lmax[row] < 0)
      lmax[row] = 0;
    else
      dly[row]++;
  }
}