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.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.