Adding FASTLED visualizations and beat detection to mode control code

Hi,
I am trying to integrate an OLED display spectrum analyzer and UI control with three buttons and LED strip to display patterns. I am using an esp32 devkit, ssd1309 128x64 OLED display and WS2812B leds with 3 pushbuttons and microphone input.

I have fumbled my way through examples and got the UI controls and spectrum analyzer working fine but I am having trouble integrating patterns and the second part is to make them react to the beat using the values gathered from the FFT.

Basically I want to draw a horizontal line across the display and trigger a beat detection when the spectrum plots a value over the line. this beat detect will be used by the different pattern functions.

My first step is to integrate Fastled correctly and have basic patterns working before I try to get too fancy and have them react to sound.

Currently the OLED display doesn’t work the moment I try to add a basic pattern MoveDotLeft() and I dont understand why.

Can anyone please help me get an understanding on:

  1. how to implement patterns correctly
  2. how to detect the “beat” across the frequency range
  3. use the beat to influence patterns

here is my code so far:

#include <FastLED.h>
#include <esp_task_wdt.h>                         //https://iotassistant.io/esp32/enable-hardware-watchdog-timer-esp32-arduino-ide/ 
#include <Wire.h>
#include "arduinoFFT.h"                           // Standard Arduino FFT library // https://github.com/kosme/arduinoFFT, 
#include "SSD1306.h"                              // https://github.com/squix78/esp8266-oled-ssd1306
//#include "Button2.h";                           //  https://github.com/LennartHennigs/Button2
//#include "ESPRotary.h";

arduinoFFT FFT = arduinoFFT();


/////////////////////////////////////////////////////////////////////////

// OLED Display
#define SDA 21
#define SCL 22
#define OLED_i2c_address 0x3c
SSD1306 display(OLED_i2c_address,SDA,SCL);                   // 0.96" OLED display object definition (address, SDA, SCL) Connect OLED SDA , SCL pins to ESP SDA, SCL pins

// FFT
#define SAMPLES 512                             // Must be a power of 2 // 512
#define SAMPLING_FREQUENCY 40000                // Hz, must be 40000 or less due to ADC conversion time. Determines maximum frequency that can be analysed by the FFT Fmax=sampleF/2.
//#define amplitude 800                         // Depending on your audio source level, you may need to increase this value 200


// WDT
#define WDT_TIMEOUT 3                           // 3 seconds WDT.  If the code freezes for 3 seconds the hardware watchdog will reset the device. 

// LEDS
#define OnboardLED 2                            // Define the Onbaoard LED for debugging (most likely will blink for watchdog) 
#define ExternalLED 23                          // Define the External LED for debugging and fancy stuff

//FASTLED 
#define LEDstripPin 4                          
#define NUM_LEDS    196
#define COLOR_ORDER    GRB
#define CHIPSET        WS2812B

CRGB leds[NUM_LEDS];
bool LEDpower = true ;                        // LED strip is on by default 

// LED Brightness 
int LED_Brightness = 50;                      // Stores the default brightness of the LED strip 
int LED_BrightnessMin = 0 ;                   // let the brightness vary between 0 and 100% 
int LED_BrightnessMax =100  ; 
int ledDisplayBrihtnessValue = 0;             // variable to store actual LED strip brightness that is mapped from 0-100% 


// ANALOG INPUTS
#define MICROPHONE_INPUT_PIN A0                 // Define microphone input pin ADC 0 
#define POTENTIOMETER_INPUT_PIN A6              // Define microphone input pin ADC 0 

// BUTTON INPUTS
#define IncreaseButtonPin  19
#define ModeButtonPin 18
#define DecreaseButtonPin  5

//// ROTARY ENCODER                             // rotary encoders suck for this application.                           
//#define ROTARY_PIN1  18
//#define ROTARY_PIN2 19
//#define BUTTON_PIN  5
//#define CLICKS_PER_STEP   2                   // this number depends on your rotary encoder 
//ESPRotary Rotary = ESPRotary(ROTARY_PIN1, ROTARY_PIN2, CLICKS_PER_STEP);
//Button2 Rotary_BTN = Button2(BUTTON_PIN);

// MODE 
int Mode = 1;                                 // stores the current mode 
int ModeMax = 6;                              // 1 = sensitivity, 2 = Pattern, 3 = Brightness 

// Pattern selection 
int Pattern = 1;                              // Stores the current Pattern
int PatternMax = 5;                           // adjust this for number of patterns 
int PatternMin = 1;                           // keep this 1 so patterns cycle in a loop 


// timer for pattern mode change 
int Pattern_period = 30000;                   // this is the time period between pattern changes
unsigned long time_now = 0;                   // variable for millis() to store the current time 

// OLED Display brightness 
int OLED_Brightness = 50;                     // sets the default brightness 
int OLED_BrightnessMin = 0 ;                  // let the brightness vary between 0 and 100%   
int OLED_BrightnessMax =100  ; 
int OledDisplayBrihtnessValue = 0;            // variable to store actual value that is mapped from 0-100% 
  
int PatternMode = 1;                          // pattern mode, cycle, single, random
int PatternModeMax = 3;                       
int PatternModeMin = 1; 

// WATCHDOG TIMER   
int WDT_i = 0;                                  // watchdog timer itteration counter for debug
int WDT_last = millis();                        // watchdog timer save current value of millis to start WDT accuratly 

//SENSITIVITY ADJUSTMENT FOR MIC INPUT
int amplitude = 70;                         // amplitude stores the multiplier for the microphone input signal start at 50% can be adjusted by 10K pot or mode button... 
int amplitudeMax = 100;                      // 
int amplitudeMin = 5;                         // defines the minimum value for amplitude... an attempt to stop it from flatlining 
int amplitudePercentage = 50;                 // variables to calucalte ADC as a percentage 
int amplitudePercentage_round = 0;              // place to store the amplitude
int OledDisplayOffsetMin = 100; 
int OledDisplayOffsetMax = 10000; 
int OledDisplayOffset = 100; 

// BEAT DETECTION 
int BeatThreshold = 20; 

unsigned int sampling_period_us;                // variables for FFT calculations 
unsigned long microseconds;
byte peak[] = {0,0,0,0,0,0,0};
double vReal[SAMPLES];
double vImag[SAMPLES];
unsigned long newTime, oldTime;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
  Serial.begin(115200);
  //Wire.begin(5,4); // SDA, SCL
  pinMode(MICROPHONE_INPUT_PIN, INPUT);
  pinMode(POTENTIOMETER_INPUT_PIN, INPUT);

  pinMode(IncreaseButtonPin, INPUT_PULLUP);
  pinMode(ModeButtonPin, INPUT_PULLUP);
  pinMode(DecreaseButtonPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(IncreaseButtonPin), Increase, FALLING);   //CHANGE , RISING , FALLING LOW HIGH
  attachInterrupt(digitalPinToInterrupt(ModeButtonPin), ChangeMode, FALLING);
  attachInterrupt(digitalPinToInterrupt(DecreaseButtonPin), Decrease, FALLING);

  pinMode(OnboardLED, OUTPUT);
  pinMode(ExternalLED, OUTPUT);
  //pinMode(LEDstrip, OUTPUT);

  //FastLED.addLeds<CHIPSET, LEDstripPin, COLOR_ORDER>(leds[0], leds.Size());
  FastLED.addLeds<WS2812B,LEDstripPin , GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(100);
  
  display.init();
  display.setFont(ArialMT_Plain_10);
  display.flipScreenVertically();                         // Adjust to suit or remove
  sampling_period_us = round(1000000 * (1.0 / SAMPLING_FREQUENCY));
  //OledDisplayOffset = (OledDisplayOffsetMax - OledDisplayOffsetMin)/2 ; 


  StartupOK();                                            // acknowlege startup and blink onboard LED
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
  ResetWatchdog();
  digitalWrite(OnboardLED, LOW);                                                          // turn the LED off after watchdog reset turns it on 
  display.clear();

  //Serial.print("amplitude = "); 
  //Serial.println(amplitude); 
  //display.setTextAlignment(TEXT_ALIGN_CENTER);
  //display.drawHorizontalLine(10,30,40);
  //setSensitivity();                                                                     // read pot input, calculate sensitity and display value. NOTE: only use this if 10K pot connected. 
  ChangePattern();                                                                        // select Cycle, single or random and 
  CalculateOLEDoffset();                                                                  // map display values 0-100% to 
  OLEDBrightness();                                                                       // set the brightness of the OLED display
  display_mode();                                                                         // 
  sampleMicInput();                                                                       // read microphone input and populate vReal array with samples. 
  calculateFFT();                                                                         // perform FFT functions 
  drawFFTtoDisplay();                                                                     // draw the VU meter values to display 
  
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// FUNCTIONS 
//////////////////////////////////////////////////////////////////////////////
void calculateFFT(){
  FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
  }

