Control Surface Library - need help with banks - CC and PC Buttons with LEDs

Hello there. I have built a Midi Foot Controller and would like to use banks with the Control Surface library, which is really great. Here is my current code with 4 CC Buttons and 4 PC Buttons, each with LED. Two LCD screens are also there to show static text (effects or presets).

//LCD
#include <Wire.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header

//hd44780_I2Cexp lcd; // declare lcd object: auto locate & auto config expander chip

hd44780_I2Cexp lcd1(0x26);
hd44780_I2Cexp lcd2(0x27);

const int LCD_COLS = 16;
const int LCD_ROWS = 4;

//Control Surface Buttons

#include <Control_Surface.h> // Include the Control Surface library

// Instantiate a MIDI over USB interface
USBMIDI_Interface midi;

// Instantiate a program changer with 8 programs
ProgramChanger<4> programChanger = {
  {
    MIDI_PC::program_1, // list of programs
    MIDI_PC::program_2,
    MIDI_PC::program_3,
    MIDI_PC::program_4,
},
  CHANNEL_1, // MIDI channel to use
};

// Instantiate a selector that reads eight buttons and controls the program
// changer. {Button PINs} {LED PINs} 
ManyButtonsSelectorLEDs<4> programSelector = {
  programChanger,
  {{0, 1, 2, 3}},
  {{11, 12, 13, 14}},
};


// Instantiate an array of CCButton objects that send MIDI control
// change messages whenever the button is pressed/released
CCButton buttons[] {
  {4, 89},
  {8, 90},
  {9, 91},
  {10, 92},
  };
// Create an array of CCValueLED objects that turn on/off an LED
// depending on the MIDI control change messages they receive
CCValueLED leds[] {
  {15, 89},
  {16, 90},
  {17, 91},
  {18, 92},  
  };


// Ignore the name “increment” button, it's simply a button
// class that can detect long and short presses.
IncrementButton btn { 0 }; // pin number of button

void setup() {
  Control_Surface.begin(); // Initialize Control Surface
int status;

  // initialize LCD with number of columns and rows: 
  
  status = lcd1.begin(LCD_COLS, LCD_ROWS);
  status = lcd2.begin(LCD_COLS, LCD_ROWS);
 
  // Print a message to the LCD
   lcd1.print("DELAY         OD(Tuner)                                 Preset1  Preset2");
   lcd2.print("CHORUS    PHASER                                        Preset3  Preset4");
}

void loop() {
  Control_Surface.loop(); // Update the Control Surface

//Longpress Button CC
switch (btn.update()) {
    
    case IncrementButton::IncrementLong: // If button is still pressed after some time
      Control_Surface.sendCC(93, 127); break;
  }
}

Next thing I wanted to implement are banks (for example 4). I tried a lot with the current examples of the library, but did not get it how to integrate it.

The banks should be use increment decrement with the pins 3 and 10. They are already in use, so I would like to change banks by holding a button long (2 sec.).

And the LCD screen should show another text when switching to bank 2, 3 and 4.

Maybe someone can help. The builder of the library helped me a lot in the past and I was very thankful. Have a good day.

Here is an attempt to program a bank for CC Buttons. I don't get it to work properly.

#include <Wire.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header

//hd44780_I2Cexp lcd; // declare lcd object: auto locate & auto config expander chip

hd44780_I2Cexp lcd1(0x27);
hd44780_I2Cexp lcd2(0x26);

const int LCD_COLS = 16;
const int LCD_ROWS = 4;


#include <Control_Surface.h> // Include the Control Surface library
 
USBMIDI_Interface midi; // Instantiate a MIDI over USB interface.


// Instantiate four Banks, with two tracks per bank. 
// Compare these numbers to the diagram above.
Bank<4> bank(2);
//   │       └───── number of tracks per bank
//   └───────────── number of banks

// Instantiate a Bank selector to control which one of the four Banks is active.
IncrementDecrementSelector<4> selector = {
    bank,       // Bank to manage
    {3, 10},     // push button pins (increment, decrement)
    Wrap::Wrap, // Wrap around
};


