From 699546df8c34e8c883e633a6fc2a7da0dc8efd97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20Degerf=C3=A4lt?= Date: Sat, 22 Jun 2019 14:25:31 +0200 Subject: [PATCH] Handle sub menus in a generic way and moved adjust menu logic to separate file This is a big one where I can finally reap what I sown. Sub menu entries now provide two functions, one to get the text for the current value and one to apply changes aka save to EEPROM. With this I can replace so much code in the menu() function that handles input, but was _almost_ identical. The process of converting the old menus are not completed, and I can probably remove about 200 lines more code. The question is still what to do with less general menus like the rotator and fast patch menu. One problem with the current implementation is that it is RAM heavy. It seems the const MenuEntry structs are placed in ram, because there is a pointer to RAM that I assume is allocated during execution and therefore the address cannot be stored in ROM. My plan has been to put all the configuration fields (that are stored in EEPROM) into a struct or an array. When that is implemented, I can instead store the offset into the array in the const struct, which should be available at compile time and therefore can reside completely in ROM. --- .gitignore | 2 + NuEVI/adjustmenu.cpp | 359 ++++++++++++++ NuEVI/menu.cpp | 1080 +++++++++++++----------------------------- NuEVI/menu.h | 24 +- NuEVI/numenu.h | 20 + simulation/Makefile | 1 + 6 files changed, 724 insertions(+), 762 deletions(-) create mode 100644 .gitignore create mode 100644 NuEVI/adjustmenu.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eafd693 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode/ipch +*.o \ No newline at end of file diff --git a/NuEVI/adjustmenu.cpp b/NuEVI/adjustmenu.cpp new file mode 100644 index 0000000..310d6f7 --- /dev/null +++ b/NuEVI/adjustmenu.cpp @@ -0,0 +1,359 @@ +#include +#include +#include + +#include "menu.h" +#include "numenu.h" +#include "globals.h" +#include "config.h" +#include "hardware.h" +#include "settings.h" + +//*********************************************************** + +extern Adafruit_SSD1306 display; +extern Adafruit_MPR121 touchSensor; +extern byte cursorNow; + +//*********************************************************** +// Variables used for the adjust menu +static byte forcePix; + +static uint16_t pos1; +static uint16_t pos2; + +static int16_t adjustOption; +static int16_t adjustCurrent; + +static int16_t sensorPixelPos1 = -1; +static int16_t sensorPixelPos2 = -1; + +static bool refreshScreen; + +//*********************************************************** + + +const AdjustMenuEntry breathAdjustMenu = { + "BREATH", + { + { &breathThrVal, breathLoLimit, breathHiLimit }, + { &breathMaxVal, breathLoLimit, breathHiLimit } + }, + [] (const AdjustMenuEntry& e) { + writeSetting(BREATH_THR_ADDR, *e.entries[0].value); + writeSetting(BREATH_MAX_ADDR, *e.entries[1].value); + } +}; + +const AdjustMenuEntry portamentoAdjustMenu = { + "PORTAMENTO", + { + { &portamThrVal, portamLoLimit, portamHiLimit }, + { &portamMaxVal, portamLoLimit, portamHiLimit } + }, + [] (const AdjustMenuEntry& e) { + writeSetting(PORTAM_THR_ADDR, *e.entries[0].value); + writeSetting(PORTAM_MAX_ADDR, *e.entries[1].value); + } +}; + +const AdjustMenuEntry pitchBendAdjustMenu = { + "PITCH BEND", + { + { &pitchbThrVal, pitchbLoLimit, pitchbHiLimit }, + { &pitchbMaxVal, pitchbLoLimit, pitchbHiLimit } + }, + [] (const AdjustMenuEntry& e) { + writeSetting(PITCHB_THR_ADDR, *e.entries[0].value); + writeSetting(PITCHB_MAX_ADDR, *e.entries[1].value); + } +}; + +const AdjustMenuEntry extraSensorAdjustMenu = { + "EXTRA CONTROLLER", + { + { &extracThrVal, extracLoLimit, extracHiLimit }, + { &extracMaxVal, extracLoLimit, extracHiLimit } + }, + [] (const AdjustMenuEntry& e) { + writeSetting(EXTRAC_THR_ADDR, *e.entries[0].value); + writeSetting(EXTRAC_MAX_ADDR, *e.entries[1].value); + } +}; + +const AdjustMenuEntry ctouchAdjustMenu = { + "TOUCH SENSE", + { + { &ctouchThrVal, ctouchLoLimit, ctouchHiLimit }, + { nullptr, 0, 0 } + }, + [] (const AdjustMenuEntry& e) { + writeSetting(CTOUCH_THR_ADDR, *e.entries[0].value); + } +}; + +const AdjustMenuEntry* adjustMenuEntries[] = { + &breathAdjustMenu, + &portamentoAdjustMenu, + &pitchBendAdjustMenu, + &extraSensorAdjustMenu, + &ctouchAdjustMenu, +}; + +static const int numAdjustEntries = ARR_LEN(adjustMenuEntries); + +//*********************************************************** + +static void drawAdjCursor(byte color) { + display.drawTriangle(16,4,20,4,18,1,color); + display.drawTriangle(16,6,20,6,18,9,color); +} + +static void drawAdjustFrame(int line) { + display.drawLine(25,line,120,line,WHITE); // Top line + display.drawLine(25,line+12,120,line+12,WHITE); // Bottom line + + display.drawLine(25,line+1,25,line+2,WHITE); + display.drawLine(120,line+1,120,line+2,WHITE); + + display.drawLine(120,line+10,120,line+11,WHITE); + display.drawLine(25,line+10,25,line+11,WHITE); +} + +static void drawAdjustBase(const char* title, bool all) { + display.clearDisplay(); + + drawAdjustFrame(17); + + // sensor marker lines. + display.drawLine(25,36,25,40,WHITE); + display.drawLine(120,36,120,40,WHITE); + + display.setTextSize(1); + display.setTextColor(WHITE); + display.setCursor(25,2); + display.println(title); + + display.setCursor(0,20); + display.println("THR"); + display.setCursor(0,35); + display.println("SNS"); + + + if(all) { + drawAdjustFrame(47); + display.setCursor(0,50); + display.println("MAX"); + } + cursorNow = WHITE; + drawAdjCursor(WHITE); +} + +static bool updateAdjustLineCursor(uint32_t timeNow, uint16_t hPos, uint16_t vPos ) { + if ((timeNow - cursorBlinkTime) > cursorBlinkInterval) { + if (cursorNow == WHITE) cursorNow = BLACK; else cursorNow = WHITE; + display.drawLine(hPos, vPos,hPos, vPos+6, cursorNow);; + cursorBlinkTime = timeNow; + return true; + } + return false; +} + +static void drawAdjustMenu(const AdjustMenuEntry *menu) { + + bool haveSecondValue = menu->entries[1].value != nullptr; + drawAdjustBase( menu->title, haveSecondValue ); + + pos1 = map( *menu->entries[0].value, menu->entries[0].limitLow, menu->entries[0].limitHigh, 27, 119); + display.drawLine( pos1, 20, pos1, 26, WHITE ); + + if(haveSecondValue) { + pos2 = map( *menu->entries[1].value, menu->entries[1].limitLow, menu->entries[1].limitHigh, 27, 119); + display.drawLine( pos2, 50, pos2, 56, WHITE ); + } +} + +//*********************************************************** + +static bool updateSensorPixel(int pos, int pos2) { + bool update = pos != sensorPixelPos1 || pos2 != sensorPixelPos2; + if(update) { + display.drawFastHLine(28, 38, 119-28, BLACK); // Clear old line + display.drawPixel(pos, 38, WHITE); + if( pos2 >= 0) display.drawPixel(pos2, 38, WHITE); + + sensorPixelPos1 = pos; + sensorPixelPos2 = pos2; + } + return update; +} + +void plotSensorPixels(){ + int redraw = 0; + + if(forcePix) + sensorPixelPos1 = -1; + + // This is hacky. It depends on the order of items in the adjust menu list. + if(adjustOption == 0) { + int pos = map(constrain(pressureSensor, breathLoLimit, breathHiLimit), breathLoLimit, breathHiLimit, 28, 118); + redraw = updateSensorPixel(pos, -1); + } + else if(adjustOption == 1) { + int pos = map(constrain(biteSensor,portamLoLimit,portamHiLimit), portamLoLimit, portamHiLimit, 28, 118); + redraw = updateSensorPixel(pos, -1); + } + else if(adjustOption == 2) { + int pos = map(constrain(pbUp, pitchbLoLimit, pitchbHiLimit), pitchbLoLimit, pitchbHiLimit, 28, 118); + int pos2 = map(constrain(pbDn, pitchbLoLimit, pitchbHiLimit), pitchbLoLimit, pitchbHiLimit, 28, 118); + redraw = updateSensorPixel(pos, pos2); + } + else if(adjustOption == 3) { + int pos = map(constrain(exSensor, extracLoLimit, extracHiLimit), extracLoLimit, extracHiLimit, 28, 118); + redraw = updateSensorPixel(pos, -1); + } + else if(adjustOption == 4) { + display.drawLine(28,38,118,38,BLACK); + for (byte i=0; i<12; i++){ + int pos = map(constrain(touchSensor.filteredData(i), ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118); + display.drawPixel(pos, 38, WHITE); + } + + int posRead = map(touchRead(halfPitchBendKeyPin),ttouchLoLimit,ttouchHiLimit,ctouchHiLimit,ctouchLoLimit); + int pos = map(constrain(posRead, ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118); + + posRead = map(touchRead(specialKeyPin),ttouchLoLimit,ttouchHiLimit,ctouchHiLimit,ctouchLoLimit); + int pos2 = map(constrain(posRead, ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118); + + updateSensorPixel(pos, pos2); + + redraw = 1; + } + if (redraw){ + display.display(); + } + forcePix = 0; +} + + +//*********************************************************** + +static bool drawAdjustBar(uint16_t buttons, int row, const AdjustValue* entry, uint16_t *pos) { + bool updated = false; + uint16_t step = (entry->limitHigh-entry->limitLow)/92; + int val = *entry->value; + switch(buttons) { + case BTN_UP: + val += step; + updated = true; + break; + + case BTN_DOWN: + val -= step; + updated = true; + break; + } + if(updated) { + *entry->value = constrain(val, entry->limitLow, entry->limitHigh); + auto p = *pos; + display.drawLine(p, row, p, row+6, BLACK); + *pos = p = map(*entry->value, entry->limitLow, entry->limitHigh, 27, 119); + display.drawLine(p, row, p, row+6, WHITE); + cursorNow = BLACK; + } + return updated; +} + +static bool updateAdjustCursor(uint32_t timeNow) { + if ((timeNow - cursorBlinkTime) > cursorBlinkInterval) { + if (cursorNow == WHITE) cursorNow = BLACK; else cursorNow = WHITE; + drawAdjCursor(cursorNow); + cursorBlinkTime = timeNow; + return true; + } + return false; +} + +int updateAdjustMenu(uint32_t timeNow, uint8_t buttons, bool firstRun, bool drawSensor) { + bool redraw = false; + int result = 0; + + const AdjustMenuEntry *currentMenu = adjustMenuEntries[adjustOption]; + + if(firstRun || refreshScreen) { + adjustCurrent = 0; + refreshScreen = false; + drawAdjustMenu(currentMenu); + // the sensor pixel stuff should be refactored (to work again) + forcePix = 1; + sensorPixelPos1 = -1; // Force draw of sensor pixels + } + + if(adjustCurrent == 0) { + // Currently selecting what option to modify + redraw |= updateAdjustCursor(timeNow); + + bool save = false; + + if( buttons == BTN_DOWN ) { + adjustOption += 1; + refreshScreen = 1; + save = true; + } + else if ( buttons == BTN_UP ) { + adjustOption -= 1; + refreshScreen = 1; + save = true; + } + else if ( buttons == BTN_ENTER ) { + adjustCurrent = 1; + } + else if (buttons == BTN_MENU ) { + adjustCurrent = 0; + result = -1; + save = true; + } + + if(save && currentMenu->saveFunc) + currentMenu->saveFunc(*currentMenu); + + } else if( adjustCurrent == 1) { + if (buttons) { + drawAdjustBar( buttons, 20, ¤tMenu->entries[0], &pos1 ); + if(buttons == BTN_ENTER) adjustCurrent += 1; + else if( buttons == BTN_MENU) adjustCurrent = 0; + redraw = true; + } else { + redraw |= updateAdjustLineCursor( timeNow, pos1, 20 ); + } + } else { + if (buttons) { + drawAdjustBar( buttons, 50, ¤tMenu->entries[1], &pos2 ); + if(buttons == BTN_ENTER) adjustCurrent += 1; + else if( buttons == BTN_MENU) adjustCurrent = 0; + redraw = true; + } else { + redraw |= updateAdjustLineCursor( timeNow, pos2, 50 ); + } + } + + // Keep adjustCurrent in range + if( adjustCurrent > 2 || (adjustCurrent == 2 && currentMenu->entries[1].value == nullptr)) + adjustCurrent = 0; + + // Keep adjust option in range. + if(adjustOption < 0) + adjustOption = numAdjustEntries-1; + else if (adjustOption >= numAdjustEntries) + adjustOption = 0; + + + if(drawSensor) { + plotSensorPixels(); + } + + if(result >= 0) + result = redraw; + + return result; +} diff --git a/NuEVI/menu.cpp b/NuEVI/menu.cpp index d7ff9f1..a8a219a 100644 --- a/NuEVI/menu.cpp +++ b/NuEVI/menu.cpp @@ -11,13 +11,6 @@ #include "settings.h" #include "numenu.h" -#define ARR_LEN(a) (sizeof (a) / sizeof (a[0])) - -#define BTN_DOWN 1 -#define BTN_ENTER 2 -#define BTN_UP 4 -#define BTN_MENU 8 - // TODO: Ask Johan the reason for using this.. // static const uint16_t minOffset = 50; @@ -39,32 +32,22 @@ enum CursorIdx { }; static byte cursors[CursorIdx::NUM_CURSORS]; +static byte offsets[CursorIdx::NUM_CURSORS]; +static byte activeSub[CursorIdx::NUM_CURSORS]; -static byte cursorNow; +byte cursorNow; static byte forceRedraw = 0; static byte FPD = 0; -// Variables used for the adjust menu -static byte forcePix = 0; - -static uint16_t pos1; -static uint16_t pos2; - -static int16_t adjustOption = 0; -static int16_t adjustCurrent = 0; - -static int16_t sensorPixelPos1 = -1; -static int16_t sensorPixelPos2 = -1; - // constants -static const unsigned long debounceDelay = 30; // the debounce time; increase if the output flickers -static const unsigned long buttonRepeatInterval = 50; -static const unsigned long buttonRepeatDelay = 400; -static const unsigned long cursorBlinkInterval = 300; // the cursor blink toggle interval time -static const unsigned long patchViewTimeUp = 2000; // ms until patch view shuts off -static const unsigned long menuTimeUp = 60000; // menu shuts off after one minute of button inactivity +const unsigned long debounceDelay = 30; // the debounce time; increase if the output flickers +const unsigned long buttonRepeatInterval = 50; +const unsigned long buttonRepeatDelay = 400; +const unsigned long cursorBlinkInterval = 300; // the cursor blink toggle interval time +const unsigned long patchViewTimeUp = 2000; // ms until patch view shuts off +const unsigned long menuTimeUp = 60000; // menu shuts off after one minute of button inactivity static unsigned long lastDebounceTime = 0; // the last time the output pin was toggled static unsigned long buttonRepeatTime = 0; @@ -84,24 +67,17 @@ static byte subBreathCC = 0; static byte subBreathAT = 0; static byte subVelocity = 0; static byte subCurve = 0; -static byte subPort = 0; -static byte subPB = 0; -static byte subExtra = 0; -static byte subVibrato = 0; -static byte subDeglitch = 0; -static byte subPinky = 0; static byte subVelSmpDl = 0; static byte subVelBias = 0; static byte subParallel = 0; static byte subRotator = 0; static byte subPriority = 0; -static byte subVibSens = 0; -static byte subVibRetn = 0; -static byte subVibDirection = 0; +// The external function of subSquelch has been broken, +// need to come up with a smart way to make it work again. +// The status led was update when the Squelch menu was open. byte subVibSquelch = 0; //extern - // 'NuEVI' logo #define LOGO16_GLCD_WIDTH 128 #define LOGO16_GLCD_HEIGHT 64 @@ -196,6 +172,8 @@ void initDisplay() { display.display(); memset(cursors, 0, sizeof(cursors)); + memset(offsets, 0, sizeof(offsets)); + memset(activeSub, 0, sizeof(activeSub)); } void showVersion() { @@ -215,18 +193,76 @@ void showVersion() { display.display(); } -void drawMenuCursor(byte itemNo, byte color){ - byte ymid = 15 + 9 * itemNo; - display.drawTriangle(57, ymid,61, ymid+2,61, ymid-2, color); +// Assumes dest points to a buffer of atleast 7 bytes. +static const char* numToString(int16_t value, char* dest, bool plusSign = false) { + char* ptr = dest; + uint16_t absVal = abs(value); + int c = 1; + + if(value < 0) { + *ptr++ = '-'; + } else if(plusSign && value) { + *ptr++ = '+'; + } + while((c*10) < absVal+1) c *= 10; + while(c > 0) { + int tmp = absVal / c; + *ptr++ = tmp + '0'; + absVal %= c; + c /= 10; + } + *ptr = 0; + return dest; } +static void plotSubOption(const char* label, int color) { + display.setTextColor(color); + display.setTextSize(2); + int x_pos = 96-strlen(label)*6; + display.setCursor(x_pos,33); + display.println(label); +} + +static void plotSubNum(int value, int color) { + int s = 0; + if(value > 99) s = 2*7; + else if(value > 9) s = 1*7; + display.setTextColor(color); + display.setTextSize(2); + display.setCursor(90-s ,33); + display.println(value); +} + + static bool drawSubMenu(const MenuPage &page, int color) { int index = cursors[page.cursor]; - // TODO: Make sure this is a MenuEntrySub // TODO: Handle MenuEntrySubRotator case // TODO: Null check subMenuFunc - ((const MenuEntrySub*)page.entries[index])->subMenuFunc(color); + const MenuEntry* subEntry = page.entries[index]; + switch(subEntry->type) { + case MenuType::ESub: + ((const MenuEntrySub*)subEntry)->subMenuFunc(color); + break; + + case MenuType::ESubNew: + { + char buffer[12]; + const char* labelPtr = nullptr; + ((const MenuEntrySubNew*)subEntry)->getSubTextFunc(buffer, &labelPtr); + plotSubOption(buffer, color); + if(labelPtr != nullptr) { + // TODO: handle this better, we should center text + label + display.setCursor(105,40); + display.setTextSize(1); + display.println(labelPtr); + } + } + break; + + default: + break; + } return true; } @@ -241,6 +277,19 @@ static bool updateSubMenuCursor(const MenuPage &page, uint32_t timeNow) return false; } +static void plotMenuEntries(const MenuPage &page, bool clear = false) { + int row = 0; + if(clear) { + display.fillRect( 0, MENU_HEADER_OFFSET, 56, 64-MENU_HEADER_OFFSET, BLACK ); + } + for(int item = offsets[page.cursor]; (item < page.numEntries) && (row < MENU_NUM_ROWS); item++, row++) { + int rowPixel = (row)*MENU_ROW_HEIGHT + MENU_HEADER_OFFSET; + const char* lineText = page.entries[item]->title; + display.setCursor(0,rowPixel); + display.println(lineText); + } +} + static void drawMenu(const MenuPage &page, const char* customTitle = nullptr) { //Initialize display and draw menu header + line display.clearDisplay(); @@ -253,13 +302,7 @@ static void drawMenu(const MenuPage &page, const char* customTitle = nullptr) { display.println(page.title); display.drawLine(0, MENU_ROW_HEIGHT, 127, MENU_ROW_HEIGHT, WHITE); - int row = 0; - for(int item = 0; (item < page.numEntries) && (row < 6); item++, row++) { - int rowPixel = (row+1)*MENU_ROW_HEIGHT + MENU_HEADER_OFFSET; - const char* lineText = page.entries[item]->title; - display.setCursor(0,rowPixel); - display.println(lineText); - } + plotMenuEntries(page); } static void drawMenuScreen() { @@ -334,46 +377,22 @@ static void drawSubBox(const char* label) display.println(label); } -static void plotSubOption(const char* label, int color) { - display.setTextColor(color); - display.setTextSize(2); - int x_pos = 91-strlen(label)*4; - display.setCursor(x_pos,33); - display.println(label); +void drawMenuCursor(byte itemNo, byte color){ + byte ymid = 15 + 9 * itemNo; + display.drawTriangle(57, ymid,61, ymid+2,61, ymid-2, color); } -static void plotSubNum(int value, int color) { - int s = 0; - if(value > 99) s = 2*7; - else if(value > 9) s = 1*7; - display.setTextColor(color); - display.setTextSize(2); - display.setCursor(90-s ,33); - display.println(value); -} static void plotTranspose(int color){ - int value = transpose - 12; - const char *sign = (value < 0) ? "-":"+"; - display.setTextColor(color); - display.setTextSize(2); - display.setCursor(80,33); - display.println(sign); - display.setCursor(93,33); - display.println(abs(value)); + char buff[12]; + numToString(transpose - 12, buff, true); + plotSubOption(buff, color); } static void plotRotator(int color,int value){ - display.setTextColor(color); - display.setTextSize(2); - display.setCursor(80,33); - if ((value) > -1){ - display.println("+"); - } else { - display.println("-"); - } - display.setCursor(93,33); - display.println(abs(value)); + char buff[12]; + numToString(value, buff, true); + plotSubOption(buff, color); } static void plotPriority(int color){ @@ -385,16 +404,9 @@ static void plotPriority(int color){ } static void plotOctave(int color){ - display.setTextColor(color); - display.setTextSize(2); - display.setCursor(80,33); - if ((octave-3) > -1){ - display.println("+"); - } else { - display.println("-"); - } - display.setCursor(93,33); - display.println(abs(octave-3)); + char buff[12]; + numToString(octave-3, buff, true); + plotSubOption(buff, color); } static void plotMIDI(int color) { @@ -443,94 +455,6 @@ static void plotCurve(int color){ plotSubOption(curveMenuLabels[curve], color); } -static void plotPort(int color){ - if (portamento == 1){ - plotSubOption("ON", color); - } else if (portamento == 2){ - plotSubOption("SW", color); - } else { - plotSubOption("OFF", color); - } -} - -static void plotPB(int color){ - display.setTextColor(color); - display.setTextSize(2); - display.setCursor(76,33); - if (PBdepth){ - display.println("1/"); - display.setCursor(101,33); - display.println(PBdepth); - } else { - display.println("OFF"); - } -} - -static const char* extraMenuLabels[] = { "OFF", "MW", "FP", "CF", "SP" }; - -static void plotExtra(int color){ - plotSubOption(extraMenuLabels[extraCT], color); -} - -static void plotVibrato(int color){ - if (vibrato){ - plotSubNum(vibrato, color); - } else { - plotSubOption("OFF", color); - } -} - -static void plotVibSens(int color){ - plotSubNum(vibSens, color); -} - -static void plotVibRetn(int color){ - plotSubNum(vibRetn, color); -} - -static void plotVibSquelch(int color){ - plotSubNum(vibSquelch, color); -} - -static void plotVibDirection(int color){ - if (DNWD == vibDirection){ - plotSubOption("NRM", color); - } else { - plotSubOption("REV", color); - } -} - - -static void plotDeglitch(int color){ - display.setTextColor(color); - display.setTextSize(2); - display.setCursor(79,33); - if (deglitch){ - display.println(deglitch); - display.setCursor(105,40); - display.setTextSize(1); - display.println("ms"); - } else { - display.println("OFF"); - } -} - - -static void plotPinkyKey(int color){ - display.setTextColor(color); - display.setTextSize(2); - display.setCursor(79,33); - if (pinkySetting < 12){ - display.println(pinkySetting - 12); - } else if (pinkySetting == PBD) { - display.println("PBD"); - } else { - display.print("+"); - display.println(pinkySetting - 12); - } -} - - static void plotVelSmpDl(int color){ display.setTextColor(color); display.setCursor(79,33); @@ -679,13 +603,62 @@ const MenuPage breathMenuPage = { ARR_LEN(breathMenuEntries), breathMenuEntries }; +//*********************************************************** // Control menu -const MenuEntrySub portMenu = { MenuType::ESub, "PORT/GLD", "PORT/GLD", &subPort, plotPort }; -const MenuEntrySub pitchBendMenu = { MenuType::ESub, "PITCHBEND", "PITCHBEND", &subPB, plotPB }; -const MenuEntrySub extraMenu = { MenuType::ESub, "EXTRA CTR", "EXTRA CTR", &subExtra, plotExtra }; +const MenuEntrySubNew portMenu = { + MenuType::ESubNew, "PORT/GLD", "PORT/GLD", &portamento, 0, 2, MenuEntryFlags::EWrap, + [](char* out, const char ** __unused label) { + const char* labs[] = { "OFF", "ON", "SW" }; + strncpy(out, labs[portamento], 4); + }, + []() { writeSetting(PORTAM_ADDR,portamento); } +}; + +const MenuEntrySubNew pitchBendMenu = { + MenuType::ESubNew, "PITCHBEND", "PITCHBEND", &PBdepth, 0, 12, MenuEntryFlags::ENone, + [](char* out, const char** __unused label) { + if(PBdepth) { + memcpy(out, "1/", 2); + numToString(PBdepth, &out[2]); + } + else strncpy(out, "OFF", 4); + }, + [](){ writeSetting(PB_ADDR,PBdepth); } +}; + +const MenuEntrySubNew extraMenu = { + MenuType::ESubNew, "EXTRA CTR", "EXTRA CTR", &extraCT, 0,4, MenuEntryFlags::EWrap, + [](char* out, const char** __unused label) { + const char* extraMenuLabels[] = { "OFF", "MW", "FP", "CF", "SP" }; + strncpy(out, extraMenuLabels[extraCT], 12); + }, + []() { writeSetting(EXTRA_ADDR,extraCT); } +}; + const MenuEntryStateCh vibratoSubMenu = { MenuType::EStateChange, "VIBRATO", VIBRATO_MENU }; -const MenuEntrySub deglitchMenu = { MenuType::ESub, "DEGLITCH", "DEGLITCH", &subDeglitch, plotDeglitch }; -const MenuEntrySub pinkyMenu = { MenuType::ESub, "PINKY KEY", "PINKY KEY", &subPinky, plotPinkyKey }; + +const MenuEntrySubNew deglitchMenu = { + MenuType::ESubNew, "DEGLITCH", "DEGLITCH", °litch, 0, 70, MenuEntryFlags::ENone, + [](char* textBuffer, const char** label) { + if(deglitch) { + numToString(deglitch, textBuffer); + *label = "ms"; + } else + strncpy(textBuffer, "OFF", 4); + }, + []() { writeSetting(DEGLITCH_ADDR,deglitch); } +}; + +const MenuEntrySubNew pinkyMenu = { + MenuType::ESubNew, "PINKY KEY", "PINKY KEY", &pinkySetting, 0, 24, MenuEntryFlags::ENone, + [](char* textBuffer, const char** __unused label) { + if (pinkySetting == PBD) + strncpy(textBuffer, "PBD", 4); + else + numToString(pinkySetting-12, textBuffer, true); + }, + []() { writeSetting(PINKY_KEY_ADDR,pinkySetting); } +}; const MenuEntry* controlMenuEntries[] = { (MenuEntry*)&portMenu, @@ -704,12 +677,54 @@ const MenuPage controlMenuPage = { }; +//*********************************************************** // Vibrato menu -const MenuEntrySub vibDepthMenu = { MenuType::ESub, "DEPTH", "LEVEL", &subVibrato, plotVibrato }; -const MenuEntrySub vibSenseMenu = { MenuType::ESub, "SENSE", "LEVEL", &subVibSens, plotVibSens }; -const MenuEntrySub vibRetnMenu = { MenuType::ESub, "RETURN", "LEVEL", &subVibRetn, plotVibRetn }; -const MenuEntrySub vibSquelchMenu = { MenuType::ESub, "SQUELCH", "LEVEL", &subVibSquelch, plotVibSquelch }; -const MenuEntrySub vibDirMenu = { MenuType::ESub, "DIRECTION", "DIRECTION", &subVibDirection, plotVibDirection }; + +const MenuEntrySubNew vibDepthMenu = { + MenuType::ESubNew, "DEPTH", "LEVEL", &vibrato, 0, 9, MenuEntryFlags::ENone, + [](char* textBuffer, const char** __unused label) { + if(vibrato) + numToString(vibrato, textBuffer); + else + strncpy(textBuffer, "OFF", 4); + }, + []() { writeSetting(VIBRATO_ADDR,vibrato); } +}; + +const MenuEntrySubNew vibSenseMenu = { + MenuType::ESubNew, "SENSE", "LEVEL", &vibSens, 1, 12, MenuEntryFlags::ENone, + [](char* textBuffer, const char** __unused label) { + numToString(vibSens, textBuffer); + }, + []() { writeSetting(VIB_SENS_ADDR,vibSens); } +}; + +const MenuEntrySubNew vibRetnMenu = { + MenuType::ESubNew, "RETURN", "LEVEL", &vibRetn, 0, 4, MenuEntryFlags::ENone, + [](char* textBuffer, const char** __unused label) { + numToString(vibRetn, textBuffer); + }, + []() { writeSetting(VIB_RETN_ADDR,vibRetn); } +}; + +const MenuEntrySubNew vibSquelchMenu = { + MenuType::ESubNew, "SQUELCH", "LEVEL", &vibSquelch, 1, 30, MenuEntryFlags::ENone, + [](char* textBuffer, const char** __unused label) { + numToString(vibSquelch, textBuffer); + }, + []() { writeSetting(VIB_SQUELCH_ADDR,vibSquelch); } +}; + +const MenuEntrySubNew vibDirMenu = { + MenuType::ESubNew, "DIRECTION", "DIRECTION", &vibDirection, 0, 1, MenuEntryFlags::EWrap, + [](char* textBuffer, const char** __unused label) { + if (DNWD == vibDirection) + strncpy(textBuffer, "NRM", 4); + else + strncpy(textBuffer, "REV", 4); + }, + []() { writeSetting(VIB_DIRECTION_ADDR,vibDirection); } +}; const MenuEntry* vibratorMenuEntries[] = { (MenuEntry*)&vibDepthMenu, @@ -729,339 +744,47 @@ const MenuPage vibratoMenuPage = { //*********************************************************** -const AdjustMenuEntry breathAdjustMenu = { - "BREATH", - { - { &breathThrVal, breathLoLimit, breathHiLimit }, - { &breathMaxVal, breathLoLimit, breathHiLimit } - }, - [] (const AdjustMenuEntry& e) { - writeSetting(BREATH_THR_ADDR, *e.entries[0].value); - writeSetting(BREATH_MAX_ADDR, *e.entries[1].value); - } -}; - -const AdjustMenuEntry portamentoAdjustMenu = { - "PORTAMENTO", - { - { &portamThrVal, portamLoLimit, portamHiLimit }, - { &portamMaxVal, portamLoLimit, portamHiLimit } - }, - [] (const AdjustMenuEntry& e) { - writeSetting(PORTAM_THR_ADDR, *e.entries[0].value); - writeSetting(PORTAM_MAX_ADDR, *e.entries[1].value); - } -}; - -const AdjustMenuEntry pitchBendAdjustMenu = { - "PITCH BEND", - { - { &pitchbThrVal, pitchbLoLimit, pitchbHiLimit }, - { &pitchbMaxVal, pitchbLoLimit, pitchbHiLimit } - }, - [] (const AdjustMenuEntry& e) { - writeSetting(PITCHB_THR_ADDR, *e.entries[0].value); - writeSetting(PITCHB_MAX_ADDR, *e.entries[1].value); - } -}; - -const AdjustMenuEntry extraSensorAdjustMenu = { - "EXTRA CONTROLLER", - { - { &extracThrVal, extracLoLimit, extracHiLimit }, - { &extracMaxVal, extracLoLimit, extracHiLimit } - }, - [] (const AdjustMenuEntry& e) { - writeSetting(EXTRAC_THR_ADDR, *e.entries[0].value); - writeSetting(EXTRAC_MAX_ADDR, *e.entries[1].value); - } -}; - -const AdjustMenuEntry ctouchAdjustMenu = { - "TOUCH SENSE", - { - { &ctouchThrVal, ctouchLoLimit, ctouchHiLimit }, - { nullptr, 0, 0 } - }, - [] (const AdjustMenuEntry& e) { - writeSetting(CTOUCH_THR_ADDR, *e.entries[0].value); - } -}; - -const AdjustMenuEntry* adjustMenuEntries[] = { - &breathAdjustMenu, - &portamentoAdjustMenu, - &pitchBendAdjustMenu, - &extraSensorAdjustMenu, - &ctouchAdjustMenu, -}; - -static const int numAdjustEntries = ARR_LEN(adjustMenuEntries); - -//*********************************************************** -static void drawAdjCursor(byte color) { - display.drawTriangle(16,4,20,4,18,1,color); - display.drawTriangle(16,6,20,6,18,9,color); -} - -static void drawAdjustFrame(int line) { - display.drawLine(25,line,120,line,WHITE); // Top line - display.drawLine(25,line+12,120,line+12,WHITE); // Bottom line - - display.drawLine(25,line+1,25,line+2,WHITE); - display.drawLine(120,line+1,120,line+2,WHITE); - - display.drawLine(120,line+10,120,line+11,WHITE); - display.drawLine(25,line+10,25,line+11,WHITE); -} - -static void drawAdjustBase(const char* title, bool all) { - display.clearDisplay(); - - drawAdjustFrame(17); - - // sensor marker lines. - display.drawLine(25,36,25,40,WHITE); - display.drawLine(120,36,120,40,WHITE); - - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(25,2); - display.println(title); - - display.setCursor(0,20); - display.println("THR"); - display.setCursor(0,35); - display.println("SNS"); - - - if(all) { - drawAdjustFrame(47); - display.setCursor(0,50); - display.println("MAX"); - } - cursorNow = WHITE; - drawAdjCursor(WHITE); -} - -static bool drawAdjustBar(uint16_t buttons, int row, const AdjustValue* entry, uint16_t *pos) { - bool updated = false; - uint16_t step = (entry->limitHigh-entry->limitLow)/92; - int val = *entry->value; - switch(buttons) { - case BTN_UP: - val += step; - updated = true; - break; - - case BTN_DOWN: - val -= step; - updated = true; - break; - } - if(updated) { - *entry->value = constrain(val, entry->limitLow, entry->limitHigh); - auto p = *pos; - display.drawLine(p, row, p, row+6, BLACK); - *pos = p = map(*entry->value, entry->limitLow, entry->limitHigh, 27, 119); - display.drawLine(p, row, p, row+6, WHITE); - cursorNow = BLACK; - } - return updated; -} - -static bool updateAdjustCursor(uint32_t timeNow) { - if ((timeNow - cursorBlinkTime) > cursorBlinkInterval) { - if (cursorNow == WHITE) cursorNow = BLACK; else cursorNow = WHITE; - drawAdjCursor(cursorNow); - cursorBlinkTime = timeNow; - return true; - } - return false; -} - -static bool updateAdjustLineCursor(uint32_t timeNow, uint16_t hPos, uint16_t vPos ) { - if ((timeNow - cursorBlinkTime) > cursorBlinkInterval) { - if (cursorNow == WHITE) cursorNow = BLACK; else cursorNow = WHITE; - display.drawLine(hPos, vPos,hPos, vPos+6, cursorNow);; - cursorBlinkTime = timeNow; - return true; - } - return false; -} - -static void drawAdjustMenu(const AdjustMenuEntry *menu) { - - bool haveSecondValue = menu->entries[1].value != nullptr; - drawAdjustBase( menu->title, haveSecondValue ); - - pos1 = map( *menu->entries[0].value, menu->entries[0].limitLow, menu->entries[0].limitHigh, 27, 119); - display.drawLine( pos1, 20, pos1, 26, WHITE ); - - if(haveSecondValue) { - pos2 = map( *menu->entries[1].value, menu->entries[1].limitLow, menu->entries[1].limitHigh, 27, 119); - display.drawLine( pos2, 50, pos2, 56, WHITE ); - } -} - -static bool updateAdjustMenu(uint32_t timeNow, uint8_t buttons) { - bool redraw = false; - const AdjustMenuEntry *currentMenu = adjustMenuEntries[adjustOption]; - - if(stateFirstRun) { - adjustCurrent = 0; - drawAdjustMenu(currentMenu); - stateFirstRun = 0; - // the sensor pixel stuff should be refactored (to work again) - forcePix = 1; - sensorPixelPos1 = -1; // Force draw of sensor pixels - } - - if(adjustCurrent == 0) { - // Currently selecting what option to modify - redraw |= updateAdjustCursor(timeNow); - - bool save = false; - - if( buttons == BTN_DOWN ) { - adjustOption += 1; - stateFirstRun = 1; - save = true; - } - else if ( buttons == BTN_UP ) { - adjustOption -= 1; - stateFirstRun = 1; - save = true; - } - else if ( buttons == BTN_ENTER ) { - adjustCurrent = 1; - } - else if (buttons == BTN_MENU ) { - adjustCurrent = 0; - state = MAIN_MENU; - stateFirstRun = 1; - save = true; - } - - if(save && currentMenu->saveFunc) - currentMenu->saveFunc(*currentMenu); - - } else if( adjustCurrent == 1) { - if (buttons) { - drawAdjustBar( buttons, 20, ¤tMenu->entries[0], &pos1 ); - if(buttons == BTN_ENTER) adjustCurrent += 1; - else if( buttons == BTN_MENU) adjustCurrent = 0; - redraw = true; - } else { - redraw |= updateAdjustLineCursor( timeNow, pos1, 20 ); - } - } else { - if (buttons) { - drawAdjustBar( buttons, 50, ¤tMenu->entries[1], &pos2 ); - if(buttons == BTN_ENTER) adjustCurrent += 1; - else if( buttons == BTN_MENU) adjustCurrent = 0; - redraw = true; - } else { - redraw |= updateAdjustLineCursor( timeNow, pos2, 50 ); - } - } - - // Keep adjustCurrent in range - if(adjustCurrent > 2) - adjustCurrent = 0; - - // Keep adjust option in range. - if(adjustOption < 0) - adjustOption = numAdjustEntries-1; - else if (adjustOption >= numAdjustEntries) - adjustOption = 0; - - return redraw; -} - -//*********************************************************** - -static bool updateSensorPixel(int pos, int pos2) { - bool update = pos != sensorPixelPos1 || pos2 != sensorPixelPos2; - if(update) { - display.drawFastHLine(28, 38, 119-28, BLACK); // Clear old line - display.drawPixel(pos, 38, WHITE); - if( pos2 >= 0) display.drawPixel(pos2, 38, WHITE); - - sensorPixelPos1 = pos; - sensorPixelPos2 = pos2; - } - return update; -} - -void drawSensorPixels(){ - if( state != ADJUST_MENU ) - return; - - int redraw = 0; - - if(forcePix) - sensorPixelPos1 = -1; - - // This is hacky. It depends on the order of items in the adjust menu list. - if(adjustOption == 0) { - int pos = map(constrain(pressureSensor, breathLoLimit, breathHiLimit), breathLoLimit, breathHiLimit, 28, 118); - redraw = updateSensorPixel(pos, -1); - } - else if(adjustOption == 1) { - int pos = map(constrain(biteSensor,portamLoLimit,portamHiLimit), portamLoLimit, portamHiLimit, 28, 118); - redraw = updateSensorPixel(pos, -1); - } - else if(adjustOption == 2) { - int pos = map(constrain(pbUp, pitchbLoLimit, pitchbHiLimit), pitchbLoLimit, pitchbHiLimit, 28, 118); - int pos2 = map(constrain(pbDn, pitchbLoLimit, pitchbHiLimit), pitchbLoLimit, pitchbHiLimit, 28, 118); - redraw = updateSensorPixel(pos, pos2); - } - else if(adjustOption == 3) { - int pos = map(constrain(exSensor, extracLoLimit, extracHiLimit), extracLoLimit, extracHiLimit, 28, 118); - redraw = updateSensorPixel(pos, -1); - } - else if(adjustOption == 4) { - display.drawLine(28,38,118,38,BLACK); - for (byte i=0; i<12; i++){ - int pos = map(constrain(touchSensor.filteredData(i), ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118); - display.drawPixel(pos, 38, WHITE); - } - - int posRead = map(touchRead(halfPitchBendKeyPin),ttouchLoLimit,ttouchHiLimit,ctouchHiLimit,ctouchLoLimit); - int pos = map(constrain(posRead, ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118); - - posRead = map(touchRead(specialKeyPin),ttouchLoLimit,ttouchHiLimit,ctouchHiLimit,ctouchLoLimit); - int pos2 = map(constrain(posRead, ctouchLoLimit, ctouchHiLimit), ctouchLoLimit, ctouchHiLimit, 28, 118); - - updateSensorPixel(pos, pos2); - - redraw = 1; - } - if (redraw){ - display.display(); - } - forcePix = 0; -} - -//*********************************************************** - -static bool ExecuteMenuSelection(int cursorPosition, const struct MenuEntry *menuEntry) +static bool ExecuteMenuSelection( const MenuPage &page ) //int cursorPosition, const struct MenuEntry *menuEntry) { + int cursorPosition = cursors[page.cursor]; + const MenuEntry* menuEntry = page.entries[cursorPosition]; + cursorBlinkTime = millis(); + switch(menuEntry->type) { case MenuType::ESub: *((const MenuEntrySub*)menuEntry)->flag = 1; + activeSub[page.cursor] = cursorPosition+1; drawMenuCursor(cursorPosition, WHITE); drawSubBox( ((const MenuEntrySub*)menuEntry)->subTitle); ((const MenuEntrySub*)menuEntry)->subMenuFunc(WHITE); return true; + case MenuType::ESubNew: + { + char buffer[12]; + const char* labelPtr = nullptr; + activeSub[page.cursor] = cursorPosition+1; + drawMenuCursor(cursorPosition, WHITE); + drawSubBox( ((const MenuEntrySubNew*)menuEntry)->subTitle); + ((const MenuEntrySubNew*)menuEntry)->getSubTextFunc(buffer, &labelPtr); + plotSubOption(buffer, WHITE); + if(labelPtr != nullptr) { + // TODO: handle this better, we should center text + label + display.setCursor(105,40); + display.setTextSize(1); + display.println(labelPtr); + } + return true; + } + break; + case MenuType::EStateChange: state = ((const MenuEntryStateCh*)menuEntry)->state; stateFirstRun = 1; break; case MenuType::ESubRotator: + activeSub[page.cursor] = cursorPosition+1; *((const MenuEntrySubRotator*)menuEntry)->flag = ((const MenuEntrySubRotator*)menuEntry)->flagValue; drawMenuCursor(cursorPosition, WHITE); ((const MenuEntrySubRotator*)menuEntry)->subMenuFunc(WHITE); @@ -1073,14 +796,67 @@ static bool ExecuteMenuSelection(int cursorPosition, const struct MenuEntry *men //*********************************************************** -static bool selectMenuOption(int cursorPosition, const MenuEntry** menuEntries){ - cursorBlinkTime = millis(); - const MenuEntry* entry = menuEntries[cursorPosition]; - return ExecuteMenuSelection( cursorPosition, entry ); +static bool selectMenuOption(const MenuPage &page){ + // const MenuEntry* entry = menuEntries[cursorPosition]; + return ExecuteMenuSelection( page ); } //*********************************************************** +static bool updateSubMenu(const MenuPage &page, uint32_t timeNow) { + + bool redraw = false; + bool redrawSubValue = false; + if (buttonPressedAndNotUsed){ + buttonPressedAndNotUsed = 0; + + int current_sub = activeSub[page.cursor] -1; + + if( current_sub < 0) + return false; + + auto sub = (const MenuEntrySubNew*)page.entries[current_sub]; + uint16_t currentVal = *sub->valuePtr; + + switch (deumButtonState){ + case BTN_DOWN: + if(currentVal > sub->min) { + currentVal -= 1; + } else if(sub->flags & MenuEntryFlags::EWrap) { + currentVal = sub->max; + } + break; + + case BTN_UP: + if(currentVal < sub->max) { + currentVal += 1; + } else if(sub->flags & MenuEntryFlags::EWrap) { + currentVal = sub->min; + } + break; + + case BTN_ENTER: // fallthrough + case BTN_MENU: + activeSub[page.cursor] = 0; + sub->applyFunc(); + break; + } + *sub->valuePtr = currentVal; + redrawSubValue = true; + } else { + redraw = updateSubMenuCursor( page, timeNow ); + } + + if(redrawSubValue) { + clearSubValue(); + redraw |= drawSubMenu(page, WHITE); + cursorNow = BLACK; + cursorBlinkTime = timeNow; + } + + return redraw; +} + static bool updateMenuPage( const MenuPage &page, uint32_t timeNow ) { byte cursorPos = cursors[page.cursor]; byte newPos = cursorPos; @@ -1098,7 +874,8 @@ static bool updateMenuPage( const MenuPage &page, uint32_t timeNow ) { break; case BTN_ENTER: - redraw |= selectMenuOption(cursorPos, page.entries); + // redraw |= selectMenuOption(cursorPos, page.entries); + redraw |= selectMenuOption(page); break; case BTN_UP: @@ -1158,7 +935,7 @@ static void checkForPatchView(int buttons) { } // This should be moved to a separate file/process that handles only led -void statusBlink() { +static void statusBlink() { digitalWrite(statusLedPin,LOW); delay(150); digitalWrite(statusLedPin,HIGH); @@ -1168,6 +945,13 @@ void statusBlink() { digitalWrite(statusLedPin,HIGH); } +static bool updateSensorPixelsFlag = false; + +void drawSensorPixels() { + updateSensorPixelsFlag = true; +} + + //*********************************************************** void menu() { @@ -1219,21 +1003,14 @@ void menu() { subBreathCC = 0; subBreathAT = 0; subVelocity = 0; - subPort = 0; - subPB = 0; - subExtra = 0; - subVibrato = 0; - subDeglitch = 0; - subPinky = 0; subVelSmpDl = 0; subVelBias = 0; + subParallel = 0; subRotator = 0; subPriority = 0; - subVibSens = 0; - subVibRetn = 0; + subVibSquelch = 0; - subVibDirection = 0; } if (state == DISPLAYOFF_IDL) { @@ -1590,9 +1367,19 @@ void menu() { } else if (state == ADJUST_MENU) { // This is a hack to update touch_Thr is it was changed.. int old_thr = ctouchThrVal; - redraw |= updateAdjustMenu( timeNow, buttonPressedAndNotUsed ? deumButtonState : 0 ); + int result = updateAdjustMenu( timeNow, buttonPressedAndNotUsed ? deumButtonState : 0, stateFirstRun, updateSensorPixelsFlag); + + updateSensorPixelsFlag = false; + stateFirstRun = 0; buttonPressedAndNotUsed = 0; + if( result < 0) + { + // Go back to main menu + state = MAIN_MENU; + stateFirstRun = true; + } + if( old_thr != ctouchThrVal) { touch_Thr = map(ctouchThrVal,ctouchHiLimit,ctouchLoLimit,ttouchLoLimit,ttouchHiLimit); } @@ -1764,254 +1551,27 @@ void menu() { } else if (state == SETUP_CT_MENU) { // SETUP CONTROLLERS MENU HERE <<<<<<<<<<<<< + currentPage = &controlMenuPage; if (stateFirstRun) { - drawMenu( controlMenuPage ); + drawMenu(*currentPage); stateFirstRun = 0; } - currentPage = &controlMenuPage; - if (subPort){ - redraw |= updateSubMenuCursor( *currentPage, timeNow ); - if (buttonPressedAndNotUsed){ - buttonPressedAndNotUsed = 0; - switch (deumButtonState){ - case BTN_DOWN: - if (portamento > 0){ - portamento--; - } else portamento = 2; - break; - - case BTN_UP: - if (portamento < 2){ - portamento++; - } else portamento = 0; - break; - - case BTN_ENTER: // fallthrough - case BTN_MENU: - subPort = 0; - writeSetting(PORTAM_ADDR,portamento); - break; - } - redrawSubValue = true; - } - } else if (subPB) { - redraw |= updateSubMenuCursor( *currentPage, timeNow ); - if (buttonPressedAndNotUsed){ - buttonPressedAndNotUsed = 0; - switch (deumButtonState){ - case BTN_DOWN: - if (PBdepth > 0) - PBdepth--; - break; - - case BTN_UP: - if (PBdepth < 12) - PBdepth++; - break; - - case BTN_ENTER: // fallthrough - case BTN_MENU: - subPB = 0; - writeSetting(PB_ADDR,PBdepth); - break; - } - redrawSubValue = true; - } - } else if (subExtra) { - redraw |= updateSubMenuCursor( *currentPage, timeNow ); - if (buttonPressedAndNotUsed){ - buttonPressedAndNotUsed = 0; - switch (deumButtonState){ - case BTN_DOWN: - if (extraCT > 0){ - extraCT--; - } else extraCT = 4; - break; - - case BTN_UP: - if (extraCT < 4){ - extraCT++; - } else extraCT = 0; - break; - - case BTN_ENTER: // fallthrough - case BTN_MENU: - subExtra = 0; - writeSetting(EXTRA_ADDR,extraCT); - break; - } - redrawSubValue = true; - } - } else if (subDeglitch) { - redraw |= updateSubMenuCursor( *currentPage, timeNow ); - if (buttonPressedAndNotUsed){ - buttonPressedAndNotUsed = 0; - switch (deumButtonState){ - case BTN_DOWN: - if (deglitch > 0) - deglitch-=1; - break; - - case BTN_UP: - if (deglitch < 70){ - deglitch+=1; - } - break; - - case BTN_ENTER: // fallthrough - case BTN_MENU: - subDeglitch = 0; - writeSetting(DEGLITCH_ADDR,deglitch); - break; - } - redrawSubValue = true; - } - } else if (subPinky) { - redraw |= updateSubMenuCursor( *currentPage, timeNow ); - if (buttonPressedAndNotUsed){ - buttonPressedAndNotUsed = 0; - switch (deumButtonState){ - case BTN_DOWN: - if (pinkySetting > 0) - pinkySetting-=1; - break; - - case BTN_UP: - if (pinkySetting < 24) - pinkySetting += 1; - break; - - case BTN_ENTER: // fallthrough - case BTN_MENU: - subPinky = 0; - writeSetting(PINKY_KEY_ADDR,pinkySetting); - break; - } - redrawSubValue = true; - } + if (activeSub[currentPage->cursor]) { + redraw |= updateSubMenu(*currentPage, timeNow); } else { - redraw |= updateMenuPage( *currentPage, timeNow ); + redraw |= updateMenuPage(*currentPage, timeNow); } } else if (state == VIBRATO_MENU) { // VIBRATO MENU HERE <<<<<<<<<<<<< + currentPage = &vibratoMenuPage; if (stateFirstRun) { - drawMenu(vibratoMenuPage); + drawMenu(*currentPage); stateFirstRun = 0; } - currentPage = &vibratoMenuPage; - if (subVibrato) { - redraw |= updateSubMenuCursor( *currentPage, timeNow ); - if (buttonPressedAndNotUsed){ - buttonPressedAndNotUsed = 0; - switch (deumButtonState){ - case BTN_DOWN: - if (vibrato > 0) - vibrato--; - break; - - case BTN_UP: - if (vibrato < 9) - vibrato++; - break; - - case BTN_ENTER: // fallthrough - case BTN_MENU: - subVibrato = 0; - writeSetting(VIBRATO_ADDR,vibrato); - break; - } - redrawSubValue = true; - } - } else if (subVibSens) { - redraw |= updateSubMenuCursor( *currentPage, timeNow ); - if (buttonPressedAndNotUsed){ - buttonPressedAndNotUsed = 0; - switch (deumButtonState){ - case BTN_DOWN: - if (vibSens > 1) - vibSens--; - break; - - case BTN_UP: - if (vibSens < 12) - vibSens++; - break; - - case BTN_ENTER: // fallthrough - case BTN_MENU: - subVibSens = 0; - writeSetting(VIB_SENS_ADDR,vibSens); - break; - } - redrawSubValue = true; - } - } else if (subVibRetn) { - redraw |= updateSubMenuCursor( *currentPage, timeNow ); - if (buttonPressedAndNotUsed){ - buttonPressedAndNotUsed = 0; - switch (deumButtonState){ - case BTN_DOWN: - if (vibRetn > 0) - vibRetn--; - break; - - case BTN_UP: - if (vibRetn < 4) - vibRetn++; - break; - - case BTN_ENTER: // fallthrough - case BTN_MENU: - subVibRetn = 0; - writeSetting(VIB_RETN_ADDR,vibRetn); - break; - } - redrawSubValue = true; - } - } else if (subVibSquelch) { - redraw |= updateSubMenuCursor( *currentPage, timeNow ); - if (buttonPressedAndNotUsed){ - buttonPressedAndNotUsed = 0; - switch (deumButtonState){ - case BTN_DOWN: - if (vibSquelch > 1) - vibSquelch--; - break; - - case BTN_UP: - if (vibSquelch < 30) - vibSquelch++; - break; - - case BTN_ENTER: // fallthrough - case BTN_MENU: - subVibSquelch = 0; - writeSetting(VIB_SQUELCH_ADDR,vibSquelch); - break; - } - redrawSubValue = true; - } - } else if (subVibDirection) { - redraw |= updateSubMenuCursor( *currentPage, timeNow ); - if (buttonPressedAndNotUsed){ - buttonPressedAndNotUsed = 0; - switch (deumButtonState){ - - case BTN_DOWN: // fallthrough - case BTN_UP: - vibDirection = !vibDirection; - break; - - case BTN_ENTER: // fallthrough - case BTN_MENU: - subVibDirection = 0; - writeSetting(VIB_DIRECTION_ADDR,vibDirection); - break; - } - redrawSubValue = true; - } + if (activeSub[currentPage->cursor]) { + redraw |= updateSubMenu(*currentPage, timeNow); } else { - redraw |= updateMenuPage( *currentPage, timeNow ); + redraw |= updateMenuPage(*currentPage, timeNow); } } diff --git a/NuEVI/menu.h b/NuEVI/menu.h index 57485ab..d0d21af 100644 --- a/NuEVI/menu.h +++ b/NuEVI/menu.h @@ -4,8 +4,8 @@ #include "Wiring.h" #define MENU_ROW_HEIGHT 9 -#define MENU_HEADER_OFFSET 3 -#define MENU_NUM_ROWS 5 +#define MENU_HEADER_OFFSET 12 +#define MENU_NUM_ROWS 6 //display states #define DISPLAYOFF_IDL 0 @@ -17,6 +17,23 @@ #define ROTATOR_MENU 100 #define VIBRATO_MENU 110 +#define ARR_LEN(a) (sizeof (a) / sizeof (a[0])) + +#define BTN_DOWN 1 +#define BTN_ENTER 2 +#define BTN_UP 4 +#define BTN_MENU 8 + + + +extern const unsigned long debounceDelay; // the debounce time; increase if the output flickers +extern const unsigned long buttonRepeatInterval; +extern const unsigned long buttonRepeatDelay; +extern const unsigned long cursorBlinkInterval; // the cursor blink toggle interval time +extern const unsigned long patchViewTimeUp; // ms until patch view shuts off +extern const unsigned long menuTimeUp; // menu shuts off after one minute of button inactivity + + extern byte subVibSquelch; @@ -27,4 +44,7 @@ void drawSensorPixels(); unsigned short readSetting(byte address); void writeSetting(byte address, unsigned short value); +int updateAdjustMenu(uint32_t timeNow, uint8_t buttons, bool firstRun, bool updateSensor); + + #endif diff --git a/NuEVI/numenu.h b/NuEVI/numenu.h index f3ac0ff..befb618 100644 --- a/NuEVI/numenu.h +++ b/NuEVI/numenu.h @@ -5,6 +5,7 @@ enum MenuType { ESub, + ESubNew, ESubRotator, EStateChange, }; @@ -22,6 +23,25 @@ struct MenuEntrySub { void (*subMenuFunc)(int color); }; +enum MenuEntryFlags { + ENone = 0, + EWrap = (1<<0), + ECustom = (1<<1), +}; + +struct MenuEntrySubNew { + enum MenuType type; + const char* title; + const char* subTitle; + uint16_t* valuePtr; + uint16_t min; + uint16_t max; + uint16_t flags; + void (*getSubTextFunc)(char*textBuffer, const char**label); + void (*applyFunc)(void); +}; + + struct MenuEntrySubRotator { enum MenuType type; const char* title; diff --git a/simulation/Makefile b/simulation/Makefile index d960a6c..30ac3d8 100644 --- a/simulation/Makefile +++ b/simulation/Makefile @@ -27,6 +27,7 @@ INCDIRS += $(addprefix -I,$(INCS)) TARGET=nuevisim CXXFILES= ../NuEVI/menu.cpp \ + ../NuEVI/adjustmenu.cpp \ src/nuevisim.cpp \ src/simeeprom.cpp \ src/Print.cpp \