//////////////////////////////////////////////////////////////////////////////
void drawFFTtoDisplay(){                                                            // these values may not be accurate because sample frequency delay 
  for (int i = 2; i < (SAMPLES/2); i++){                                            // Don't use sample 0 and only first SAMPLES/2 are usable. Each array eleement represents a frequency and its value the amplitude.
    if (vReal[i] > 2000) {                                                          // Add a crude noise filter, 10 x amplitude or more
      if (i<=2 )             displayBand(0,(int)vReal[i]/OledDisplayOffset);        // 125Hz
      if (i >3   && i<=5 )   displayBand(1,(int)vReal[i]/OledDisplayOffset);        // 250Hz
      if (i >5   && i<=7 )   displayBand(2,(int)vReal[i]/OledDisplayOffset);        // 500Hz
      if (i >7   && i<=15 )  displayBand(3,(int)vReal[i]/OledDisplayOffset);        // 1000Hz
      if (i >15  && i<=30 )  displayBand(4,(int)vReal[i]/OledDisplayOffset);        // 2000Hz
      if (i >30  && i<=53 )  displayBand(5,(int)vReal[i]/OledDisplayOffset);        // 4000Hz
      if (i >53  && i<=200 ) displayBand(6,(int)vReal[i]/OledDisplayOffset);        // 8000Hz
      //if (i >200           ) displayBand(7,(int)vReal[i]/amplitude);              // 16000Hz // this looks crap on the display so ignore. 
      //Serial.println(i);
    }
    for (byte band = 0; band <= 6; band++){
      display.drawHorizontalLine(18*band,64-peak[band],14);
    }
  }
  if (millis()%2 == 0) {                                                                  // Decay the peak//     if (millis()%4 == 0) {for (byte band = 0; band <= 6; band++) {if (peak[band] > 0) peak[band] -= 1;}} // Decay the peak
    for (byte band = 0; band <= 6; band++) {        
      if (peak[band] > 0) peak[band] -= 1;
      }
    } 
  display.display();
}


//////////////////////////////////////////////////////////////////////////////
//void setSensitivity(){                                                                  //use this if 10K potentiometer added instead of using buttons... 
////  amplitude = analogRead(POTENTIOMETER_INPUT_PIN);                                    // read sensitivity value from 10K potentiometer NOTE: sensitivity could come from mode buttons so comment this out if no pot attached
//
//  amplitudePercentage = 100-((amplitude/4095)*100);                                     // calculate percentage
//  Serial.print("amplitude Percentage = "); 
//  Serial.println(amplitudePercentage); 
//  amplitudePercentage_round = round(amplitudePercentage);                               //round value to integer
//  display.drawString(0, 0, "Sensitivity: " + String(amplitudePercentage_round)+"%");    // print sensitivity 
//  }

//////////////////////////////////////////////////////////////////////////////
void sampleMicInput(){
  for (int i = 0; i < SAMPLES; i++) {
    newTime = micros()-oldTime;
    oldTime = newTime;
    vReal[i] = analogRead(MICROPHONE_INPUT_PIN);                                        // A conversion takes about 1uS on an ESP32
    vImag[i] = 0;
    while (micros() < (newTime + sampling_period_us)) { /* do nothing to wait */ }
  }
}


//////////////////////////////////////////////////////////////////////////////
void displayBand(int band, int dsize){
  int dmax = 50;
  if (dsize > dmax){
    dsize = dmax;
  }
  if (band == 7){
    display.drawHorizontalLine(18*6,0, 14);
  }
  for (int s = 0; s <= dsize; s=s+2){
    display.drawHorizontalLine(18*band,64-s, 14);
  }
  if (dsize > peak[band]) {
    peak[band] = dsize;
  }
}


//////////////////////////////////////////////////////////////////////////////
void ResetWatchdog(){
  if (millis() - WDT_last >= 2000) {                //  if (millis() - WDT_last >= 2000 && WDT_i < 5)
      digitalWrite(OnboardLED, HIGH);                // turn the LED ON
      Serial.println("Resetting WDT... all OK");    // serial print for debug 
      esp_task_wdt_reset();                         //reset the hardware watchdog timer 
      WDT_last = millis();                  
      WDT_i++;
      Serial.print("watchdog count = ");            // serial print for debug 
      Serial.println(WDT_i);                        // serial print for debug 
      if (WDT_i >= 32767) {                        // prevent watchdog counter from overflowing and shooting itself in the foot. 
        WDT_i = 0;                                  // reset to zero 
      }
  }
}

//////////////////////////////////////////////////////////////////////////////
  void StartupOK(){
    for (int X = 0; X < 10; X++){
      digitalWrite(OnboardLED, HIGH);               // turn the INTERNAL LED on 
      digitalWrite(ExternalLED, HIGH);              // turn the  EXTERNAL LED on 
      delay(100);                                   // delay
      digitalWrite(OnboardLED, LOW);                // turn the INTERNAL LED off 
      digitalWrite(ExternalLED, LOW);               // turn the EXTERNAL LED off 
      delay(50);                                    // delay 
    }
  Serial.println("STARTUP OK");                     // serial print for debug 
 }

//////////////////////////////////////////////////////////////////////////////
void Increase(){
  //Serial.println("INCREASE");                     // serial print for debug 
  switch (Mode){
    case 1:                           //mode = sensitivity 
     Pattern++;
      if (Pattern > PatternMax){                                                       // dont let ADC = 0 mess up calculation 
        Pattern = PatternMin;
      }
    break;
    case 2:                           //mode = Pattern 
       PatternMode++;
      if (PatternMode > PatternModeMax){                                                       // dont let ADC = 0 mess up calculation 
        PatternMode = PatternModeMin;
      }
    break;
    case 3:                           //mode = Pattern 
       amplitude = amplitude +5; 
      if (amplitude > amplitudeMax){                                                       // dont let ADC = 0 mess up calculation 
        amplitude = amplitudeMax;
      }
      
    break;
    case 4:                           //mode = Display brightness
      LED_Brightness = LED_Brightness +5;
      if (LED_Brightness > 100){                                                       //  
        LED_Brightness = 100;
      }
    break;
    case 5:                           //mode = LED power
      LEDpower = !LEDpower;
    break;
    case 6:
      OLED_Brightness = OLED_Brightness +5;
      if (OLED_Brightness > 100){                                                       // dont let ADC = 0 mess up calculation 
        OLED_Brightness = 100;
      }
    break;
  }
}

//////////////////////////////////////////////////////////////////////////////
void ChangePattern(){
   switch (PatternMode){
    case 1:                                                         //cycle 
    if(millis() >= time_now + Pattern_period){
      time_now += Pattern_period;
        //Serial.println("Cycle");                                  //serial print for debug 
      Pattern++;
      if (Pattern > PatternMax){
        Pattern = PatternMin; 
      }
    }
    break;
    default: 
    case 2:                                                         //Single 
      //Serial.println("Single");                                   //serial print for debug 
    break;
    case 3:                                                         // Random 
    if(millis() >= time_now + Pattern_period){
      //Serial.println("Random");                                   //serial print for debug 
      time_now += Pattern_period;       
      Pattern = random(PatternMin,PatternMax); 
    }
    break;
   }
}

//////////////////////////////////////////////////////////////////////////////
void ChangeMode(){
  Mode++ ; 
  }

//////////////////////////////////////////////////////////////////////////////
void Decrease(){                                                                        // DECREASE
  //Serial.println("DECREASE");                                                         // serial print for debug 
switch (Mode){
    case 1:                                                   //mode = Pattern  
       Pattern--;
       if (Pattern < PatternMin){                                                       // make sure pattern wraps around and doesnt go negative
          Pattern = PatternMax;
       }   
    break;
    case 2:                                                   //mode =  
    PatternMode--;
      if (PatternMode < PatternModeMin){                                                // make sure pattern wraps around and doesnt go negative
        PatternMode = PatternModeMax;
      } 
    break;
    case 3:                                                   //mode = OLED brightness
      amplitude = amplitude -5;
      if (amplitude < amplitudeMin){                                                    // dont let amplidute overflow to zero 
        amplitude = amplitudeMin;
      }
    break;
    case 4:                                                   //mode = LED brightness
      LED_Brightness = LED_Brightness -5;
      if (LED_Brightness < 0){                                                       
        LED_Brightness = 0;
      }
    break;
    case 5:                                                   //mode = LED power
      LEDpower = !LEDpower;
    break;
    case 6:                                                   //mode = Pattern mode
      OLED_Brightness = OLED_Brightness -5;
      if (OLED_Brightness < 0){                                                      
          OLED_Brightness = 0;
      }
    break;
}
}
//////////////////////////////////////////////////////////////////////////////
void display_mode(){                                                                // MODE

if (Mode > ModeMax) Mode = 1; 
  switch (Mode){
    case 1:                                                                         // CASE 1 - Microphone Sensitivity 
      //Serial.println("MODE = 2");                                             
      display.clear();
      switch(Pattern){
        case 1:
          display.drawString(0, 0, "Pattern: MoveDotLeft"); 
          //MoveDotLeft();                                                           // call pattern 
        break;
        case 2:
          display.drawString(0, 0, "Pattern: Sparkle"); 
        break;
        case 3:
          display.drawString(0, 0, "Pattern: Snake"); 
        break;
        case 4:
          display.drawString(0, 0, "Pattern: Rainbow"); 
        break;
        case 5:
          display.drawString(0, 0, "Pattern: Stuff"); 
        break;
        }

      //display.drawString(0, 0, "Pattern: " + String(Pattern));    
    break; 
    default:
    case 2:                                                                         // CASE 2 - Pattern 
        //Serial.println("MODE = 6");  
      switch (PatternMode){
      case 1:
        display.clear();
        display.drawString(0, 0, "Pattern Mode: Cycle");
      break;
      case 2:
        display.clear();
        display.drawString(0, 0, "Pattern Mode: Single");
      break;
      case 3:
      display.clear();
      display.drawString(0, 0, "Pattern Mode: Random");
      break; 
      } 
    break; 
    case 3:                                                                         // CASE 3 - Display Brightness 
      //Serial.println("MODE = 1");                                             
      display.clear();
      display.drawString(0, 0, "Mic Sensitivity: " + String(amplitude)+"%"); 
    break; 
    case 4:                                                                         // CASE 4 - LED Brightness
      //Serial.println("MODE = 4");                                             
      display.clear();
      display.drawString(0, 0, "LED Brightness: " + String(LED_Brightness)+"%");
    break; 
    case 5:                                                                         // CASE 5 - LEDS ON/OFF
      //Serial.println("MODE = 5");                                             
      display.clear();
      if (LEDpower == true){
        display.drawString(0, 0, "LEDS ON/OFF: ON");
      }else{
        display.drawString(0, 0, "LEDS ON/OFF: OFF");
      }
    break; 
    case 6:
    //Serial.println("MODE = 3");   
      display.clear();
      display.drawString(0, 0, "Display Brightness: " + String(OLED_Brightness)+"%");
    break;
    } 
}

