Hi everyone i make a custom midi controller, but at the same time I have an issue, the software I used is from @stoonoon on GitHub,some little change but it work fine, only, I wanted to put continue blink on 3 switch or static led on the string of the lcd, this 3 switches are snap shots if somebody can help for program only this I will be greatful. Thanks guys!
Links, schematic, your code in </> CODE TAGS
Only then do we have any idea what you’re talking about.
Yup here is the entire code, i can't upload the .ino file here I don't know why. Thankss
/*
-
- Simple 8 button MIDI controller for Line 6 HX Stomp using Nano clone
- MIDI connectivity based on https://www.instructables.com/id/Send-and-Receive-MIDI-with-Arduino/
- MIDI pin 4 to TX1
- 128x64 I2C OLED - the one I used was https://smile.amazon.co.uk/gp/product/B076PL474K
- SDA to A4
- SCL to A5
- 8x momentary SPST switches connected between GND and D2 - D9
-
*/
#include <MIDI.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # ((was 4) or -1 if sharing Arduino reset pin)
#define OLED_ADDR 0x3C // address of my 128x64 OLED
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// error blink codes
#define ERR_DISP_ALLOC 3 // display allocation error
static const unsigned ledPin = LED_BUILTIN; // use onboard LED as activity indicator
static const byte switchPin[] = {2,3,4,5,6,7,8,9}; // pins for footswitch inputs
static const byte switchCount = 8; // number of footswitches used
static bool switchPressed[switchCount]; // current state of footswitches
static bool switchLastState[switchCount]; //previous state of footswitches (used for long press detection)
static unsigned long lastPressMillis[switchCount]; // when the last button press was detected
static unsigned long lastReleaseMillis[switchCount]; // when the last button was released
// Created and binds the MIDI interface to the default hardware Serial port
MIDI_CREATE_DEFAULT_INSTANCE();
void errBlink(int errCode) {
byte blinkTime = 200; // duration for each blink
byte blinkGap = 200; // gap between each blink
int burstWait = 1000; // wait time between bursts
for (;
{ // loop forever
for (int i = 1; i <= errCode; i++) {
digitalWrite(ledPin,HIGH);
delay(blinkTime);
digitalWrite(ledPin,LOW);
delay(blinkGap);
}
delay(burstWait);
}
} // end of errBlink()
void setup() {
pinMode(ledPin, OUTPUT); // setup activity LED pin for output
MIDI.begin(MIDI_CHANNEL_OMNI); // Listen to all incoming messages
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) { // Address 0x3C for my 128x64 variant
errBlink(ERR_DISP_ALLOC);
}
// Show initial display buffer contents on the screen --
// the library initializes this with an Adafruit splash screen.
display.display();
delay(500); // Pause for 0.5 seconds
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.cp437(true); // Use full 256 char 'Code Page 437' font
display.clearDisplay();
// Initialise switches and related variable arrays
for (int i=0;i<switchCount;i++) {
pinMode(switchPin[i], INPUT_PULLUP); // add pullup resistors to all footswitch input pins
switchPressed[i] = false; //initialise switch state
switchLastState[i] = false; //initialse last switch state
lastReleaseMillis[i] = millis(); // initialise time switch last released
lastPressMillis[i] = lastPressMillis[i] -1; // initialise time switch last pressed
}
} // end of setup
void loop() {
readButtons();
displayUpdate();
midiSend();
} // end of loop
/*
-
- Input related declarations and functions
-
*/
static const bool switchDown = LOW; // because we are using pullup resistor and switch to GND
static const byte debounceTime = 20; // after processing a button press, ignore further input for some milliseconds
static const byte debounceDelay = 5; // amount of time to wait before retesting debounceTime
static const int longPressTime = 1000; // how long a switch has to be held to count as a long press
static int switchPressedCounter = 0; // how many switches are currently pressed
static byte nextCommand = -1; // most important pending action - the switch that was last pressed, or other command via multi or long press
static byte lastCommand = -1; // last command sent (used for display confirmation)
static unsigned long commandMillis = millis(); // the time that nextCommand was last set - ie the last switch to be pressed
static const byte pagePatchReset = 5switchCount + 3;
static const byte pageUp = 5switchCount + 2;
static const byte pageDn = 5*switchCount + 1;
static byte currentPage = 0; // the current page / bank to be displayed
static const byte pageCount =4; // how many pages we have configured
void readButtons() {
switchPressedCounter = 0;
for (int i=0;i<switchCount;i++) {
switchPressed[i] = ( digitalRead(switchPin[i]) == switchDown ); // set array element to true if switch is currently pressed, or false if not
if (switchPressed[i] != switchLastState[i]) { //potential press or release detected
if (switchPressed[i]) { // potential new press detected
if ( millis() > (lastPressMillis[i] + debounceTime) ) { // genuine press and not switch bounce
lastPressMillis[i] = millis();
switchLastState[i] = true;
nextCommand = i;
commandMillis = millis();
}
}
else if (!switchPressed[i]) { //potential switch release detected
if ( millis() > (lastReleaseMillis[i] + debounceTime ) ) { // genuine release and not switch bounce
lastReleaseMillis[i] = millis();
switchLastState[i] = false;
}
}
}
if (switchPressed[i]) {
switchPressedCounter++; //increment counter used to check multiple presses
if ( millis() > (lastPressMillis[i] + longPressTime) ) { // long press detected
lastPressMillis[i] = millis(); // reset timer so it doesn't re-trigger every loop
nextCommand = i + switchCount; // use the next n numbers as a second bank of commands representing long press actions
}
}
}
static bool comboActive = false; // remembers whether multiple presses were detected to avoid re-triggering every loop
if (switchPressedCounter > 1 ) { // multiple presses detected
if (!comboActive) {
comboActive = true;
if ( switchPressed[0] && switchPressed[1]) { // first two switches -> Page Down
nextCommand = pageDn;
changePageDown();
}
else if ( switchPressed[1] && switchPressed[2]) { // second two switches -> Page Up
nextCommand = pageUp;
changePageUp();
}
else if ( switchPressed[6] && switchPressed[7]) { // last two switches - reset to page 0 and patch 0
nextCommand = pagePatchReset;
currentPage = 0;
}
}
}
else {
comboActive = false; // we can reset this as no more than one switch currently pressed
}
lastCommand = nextCommand;
} // end of read_buttons()
void changePageUp() {
currentPage++;
if (currentPage >= pageCount) { // we have gone past the last page
currentPage = 0; // reset to first page
}
}
void changePageDown() {
currentPage--;
if (currentPage > pageCount) { // we have scrolled back past the first page
currentPage = (pageCount -1); // reset to last page
}
}
/*
*
- Display related functions
*/
void invSelection(int i=(lastCommand+1)) {
if (lastCommand == i) {
display.setTextColor(BLACK, WHITE);
}
else {
display.setTextColor(WHITE, BLACK);
}
}
void displayLine(const __FlashStringHelper *str0, const __FlashStringHelper *str1, const __FlashStringHelper *str2, const __FlashStringHelper *str3, int startBtn) {
display.print(F("|"));
invSelection(0+startBtn);
display.print(str0);
invSelection();
display.print(F("|"));
invSelection(1+startBtn);
display.print(str1);
invSelection();
display.print(F("|"));
invSelection(2+startBtn);
display.print(str2);
invSelection();
display.print(F("|"));
invSelection(3+startBtn);
display.print(str3);
invSelection();
display.println(F("|"));
}
void displayUpdate(void) { // maybe change this to put labels in arrays, but this will do for now
display.clearDisplay();
display.setCursor(0, 0); // Start at top-left corner
switch (currentPage) {
case 0:
displayLine(F("PRE "),F("STMP"),F("FS4 "),F("FS5 "),4);
displayLine(F("SET "),F(" "),F(" / "),F(" / "),4);
displayLine(F("MODE"),F("MODE"),F("DOWN"),F(" UP "),4);
display.println(F("---------------------"));
displayLine(F("SNAP"),F("SNAP"),F("SNAP"),F("TUNR"),0);
displayLine(F("SHOT"),F("SHOT"),F("SHOT"),F(" TAP"),0);
displayLine(F(" 1 "),F(" 2 "),F(" 3 "),F("TMPO"),0);
break;
case 1:
displayLine(F("PRE "),F("PRE "),F("PRE "),F("PRE "),4);
displayLine(F("SET "),F("SET "),F("SET "),F("SET "),4);
displayLine(F(" 00 "),F(" 01 "),F(" 02 "),F(" 03 "),4);
display.println(F("---------------------"));
displayLine(F("SNAP"),F("SNAP"),F("SNAP"),F("TUNR"),0);
displayLine(F("SHOT"),F("SHOT"),F("SHOT"),F(" TAP"),0);
displayLine(F(" 1 "),F(" 2 "),F(" 3 "),F("TMPO"),0);
break;
case 2:
displayLine(F("PRE "),F("PRE "),F("PRE "),F("PRE "),4);
displayLine(F("SET "),F("SET "),F("SET "),F("SET "),4);
displayLine(F("122 "),F("123 "),F("124 "),F("125 "),4);
display.println(F("---------------------"));
displayLine(F("SNAP"),F("SNAP"),F("SNAP"),F("TUNR"),0);
displayLine(F("SHOT"),F("SHOT"),F("SHOT"),F(" TAP"),0);
displayLine(F(" 1 "),F(" 2 "),F(" 3 "),F("TMPO"),0);
break;
case 3:
displayLine(F("PLAY"),F("UNDO"),F(" "),F(" "),4);
displayLine(F("ONCE"),F(" / "),F("FWD "),F("REV "),4);
displayLine(F(" "),F("REDO"),F(" "),F(" "),4);
display.println(F("---------------------"));
displayLine(F(" "),F(" "),F(" "),F(" "),0);
displayLine(F("PLAY"),F("STOP"),F("REC "),F("OVER"),0);
displayLine(F(" "),F(" "),F(" "),F("DUB"),0);
break;
}
display.display();
}
/*
*
- MIDI output related functions
*/
void midiSend() {
// do something
if (nextCommand >=0) {
if (nextCommand == pagePatchReset) { // SW7 & SW8 should reset page and patch to 0 regardless of which page/patch currently active
MIDI.sendProgramChange(0,1);
}
switch(currentPage) {
case 0: // menu page 0 (1 of 4)
switch(nextCommand) {
case 0:
MIDI.sendControlChange(69,0,1); //snapshot 1
break;
case 1:
MIDI.sendControlChange(69,1,1); // snapshot 2
break;
case 2:
MIDI.sendControlChange(69,2,1); //snapshot 3
break;
case 3:
MIDI.sendControlChange(64,64,1); //tap tempo
break;
case 4:
MIDI.sendControlChange(71,2,1); //preset mode
break;
case 5:
MIDI.sendControlChange(71,0,1); //stomp mode
break;
case 6:
MIDI.sendControlChange(52,2,1); //FS4
break;
case 7:
MIDI.sendControlChange(53,2,1); //FS5
break;
case 11: // long press on SW4 (bottom right switch)
MIDI.sendControlChange(68,68,1); //tuner
break;
} // end of menu page 0
break;
case 1: // menu page 1 (2 of 4)
switch(nextCommand) {
case 0:
MIDI.sendControlChange(69,0,1); //snapshot 1
break;
case 1:
MIDI.sendControlChange(69,1,1); // snapshot 2
break;
case 2:
MIDI.sendControlChange(69,2,1); //snapshot 3
break;
case 3:
MIDI.sendControlChange(64,64,1); //tap tempo
break;
case 4:
MIDI.sendProgramChange(0,1); //preset 00
break;
case 5:
MIDI.sendProgramChange(1,1); //preset 01
break;
case 6:
MIDI.sendProgramChange(2,1); //preset 02
break;
case 7:
MIDI.sendProgramChange(3,1); //preset 03
break;
case 11: // long press on SW4 (bottom right switch)
MIDI.sendControlChange(68,68,1); //tuner
break;
} // end of menu page 1
break;
case 2: // menu page 2 (3 of 4)
switch(nextCommand) {
case 0:
MIDI.sendControlChange(69,0,1); //snapshot 1
break;
case 1:
MIDI.sendControlChange(69,1,1); // snapshot 2
break;
case 2:
MIDI.sendControlChange(69,2,1); //snapshot 3
break;
case 3:
MIDI.sendControlChange(64,64,1); //tap tempo
break;
case 4:
MIDI.sendProgramChange(122,1); //preset 00
break;
case 5:
MIDI.sendProgramChange(123,1); //preset 01
break;
case 6:
MIDI.sendProgramChange(124,1); //preset 02
break;
case 7:
MIDI.sendProgramChange(125,1); //preset 03
break;
case 11: // long press on SW4 (bottom right switch)
MIDI.sendControlChange(68,68,1); //tuner
break;
} // end of menu page 2
case 3: // menu page 3 (4 of 4)
switch(nextCommand) {
case 0:
MIDI.sendControlChange(61,127,1); //play
break;
case 1:
MIDI.sendControlChange(61,0,1); //stop
break;
case 2:
MIDI.sendControlChange(60,127,1); //record
break;
case 3:
MIDI.sendControlChange(60,0,1); //overdub
break;
case 4:
MIDI.sendProgramChange(62,127); //play once
break;
case 5:
MIDI.sendProgramChange(63,127); //undo/redo
break;
case 6:
MIDI.sendProgramChange(65,0); //Forward
break;
case 7:
MIDI.sendProgramChange(65,127); //Reverse
break;
case 11: // long press on SW4 (bottom right switch)
MIDI.sendControlChange(68,68,1); //tuner
break;
} // end of menu page 3
break;
} // end of outer nested switch case
nextCommand = -1; // re-initialise this so we don't send the same message repeatedly
}
} // end midisend
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.