// Instantiate an array of CCButton objects that send MIDI control
// change messages whenever the button is pressed/released
Bankable::CCButton button1 = { bank,
  0, 1           // button pin number, controller number
   };
Bankable::CCButton button2 = { bank,
  1, 2           // button pin number, controller number
   };
Bankable::CCButton button3 = { bank,
  2, 3           // button pin number, controller number
   };
Bankable::CCButton button4 = { bank,
  4, 4           // button pin number, controller number
  };  
Bankable::CCButton button5 = { bank,
  8, 5           // button pin number, controller number
  };
Bankable::CCButton button6 = { bank,
  9, 6           // button pin number, controller number
  };

// Create an array of CCValueLED objects that turn on/off an LED
// depending on the MIDI control change messages they receive
CCValueLED led1 = {      // LED 1, Bank 1
  11, 1                  // LED pin number, controller number             
  };
CCValueLED led2 = {      // LED 2, Bank 1
  12, 2
  };
CCValueLED led3 = {      // LED 3, Bank 1
  13, 3                             
  };
CCValueLED led4 = {      // LED 4, Bank 1
  15, 4
  };
CCValueLED led5 = {      // LED 5, Bank 1
  16, 5                            
  };
CCValueLED led6 = {      // LED 6, Bank 1
  17, 6
  };


CCValueLED led7 = {      // LED 1, Bank 2
  11, 7
  };
CCValueLED led8 = {      // LED 2, Bank 2
  12, 8
  };
CCValueLED led9 = {      // LED 3, Bank 2
  13, 9                         
  };
CCValueLED led10 = {      // LED 4, Bank 2
  15, 10
  };
CCValueLED led11 = {      // LED 5, Bank 2
  16, 11                            
  };
CCValueLED led12 = {      // LED 6, Bank 2
  17, 12
  };


// Instantiate a CCPotentiometer object
CCPotentiometer potentiometer[] = {
  {A0,0x10},                                   // Analog pin connected to potentiometer
  {MIDI_CC::Channel_Volume, CHANNEL_1}, // Channel volume of channel 1
  {A1,0x11},
  {MIDI_CC::Channel_Volume, CHANNEL_1}, // Channel volume of channel 1
  {A11, 0x12},
  {MIDI_CC::Channel_Volume, CHANNEL_1}, // Channel volume of channel 1
      };


void setup() {
  Control_Surface.begin(); // Initialize Control Surface


  int status;

  // initialize LCD with number of columns and rows: 
  // hd44780 returns a status from begin() that can be used
  // to determine if initalization failed.
  // the actual status codes are defined in <hd44780.h>
  // See the values RV_XXXX
  //
  // looking at the return status from begin() is optional
  // it is being done here to provide feedback should there be an issue
  //
  // note:
  //  begin() will automatically turn on the backlight
  //
  status = lcd1.begin(LCD_COLS, LCD_ROWS);
  status = lcd2.begin(LCD_COLS, LCD_ROWS);
  //if(status) // non zero status means it was unsuccesful

  
  {
    // hd44780 has a fatalError() routine that blinks an led if possible
    // begin() failed so blink error code using the onboard LED if possible
    //hd44780::fatalError(status); // does not return
  }

  // initalization was successful, the backlight should be on now

  // Print a message to the LCD
   lcd2.print("CHORUS    PHASER                                        DELAY 1  DELAY 2");
   lcd1.print("FLANGER  TREMOLO                                        OD     CW Filter");
}
 
void loop() {
  Control_Surface.loop(); // Update the Control Surface
}

I am sure this is not correct and can be done easier. The problem I get is, when I am switching effects, the LED don't show the correct thing. I have an effect set on bank 1 pin 0 and and another effect on bank 2 pin 0. When the effect on both banks are on and I am changing presets, the LED goes off instead of staying on like it should.

I think I answered most of your questions in your other thread: Could not figure out midi receive - help! - #39 by PieterP

It might be worth noting that most of the high-level classes included with Control Surface are relatively simple, so if you want custom behavior like long presses etc. you can easily call the low-level functions yourself. For example, this is the (trivial) implementation of ProgramChanger:

You can call bank.getSelection() in the loop and use that to update your display accordingly.