//////////////////////////////////////////////////////////////////////////////
void OLEDBrightness(){
   OledDisplayBrihtnessValue = map(OLED_Brightness,OLED_BrightnessMin,OLED_BrightnessMax,0,255);
  if (OledDisplayBrihtnessValue < 0){
      OledDisplayBrihtnessValue = 0;
    }
  if (OledDisplayBrihtnessValue > 255){
      OledDisplayBrihtnessValue = 255;
    }
  display.setBrightness(OledDisplayBrihtnessValue);
  }

//////////////////////////////////////////////////////////////////////////////
void LEDBrightness(){
    ledDisplayBrihtnessValue= map(100-LED_Brightness,LED_BrightnessMin,LED_BrightnessMax,0,255);
  if (ledDisplayBrihtnessValue < 0){
      ledDisplayBrihtnessValue = 0;
    }
  if (ledDisplayBrihtnessValue > 255){
      ledDisplayBrihtnessValue = 255;
    }
}

//////////////////////////////////////////////////////////////////////////////
void CalculateOLEDoffset(){
   OledDisplayOffset = map(100-amplitude,amplitudeMin,amplitudeMax,OledDisplayOffsetMin,OledDisplayOffsetMax);
  if (OledDisplayOffset < OledDisplayOffsetMin){
      OledDisplayOffset = OledDisplayOffsetMin;
    }
  if (OledDisplayOffset > OledDisplayOffsetMax){
      OledDisplayOffset = OledDisplayOffsetMax;
    }
  }

//////////////////////////////////////////////////////////////////////////////
void MoveDotLeft(){
for(int dot = NUM_LEDS; dot > 0; dot--) { 
            leds[dot] = CRGB::Green;
            FastLED.show();
            // clear this led for the next time around the loop
            leds[dot] = CRGB::Black;
            //delay(100);
        }
}
//////////////////////////////////////////////////////////////////////////////

got some beat detection working but could prpbably use some twaeks…

#include <FastLED.h>
#include <esp_task_wdt.h>                         //https://iotassistant.io/esp32/enable-hardware-watchdog-timer-esp32-arduino-ide/ 
#include <Wire.h>
#include "arduinoFFT.h"                           // Standard Arduino FFT library // https://github.com/kosme/arduinoFFT, 
#include "SSD1306.h"                              // https://github.com/squix78/esp8266-oled-ssd1306
//#include "Button2.h";                           //  https://github.com/LennartHennigs/Button2
//#include "ESPRotary.h";

arduinoFFT FFT = arduinoFFT();


/////////////////////////////////////////////////////////////////////////

// OLED Display
#define SDA 21
#define SCL 22
#define OLED_i2c_address 0x3c
SSD1306 display(OLED_i2c_address,SDA,SCL);                   // 0.96" OLED display object definition (address, SDA, SCL) Connect OLED SDA , SCL pins to ESP SDA, SCL pins

// FFT
#define SAMPLES 512                             // Must be a power of 2 // 512
#define SAMPLING_FREQUENCY 40000                // Hz, must be 40000 or less due to ADC conversion time. Determines maximum frequency that can be analysed by the FFT Fmax=sampleF/2.
//#define amplitude 800                         // Depending on your audio source level, you may need to increase this value 200


// WDT
#define WDT_TIMEOUT 5                           // 3 seconds WDT.  If the code freezes for 3 seconds the hardware watchdog will reset the device. 

// LEDS
#define OnboardLED 2                            // Define the Onbaoard LED for debugging (most likely will blink for watchdog) 
#define ExternalLED 23                          // Define the External LED for debugging and fancy stuff

//FASTLED 
#define LEDstripPin 4                          
#define NUM_LEDS    196
#define COLOR_ORDER    GRB
#define CHIPSET        WS2812B

CRGB leds[NUM_LEDS];
bool LEDpower = true ;                        // LED strip is on by default 

// LED Brightness 
int LED_Brightness = 50;                      // Stores the default brightness of the LED strip 
int LED_BrightnessMin = 0 ;                   // let the brightness vary between 0 and 100% 
int LED_BrightnessMax =100  ; 
int ledDisplayBrihtnessValue = 0;             // variable to store actual LED strip brightness that is mapped from 0-100% 


// ANALOG INPUTS
#define MICROPHONE_INPUT_PIN A0                 // Define microphone input pin ADC 0 
#define POTENTIOMETER_INPUT_PIN A6              // Define microphone input pin ADC 0 

// BUTTON INPUTS
#define IncreaseButtonPin  19
#define ModeButtonPin 18
#define DecreaseButtonPin  5

//// ROTARY ENCODER                             // rotary encoders suck for this application.                           
//#define ROTARY_PIN1  18
//#define ROTARY_PIN2 19
//#define BUTTON_PIN  5
//#define CLICKS_PER_STEP   2                   // this number depends on your rotary encoder 
//ESPRotary Rotary = ESPRotary(ROTARY_PIN1, ROTARY_PIN2, CLICKS_PER_STEP);
//Button2 Rotary_BTN = Button2(BUTTON_PIN);

// MODE 
int Mode = 1;                                 // stores the current mode 
int ModeMax = 6;                              // 1 = sensitivity, 2 = Pattern, 3 = Brightness 

// Pattern selection 
int Pattern = 1;                              // Stores the current Pattern
int PatternMax = 5;                           // adjust this for number of patterns 
int PatternMin = 1;                           // keep this 1 so patterns cycle in a loop 


// timer for pattern mode change 
int Pattern_period = 30000;                   // this is the time period between pattern changes
unsigned long time_now = 0;                   // variable for millis() to store the current time 

// Beat Detection 
int beatspace = 20;                           // stop beat from being triggered continously 
unsigned long LastBeat = 0;                   // variable for millis() to store the current time for beat detection 

// OLED Display brightness 
int OLED_Brightness = 50;                     // sets the default brightness 
int OLED_BrightnessMin = 0 ;                  // let the brightness vary between 0 and 100%   
int OLED_BrightnessMax =100  ; 
int OledDisplayBrihtnessValue = 0;            // variable to store actual value that is mapped from 0-100% 
  
int PatternMode = 1;                          // pattern mode, cycle, single, random
int PatternModeMax = 3;                       
int PatternModeMin = 1; 

// WATCHDOG TIMER   
int WDT_i = 0;                                  // watchdog timer itteration counter for debug
int WDT_last = millis();                        // watchdog timer save current value of millis to start WDT accuratly 

//SENSITIVITY ADJUSTMENT FOR MIC INPUT
int amplitude = 85;                         // amplitude stores the multiplier for the microphone input signal start at 50% can be adjusted by 10K pot or mode button... 
int amplitudeMax = 100;                      // 
int amplitudeMin = 5;                         // defines the minimum value for amplitude... an attempt to stop it from flatlining 
int amplitudePercentage = 50;                 // variables to calucalte ADC as a percentage 
int amplitudePercentage_round = 0;              // place to store the amplitude
int OledDisplayOffsetMin = 100; 
int OledDisplayOffsetMax = 10000; 
int OledDisplayOffset = 100; 

// BEAT DETECTION 
int BeatThreshold = 47; 
bool BeatTrigger = false ; 

