Control-Surface
Control-Surface copied to clipboard
Need help for bank buttons & pots
Hi, i need you help for make code of this midi controller
But i have the 16 buttons and 4 pots + 1 bank changed button like this, i don't know how to code with banks of button & pot like this explain
Best regards
If I understand your question correctly, this should work:
#include <Control_Surface.h>
// Helper for using multiple banks with different offsets with
// a single selector.
template <setting_t N, size_t M>
struct MultiBank : public Selectable<N> {
MultiBank(const Array<Bank<N>, M> &banks) : banks(banks) {}
void select(setting_t bankSetting) override {
for (auto &bank : banks)
bank.select(bankSetting);
}
Bank<N> &operator[](size_t i) { return banks[i]; }
const Bank<N> &operator[](size_t i) const { return banks[i]; }
Array<Bank<N>, M> banks;
};
// Two times 4 banks, one has an offset of 4, because the addresses
// of the potentiometers go up by 4 for each bank, and the other has
// an offset of 8, because the addresses of the buttons go up by 8
// for each bank.
MultiBank<4, 2> banks = {{ 4, 8 }};
// The small back button. When pressed, it allows you to change the
// bank by pressing one of the 4 first colored buttons.
Button bankButton = 11;
// The main selector, just selects the bank of the button that's
// pressed.
ManyButtonsSelector<4> selector = {banks, {2, 3, 4, 5}};
Bankable::CCPotentiometer knobs[] = {
{banks[0], A0, 102},
{banks[0], A1, 103},
{banks[0], A2, 104},
{banks[0], A3, 105},
};
Bankable::NoteButton buttons[] = {
{banks[1], 2, 52}, // Note that the first 4 NoteButtons use the
{banks[1], 3, 53}, // same pins as the bank selector
{banks[1], 4, 54},
{banks[1], 5, 55},
{banks[1], 6, 56},
{banks[1], 7, 57},
{banks[1], 8, 58},
{banks[1], 9, 59},
};
USBMIDI_Interface midi;
void setup() {
bankButton.begin();
Control_Surface.begin();
// Disable the bank selector, by default the buttons are used for
// the NoteButtons
Selector<4>::disable(selector);
}
void loop() {
if (bankButton.update() == Button::Falling) {
// If the small button is pressed, disable the NoteButtons, and
// use the buttons to select the bank by enabling the selector.
Bankable::NoteButton::disable(buttons);
ManyButtonsSelector<4>::enable(selector);
} else if (bankButton.getState() == Button::Rising) {
// If the small button is released, do the reverse, disable the
// selector and enable the NoteButtons again.
ManyButtonsSelector<4>::disable(selector);
Bankable::NoteButton::enable(buttons);
}
Control_Surface.loop();
}
If I understand your question correctly, this should work:
#include <Control_Surface.h> // Helper for using multiple banks with different offsets with // a single selector. template <setting_t N, size_t M> struct MultiBank : public Selectable<N> { MultiBank(const Array<Bank<N>, M> &banks) : banks(banks) {} void select(setting_t bankSetting) override { for (auto &bank : banks) bank.select(bankSetting); } Bank<N> &operator[](size_t i) { return banks[i]; } const Bank<N> &operator[](size_t i) const { return banks[i]; } Array<Bank<N>, M> banks; }; // Two times 4 banks, one has an offset of 4, because the addresses // of the potentiometers go up by 4 for each bank, and the other has // an offset of 8, because the addresses of the buttons go up by 8 // for each bank. MultiBank<4, 2> banks = {{ 4, 8 }}; // The small back button. When pressed, it allows you to change the // bank by pressing one of the 4 first colored buttons. Button bankButton = 11; // The main selector, just selects the bank of the button that's // pressed. ManyButtonsSelector<4> selector = {banks, {2, 3, 4, 5}}; Bankable::CCPotentiometer knobs[] = { {banks[0], A0, 102}, {banks[0], A1, 103}, {banks[0], A2, 104}, {banks[0], A3, 105}, }; Bankable::NoteButton buttons[] = { {banks[1], 2, 52}, // Note that the first 4 NoteButtons use the {banks[1], 3, 53}, // same pins as the bank selector {banks[1], 4, 54}, {banks[1], 5, 55}, {banks[1], 6, 56}, {banks[1], 7, 57}, {banks[1], 8, 58}, {banks[1], 9, 59}, }; USBMIDI_Interface midi; void setup() { bankButton.begin(); Control_Surface.begin(); // Disable the bank selector, by default the buttons are used for // the NoteButtons Selector<4>::disable(selector); } void loop() { if (bankButton.update() == Button::Falling) { // If the small button is pressed, disable the NoteButtons, and // use the buttons to select the bank by enabling the selector. Bankable::NoteButton::disable(buttons); ManyButtonsSelector<4>::enable(selector); } else if (bankButton.getState() == Button::Rising) { // If the small button is released, do the reverse, disable the // selector and enable the NoteButtons again. ManyButtonsSelector<4>::disable(selector); Bankable::NoteButton::enable(buttons); } Control_Surface.loop(); }
I use the arduino uno with button matrix method to save the pinout, can you update the code for matrix 4x4, thanks you!
You cannot use this approach with button matrices, you'd have to roll your own matrix scanning code. I'll see if I can add ExtIO support for button matrices, but I don't have much time.
You cannot use this approach with button matrices, you'd have to roll your own matrix scanning code. I'll see if I can add ExtIO support for button matrices, but I don't have much time.
The arduino mega too big,if you have free time pls update it, i'm making the wood case for matrix ^^, aslo thank you for support me all time!
Oh the pots and buttons like this @tttapa
You cannot use this approach with button matrices, you'd have to roll your own matrix scanning code. I'll see if I can add ExtIO support for button matrices, but I don't have much time.
I really need the matrcies for arduino uno, can you update the library, because the digital and analog pinout are full if not use matrix buttons :(

You could try something like this:
ScanningMatrix.zip
Add it to your src/AH/Hardware/ExtendedInputOutput folder and #include it in your sketch.
You could try something like this:
Add it to your
src/AH/Hardware/ExtendedInputOutputfolder and #include it in your sketch.
Thank you! Can you update the code for 16 buttons matrices bank with this library?
You can just use it like the other ExtendedInputOutput elements, create an instance of ScanningMatrix, and pass its pins to the Bankable::NoteButton constructor.
ScanningMatrix<4, 2> matrix {
{2, 3, 4, 5}, // row pins
{6, 7}, // column pins
};
Bankable::NoteButton buttons[] = {
{banks[1], matrix.pin(0), 52}, // Note that the first 4 NoteButtons use the
{banks[1], matrix.pin(1), 53}, // same pins as the bank selector
{banks[1], matrix.pin(2), 54},
{banks[1], matrix.pin(3), 55},
// ...
};
You could add a function to the ScanningMatrix to get the pin given a row and column index, instead of a single linear index.
You can just use it like the other ExtendedInputOutput elements, create an instance of
ScanningMatrix, and pass its pins to theBankable::NoteButtonconstructor.ScanningMatrix<4, 2> matrix { {2, 3, 4, 5}, // row pins {6, 7}, // column pins }; Bankable::NoteButton buttons[] = { {banks[1], matrix.pin(0), 52}, // Note that the first 4 NoteButtons use the {banks[1], matrix.pin(1), 53}, // same pins as the bank selector {banks[1], matrix.pin(2), 54}, {banks[1], matrix.pin(3), 55}, // ... };You could add a function to the
ScanningMatrixto get the pin given a row and column index, instead of a single linear index.
Oh i got it, also thank you for this feauture, Is that right for 16 buttons? here is my code `ScanningMatrix<4, 4> matrix { {2, 3, 4, 5}, // row pins {6, 7, 8, 9}, // column pins };
Bankable::NoteButton buttons[] = { {banks[0], matrix.pin(0), 36}, // Note that the first 4 NoteButtons use the {banks[0], matrix.pin(1), 37}, // same pins as the bank selector {banks[0], matrix.pin(2), 38}, {banks[0], matrix.pin(3), 39},
{banks[0], matrix.pin(4), 40}, {banks[0], matrix.pin(5), 41}, // Note that the first 4 NoteButtons use the {banks[0], matrix.pin(6), 42}, // same pins as the bank selector {banks[0], matrix.pin(7), 43},
{banks[0], matrix.pin(8), 44}, {banks[0], matrix.pin(9), 45}, {banks[0], matrix.pin(10), 46}, // Note that the first 4 NoteButtons use the {banks[0], matrix.pin(11), 47},
{banks[0], matrix.pin(12), 48}, {banks[0], matrix.pin(13), 49}, {banks[0], matrix.pin(14), 50}, {banks[0], matrix.pin(15), 51},
};`
You can just use it like the other ExtendedInputOutput elements, create an instance of
ScanningMatrix, and pass its pins to theBankable::NoteButtonconstructor.ScanningMatrix<4, 2> matrix { {2, 3, 4, 5}, // row pins {6, 7}, // column pins }; Bankable::NoteButton buttons[] = { {banks[1], matrix.pin(0), 52}, // Note that the first 4 NoteButtons use the {banks[1], matrix.pin(1), 53}, // same pins as the bank selector {banks[1], matrix.pin(2), 54}, {banks[1], matrix.pin(3), 55}, // ... };You could add a function to the
ScanningMatrixto get the pin given a row and column index, instead of a single linear index.Oh i got it, also thank you for this feauture, Is that right for 16 buttons? here is my code `ScanningMatrix<4, 4> matrix { {2, 3, 4, 5}, // row pins {6, 7, 8, 9}, // column pins };
Bankable::NoteButton buttons[] = { {banks[0], matrix.pin(0), 36}, // Note that the first 4 NoteButtons use the {banks[0], matrix.pin(1), 37}, // same pins as the bank selector {banks[0], matrix.pin(2), 38}, {banks[0], matrix.pin(3), 39},
{banks[0], matrix.pin(4), 40}, {banks[0], matrix.pin(5), 41}, // Note that the first 4 NoteButtons use the {banks[0], matrix.pin(6), 42}, // same pins as the bank selector {banks[0], matrix.pin(7), 43},
{banks[0], matrix.pin(8), 44}, {banks[0], matrix.pin(9), 45}, {banks[0], matrix.pin(10), 46}, // Note that the first 4 NoteButtons use the {banks[0], matrix.pin(11), 47},
{banks[0], matrix.pin(12), 48}, {banks[0], matrix.pin(13), 49}, {banks[0], matrix.pin(14), 50}, {banks[0], matrix.pin(15), 51},
};`
i need help for this :(
Please explain the problem and post your full code.
Please explain the problem and post your full code.
Can can't define to map it to 4x4 matrices, ( 16 buttons bank from note 36-51 )

Can can't define to map it to 4x4 matrices, ( 16 buttons bank from note 36-51 )
I can't help you if you don't provide more information.
Can can't define to map it to 4x4 matrices, ( 16 buttons bank from note 36-51 )
I can't help you if you don't provide more information.
Oh i mean that how to transfer the old matrix code to make 4 bank matrices code scan: const AddressMatrix<4, 4> addresses = { { {48, 49, 50, 51}, {44, 45, 46, 47}, {40, 41, 42, 43}, {36, 37, 38, 39}, } };
If you use ScanningMatrix, you have to define each button separately, you cannot use an address matrix. See https://tttapa.github.io/Control-Surface-doc/Doxygen/da/d2d/Transposer_8ino-example.html.
But that's almost the same as the code you already had here: https://github.com/tttapa/Control-Surface/issues/308#issuecomment-723583801
So I don't understand what you're having trouble with?
But that's almost the same as the code you already had here: https://github.com/tttapa/Control-Surface/issues/308#issuecomment-723583801
So I don't understand what you're having trouble with?
I have trouble to make it work with 4x4 like this:
ScanningMatrix<4, 4> matrix { {2, 3, 4, 5}, // row pins {6, 7, 8, 9}, // column pins };
Bankable::NoteButton buttons[] = { {banks[1], matrix.pin(0), 52}, // Note that the first 4 NoteButtons use the {banks[1], matrix.pin(1), 53}, // same pins as the bank selector {banks[1], matrix.pin(2), 54}, {banks[1], matrix.pin(3), 55}, // is that create 16 notes like this? " which is that "matrix.pin(2)" mean on digital pin of arduino or pin of rows & collums? };
Yes, you have to declare all 16 notes like that.
matrix.pin(2) is the switch in the third column of the first row, you can see the calculation in the ScanningMatrix.hpp file I posted:
uint8_t indexToRow(pin_t pinIndex) const { return pinIndex / NumCols; }
uint8_t indexToCol(pin_t pinIndex) const { return pinIndex % NumCols; }
You can just use it like the other ExtendedInputOutput elements, create an instance of
ScanningMatrix, and pass its pins to theBankable::NoteButtonconstructor.ScanningMatrix<4, 2> matrix {
{2, 3, 4, 5}, // row pins
{6, 7}, // column pins
};
Bankable::NoteButton buttons[] = {
{banks[1], matrix.pin(0), 52}, // Note that the first 4 NoteButtons use the
{banks[1], matrix.pin(1), 53}, // same pins as the bank selector
{banks[1], matrix.pin(2), 54},
{banks[1], matrix.pin(3), 55},
// ...
};
You could add a function to the
ScanningMatrixto get the pin given a row and column index, instead of a single linear index.Oh i got it, also thank you for this feauture,
Is that right for 16 buttons? here is my code
`ScanningMatrix<4, 4> matrix {
{2, 3, 4, 5}, // row pins
{6, 7, 8, 9}, // column pins
};
Bankable::NoteButton buttons[] = {
{banks[0], matrix.pin(0), 36}, // Note that the first 4 NoteButtons use the
{banks[0], matrix.pin(1), 37}, // same pins as the bank selector
{banks[0], matrix.pin(2), 38},
{banks[0], matrix.pin(3), 39},
{banks[0], matrix.pin(4), 40},
{banks[0], matrix.pin(5), 41}, // Note that the first 4 NoteButtons use the
{banks[0], matrix.pin(6), 42}, // same pins as the bank selector
{banks[0], matrix.pin(7), 43},
{banks[0], matrix.pin(8), 44},
{banks[0], matrix.pin(9), 45},
{banks[0], matrix.pin(10), 46}, // Note that the first 4 NoteButtons use the
{banks[0], matrix.pin(11), 47},
{banks[0], matrix.pin(12), 48},
{banks[0], matrix.pin(13), 49},
{banks[0], matrix.pin(14), 50},
{banks[0], matrix.pin(15), 51},
};`
i need help for this :(
So is that right? ^^ i added to 16 notes but not sure the pin()
It looks alright at first sight. Why don't you try it? Does it compile? Does it send the note events you expect?
It looks alright at first sight. Why don't you try it? Does it compile? Does it send the note events you expect?
Is show that maybe out of memory on arduino uno 🧐
You could try disabling the SysEx input, which should save you over 120 bytes of RAM. You do need the latest patch (f351bffd3a674cd68998a8900daa1a45fc257615). Set the following setting to 1:
https://github.com/tttapa/Control-Surface/blob/f351bffd3a674cd68998a8900daa1a45fc257615/src/Settings/Settings.hpp#L47-L48
If you don't need to invert specific buttons, you can comment out this line: https://github.com/tttapa/Control-Surface/blob/f351bffd3a674cd68998a8900daa1a45fc257615/src/AH/Settings/Settings.hpp#L87-L89
You could also try marking the UpdatableCRTP::applyToAll methods always_inline, like this:
https://github.com/tttapa/Control-Surface/blob/71cc73370d32c5a2a7ad94bb162299ef3fadf5be/src/AH/Containers/Updatable.hpp#L84-L96
If that's not enough, you'll either have to accept that the UNO is not a suitable board for your project, or roll your own optimized code. Abstractions like the ScanningMatrix class I sent you are easy to use, but this comes at a cost.
this code works for 12 buttons. its going to be 16. Im sorry for jumping on this post but im unaware on how to get publicity for mine. i also need help in making a 4x4 button matrix. i want 16 buttons for notes and a stepped pot that has 4 banks. could you show me how to do this? its most likely a sendProgramChange i just need to know how to build the arrays that hold the banks and their patches in each bank. could you help me?
#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
int middleCpin = 2;
int cSharpPin = 3;
int middleDpin = 4;
int dSharpPin= 5;
int middleEpin = 6;
int middleFpin = 7;
int fSharpPin = 8;
int middleGpin = 9;
int gSharpPin = 10;
int middleApin = 11;
int aSharpPin = 12;
int middleBpin = 13;
int analogpot1 = A0; //knob 1 int analogpot2 = A1; //knob 2
int analogpot1Old = 0; int analogpot2Old = 0; int analogpot1New = 0; int analogpot2New = 0;
#define analogpot1CC 54 #define analogpot2CC 55
void setup() { // put your setup code here, to run once: MIDI.begin (); // MIDI START
pinMode(middleCpin, INPUT_PULLUP); pinMode(cSharpPin, INPUT_PULLUP); pinMode(middleDpin, INPUT_PULLUP); pinMode(dSharpPin, INPUT_PULLUP); pinMode(middleEpin, INPUT_PULLUP); pinMode(middleFpin, INPUT_PULLUP); pinMode(fSharpPin, INPUT_PULLUP); pinMode(middleGpin, INPUT_PULLUP); pinMode(gSharpPin, INPUT_PULLUP); pinMode(middleApin, INPUT_PULLUP); pinMode(aSharpPin, INPUT_PULLUP); pinMode(middleBpin, INPUT_PULLUP);
pinMode(analogpot1, INPUT); pinMode(analogpot2, INPUT);
//Serial.begin(9600); }
void loop() { // put your main code here, to run repeatedly:
static bool middleCvalueOld = HIGH; static bool cSharpValueOld = HIGH; static bool middleDvalueOld = HIGH; static bool dSharpValueOld = HIGH; static bool middleEvalueOld = HIGH; static bool middleFvalueOld = HIGH; static bool fSharpValueOld = HIGH; static bool middleGvalueOld = HIGH; static bool gSharpValueOld = HIGH; static bool middleAvalueOld = HIGH; static bool aSharpValueOld = HIGH; static bool middleBvalueOld = HIGH;
//footswitches bool middleCvalueNew = digitalRead(middleCpin); bool cSharpValueNew = digitalRead(cSharpPin); bool middleDvalueNew = digitalRead(middleDpin); bool dSharpValueNew = digitalRead(dSharpPin); bool middleEvalueNew = digitalRead(middleEpin); bool middleFvalueNew = digitalRead(middleFpin); bool fSharpValueNew = digitalRead(fSharpPin); bool middleGvalueNew = digitalRead(middleGpin); bool gSharpValueNew = digitalRead(gSharpPin); bool middleAvalueNew = digitalRead(middleApin); bool aSharpValueNew = digitalRead(aSharpPin); bool middleBvalueNew = digitalRead(middleBpin);
if (middleCvalueNew != middleCvalueOld){
if (middleCvalueNew == LOW){
MIDI.sendNoteOn(60, 127, 1);
//Serial.println("Note C On");
}
else {
MIDI.sendNoteOff(60, 0, 1);
//Serial.println("Note C Off");
}
middleCvalueOld = middleCvalueNew;
}
if (cSharpValueNew != cSharpValueOld){
if (cSharpValueNew == LOW){
MIDI.sendNoteOn(61, 127, 1);
//Serial.println("Note E On");
}
else {
MIDI.sendNoteOff(61, 0, 1);
//Serial.println("Note E Off");
}
cSharpValueOld = cSharpValueNew;
}
if (middleDvalueNew != middleDvalueOld){
if (middleDvalueNew == LOW){
MIDI.sendNoteOn(62, 127, 1);
//Serial.println("Note C On");
}
else {
MIDI.sendNoteOff(62, 0, 1);
//Serial.println("Note C Off");
}
middleDvalueOld = middleDvalueNew;
}
if (dSharpValueNew != dSharpValueOld){
if (dSharpValueNew == LOW){
MIDI.sendNoteOn(63, 127, 1);
//Serial.println("Note E On");
}
else {
MIDI.sendNoteOff(63, 0, 1);
//Serial.println("Note E Off");
}
dSharpValueOld = dSharpValueNew;
}
if (middleEvalueNew != middleEvalueOld){
if (middleEvalueNew == LOW){
MIDI.sendNoteOn(64, 127, 1);
//Serial.println("Note C On");
}
else {
MIDI.sendNoteOff(64, 0, 1);
//Serial.println("Note C Off");
}
middleEvalueOld = middleEvalueNew;
}
if (middleFvalueNew != middleFvalueOld){
if (middleFvalueNew == LOW){
MIDI.sendNoteOn(65, 127, 1);
//Serial.println("Note C On");
}
else {
MIDI.sendNoteOff(65, 0, 1);
//Serial.println("Note C Off");
}
middleFvalueOld = middleFvalueNew;
}
if (fSharpValueNew != fSharpValueOld){
if (fSharpValueNew == LOW){
MIDI.sendNoteOn(66, 127, 1);
//Serial.println("Note E On");
}
else {
MIDI.sendNoteOff(66, 0, 1);
//Serial.println("Note E Off");
}
fSharpValueOld = fSharpValueNew;
}
if (middleGvalueNew != middleGvalueOld){
if (middleGvalueNew == LOW){
MIDI.sendNoteOn(67, 127, 1);
//Serial.println("Note C On");
}
else {
MIDI.sendNoteOff(67, 0, 1);
//Serial.println("Note C Off");
}
middleGvalueOld = middleGvalueNew;
}
if (gSharpValueNew != gSharpValueOld){
if (gSharpValueNew == LOW){
MIDI.sendNoteOn(68, 127, 1);
//Serial.println("Note E On");
}
else {
MIDI.sendNoteOff(68, 0, 1);
//Serial.println("Note E Off");
}
gSharpValueOld = gSharpValueNew;
}
if (middleAvalueNew != middleAvalueOld){ if (middleAvalueNew == LOW){ MIDI.sendNoteOn(69, 127, 1); //Serial.println("Note C On"); } else { MIDI.sendNoteOff(69, 0, 1); //Serial.println("Note C Off"); } middleAvalueOld = middleAvalueNew; }
if (aSharpValueNew != aSharpValueOld){ if (aSharpValueNew == LOW){ MIDI.sendNoteOn(70, 127, 1); //Serial.println("Note E On"); } else { MIDI.sendNoteOff(70, 0, 1); //Serial.println("Note E Off"); } aSharpValueOld = aSharpValueNew; }
if (middleBvalueNew != middleBvalueOld){
if (middleBvalueNew == LOW){
MIDI.sendNoteOn(71, 127, 1);
//Serial.println("Note C On");
}
else {
MIDI.sendNoteOff(71, 0, 1);
//Serial.println("Note C Off");
}
middleBvalueOld = middleBvalueNew;
}
//potentiometers
int pot1 = analogRead(A0); int pot2 = analogRead(A1); int analogpot1New = analogRead(A0); int analogpot2New = analogRead(A1);
if (analogpot1New - analogpot1Old >= 35 || analogpot1Old - analogpot1New >= 35) {
analogpot1Old = analogpot1New;
analogpot1New = (map(analogpot1New, 1023, 0, 0, 120));
analogpot1New = (constrain(analogpot1New, 0, 120));
MIDI.sendControlChange(analogpot1CC, analogpot1New, 1);
// Serial.print ("pot: "); // Serial.println(pot1); // Serial.print("potread: "); // Serial.println(analogpot1New); }
if (analogpot2New - analogpot2Old >= 35 || analogpot2Old - analogpot2New >= 35) {
analogpot2Old = analogpot2New;
analogpot2New = (map(analogpot2New, 1023, 0, 0, 120));
analogpot2New = (constrain(analogpot2New, 0, 120));
MIDI.sendControlChange(analogpot2CC, analogpot2New, 1);
// Serial.print ("pot: "); // Serial.println(pot2); // Serial.print("potread: "); // Serial.println(analogpot2New); }
delay(25); }