The Sonicake pocket master is a great cheap guitar effects you can buy. But it lacks control

The code
#include <Arduino.h>
#include <Control_Surface.h>
#include <MIDI_Interfaces/BluetoothMIDI_Interface.hpp>
#include <SPI.h>
#include <TFT_eSPI.h>
#include <XPT2046_Touchscreen.h>
// Backlight and Display Pins
#define CYD_BACKLIGHT_PIN 21
TFT_eSPI tft = TFT_eSPI();
// CYD Dedicated Touch SPI Pins
#define XPT2046_IRQ 36
#define XPT2046_MOSI 32
#define XPT2046_MISO 39
#define XPT2046_CLK 25
#define XPT2046_CS 33
SPIClass touchSpi = SPIClass(VSPI);
XPT2046_Touchscreen ts(XPT2046_CS, XPT2046_IRQ);
// Bluetooth MIDI Instance
BluetoothMIDI_Interface midi_ble;
unsigned long lastTouchTime = 0;
int activePreset = 0; // 0 means no preset active, 1-4 for buttons
bool isOutOfSync = false; // True when bank changes while a preset was active
int bank = 0; // Bank variable from 0 to 4
int volume = 70; // Volume variable initialized to 70 (Range: 20 to 100)
// Bank & Preset Arrays
const char* presets_name[] = {"rock", "ballad", "pop", "jazz", "blues"};
const int button1_presets[] = {1, 2, 3, 4, 5};
const int button2_presets[] = {6, 7, 8, 9, 10};
const int button3_presets[] = {11, 12, 13, 14, 15};
const int button4_presets[] = {16, 17, 18, 19, 20};
// UI Button Locations & Dimensions (Landscape: 320x240)
#define BTN_Y 145
#define BTN_W 68
#define BTN_H 65
#define BTN_1_X 15
#define BTN_2_X 91
#define BTN_3_X 167
#define BTN_4_X 243
// Volume Top Bar Controls
#define VOL_DEC_X 10
#define VOL_DEC_Y 10
#define VOL_DEC_W 60
#define VOL_DEC_H 35
#define VOL_BOX_X 80
#define VOL_BOX_Y 10
#define VOL_BOX_W 160
#define VOL_BOX_H 35
#define VOL_INC_X 250
#define VOL_INC_Y 10
#define VOL_INC_W 60
#define VOL_INC_H 35
// Bank Nav Buttons & Display Box
#define BANK_BOX_X 90
#define BANK_BOX_Y 65
#define BANK_BOX_W 140
#define BANK_BOX_H 50
#define BANK_DEC_X 20
#define BANK_DEC_Y 65
#define BANK_DEC_W 65
#define BANK_DEC_H 50
#define BANK_INC_X 235
#define BANK_INC_Y 65
#define BANK_INC_W 65
#define BANK_INC_H 50
void drawButton(int btnNum, int x, int y, int w, int h) {
bool isActive = (activePreset == btnNum);
uint16_t fillColor = TFT_BLUE;
uint16_t textColor = TFT_WHITE;
if (isActive) {
if (isOutOfSync) {
fillColor = TFT_RED;
textColor = TFT_WHITE;
} else {
fillColor = TFT_YELLOW;
textColor = TFT_BLACK;
}
}
tft.fillRoundRect(x, y, w, h, 10, fillColor);
tft.drawRoundRect(x, y, w, h, 10, TFT_WHITE);
tft.setTextColor(textColor, fillColor);
tft.setTextDatum(MC_DATUM);
tft.drawString(String(btnNum), x + (w / 2), y + (h / 2), 4);
}
void drawBankDisplay() {
tft.fillRoundRect(BANK_BOX_X, BANK_BOX_Y, BANK_BOX_W, BANK_BOX_H, 8, TFT_DARKGREY);
tft.drawRoundRect(BANK_BOX_X, BANK_BOX_Y, BANK_BOX_W, BANK_BOX_H, 8, TFT_WHITE);
tft.setTextColor(TFT_WHITE, TFT_DARKGREY);
tft.setTextDatum(MC_DATUM);
// Format bank number next to preset name (e.g., "1 - rock")
String bankStr = String(bank + 1) + " - " + presets_name[bank];
tft.drawString(bankStr, BANK_BOX_X + (BANK_BOX_W / 2), BANK_BOX_Y + (BANK_BOX_H / 2), 4);
}
void drawVolumeDisplay() {
tft.fillRoundRect(VOL_BOX_X, VOL_BOX_Y, VOL_BOX_W, VOL_BOX_H, 6, TFT_NAVY);
tft.drawRoundRect(VOL_BOX_X, VOL_BOX_Y, VOL_BOX_W, VOL_BOX_H, 6, TFT_WHITE);
tft.setTextColor(TFT_WHITE, TFT_NAVY);
tft.setTextDatum(MC_DATUM);
tft.drawString("VOL: " + String(volume), VOL_BOX_X + (VOL_BOX_W / 2), VOL_BOX_Y + (VOL_BOX_H / 2), 2);
}
void drawUI() {
tft.fillScreen(TFT_BLACK);
// Volume - Button
tft.fillRoundRect(VOL_DEC_X, VOL_DEC_Y, VOL_DEC_W, VOL_DEC_H, 6, TFT_DARKGREY);
tft.drawRoundRect(VOL_DEC_X, VOL_DEC_Y, VOL_DEC_W, VOL_DEC_H, 6, TFT_WHITE);
tft.setTextColor(TFT_WHITE, TFT_DARKGREY);
tft.setTextDatum(MC_DATUM);
tft.drawString("VOL-", VOL_DEC_X + (VOL_DEC_W / 2), VOL_DEC_Y + (VOL_DEC_H / 2), 2);
// Volume + Button
tft.fillRoundRect(VOL_INC_X, VOL_INC_Y, VOL_INC_W, VOL_INC_H, 6, TFT_DARKGREY);
tft.drawRoundRect(VOL_INC_X, VOL_INC_Y, VOL_INC_W, VOL_INC_H, 6, TFT_WHITE);
tft.setTextColor(TFT_WHITE, TFT_DARKGREY);
tft.setTextDatum(MC_DATUM);
tft.drawString("VOL+", VOL_INC_X + (VOL_INC_W / 2), VOL_INC_Y + (VOL_INC_H / 2), 2);
// Draw Volume Display Box
drawVolumeDisplay();
// Bank - Button
tft.fillRoundRect(BANK_DEC_X, BANK_DEC_Y, BANK_DEC_W, BANK_DEC_H, 8, TFT_MAROON);
tft.drawRoundRect(BANK_DEC_X, BANK_DEC_Y, BANK_DEC_W, BANK_DEC_H, 8, TFT_WHITE);
tft.setTextColor(TFT_WHITE, TFT_MAROON);
tft.setTextDatum(MC_DATUM);
tft.drawString("BANK-", BANK_DEC_X + (BANK_DEC_W / 2), BANK_DEC_Y + (BANK_DEC_H / 2), 2);
// Bank + Button
tft.fillRoundRect(BANK_INC_X, BANK_INC_Y, BANK_INC_W, BANK_INC_H, 8, TFT_DARKGREEN);
tft.drawRoundRect(BANK_INC_X, BANK_INC_Y, BANK_INC_W, BANK_INC_H, 8, TFT_WHITE);
tft.setTextColor(TFT_WHITE, TFT_DARKGREEN);
tft.setTextDatum(MC_DATUM);
tft.drawString("BANK+", BANK_INC_X + (BANK_INC_W / 2), BANK_INC_Y + (BANK_INC_H / 2), 2);
// Draw Bank Name Box
drawBankDisplay();
// Draw 4 Preset Buttons
drawButton(1, BTN_1_X, BTN_Y, BTN_W, BTN_H);
drawButton(2, BTN_2_X, BTN_Y, BTN_W, BTN_H);
drawButton(3, BTN_3_X, BTN_Y, BTN_W, BTN_H);
drawButton(4, BTN_4_X, BTN_Y, BTN_W, BTN_H);
}
void handlePresetPress(int btnNum, const int* presetArray) {
activePreset = btnNum;
isOutOfSync = false;
int val = presetArray[bank];
Control_Surface.sendCC({1, CHANNEL_1}, val);
drawUI();
Serial.print("Status: Touch Button ");
Serial.print(btnNum);
Serial.print(" -> Sent CC {1, 1} value: ");
Serial.println(val);
}
void setup() {
Serial.begin(115200);
delay(500);
// Enable Backlight
pinMode(CYD_BACKLIGHT_PIN, OUTPUT);
digitalWrite(CYD_BACKLIGHT_PIN, HIGH);
// Initialize Display
tft.init();
tft.setRotation(1); // Landscape mode
drawUI();
// Initialize Touch Bus
touchSpi.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
ts.begin(touchSpi);
ts.setRotation(1);
// Initialize MIDI
Control_Surface.begin();
Serial.println("Status: CYD Ready & BLE Server Active");
}
void loop() {
// Continuously service BLE MIDI processing
Control_Surface.loop();
// Debounced Touch Scanner
if (millis() - lastTouchTime > 250) {
if (ts.touched()) {
TS_Point p = ts.getPoint();
// Map touch coordinates for landscape (320x240)
int touchX = map(p.x, 200, 3700, 0, 320);
int touchY = map(p.y, 240, 3800, 0, 240);
// VOL - Button Pressed
if (touchX >= VOL_DEC_X && touchX <= (VOL_DEC_X + VOL_DEC_W) && touchY >= VOL_DEC_Y && touchY <= (VOL_DEC_Y + VOL_DEC_H)) {
if (volume > 20) {
volume--;
drawVolumeDisplay();
Control_Surface.sendCC({6, CHANNEL_1}, volume);
Serial.print("Status: VOL- -> Sent CC {6, 1} value: ");
Serial.println(volume);
lastTouchTime = millis();
}
}
// VOL + Button Pressed
if (touchX >= VOL_INC_X && touchX <= (VOL_INC_X + VOL_INC_W) && touchY >= VOL_INC_Y && touchY <= (VOL_INC_Y + VOL_INC_H)) {
if (volume < 100) {
volume++;
drawVolumeDisplay();
Control_Surface.sendCC({6, CHANNEL_1}, volume);
Serial.print("Status: VOL+ -> Sent CC {6, 1} value: ");
Serial.println(volume);
lastTouchTime = millis();
}
}
// BANK - Button Pressed
if (touchX >= BANK_DEC_X && touchX <= (BANK_DEC_X + BANK_DEC_W) && touchY >= BANK_DEC_Y && touchY <= (BANK_DEC_Y + BANK_DEC_H)) {
if (bank > 0) {
bank--;
if (activePreset != 0) {
isOutOfSync = true;
}
drawUI();
Serial.print("Status: Bank Decremented -> ");
Serial.println(presets_name[bank]);
lastTouchTime = millis();
}
}
// BANK + Button Pressed
if (touchX >= BANK_INC_X && touchX <= (BANK_INC_X + BANK_INC_W) && touchY >= BANK_INC_Y && touchY <= (BANK_INC_Y + BANK_INC_H)) {
if (bank < 4) {
bank++;
if (activePreset != 0) {
isOutOfSync = true;
}
drawUI();
Serial.print("Status: Bank Incremented -> ");
Serial.println(presets_name[bank]);
lastTouchTime = millis();
}
}
// Button 1 Pressed
if (touchX >= BTN_1_X && touchX <= (BTN_1_X + BTN_W) && touchY >= BTN_Y && touchY <= (BTN_Y + BTN_H)) {
handlePresetPress(1, button1_presets);
lastTouchTime = millis();
}
// Button 2 Pressed
if (touchX >= BTN_2_X && touchX <= (BTN_2_X + BTN_W) && touchY >= BTN_Y && touchY <= (BTN_Y + BTN_H)) {
handlePresetPress(2, button2_presets);
lastTouchTime = millis();
}
// Button 3 Pressed
if (touchX >= BTN_3_X && touchX <= (BTN_3_X + BTN_W) && touchY >= BTN_Y && touchY <= (BTN_Y + BTN_H)) {
handlePresetPress(3, button3_presets);
lastTouchTime = millis();
}
// Button 4 Pressed
if (touchX >= BTN_4_X && touchX <= (BTN_4_X + BTN_W) && touchY >= BTN_Y && touchY <= (BTN_Y + BTN_H)) {
handlePresetPress(4, button4_presets);
lastTouchTime = millis();
}
}
}
}