unsigned int sampling_period_us;                // variables for FFT calculations 
unsigned long microseconds;
byte peak[] = {0,0,0,0,0,0,0};
double vReal[SAMPLES];
double vImag[SAMPLES];
unsigned long newTime, oldTime;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
  Serial.begin(115200);
  //Wire.begin(5,4); // SDA, SCL
  pinMode(MICROPHONE_INPUT_PIN, INPUT);
  pinMode(POTENTIOMETER_INPUT_PIN, INPUT);

  pinMode(IncreaseButtonPin, INPUT_PULLUP);
  pinMode(ModeButtonPin, INPUT_PULLUP);
  pinMode(DecreaseButtonPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(IncreaseButtonPin), Increase, FALLING);   //CHANGE , RISING , FALLING LOW HIGH
  attachInterrupt(digitalPinToInterrupt(ModeButtonPin), ChangeMode, FALLING);
  attachInterrupt(digitalPinToInterrupt(DecreaseButtonPin), Decrease, FALLING);

  pinMode(OnboardLED, OUTPUT);
  pinMode(ExternalLED, OUTPUT);
  //pinMode(LEDstrip, OUTPUT);

  //FastLED.addLeds<CHIPSET, LEDstripPin, COLOR_ORDER>(leds[0], leds.Size());
  FastLED.addLeds<WS2812B,LEDstripPin , GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(100);
  
  display.init();
  display.setFont(ArialMT_Plain_10);
  display.flipScreenVertically();                         // Adjust to suit or remove
  sampling_period_us = round(1000000 * (1.0 / SAMPLING_FREQUENCY));
  //OledDisplayOffset = (OledDisplayOffsetMax - OledDisplayOffsetMin)/2 ; 


  StartupOK();                                            // acknowlege startup and blink onboard LED
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
  ResetWatchdog();
  digitalWrite(OnboardLED, LOW);                                                          // turn the LED off after watchdog reset turns it on 
  //digitalWrite(ExternalLED, LOW);
  display.clear();

  //Serial.print("amplitude = "); 
  //Serial.println(amplitude); 
  //display.setTextAlignment(TEXT_ALIGN_CENTER);

  //setSensitivity();                                                                     // read pot input, calculate sensitity and display value. NOTE: only use this if 10K pot connected. 
  ChangePattern();                                                                        // select Cycle, single or random and 
  CalculateOLEDoffset();                                                                  // map display values 0-100% to 
  OLEDBrightness();                                                                       // set the brightness of the OLED display
  display_mode();                                                                         // 
  sampleMicInput();                                                                       // read microphone input and populate vReal array with samples. 
  calculateFFT();                                                                         // perform FFT functions 
  drawFFTtoDisplay();                                                                     // draw the VU meter values to display 
  //MoveDotLeft(); 
  //FastLED.show();

  beattrigger();
  
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// FUNCTIONS 
//////////////////////////////////////////////////////////////////////////////
void calculateFFT(){
  FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
  }

//////////////////////////////////////////////////////////////////////////////
void drawFFTtoDisplay(){                                                            // these values may not be accurate because sample frequency delay 
  for (int i = 2; i < (SAMPLES/2); i++){                                            // Don't use sample 0 and only first SAMPLES/2 are usable. Each array eleement represents a frequency and its value the amplitude.
    if (vReal[i] > 2000) {                                                          // Add a crude noise filter, 10 x amplitude or more
      if (i<=2 )             displayBand(0,(int)vReal[i]/OledDisplayOffset);        // 125Hz
      if (i >3   && i<=5 )   displayBand(1,(int)vReal[i]/OledDisplayOffset);        // 250Hz
      if (i >5   && i<=7 )   displayBand(2,(int)vReal[i]/OledDisplayOffset);        // 500Hz
      if (i >7   && i<=15 )  displayBand(3,(int)vReal[i]/OledDisplayOffset);        // 1000Hz
      if (i >15  && i<=30 )  displayBand(4,(int)vReal[i]/OledDisplayOffset);        // 2000Hz
      if (i >30  && i<=53 )  displayBand(5,(int)vReal[i]/OledDisplayOffset);        // 4000Hz
      if (i >53  && i<=200 ) displayBand(6,(int)vReal[i]/OledDisplayOffset);        // 8000Hz
      //if (i >200           ) displayBand(7,(int)vReal[i]/amplitude);              // 16000Hz // this looks crap on the display so ignore. 
      //Serial.println(i);
    }
    for (byte band = 0; band <= 6; band++){
      display.drawHorizontalLine(18*band,64-peak[band],14);
//      Serial.print("BAND = ");                                                    // debugging 
//      Serial.print(band);
//      Serial.print("      Peak = ");
//      Serial.println(peak[band]);
     if (peak[band]>BeatThreshold){
        BeatTrigger = true; 
     }
    }
  }
  if (millis()%2 == 0) {                                                                  // Decay the peak//     if (millis()%4 == 0) {for (byte band = 0; band <= 6; band++) {if (peak[band] > 0) peak[band] -= 1;}} // Decay the peak
    for (byte band = 0; band <= 6; band++) {        
      if (peak[band] > 0) peak[band] -= 1;
      }
    } 
  
  display.drawString(0,7,". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .");        //Display a horizontal dotted line to indicate beat trigger threshold. 
  display.display();
}


//////////////////////////////////////////////////////////////////////////////
//void setSensitivity(){                                                                  //use this if 10K potentiometer added instead of using buttons... 
////  amplitude = analogRead(POTENTIOMETER_INPUT_PIN);                                    // read sensitivity value from 10K potentiometer NOTE: sensitivity could come from mode buttons so comment this out if no pot attached
//
//  amplitudePercentage = 100-((amplitude/4095)*100);                                     // calculate percentage
//  Serial.print("amplitude Percentage = "); 
//  Serial.println(amplitudePercentage); 
//  amplitudePercentage_round = round(amplitudePercentage);                               //round value to integer
//  display.drawString(0, 0, "Sensitivity: " + String(amplitudePercentage_round)+"%");    // print sensitivity 
//  }

//////////////////////////////////////////////////////////////////////////////
void sampleMicInput(){
  for (int i = 0; i < SAMPLES; i++) {
    newTime = micros()-oldTime;
    oldTime = newTime;
    vReal[i] = analogRead(MICROPHONE_INPUT_PIN);                                        // A conversion takes about 1uS on an ESP32
    vImag[i] = 0;
    while (micros() < (newTime + sampling_period_us)) { /* do nothing to wait */ }
  }
}


//////////////////////////////////////////////////////////////////////////////
void displayBand(int band, int dsize){
  int dmax = 50;
  if (dsize > dmax){
    dsize = dmax;
  }
  if (band == 7){
    display.drawHorizontalLine(18*6,0, 14);
  }
  for (int s = 0; s <= dsize; s=s+2){
    display.drawHorizontalLine(18*band,64-s, 14);
  }
  if (dsize > peak[band]) {
    peak[band] = dsize;
  }
}


//////////////////////////////////////////////////////////////////////////////
void ResetWatchdog(){
  if (millis() - WDT_last >= 2000) {                //  if (millis() - WDT_last >= 2000 && WDT_i < 5)
      digitalWrite(OnboardLED, HIGH);                // turn the LED ON
      Serial.println("Resetting WDT... all OK");    // serial print for debug 
      esp_task_wdt_reset();                         //reset the hardware watchdog timer 
      WDT_last = millis();                  
      WDT_i++;
      Serial.print("watchdog count = ");            // serial print for debug 
      Serial.println(WDT_i);                        // serial print for debug 
      if (WDT_i >= 32767) {                        // prevent watchdog counter from overflowing and shooting itself in the foot. 
        WDT_i = 0;                                  // reset to zero 
      }
  }
}

//////////////////////////////////////////////////////////////////////////////
  void StartupOK(){
    for (int X = 0; X < 10; X++){
      digitalWrite(OnboardLED, HIGH);               // turn the INTERNAL LED on 
     
      delay(100);                                   // delay
      digitalWrite(OnboardLED, LOW);                // turn the INTERNAL LED off 
      
      delay(50);                                    // delay 
    }
  Serial.println("STARTUP OK");                     // serial print for debug 
 }

//////////////////////////////////////////////////////////////////////////////
void Increase(){
  //Serial.println("INCREASE");                     // serial print for debug 
  switch (Mode){
    case 1:                           //mode = sensitivity 
     Pattern++;
      if (Pattern > PatternMax){                                                       // dont let ADC = 0 mess up calculation 
        Pattern = PatternMin;
      }
    break;
    case 2:                           //mode = Pattern 
       PatternMode++;
      if (PatternMode > PatternModeMax){                                                       // dont let ADC = 0 mess up calculation 
        PatternMode = PatternModeMin;
      }
    break;
    case 3:                           //mode = Pattern 
       amplitude = amplitude +5; 
      if (amplitude > amplitudeMax){                                                       // dont let ADC = 0 mess up calculation 
        amplitude = amplitudeMax;
      }
      
    break;
    case 4:                           //mode = Display brightness
      LED_Brightness = LED_Brightness +5;
      if (LED_Brightness > 100){                                                       //  
        LED_Brightness = 100;
      }
    break;
    case 5:                           //mode = LED power
      LEDpower = !LEDpower;
    break;
    case 6:
      OLED_Brightness = OLED_Brightness +5;
      if (OLED_Brightness > 100){                                                       // dont let ADC = 0 mess up calculation 
        OLED_Brightness = 100;
      }
    break;
  }
}

//////////////////////////////////////////////////////////////////////////////
void ChangePattern(){
   switch (PatternMode){
    case 1:                                                         //cycle 
    if(millis() >= time_now + Pattern_period){
      time_now += Pattern_period;
        //Serial.println("Cycle");                                  //serial print for debug 
      Pattern++;
      if (Pattern > PatternMax){
        Pattern = PatternMin; 
      }
    }
    break;
    default: 
    case 2:                                                         //Single 
      //Serial.println("Single");                                   //serial print for debug 
    break;
    case 3:                                                         // Random 
    if(millis() >= time_now + Pattern_period){
      //Serial.println("Random");                                   //serial print for debug 
      time_now += Pattern_period;       
      Pattern = random(PatternMin,PatternMax); 
    }
    break;
   }
}

//////////////////////////////////////////////////////////////////////////////
void ChangeMode(){
  Mode++ ; 
  }

//////////////////////////////////////////////////////////////////////////////
void Decrease(){                                                                        // DECREASE
  //Serial.println("DECREASE");                                                         // serial print for debug 
switch (Mode){
    case 1:                                                   //mode = Pattern  
       Pattern--;
       if (Pattern < PatternMin){                                                       // make sure pattern wraps around and doesnt go negative
          Pattern = PatternMax;
       }   
    break;
    case 2:                                                   //mode =  
    PatternMode--;
      if (PatternMode < PatternModeMin){                                                // make sure pattern wraps around and doesnt go negative
        PatternMode = PatternModeMax;
      } 
    break;
    case 3:                                                   //mode = OLED brightness
      amplitude = amplitude -5;
      if (amplitude < amplitudeMin){                                                    // dont let amplidute overflow to zero 
        amplitude = amplitudeMin;
      }
    break;
    case 4:                                                   //mode = LED brightness
      LED_Brightness = LED_Brightness -5;
      if (LED_Brightness < 0){                                                       
        LED_Brightness = 0;
      }
    break;
    case 5:                                                   //mode = LED power
      LEDpower = !LEDpower;
    break;
    case 6:                                                   //mode = Pattern mode
      OLED_Brightness = OLED_Brightness -5;
      if (OLED_Brightness < 0){                                                      
          OLED_Brightness = 0;
      }
    break;
}
}
//////////////////////////////////////////////////////////////////////////////
void display_mode(){                                                                // MODE

if (Mode > ModeMax) Mode = 1; 
  switch (Mode){
    case 1:                                                                         // CASE 1 
      //Serial.println("MODE = 2");                                             
      display.clear();
      switch(Pattern){
        case 1:
          display.drawString(0, 0, "Pattern: MoveDotLeft"); 
          //MoveDotLeft();                                                           // call pattern 
        break;
        case 2:
          display.drawString(0, 0, "Pattern: Sparkle"); 
        break;
        case 3:
          display.drawString(0, 0, "Pattern: Snake"); 
        break;
        case 4:
          display.drawString(0, 0, "Pattern: Rainbow"); 
        break;
        case 5:
          display.drawString(0, 0, "Pattern: Stuff"); 
        break;
        }

      //display.drawString(0, 0, "Pattern: " + String(Pattern));    
    break; 
    default:
    case 2:                                                                         // CASE 2 - Pattern 
        //Serial.println("MODE = 6");  
      switch (PatternMode){
      case 1:
        display.clear();
        display.drawString(0, 0, "Pattern Mode: Cycle");
      break;
      case 2:
        display.clear();
        display.drawString(0, 0, "Pattern Mode: Single");
      break;
      case 3:
      display.clear();
      display.drawString(0, 0, "Pattern Mode: Random");
      break; 
      } 
    break; 
    case 3:                                                                         // CASE 3 - Display Brightness 
      //Serial.println("MODE = 1");                                             
      display.clear();
      display.drawString(0, 0, "Mic Sensitivity: " + String(amplitude)+"%"); 
    break; 
    case 4:                                                                         // CASE 4 - LED Brightness
      //Serial.println("MODE = 4");                                             
      display.clear();
      display.drawString(0, 0, "LED Brightness: " + String(LED_Brightness)+"%");
    break; 
    case 5:                                                                         // CASE 5 - LEDS ON/OFF
      //Serial.println("MODE = 5");                                             
      display.clear();
      if (LEDpower == true){
        display.drawString(0, 0, "LEDS ON/OFF: ON");
      }else{
        display.drawString(0, 0, "LEDS ON/OFF: OFF");
      }
    break; 
    case 6:
    //Serial.println("MODE = 3");   
      display.clear();
      display.drawString(0, 0, "Display Brightness: " + String(OLED_Brightness)+"%");
    break;
    } 
}

//////////////////////////////////////////////////////////////////////////////
void OLEDBrightness(){
   OledDisplayBrihtnessValue = map(OLED_Brightness,OLED_BrightnessMin,OLED_BrightnessMax,0,255);
  if (OledDisplayBrihtnessValue < 0){
      OledDisplayBrihtnessValue = 0;
    }
  if (OledDisplayBrihtnessValue > 255){
      OledDisplayBrihtnessValue = 255;
    }
  display.setBrightness(OledDisplayBrihtnessValue);
  }

//////////////////////////////////////////////////////////////////////////////
void LEDBrightness(){
    ledDisplayBrihtnessValue= map(100-LED_Brightness,LED_BrightnessMin,LED_BrightnessMax,0,255);
  if (ledDisplayBrihtnessValue < 0){
      ledDisplayBrihtnessValue = 0;
    }
  if (ledDisplayBrihtnessValue > 255){
      ledDisplayBrihtnessValue = 255;
    }
}

//////////////////////////////////////////////////////////////////////////////
void CalculateOLEDoffset(){
   OledDisplayOffset = map(100-amplitude,amplitudeMin,amplitudeMax,OledDisplayOffsetMin,OledDisplayOffsetMax);
  if (OledDisplayOffset < OledDisplayOffsetMin){
      OledDisplayOffset = OledDisplayOffsetMin;
    }
  if (OledDisplayOffset > OledDisplayOffsetMax){
      OledDisplayOffset = OledDisplayOffsetMax;
    }
  }

//////////////////////////////////////////////////////////////////////////////
void MoveDotLeft(){
for(int dot = NUM_LEDS; dot > 0; dot--) { 
            leds[dot] = CRGB::Green;
            
            // clear this led for the next time around the loop
            leds[dot] = CRGB::Black;
            //delay(100);
        }
}
//////////////////////////////////////////////////////////////////////////////

void beattrigger(){

      if (BeatTrigger == true && (millis() >= LastBeat + 200)){
       //Serial.println("TRIGGER ON ");                     // serial print for debug 
       digitalWrite(ExternalLED, HIGH);              // turn the  EXTERNAL LED on
       LastBeat = millis(); 
      }
       if (millis() >= LastBeat + 100){//( millis()+50> LastBeat){                                  // delay   
        //Serial.println("TRIGGER OFF ");                     // serial print for debug 
        digitalWrite(ExternalLED, LOW);              // turn the  EXTERNAL LED on        // flash led to indicate beat triger 
        BeatTrigger = false; 
      }


  }

Got some patterns worknig too

#include <FastLED.h>
#include <esp_task_wdt.h>                         //https://iotassistant.io/esp32/enable-hardware-watchdog-timer-esp32-arduino-ide/ 
#include <Wire.h>
#include "arduinoFFT.h"                           // Standard Arduino FFT library // https://github.com/kosme/arduinoFFT, 
#include "SSD1306.h"                              // https://github.com/squix78/esp8266-oled-ssd1306
//#include "Button2.h";                           //  https://github.com/LennartHennigs/Button2
//#include "ESPRotary.h";

arduinoFFT FFT = arduinoFFT();

/////////////////////////////////////////////////////////////////////////

// OLED Display
#define SDA 21
#define SCL 22
#define OLED_i2c_address 0x3c
SSD1306 display(OLED_i2c_address,SDA,SCL);                   // 0.96" OLED display object definition (address, SDA, SCL) Connect OLED SDA , SCL pins to ESP SDA, SCL pins

// FFT
#define SAMPLES 512                             // Must be a power of 2 // 512
#define SAMPLING_FREQUENCY 40000                // Hz, must be 40000 or less due to ADC conversion time. Determines maximum frequency that can be analysed by the FFT Fmax=sampleF/2.
//#define amplitude 800                         // Depending on your audio source level, you may need to increase this value 200

// WDT
#define WDT_TIMEOUT 5                           // 3 seconds WDT.  If the code freezes for 3 seconds the hardware watchdog will reset the device. 

// LEDS
#define OnboardLED 2                            // Define the Onbaoard LED for debugging (most likely will blink for watchdog) 
#define ExternalLED 23                          // Define the External LED for debugging and fancy stuff

//FASTLED 
#define LEDstripPin 4                          
#define NUM_LEDS    196
#define COLOR_ORDER    GRB
#define CHIPSET        WS2812B

CRGB leds[NUM_LEDS];
bool LEDpower = true ;                        // LED strip is on by default 

// LED Brightness 
int LED_Brightness = 50;                      // Stores the default brightness of the LED strip 
int LED_BrightnessMin = 0 ;                   // let the brightness vary between 0 and 100% 
int LED_BrightnessMax =100  ; 
int ledDisplayBrihtnessValue = 0;             // variable to store actual LED strip brightness that is mapped from 0-100% 


// ANALOG INPUTS
#define MICROPHONE_INPUT_PIN A0                 // Define microphone input pin ADC 0 
#define POTENTIOMETER_INPUT_PIN A6              // Define microphone input pin ADC 0 

// BUTTON INPUTS
#define IncreaseButtonPin  19
#define ModeButtonPin 18
#define DecreaseButtonPin  5

//// ROTARY ENCODER                             // rotary encoders suck for this application.                           
//#define ROTARY_PIN1  18
//#define ROTARY_PIN2 19
//#define BUTTON_PIN  5
//#define CLICKS_PER_STEP   2                   // this number depends on your rotary encoder 
//ESPRotary Rotary = ESPRotary(ROTARY_PIN1, ROTARY_PIN2, CLICKS_PER_STEP);
//Button2 Rotary_BTN = Button2(BUTTON_PIN);

// MODE 
int Mode = 1;                                 // stores the current mode 
int ModeMax = 6;                              // 1 = sensitivity, 2 = Pattern, 3 = Brightness 

// Pattern selection 
int Pattern = 1;                              // Stores the current Pattern
int PatternMax = 2;                           // adjust this for number of patterns 
int PatternMin = 1;                           // keep this 1 so patterns cycle in a loop 

// timer for pattern mode change 
int Pattern_period = 30000;                   // this is the time period between pattern changes
unsigned long time_now = 0;                   // variable for millis() to store the current time 

// Beat Detection 
int beatspace = 20;                           // stop beat from being triggered continously 
unsigned long LastBeat = 0;                   // variable for millis() to store the current time for beat detection 

// OLED Display brightness 
int OLED_Brightness = 50;                     // sets the default brightness 
int OLED_BrightnessMin = 0 ;                  // let the brightness vary between 0 and 100%   
int OLED_BrightnessMax =100  ; 
int OledDisplayBrihtnessValue = 0;            // variable to store actual value that is mapped from 0-100% 
  
int PatternMode = 2;                          // pattern mode, cycle, single, random
int PatternModeMax = 3;                       
int PatternModeMin = 1; 

// WATCHDOG TIMER   
unsigned long WDT_i = 0;                                  // watchdog timer itteration counter for debug
unsigned long WDT_last = millis();                        // watchdog timer save current value of millis to start WDT accuratly 

//SENSITIVITY ADJUSTMENT FOR MIC INPUT
int amplitude = 85;                         // amplitude stores the multiplier for the microphone input signal start at 50% can be adjusted by 10K pot or mode button... 
int amplitudeMax = 100;                      // 
int amplitudeMin = 5;                         // defines the minimum value for amplitude... an attempt to stop it from flatlining 
int amplitudePercentage = 50;                 // variables to calucalte ADC as a percentage 
int amplitudePercentage_round = 0;              // place to store the amplitude
int OledDisplayOffsetMin = 100; 
int OledDisplayOffsetMax = 10000; 
int OledDisplayOffset = 100; 

// BEAT DETECTION 
int BeatThreshold = 47; 
bool BeatTrigger = false ; 

unsigned int sampling_period_us;                // variables for FFT calculations 
unsigned long microseconds;
byte peak[] = {0,0,0,0,0,0,0};
double vReal[SAMPLES];
double vImag[SAMPLES];
unsigned long newTime, oldTime;

//pattern stuff
int dot = 0;
bool left = false;

// Colour Gradients 

unsigned long currentTimer = 0; 
unsigned long startTimer = 0; 

// PALETTE 
unsigned long changeInterval = 10000; 
int Palette = 0;
uint8_t paletteIndex =0;


// Gradient palette "Sunset_Real_gp", originally from
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Sunset_Real.png.index.html
// converted for FastLED with gammas (2.6, 2.2, 2.5)
// Size: 28 bytes of program space.

DEFINE_GRADIENT_PALETTE( Sunset_Real_gp ) {
    0, 120,  0,  0,
   22, 179, 22,  0,
   51, 255,104,  0,
   85, 167, 22, 18,
  135, 100,  0,103,
  198,  16,  0,130,
  255,   0,  0,160};


//DEFINE_GRADIENT_PALETTE( Rainbow_gp ) {
//0, 255, 0, 0,       //Red
//21, 255, 0, 0,      //Orange
//62, 255, 255, 0,    //Yellow
//102, 0, 255, 0,     //Green
//143, 0, 0, 255,     //Blue
//184, 75,0, 130,     //Indego
//224, 148,0, 211,    //Violet
//255, 255, 0, 0};   //Red        
//
CRGBPalette16 Sunset(Sunset_Real_gp);
CRGBPalette16 Rainbow(Rainbow_gp);

CRGBPalette16 currentPalette;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
  Serial.begin(115200);
  //Wire.begin(5,4); // SDA, SCL
  pinMode(MICROPHONE_INPUT_PIN, INPUT);
  pinMode(POTENTIOMETER_INPUT_PIN, INPUT);

  pinMode(IncreaseButtonPin, INPUT_PULLUP);
  pinMode(ModeButtonPin, INPUT_PULLUP);
  pinMode(DecreaseButtonPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(IncreaseButtonPin), Increase, FALLING);   //CHANGE , RISING , FALLING LOW HIGH
  attachInterrupt(digitalPinToInterrupt(ModeButtonPin), ChangeMode, FALLING);
  attachInterrupt(digitalPinToInterrupt(DecreaseButtonPin), Decrease, FALLING);

  pinMode(OnboardLED, OUTPUT);
  pinMode(ExternalLED, OUTPUT);
  //pinMode(LEDstrip, OUTPUT);

  //FastLED.addLeds<CHIPSET, LEDstripPin, COLOR_ORDER>(leds[0], leds.Size());
  FastLED.addLeds<WS2812B,LEDstripPin , GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(100);
  
  display.init();
  display.setFont(ArialMT_Plain_10);
  display.flipScreenVertically();                         // Adjust to suit or remove
  sampling_period_us = round(1000000 * (1.0 / SAMPLING_FREQUENCY));
  //OledDisplayOffset = (OledDisplayOffsetMax - OledDisplayOffsetMin)/2 ; 


  FastLED.setBrightness(255);                                      //FANCY STARTUP SEQUENCE TO SHOW LEDS ARE WORKING 
  for (int i = 0; i<= NUM_LEDS-1;i++){
   leds[i] = CRGB::Blue;
   FastLED.show();
   delay(10);
  }
  fill_solid(leds, NUM_LEDS, CRGB( 0, 0, 0));
  FastLED.show();
  FastLED.setBrightness(255);
  StartupOK();                                            // acknowlege startup and blink onboard LED
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
  ResetWatchdog();
  digitalWrite(OnboardLED, LOW);                                                          // turn the LED off after watchdog reset turns it on 
  //digitalWrite(ExternalLED, LOW);
  display.clear();

  //Serial.print("amplitude = "); 
  //Serial.println(amplitude); 
  //display.setTextAlignment(TEXT_ALIGN_CENTER);

  //setSensitivity();                                                                     // read pot input, calculate sensitity and display value. NOTE: only use this if 10K pot connected. 
  ChangePattern();                                                                        // select Cycle, single or random and 
  CalculateOLEDoffset();                                                                  // map display values 0-100% to 
  OLEDBrightness();                                                                       // set the brightness of the OLED display
  display_mode();                                                                         // 
  sampleMicInput();                                                                       // read microphone input and populate vReal array with samples. 
  calculateFFT();                                                                         // perform FFT functions 
  drawFFTtoDisplay();                                                                     // draw the VU meter values to display 
  ChangePalette();
  
  //MoveDotLeft(); 
  //FastLED.show();


  //beattrigger();
  

  
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// FUNCTIONS 
//////////////////////////////////////////////////////////////////////////////
void calculateFFT(){
  FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
  }

//////////////////////////////////////////////////////////////////////////////
void drawFFTtoDisplay(){                                                            // these values may not be accurate because sample frequency delay 
  for (int i = 2; i < (SAMPLES/2); i++){                                            // Don't use sample 0 and only first SAMPLES/2 are usable. Each array eleement represents a frequency and its value the amplitude.
    if (vReal[i] > 2000) {                                                          // Add a crude noise filter, 10 x amplitude or more
      if (i<=2 ){                                               // 125Hz
        displayBand(0,(int)vReal[i]/OledDisplayOffset);
             if (vReal[i]/OledDisplayOffset > BeatThreshold){
        BeatTrigger = true;                                                              
        }
      }
      if (i >3   && i<=5 ){                                     // 250Hz
        displayBand(1,(int)vReal[i]/OledDisplayOffset); 
        if (vReal[i]/OledDisplayOffset > BeatThreshold){
        BeatTrigger = true;                                                              
        }
      }
      if (i >5   && i<=7 ){                                     // 500Hz
        displayBand(2,(int)vReal[i]/OledDisplayOffset);
        if (vReal[i]/OledDisplayOffset > BeatThreshold){
        BeatTrigger = true;                                                              
        }        
      }
      if (i >7   && i<=15 ){                                    // 1000Hz
        displayBand(3,(int)vReal[i]/OledDisplayOffset);  
        if (vReal[i]/OledDisplayOffset > BeatThreshold){
        BeatTrigger = true;                                                              
        }      
      }
      if (i >15  && i<=30 ){                                    // 2000Hz
        displayBand(4,(int)vReal[i]/OledDisplayOffset); 
        if (vReal[i]/OledDisplayOffset > BeatThreshold){
        BeatTrigger = true;                                                              
        }       
      }
      if (i >30  && i<=53 ){                                    // 4000Hz
        displayBand(5,(int)vReal[i]/OledDisplayOffset);  
        if (vReal[i]/OledDisplayOffset > BeatThreshold){
        BeatTrigger = true;                                                              
        }      
      }
      if (i >53  && i<=200 ){                                   // 8000Hz
        displayBand(6,(int)vReal[i]/OledDisplayOffset);  
        if (vReal[i]/OledDisplayOffset > BeatThreshold){
        BeatTrigger = true;                                                              
        }      
      }
    }
    }
//for (int i = 2; i < (SAMPLES/2); i++){                                            // Don't use sample 0 and only first SAMPLES/2 are usable. Each array eleement represents a frequency and its value the amplitude.
//    if (vReal[i] > 2000) {                                                          // Add a crude noise filter, 10 x amplitude or more
//      if (i<=2 )             displayBand(0,(int)vReal[i]/OledDisplayOffset);        // 125Hz
//      if (i >3   && i<=5 )   displayBand(1,(int)vReal[i]/OledDisplayOffset);        // 250Hz
//      if (i >5   && i<=7 )   displayBand(2,(int)vReal[i]/OledDisplayOffset);        // 500Hz
//      if (i >7   && i<=15 )  displayBand(3,(int)vReal[i]/OledDisplayOffset);        // 1000Hz
//      if (i >15  && i<=30 )  displayBand(4,(int)vReal[i]/OledDisplayOffset);        // 2000Hz
//      if (i >30  && i<=53 )  displayBand(5,(int)vReal[i]/OledDisplayOffset);        // 4000Hz
//      if (i >53  && i<=200 ) displayBand(6,(int)vReal[i]/OledDisplayOffset);        // 8000Hz
//      //if (i >200           ) displayBand(7,(int)vReal[i]/amplitude);              // 16000Hz // this looks crap on the display so ignore. 
//      //Serial.println(i);
//    }


    
    for (byte band = 0; band <= 6; band++){
      display.drawHorizontalLine(18*band,64-peak[band],14);
//      Serial.print("BAND = ");                                                    // debugging 
//      Serial.print(band);
//      Serial.print("      Peak = ");
//      Serial.println(peak[band]);
//     if (peak[band]>BeatThreshold){
//        BeatTrigger = true; 
     }
  
  if (millis()%2 == 0) {                                                                  // Decay the peak//     if (millis()%4 == 0) {for (byte band = 0; band <= 6; band++) {if (peak[band] > 0) peak[band] -= 1;}} // Decay the peak
    for (byte band = 0; band <= 6; band++) {        
      if (peak[band] > 0) peak[band] -= 1;
      }
    } 
  
  display.drawString(0,7,". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .");        //Display a horizontal dotted line to indicate beat trigger threshold. 
  display.display();
}


//////////////////////////////////////////////////////////////////////////////
//void setSensitivity(){                                                                  //use this if 10K potentiometer added instead of using buttons... 
////  amplitude = analogRead(POTENTIOMETER_INPUT_PIN);                                    // read sensitivity value from 10K potentiometer NOTE: sensitivity could come from mode buttons so comment this out if no pot attached
//
//  amplitudePercentage = 100-((amplitude/4095)*100);                                     // calculate percentage
//  Serial.print("amplitude Percentage = "); 
//  Serial.println(amplitudePercentage); 
//  amplitudePercentage_round = round(amplitudePercentage);                               //round value to integer
//  display.drawString(0, 0, "Sensitivity: " + String(amplitudePercentage_round)+"%");    // print sensitivity 
//  }

//////////////////////////////////////////////////////////////////////////////
void sampleMicInput(){
  for (int i = 0; i < SAMPLES; i++) {
    newTime = micros()-oldTime;
    oldTime = newTime;
    vReal[i] = analogRead(MICROPHONE_INPUT_PIN);                                        // A conversion takes about 1uS on an ESP32
    vImag[i] = 0;
    while (micros() < (newTime + sampling_period_us)) { /* do nothing to wait */ }
  }
}


//////////////////////////////////////////////////////////////////////////////
void displayBand(int band, int dsize){
  int dmax = 50;
  if (dsize > dmax){
    dsize = dmax;
  }
  if (band == 7){
    display.drawHorizontalLine(18*6,0, 14);
  }
  for (int s = 0; s <= dsize; s=s+2){
    display.drawHorizontalLine(18*band,64-s, 14);
  }
  if (dsize > peak[band]) {
    peak[band] = dsize;
  }
}


//////////////////////////////////////////////////////////////////////////////
void ResetWatchdog(){
  if (millis() - WDT_last >= 2000) {                //  if (millis() - WDT_last >= 2000 && WDT_i < 5)
      digitalWrite(OnboardLED, HIGH);                // turn the LED ON
      //Serial.println("Resetting WDT... all OK");    // serial print for debug 
      esp_task_wdt_reset();                         //reset the hardware watchdog timer 
      WDT_last = millis();                  
      WDT_i++;
      //Serial.print("watchdog count = ");            // serial print for debug 
      //Serial.println(WDT_i);                        // serial print for debug 
      if (WDT_i >= 32767) {                        // prevent watchdog counter from overflowing and shooting itself in the foot. 
        WDT_i = 0;                                  // reset to zero 
      }
  }
}

//////////////////////////////////////////////////////////////////////////////
  void StartupOK(){
    for (int X = 0; X < 10; X++){
      digitalWrite(OnboardLED, HIGH);               // turn the INTERNAL LED on 
     
      delay(100);                                   // delay
      digitalWrite(OnboardLED, LOW);                // turn the INTERNAL LED off 
      
      delay(50);                                    // delay 
    }
  Serial.println("STARTUP OK");                     // serial print for debug 
 }

//////////////////////////////////////////////////////////////////////////////
void Increase(){
  //Serial.println("INCREASE");                     // serial print for debug 
  switch (Mode){
    case 1:                                         //mode = sensitivity 
     Pattern++;
      if (Pattern > PatternMax){                    // dont let ADC = 0 mess up calculation 
        Pattern = PatternMin;
      }
    break;
    case 2:                                         //mode = Pattern 
       PatternMode++;
      if (PatternMode > PatternModeMax){            // dont let ADC = 0 mess up calculation 
        PatternMode = PatternModeMin;
      }
    break;
    case 3:                                         //mode = Pattern 
       amplitude = amplitude +5; 
      if (amplitude > amplitudeMax){                // dont let ADC = 0 mess up calculation 
        amplitude = amplitudeMax;
      }
      
    break;
    case 4:                                        //mode = Display brightness
      LED_Brightness = LED_Brightness +5;
      if (LED_Brightness > 100){                   //  
        LED_Brightness = 100;
      }
    break;
    case 5:                                       //mode = LED power
      LEDpower = !LEDpower;
    break;
    case 6:
      OLED_Brightness = OLED_Brightness +5;
      if (OLED_Brightness > 100){                 // 
        OLED_Brightness = 100;
      }
    break;
  }
}

//////////////////////////////////////////////////////////////////////////////
void ChangePattern(){
   switch (PatternMode){
    case 1:                                                         //cycle 
    if(millis() >= time_now + Pattern_period){
      time_now += Pattern_period;
        //Serial.println("Cycle");                                  //serial print for debug 
      Pattern++;
      if (Pattern > PatternMax){
        Pattern = PatternMin; 
      }
    }
    break;
    default: 
    case 2:                                                         //Single 
      //Serial.println("Single");                                   //serial print for debug 
    break;
    case 3:                                                         // Random 
    if(millis() >= time_now + Pattern_period){
      //Serial.println("Random");                                   //serial print for debug 
      time_now += Pattern_period;       
      Pattern = random(PatternMin,PatternMax); 
    }
    break;
   }
}

//////////////////////////////////////////////////////////////////////////////
void ChangeMode(){
  Mode++ ; 
  }

//////////////////////////////////////////////////////////////////////////////
void Decrease(){                                                                        // DECREASE
  //Serial.println("DECREASE");                                                         // serial print for debug 
switch (Mode){
    case 1:                                                   //mode = Pattern  
       Pattern--;
       if (Pattern < PatternMin){                                                       // make sure pattern wraps around and doesnt go negative
          Pattern = PatternMax;
       }   
    break;
    case 2:                                                   //mode =  
    PatternMode--;
      if (PatternMode < PatternModeMin){                                                // make sure pattern wraps around and doesnt go negative
        PatternMode = PatternModeMax;
      } 
    break;
    case 3:                                                   //mode = OLED brightness
      amplitude = amplitude -5;
      if (amplitude < amplitudeMin){                                                    // dont let amplidute overflow to zero 
        amplitude = amplitudeMin;
      }
    break;
    case 4:                                                   //mode = LED brightness
      LED_Brightness = LED_Brightness -5;
      if (LED_Brightness < 0){                                                       
        LED_Brightness = 0;
      }
    break;
    case 5:                                                   //mode = LED power
      LEDpower = !LEDpower;
    break;
    case 6:                                                   //mode = Pattern mode
      OLED_Brightness = OLED_Brightness -5;
      if (OLED_Brightness < 0){                                                      
          OLED_Brightness = 0;
      }
    break;
}
}
//////////////////////////////////////////////////////////////////////////////
void display_mode(){                                                                // MODE

if (Mode > ModeMax) Mode = 1; 
  switch (Mode){
    case 1:                                                                         // CASE 1 
      //Serial.println("MODE = 2");                                             
      display.clear();
      switch(Pattern){
        case 1:
          display.drawString(0, 0, "Pattern: Rainbow Strobe"); 
          //Snake();
          RainbowStrobe();                                                         // call pattern 
  
        break;
        case 2:
          display.drawString(0, 0, "Pattern: Paintball"); 
          Paintball();
        break;
        case 3:
          display.drawString(0, 0, "Pattern: Snake"); 
          
        break;
        case 4:
          display.drawString(0, 0, "Pattern: Pulse"); 
        break;
        case 5:
          display.drawString(0, 0, "Pattern: Fire"); 
        break;
        }

      //display.drawString(0, 0, "Pattern: " + String(Pattern));    
    break; 
    default:
    case 2:                                                                         // CASE 2 - Pattern 
        //Serial.println("MODE = 6");  
      switch (PatternMode){
      case 1:
        display.clear();
        display.drawString(0, 0, "Pattern Mode: Cycle");
      break;
      case 2:
        display.clear();
        display.drawString(0, 0, "Pattern Mode: Single");
      break;
      case 3:
      display.clear();
      display.drawString(0, 0, "Pattern Mode: Random");
      break; 
      } 
    break; 
    case 3:                                                                         // CASE 3 - Display Brightness 
      //Serial.println("MODE = 1");                                             
      display.clear();
      display.drawString(0, 0, "Mic Sensitivity: " + String(amplitude)+"%"); 
    break; 
    case 4:                                                                         // CASE 4 - LED Brightness
      //Serial.println("MODE = 4");                                             
      display.clear();
      display.drawString(0, 0, "LED Brightness: " + String(LED_Brightness)+"%");
    break; 
    case 5:                                                                         // CASE 5 - LEDS ON/OFF
      //Serial.println("MODE = 5");                                             
      display.clear();
      if (LEDpower == true){
        display.drawString(0, 0, "LEDS ON/OFF: ON");
      }else{
        display.drawString(0, 0, "LEDS ON/OFF: OFF");
      }
    break; 
    case 6:
    //Serial.println("MODE = 3");   
      display.clear();
      display.drawString(0, 0, "Display Brightness: " + String(OLED_Brightness)+"%");
    break;
    } 
}

//////////////////////////////////////////////////////////////////////////////
void OLEDBrightness(){
   OledDisplayBrihtnessValue = map(OLED_Brightness,OLED_BrightnessMin,OLED_BrightnessMax,0,255);
  if (OledDisplayBrihtnessValue < 0){
      OledDisplayBrihtnessValue = 0;
    }
  if (OledDisplayBrihtnessValue > 255){
      OledDisplayBrihtnessValue = 255;
    }
  display.setBrightness(OledDisplayBrihtnessValue);
  }

//////////////////////////////////////////////////////////////////////////////
void LEDBrightness(){
    ledDisplayBrihtnessValue= map(100-LED_Brightness,LED_BrightnessMin,LED_BrightnessMax,0,255);
  if (ledDisplayBrihtnessValue < 0){
      ledDisplayBrihtnessValue = 0;
    }
  if (ledDisplayBrihtnessValue > 255){
      ledDisplayBrihtnessValue = 255;
    }
}

//////////////////////////////////////////////////////////////////////////////
void CalculateOLEDoffset(){
   OledDisplayOffset = map(100-amplitude,amplitudeMin,amplitudeMax,OledDisplayOffsetMin,OledDisplayOffsetMax);
  if (OledDisplayOffset < OledDisplayOffsetMin){
      OledDisplayOffset = OledDisplayOffsetMin;
    }
  if (OledDisplayOffset > OledDisplayOffsetMax){
      OledDisplayOffset = OledDisplayOffsetMax;
    }
  }

//////////////////////////////////////////////////////////////////////////////
void Paintball(){
  int randomLED = random8(0,NUM_LEDS-1);
  int randomColor = random8();
  int paintballWidth = 5;
  int paintballBrightness = 255;
  int Fadetime = 40;
  float spreadmultiplier = 0.8;
  
  if (BeatTrigger == true ){ 
    leds[randomLED] = ColorFromPalette(currentPalette,randomColor,paintballBrightness,LINEARBLEND);
      for(int i = 1; i < paintballWidth; i++){
        if ((randomLED-i < 0+paintballWidth) ||(randomLED+i > NUM_LEDS-paintballWidth)){
                    //do nothing so it doesnt overflow leds array 
        }else{
          leds[randomLED-i] = ColorFromPalette(currentPalette,randomColor,paintballBrightness,LINEARBLEND);
          leds[randomLED+i] = ColorFromPalette(currentPalette,randomColor,paintballBrightness,LINEARBLEND);
          paintballBrightness = paintballBrightness*spreadmultiplier ;
        }
      } 
  BeatTrigger = false;
  }
  fadeToBlackBy(leds,NUM_LEDS,Fadetime);
  FastLED.show();
  }

//////////////////////////////////////////////////////////////////////////////
void RainbowStrobe(){
  int randomLED = random8(0,NUM_LEDS-1);
  int StrobeWidth =2;

fill_palette(leds, NUM_LEDS, paletteIndex, 255/NUM_LEDS,Rainbow,100,LINEARBLEND); 
if (BeatTrigger == true ){ 
  leds[randomLED] = CHSV(100, 0, 255);
  for(int i = 1; i < StrobeWidth; i++){
        if ((randomLED-i < 0+ StrobeWidth) ||(randomLED+i > NUM_LEDS-StrobeWidth)){
                    //do nothing so it doesnt overflow leds array 
        }else{
          leds[randomLED-i] = CHSV(100, 0, 255);
          leds[randomLED+i] = CHSV(100, 0, 255);
        }
      } 
  BeatTrigger = false;
}
EVERY_N_MILLISECONDS(2){
  paletteIndex++;
}

FastLED.show();
  
}
//////////////////////////////////////////////////////////////////////////////
void Snake(){
int TailLength = 40;
int SnakeHead = 0;
int Fadetime = 100;

if (BeatTrigger == true ){ 
  left = !left;
}
for(int dot = 0;dot < NUM_LEDS; dot++)
fill_palette(leds, TailLength, SnakeHead, 255/NUM_LEDS,currentPalette,255,LINEARBLEND); 

 
EVERY_N_MILLISECONDS(2){
  SnakeHead++;
  }
fadeToBlackBy(leds,NUM_LEDS,Fadetime);
FastLED.show();
}
//////////////////////////////////////////////////////////////////////////////













void MoveDotRight(){
        
         if (BeatTrigger == true ){  //         if (BeatTrigger == true && (millis() >= LastBeat + 1)){
            leds[dot] = CRGB::Green; 
            dot++;
            Serial.println(dot);
            if (dot == NUM_LEDS){
              dot = 0; 
              fill_solid(leds, NUM_LEDS, CRGB::Black);
              //FastLED.show();
              }
            }
            FastLED.show();
            BeatTrigger = false;
                                                  //LastBeat = millis(); 
              
  }



///////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////

void beattrigger(){                                                           // debug function to blink an external LED to to the beat.( i say beat loosly) 
      if (BeatTrigger == true && (millis() >= LastBeat + 100)){               // test if beat has been detected and add a small delay so the tirgger isnt too fast.
       //Serial.println("TRIGGER ON ");                                       // serial print for debug 
       digitalWrite(ExternalLED, HIGH);                                       // turn the  EXTERNAL LED ON
       LastBeat = millis(); 
      }
       if (millis() >= LastBeat + 150){                                       //( millis()+50> LastBeat){                                  // delay   
        //Serial.println("TRIGGER OFF ");                                     // serial print for debug 
        digitalWrite(ExternalLED, LOW);                                       // turn the  EXTERNAL LED OFF        // flash led to indicate beat triger 
        BeatTrigger = false;                                                  // reset the flag to false 
      }
  }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ChangePalette(){
switch (Palette) //more info here: https://github.com/FastLED/FastLED/blob/master/colorpalettes.cpp
  {
  case 0:   currentPalette = LavaColors_p;          break;  // orange, red, black and yellow), 
  case 1:   currentPalette = CloudColors_p;         break;  // blue and white
  case 2:   currentPalette = OceanColors_p;         break;  // blue, cyan and white
  case 3:   currentPalette = ForestColors_p;        break;  // greens and blues
  case 4:   currentPalette = RainbowColors_p;       break;  // standard rainbow animation
  case 5:   currentPalette = RainbowStripeColors_p; break;  // single colour, black space, next colour and so forth
  case 6:   currentPalette = PartyColors_p;         break;  // red, yellow, orange, purple and blue
  case 7:   currentPalette = HeatColors_p;          break;  // red, orange, yellow and white
  }

  currentTimer = millis();
  if (currentTimer - startTimer >= changeInterval)
  {
    startTimer = millis();
    if(Palette >7)
      {Palette = 0;}
    else
      {++Palette;}
  }

}
///////////////////////////////////////////////////////////////////////////////////////////////