From 1a543a6734edcf5b055e5ba54c04b25ee3e23281 Mon Sep 17 00:00:00 2001 From: John Stack Date: Mon, 27 Feb 2023 12:56:49 +0100 Subject: [PATCH] Changes up to 1.6.0 --- .gitignore | 3 +- NuEVI/NuEVI.ino | 315 +++++++++++++++++++++++++++------------- NuEVI/adjustmenu.cpp | 10 +- NuEVI/config.h | 2 +- NuEVI/globals.h | 2 + NuEVI/hardware.h | 2 + NuEVI/led.cpp | 14 +- NuEVI/menu.cpp | 339 +++++++++++++++++++++++++++++++------------ NuEVI/menu.h | 3 + NuEVI/settings.cpp | 5 + NuEVI/settings.h | 8 +- 11 files changed, 507 insertions(+), 196 deletions(-) diff --git a/.gitignore b/.gitignore index eafd693..b6ece0b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .vscode/ipch -*.o \ No newline at end of file +*.o +.DS_STORE diff --git a/NuEVI/NuEVI.ino b/NuEVI/NuEVI.ino index 60d914b..db8ab5b 100644 --- a/NuEVI/NuEVI.ino +++ b/NuEVI/NuEVI.ino @@ -35,7 +35,7 @@ FOR: PJRC Teensy 3.2 and three MPR121 capactive touch sensor bo Uses an SSD1306 controlled OLED display communicating over I2C. PROGRAMME FUNCTION: EWI Wind Controller using the Freescale MP3V5004GP breath sensor and capacitive touch keys. Output to both USB MIDI and DIN MIDI. - + ...if you just uncomment the #define NURAD in hardware.h */ @@ -92,6 +92,7 @@ unsigned short extraCT2; // OFF:1-127 unsigned short levelCC; // 0-127 unsigned short levelVal; // 0-127 unsigned short fingering; // 0-4 EWI,EWX,SAX,EVI,EVR +unsigned short rollerMode; //0-2 unsigned short lpinky3; // 0-25 (OFF, -12 - MOD - +12) unsigned short batteryType; // 0-2 ALK,NIM,LIP unsigned short harmSetting; // 0-7 @@ -99,10 +100,10 @@ unsigned short harmSelect; // 0-5 unsigned short brHarmSetting; // 0-7 unsigned short brHarmSelect; // 0-3 unsigned short polySelect; // OFF, MGR, MGD, MND, MNH, FWC, RTA, RTB or RTC -unsigned short fwcType; // 6, m6, 7, m7 +unsigned short fwcType; // 6, m6, 7, m7 unsigned short fwcLockH; // OFF:ON unsigned short fwcDrop2; // OFF:ON -unsigned short hmzKey; // 0-11 (0 is C) +unsigned short hmzKey; // 0-11 (0 is C) unsigned short hmzLimit; // 2-5 unsigned short otfKey; //OFF:ON unsigned short breathInterval = 6; // 3-15 @@ -151,10 +152,16 @@ byte ccList[11] = {0,1,2,7,11,1,2,7,11,74,20}; // OFF, Modulation, Breath, Volu int pbDepthList[13] = {8192,8192,4096,2731,2048,1638,1365,1170,1024,910,819,744,683}; #if defined(NURAD) +#if defined(SEAMUS) +int calOffsetRollers[6] = {-70,20,20,20,20,120}; +int calOffsetRH[12] = {0,0,0,0,0,-50,121,0,0,50,0,120}; +int calOffsetLH[12] = {120,0,120,0,50,115,118,0,50,0,0,0}; +#else int calOffsetRollers[6] = {16,10,8,21,24,41}; int calOffsetRH[12] = {-88,-68,-31,13,4,120,121,-68,-85,-34,23,87}; int calOffsetLH[12] = {90,-13,-33,-93,-82,115,118,2,4,-40,-75,-94}; #endif +#endif int battMeasured[50]; int battAvg = 0; @@ -191,6 +198,7 @@ uint16_t legacy = 0; uint16_t legacyBrAct = 0; byte halfTime = 0; boolean programonce = false; +boolean oneroll; byte widiOn = 0; int breathLevel=0; // breath level (smoothed) not mapped to CC value @@ -248,6 +256,7 @@ byte vibLedOff = 0; byte oldpkey = 0; byte lap = 0; +byte rSum = 0; static const float vibDepth[10] = {0,0.05,0.1,0.15,0.2,0.25,0.3,0.35,0.40,0.45}; // max pitch bend values (+/-) for the vibrato settings static const short vibMaxBiteList[17] = {1600,1400,1200,1000,900,800,700,600,500,400,300,250,200,150,100,50,25}; @@ -330,7 +339,7 @@ const int blockFWC[4][12][3] = {{{ -3, -5, -8 }, // C or key base { -3, -6, -9 }, // D or base +2 { -3, -5, -9 }, // D# or base +3 { -4, -5, -9 }, // E or base +4 - { -3, -6, -9 }, // F or base +5 + { -3, -6, -9 }, // F or base +5 { -3, -5, -8 }, // F# or base +6 { -3, -5, -8 }, // G or base +7 { -3, -6, -9 }, // G# or base +8 @@ -343,7 +352,7 @@ const int blockFWC[4][12][3] = {{{ -3, -5, -8 }, // C or key base { -3, -6, -9 }, // D or base +2 { -3, -6, -8 }, // D# or base +3 { -3, -6, -9 }, // E or base +4 - { -3, -6, -9 }, // F or base +5 + { -3, -6, -9 }, // F or base +5 { -3, -6, -8 }, // F# or base +6 { -3, -6, -8 }, // G or base +7 { -3, -6, -9 }, // G# or base +8 @@ -356,26 +365,26 @@ const int blockFWC[4][12][3] = {{{ -3, -5, -8 }, // C or key base { -3, -6, -9 }, // D or base +2 { -4, -6, -9 }, // D# or base +3 { -4, -6, -9 }, // E or base +4 - { -3, -6, -9 }, // F or base +5 + { -3, -6, -9 }, // F or base +5 { -3, -7, -9 }, // F# or base +6 { -3, -7, -9 }, // G or base +7 { -3, -6, -9 }, // G# or base +8 { -3, -6, -9 }, // A or base +9 { -3, -6, -10 }, // Bb or base +10 - { -3, -6, -9 }}, // B or base +11 + { -3, -6, -9 }}, // B or base +11 // m7 {{ -2, -5, -9 }, // C or key base { -2, -5, -9 }, // C# or base +1 { -3, -6, -9 }, // D or base +2 { -3, -5, -8 }, // D# or base +3 { -3, -5, -8 }, // E or base +4 3 6 9 - { -3, -6, -9 }, // F or base +5 + { -3, -6, -9 }, // F or base +5 { -4, -7, -9 }, // F# or base +6 { -4, -7, -9 }, // G or base +7 { -3, -6, -9 }, // G# or base +8 { -3, -6, -9 }, // A or base +9 { -3, -7, -10 }, // Bb or base +10 - { -3, -6, -9 }}}; // B or base +11 + { -3, -6, -9 }}}; // B or base +11 // Major Gospel Root (MGR), Bert Lochs const int majGosRootHmz[12][3] = {{ -5, -8, -12 }, // C or key base @@ -383,7 +392,7 @@ const int majGosRootHmz[12][3] = {{ -5, -8, -12 }, // C or key base { -3, -7, -12 }, // D or base +2 { -6, -9, -12 }, // D# or base +3 { -4, -9, -12 }, // E or base +4 - { -5, -8, -12 }, // F or base +5 + { -5, -8, -12 }, // F or base +5 { -3, -6, -12 }, // F# or base +6 { -3, -7, -12 }, // G or base +7 { -3, -8, -12 }, // G# or base +8 @@ -397,7 +406,7 @@ const int majGosDomHmz[12][3] = {{ -5, -8, -12 }, // C or key base { -3, -7, -12 }, // D or base +2 { -6, -9, -12 }, // D# or base +3 { -4, -9, -12 }, // E or base +4 - { -5, -8, -12 }, // F or base +5 + { -5, -8, -12 }, // F or base +5 { -3, -6, -12 }, // F# or base +6 { -5, -8, -12 }, // G or base +7 { -3, -8, -12 }, // G# or base +8 @@ -411,13 +420,13 @@ const int majAdd9Hmz[12][3] = {{ -5, -8, -10 }, // C or key base { -3, -5, -7 }, // D or base +2 { -3, -7, -9 }, // D# or base +3 { -2, -4, -9 }, // E or base +4 - { -5, -8, -10 }, // F or base +5 + { -5, -8, -10 }, // F or base +5 { -4, -6, -10 }, // F# or base +6 { -3, -5, -7 }, // G or base +7 { -4, -6, -10 }, // G# or base +8 { -2, -4, -9 }, // A or base +9 { -5, -8, -10 }, // Bb or base +10 - { -2, -4, -9 }}; // B or base +11 + { -2, -4, -9 }}; // B or base +11 // Minor Dorian (MND), Bert Lochs const int minDorHmz[12][3] = {{ -5, -9, -12 }, // C or key base @@ -425,7 +434,7 @@ const int minDorHmz[12][3] = {{ -5, -9, -12 }, // C or key base { -5, -9, -12 }, // D or base +2 { -3, -8, -12 }, // D# or base +3 { -3, -8, -12 }, // E or base +4 - { -3, -8, -12 }, // F or base +5 + { -3, -8, -12 }, // F or base +5 { -5, -9, -12 }, // F# or base +6 { -5, -9, -12 }, // G or base +7 { -5, -8, -12 }, // G# or base +8 @@ -439,7 +448,7 @@ const int minAeoHmz[12][3] = {{ -5, -9, -12 }, // C or key base { -3, -9, -12 }, // D or base +2 { -3, -8, -12 }, // D# or base +3 { -6, -9, -12 }, // E or base +4 - { -5, -9, -12 }, // F or base +5 + { -5, -9, -12 }, // F or base +5 { -5, -9, -12 }, // F# or base +6 { -5, -9, -12 }, // G or base +7 { -3, -8, -12 }, // G# or base +8 @@ -447,13 +456,13 @@ const int minAeoHmz[12][3] = {{ -5, -9, -12 }, // C or key base { -3, -8, -12 }, // Bb or base +10 { -6, -8, -12 }}; // B or base +11 -// Minor 4-voice Hip (MNH), Bert Lochs +// Minor 4-voice Hip (MNH), Bert Lochs const int minHipHmz[12][3] = {{ -5, -9, -10 }, // C or key base { -5, -9, -10 }, // C# or base +1 { -5, -9, -10 }, // D or base +2 { -3, -4, -8 }, // D# or base +3 { -3, -4, -8 }, // E or base +4 - { -3, -4, -8 }, // F or base +5 + { -3, -4, -8 }, // F or base +5 { -5, -9, -10 }, // F# or base +6 { -5, -9, -10 }, // G or base +7 { -5, -6, -8 }, // G# or base +8 @@ -482,13 +491,13 @@ const int harmonicResult[8][7] = {{ 0, 7, 12, 16, 19, 24, 28 }, //HM1 const int brHarmonicResult[4][7] = {{ 0, 7, 12, 16, 19, 24, 28 }, //HM1 { 0, 7, 12, 16, 19, 22, 24 }, //HM2 (7th harmonic not excluded) { 0, 7, 12, 19, 24, 31, 36 }, //5TH - { 0, 12, 24, 36, 48, 60, 72 }}; //OCT - + { 0, 12, 24, 36, 48, 60, 72 }}; //OCT + const int rollerHarmonic[2][7] = {{ 0, 7, 12, 16, 19, 24, 26 }, //F horn 2,3,4,5,6,8,9 hrm { 7, 12, 16, 19, 24, 26, 31 }}; //Bb horn 3,4,5,6,8,9,12 hrm -const int trumpetHarmonic[2][7] = {{ 0, 7, 12, 16, 19, 26, 31 }, //!K4: hrm 8->9, 10->12 - { 0, 7, 12, 16, 19, 24, 28 }}; //trumpet 2,3,4,5,6,8,10 hrm +const int trumpetHarmonic[2][7] = {{ 0, 7, 12, 16, 19, 26, 31 }, //!K4: hrm 8->9, 10->12 + { 0, 7, 12, 16, 19, 24, 28 }}; //trumpet 2,3,4,5,6,8,10 hrm int vibThr; // this gets auto calibrated in setup @@ -510,7 +519,7 @@ byte addedIntervals = 1; #if defined(NURAD) // Key variables, TRUE (1) for pressed, FALSE (0) for not pressed -byte LHs; +byte LHs; byte LH1; // Left Hand key 1 (pitch change -2) byte LHb; // Left Hand bis key (pitch change -1 unless both LH1 and LH2 are pressed) byte LH2; // Left Hand key 2 (with LH1 also pressed pitch change is -2, otherwise -1) @@ -550,6 +559,7 @@ byte R2; byte R3; byte R4; byte R5; +byte R6; byte octaveR = 0; byte lastOctaveR = 0; @@ -557,7 +567,8 @@ byte lastOctaveR = 0; byte halfPitchBendKey; byte quarterToneTrigger; byte specialKey; -byte pinkyKey; +byte patchKey = 0; +byte pinkyKey = 0; byte lastSpecialKey = 0; byte lastPinkyKey = 0; int pitchlatch; @@ -571,6 +582,7 @@ byte lastpcc2 = 0; byte slurSustain = 0; byte parallelChord = 0; byte subOctaveDouble = 0; +byte slurSostenuto = 0; #if defined(NURAD) Adafruit_MPR121 touchSensorRollers = Adafruit_MPR121(); @@ -640,14 +652,14 @@ void setup() { digitalWrite(widiJumperGndPin, LOW); //WIDI widiJumper = !digitalRead(widiJumperPin); //WIDI - + Serial2.setRX (26); //WIDI Serial2.setTX (31); //WIDI bool factoryReset = !digitalRead(ePin) && !digitalRead(mPin); configManagementMode = !factoryReset && !digitalRead(uPin) && !digitalRead(dPin); i2cScan = !factoryReset && !digitalRead(mPin); - + initDisplay(); //Start up display and show logo //If going into config management mode, stop here before we even touch the EEPROM. @@ -662,15 +674,15 @@ void setup() { i2cScanDisplay(); } #endif - + //Read eeprom data into global vars readEEPROM(factoryReset); - + touch_Thr = map(ctouchThrVal,ctouchHiLimit,ctouchLoLimit,ttouchLoLimit,ttouchHiLimit); - + activePatch = patch; - + #if defined(NURAD) digitalWrite(statusLedPin,HIGH); delay(100); @@ -770,7 +782,7 @@ void setup() { } if (widiJumper && widiOn) digitalWrite(widiPowerPin, HIGH); else digitalWrite(widiPowerPin, LOW); - + activeMIDIchannel = MIDIchannel; midiInitialize(MIDIchannel); @@ -844,6 +856,7 @@ void loop() { lastpcc1=pcCombo1; lastpcc2=pcCombo2; if ( + patchKey || (bothPB && legacy) || (brSuck && legacyBrAct && justPbUp) || (brSuck && legacyBrAct && bcasMode && noPb) @@ -956,6 +969,7 @@ void loop() { if (K4) { if (!slurSustain) { slurSustain = 1; + slurSostenuto = 0; parallelChord = 0; rotatorOn = 0; } else slurSustain = 0; @@ -973,11 +987,19 @@ void loop() { rotatorOn = 0; } else subOctaveDouble = 0; } - if (!K1 && !K4 && !K5) { + if (K2) { + if (!slurSostenuto) { + slurSostenuto = 1; + slurSustain = 0; + //rotatorOn = 0; + } else slurSostenuto = 0; + } + if (!K1 && !K4 && !K5 && !K2 && !pinkyKey) { slurSustain = 0; parallelChord = 0; subOctaveDouble = 0; rotatorOn = 0; + slurSostenuto = 0; } if (pinkyKey) { if (!rotatorOn) { @@ -996,6 +1018,7 @@ void loop() { slurSustain = 0; parallelChord = 0; subOctaveDouble = 0; + slurSostenuto = 0; } if ((pinkySetting == LVL) || (pinkySetting == LVLP)){ if (pinkyKey && K7){ @@ -1145,6 +1168,9 @@ void loop() { if (!priority) { // mono prio to base note midiSendNoteOn(fingeredNote, velocitySend); // send Note On message for new note } + if (slurSostenuto) { + midiSendControlChange(66, 127); + } activeNote = fingeredNote; mainState = NOTE_ON; } @@ -1220,6 +1246,9 @@ void loop() { if (slurSustain) { midiSendControlChange(64, 0); } + if (slurSostenuto) { + midiSendControlChange(66, 0); + } breathLevel = 0; mainState = NOTE_OFF; } else { @@ -1429,7 +1458,7 @@ void loop() { // even if we just alter a pixel, the whole display is redrawn (35ms of MPU lockup) and we can't do that all the time // this is one of the big reasons the display is for setup use only drawSensorPixels(); // live sensor monitoring for the setup screens - if (rotatorOn || slurSustain || parallelChord || subOctaveDouble || gateOpen) { + if (rotatorOn || slurSustain || parallelChord || subOctaveDouble || slurSostenuto || gateOpen) { statusLedFlip(); } else { statusLedOn(); @@ -1466,7 +1495,7 @@ void loop() { } else { cvPitch = targetPitch; } - + if (cvVibRate){ int timeDivider = timeDividerList[cvVibRate]; int cvVib = map(((waveformsTable[map(currentTime%timeDivider, 0, timeDivider, 0, maxSamplesNum-1)] - 2047) * exSensorIndicator), -259968,259969,-11,11); @@ -1546,7 +1575,7 @@ void breath() { if (breathCCval != oldbreath) { // only send midi data if breath has changed from previous value if (breathCC) { // send midi cc - midiSendControlChange(ccList[breathCC], breathCCval); + midiSendControlChange(ccList[breathCC], breathCCval); } if (breathAT) { // send aftertouch @@ -1597,7 +1626,7 @@ void pitch_bend() { vibReadBite = analogRead(bitePressurePin); // alternative kind bite sensor (air pressure tube and sensor) PBITE } else { vibReadBite = touchRead(bitePin); // get sensor data, do some smoothing - SENSOR PIN 17 - PCB PINS LABELED "BITE" (GND left, sensor pin right) - } + } if (vibReadBite < vibThrBite) { if (UPWD == vibDirection) { vibSignal = (vibSignal + map(constrain(vibReadBite, (vibZeroBite - vibMaxBite), vibThrBite), vibThrBite, (vibZeroBite - vibMaxBite), 0, calculatedPBdepth * vibDepth[vibrato]))/2; @@ -1753,7 +1782,7 @@ void battCheck(){ } battAvg /= 50; battCheckPos++; - if (battCheckPos == 50) battCheckPos = 0; + if (battCheckPos == 50) battCheckPos = 0; } void extraController() { @@ -1812,7 +1841,7 @@ void extraController() { } else if ((pinkySetting == ECH) && !pinkyKey) { harmonics = 0; } - + if ((extraCT || extraCT2) && (exSensor >= extracThrVal)) { // if we are enabled and over the threshold, send data if (!extracIsOn) { extracIsOn = 1; @@ -1881,7 +1910,7 @@ void extraController() { } //*********************************************************** - + void portamento_() { int portSumCC = 0; if (pinkySetting == GLD){ @@ -1903,11 +1932,17 @@ void portamento_() { if (2 == leverControl) { // Portamento is controlled with thumb lever leverPortRead = touchRead(vibratoPin); +#if defined(SEAMUS) + if (portamento && ((leverPortRead) >= leverThrVal)) { // if we are enabled and over the threshold, send portamento + portSumCC += map(constrain((leverPortRead), leverThrVal, leverMaxVal), leverThrVal, leverMaxVal, 0, portLimit); + } +#else if (portamento && ((3000-leverPortRead) >= leverThrVal)) { // if we are enabled and over the threshold, send portamento portSumCC += map(constrain((3000-leverPortRead), leverThrVal, leverMaxVal), leverThrVal, leverMaxVal, 0, portLimit); } +#endif } - portSumCC = constrain(portSumCC, 0, portLimit); // Total output glide rate limited to glide max setting + portSumCC = constrain(portSumCC, 0, portLimit); // Total output glide rate limited to glide max setting if (portSumCC) { // there is a portamento level, so go for it if (!portIsOn) { portOn(); @@ -1974,7 +2009,7 @@ void biteCC_() { if (!biteIsOn) { biteIsOn = 1; } - if (biteCClevel != oldbitecc) { + if (biteCClevel != oldbitecc) { midiSendControlChange(biteCC, biteCClevel); } oldbitecc = biteCClevel; @@ -1997,7 +2032,7 @@ void leverCC_() { if (!leverIsOn) { leverIsOn = 1; } - if (leverCClevel != oldlevercc) { + if (leverCClevel != oldlevercc) { midiSendControlChange(leverCC, leverCClevel); } oldlevercc = leverCClevel; @@ -2047,7 +2082,7 @@ void autoCal() { writeSetting(PORTAM_THR_ADDR, portamThrVal); writeSetting(PORTAM_MAX_ADDR, portamMaxVal); // Touch sensors - calRead = ctouchHiLimit; + calRead = ctouchHiLimit; for (byte i = 0; i < 6; i++) { calReadNext = touchSensorRollers.filteredData(i) * (300-calOffsetRollers[i])/300; if (calReadNext < calRead) calRead = calReadNext; //use lowest value @@ -2081,7 +2116,7 @@ void autoCal() { writeSetting(PORTAM_MAX_ADDR, portamMaxVal); } // Touch sensors - calRead = ctouchHiLimit; + calRead = ctouchHiLimit; for (byte i = 0; i < 12; i++) { calReadNext = touchSensor.filteredData(i); if (calReadNext < calRead) calRead = calReadNext; //use lowest value @@ -2106,41 +2141,95 @@ void readSwitches() { switch (lap){ case 0: // Octave rollers - int touchValueRollers[12]; + int touchValueRollers[12]; for (byte i=0; i<6; i++){ //touchValueRollers[i]=touchSensorRollers.filteredData(i) - calOffsetRollers[i]; touchValueRollers[i]=touchSensorRollers.filteredData(i) * (300-calOffsetRollers[i])/300; } - // 6-pin version - octaveR = 0; - if (touchValueRollers[rPin6] < ctouchThrVal) octaveR = 6; //R6 - else if (R5=(touchValueRollers[rPin5] < ctouchThrVal)) octaveR = 5; //R5 (store for combo check) - else if (R4=(touchValueRollers[rPin4] < ctouchThrVal)) octaveR = 4; //R4 (store for combo check) - else if (R3=(touchValueRollers[rPin3] < ctouchThrVal)) octaveR = 3; //R3 (store for combo check) - else if (R2=(touchValueRollers[rPin2] < ctouchThrVal)) octaveR = 2; //R2 (store for combo check) - else if (touchValueRollers[rPin1] < ctouchThrVal) octaveR = 1; //R1 - else if (lastOctaveR > 1) { - octaveR = lastOctaveR; - if (otfKey && polySelect && (polySelect 1) { + octaveR = lastOctaveR; + if (otfKey && polySelect && (polySelect 1) { + if (rollerMode) octaveR = lastOctaveR; //if rollers are released and we are not coming down from roller 1, stay at the higher octave + if (otfKey && !rSum && polySelect && (polySelect 1) { + if (rollerMode) octaveR = lastOctaveR; //if rollers are released and we are not coming down from roller 1, stay at the higher octave + if (otfKey && !rSum && polySelect && (polySelect 1) { - octaveR = lastOctaveR; - if (otfKey && polySelect && (polySelectgetSubTextFunc(*sub, buffer, &labelPtr); - // If EMenuEntryCustom flag is set, we assume that the getSubTextFunc + // If EMenuEntryCustom flag is set, we assume that the getSubTextFunc // rendered by it self. if( !(sub->flags & EMenuEntryCustom)) { plotSubOption(buffer, labelPtr); @@ -398,7 +401,7 @@ static void plotMenuEntries(const MenuPage *page, bool clear = false) { display.setCursor(0,rowPixel); display.println(lineText); } - + if(offset) display.drawTriangle(58, MENU_HEADER_OFFSET, 57, MENU_HEADER_OFFSET+3, 59, MENU_HEADER_OFFSET+3, WHITE); @@ -447,7 +450,7 @@ static void mainTitleGetStr(char* out) { case 2: vLowLimit = LIP_BAT_LOW; } - if (vMeterReading <= vLowLimit) { //2300 alkaline, 2250 lipo, 2200 nimh + if (vMeterReading <= vLowLimit) { //2300 alkaline, 2250 lipo, 2200 nimh memcpy(splice2, "LOW ", 4); } else { int voltage = map(vMeterReading,2200,3060,36,50); @@ -546,6 +549,10 @@ static void clearFPS(int trills) { //*********************************************************** // Poly Play menu +const MenuEntryStateCh rotSubAMenu = { MenuType::EStateChange, "ROTATOR A", ROTA_MENU }; +const MenuEntryStateCh rotSubBMenu = { MenuType::EStateChange, "ROTATOR B", ROTB_MENU }; +const MenuEntryStateCh rotSubCMenu = { MenuType::EStateChange, "ROTATOR C", ROTC_MENU }; + static void rotatorSave(const MenuEntrySub& __unused sub) { int16_t stored; for(int i = 0; i < 4; ++i) { @@ -687,7 +694,7 @@ static void rotatorPrioSave(SubMenuRef __unused) { } const MenuEntrySub rotatorPrioMenu = { - MenuType::ESub, "PRIORITY", "MONO PRIO", &priority, 0,1, MenuEntryFlags::EMenuEntryWrap, + MenuType::ESub, "PRIORITY", "MONO PRIO", &priority, 0,1, MenuEntryFlags::EMenuEntryWrap, rotatorPrioOptionGet, rotatorPrioSave, nullptr, }; @@ -713,7 +720,7 @@ static void fwcTypeSave(SubMenuRef __unused) { } const MenuEntrySub fwcTypeMenu = { - MenuType::ESub, "FWC TYPE", "CHORD", &fwcType, 0,3, MenuEntryFlags::EMenuEntryWrap, + MenuType::ESub, "FWC TYPE", "CHORD", &fwcType, 0,3, MenuEntryFlags::EMenuEntryWrap, fwcTypeOptionGet, fwcTypeSave, nullptr, }; @@ -727,7 +734,7 @@ static void fwcLockHSave(SubMenuRef __unused) { } const MenuEntrySub fwcLockHMenu = { - MenuType::ESub, "FWC LOCKH", "LH MELODY", &fwcLockH, 0,1, MenuEntryFlags::EMenuEntryWrap, + MenuType::ESub, "FWC LOCKH", "LH MELODY", &fwcLockH, 0,1, MenuEntryFlags::EMenuEntryWrap, fwcLockHOptionGet, fwcLockHSave, nullptr, }; @@ -741,7 +748,7 @@ static void fwcDrop2Save(SubMenuRef __unused) { } const MenuEntrySub fwcDrop2Menu = { - MenuType::ESub, "FWC DROP2", "DROP 2", &fwcDrop2, 0,1, MenuEntryFlags::EMenuEntryWrap, + MenuType::ESub, "FWC DROP2", "DROP 2", &fwcDrop2, 0,1, MenuEntryFlags::EMenuEntryWrap, fwcDrop2OptionGet, fwcDrop2Save, nullptr, }; @@ -791,7 +798,7 @@ static void hmzKeySave(SubMenuRef __unused) { } const MenuEntrySub hmzKeyMenu = { - MenuType::ESub, "HMZ KEY", "KEY PLAYED", &hmzKey, 0,11, MenuEntryFlags::EMenuEntryWrap, + MenuType::ESub, "HMZ KEY", "KEY PLAYED", &hmzKey, 0,11, MenuEntryFlags::EMenuEntryWrap, hmzKeyOptionGet, hmzKeySave, nullptr, }; @@ -839,7 +846,7 @@ static void polySelectSave(SubMenuRef __unused) { } const MenuEntrySub polySelectMenu = { - MenuType::ESub, "POLY MODE", "SELECT", &polySelect, 0,10, MenuEntryFlags::EMenuEntryWrap, + MenuType::ESub, "POLY MODE", "SELECT", &polySelect, 0,10, MenuEntryFlags::EMenuEntryWrap, polySelectOptionGet, polySelectSave, nullptr, }; @@ -852,7 +859,7 @@ static void hmzLimitSave(SubMenuRef __unused) { } const MenuEntrySub hmzLimitMenu = { - MenuType::ESub, "HMZ LIMIT", "VOICES", &hmzLimit, 2,5, MenuEntryFlags::EMenuEntryWrap, + MenuType::ESub, "HMZ LIMIT", "VOICES", &hmzLimit, 2,5, MenuEntryFlags::EMenuEntryWrap, hmzLimitOptionGet, hmzLimitSave, nullptr, }; @@ -866,11 +873,48 @@ static void otfKeySave(SubMenuRef __unused) { } const MenuEntrySub otfKeyMenu = { - MenuType::ESub, "OTF KEY", "OTF KEYSW", &otfKey, 0,1, MenuEntryFlags::EMenuEntryWrap, + MenuType::ESub, "OTF KEY", "OTF KEYSW", &otfKey, 0,1, MenuEntryFlags::EMenuEntryWrap, otfKeyOptionGet, otfKeySave, nullptr, }; +const MenuEntry* rotSubAMenuEntries[] = { + (MenuEntry*)&rotatorParaMenu, + (MenuEntry*)&rotator1Menu, + (MenuEntry*)&rotator2Menu, + (MenuEntry*)&rotator3Menu, + (MenuEntry*)&rotator4Menu +}; + +const MenuPage rotSubAMenuPage = { + "ROTATOR A", 0, CursorIdx::ERotSubA, ROTATOR_MENU, ARR_LEN(rotSubAMenuEntries), rotSubAMenuEntries +}; + +const MenuEntry* rotSubBMenuEntries[] = { + (MenuEntry*)&rotatorParaBMenu, + (MenuEntry*)&rotatorB1Menu, + (MenuEntry*)&rotatorB2Menu, + (MenuEntry*)&rotatorB3Menu, + (MenuEntry*)&rotatorB4Menu +}; + +const MenuPage rotSubBMenuPage = { + "ROTATOR B", 0, CursorIdx::ERotSubB, ROTATOR_MENU, ARR_LEN(rotSubBMenuEntries), rotSubBMenuEntries +}; + +const MenuEntry* rotSubCMenuEntries[] = { + (MenuEntry*)&rotatorParaCMenu, + (MenuEntry*)&rotatorC1Menu, + (MenuEntry*)&rotatorC2Menu, + (MenuEntry*)&rotatorC3Menu, + (MenuEntry*)&rotatorC4Menu +}; + +const MenuPage rotSubCMenuPage = { + "ROTATOR C", 0, CursorIdx::ERotSubC, ROTATOR_MENU, ARR_LEN(rotSubCMenuEntries), rotSubCMenuEntries +}; + + const MenuEntry* rotatorMenuEntries[] = { (MenuEntry*)&polySelectMenu, @@ -881,7 +925,7 @@ const MenuEntry* rotatorMenuEntries[] = { (MenuEntry*)&fwcLockHMenu, (MenuEntry*)&fwcDrop2Menu, (MenuEntry*)&rotatorPrioMenu, - (MenuEntry*)&rotatorParaMenu, +/*(MenuEntry*)&rotatorParaMenu, (MenuEntry*)&rotator1Menu, (MenuEntry*)&rotator2Menu, (MenuEntry*)&rotator3Menu, @@ -895,7 +939,10 @@ const MenuEntry* rotatorMenuEntries[] = { (MenuEntry*)&rotatorC1Menu, (MenuEntry*)&rotatorC2Menu, (MenuEntry*)&rotatorC3Menu, - (MenuEntry*)&rotatorC4Menu + (MenuEntry*)&rotatorC4Menu */ + (MenuEntry*)&rotSubAMenu, + (MenuEntry*)&rotSubBMenu, + (MenuEntry*)&rotSubCMenu }; /* const MenuPage rotatorMenuPage = { @@ -912,22 +959,116 @@ const MenuPage rotatorMenuPage = { CursorIdx::ERotator, MAIN_MENU, ARR_LEN(rotatorMenuEntries), rotatorMenuEntries -}; +}; //*********************************************************** // Main menu +/* const MenuEntrySub transposeMenu = { - MenuType::ESub, "TRANSPOSE", "TRANSPOSE", &transpose, 0, 24, MenuEntryFlags::ENone, + MenuType::ESub, "TRANSPOSE", "TRANSPOSE", &transpose, 0, 24, MenuEntryFlags::ENone, [](SubMenuRef __unused, char* out, const char** __unused unit) { numToString(transpose - 12, out, true); }, [](const MenuEntrySub &sub) { writeSetting(TRANSP_ADDR,*sub.valuePtr); } , nullptr }; +*/ +static void transposeOptionGet(SubMenuRef __unused, char* out, const char** __unused) { + switch (transpose){ + case 0: + strncpy(out, "C>", 4); + break; + case 1: + strncpy(out, "C#>", 4); + break; + case 2: + strncpy(out, "D>", 4); + break; + case 3: + strncpy(out, "D#>", 4); + break; + case 4: + strncpy(out, "E>", 4); + break; + case 5: + strncpy(out, "F>", 4); + break; + case 6: + strncpy(out, "F#>", 4); + break; + case 7: + strncpy(out, "G>", 4); + break; + case 8: + strncpy(out, "G#>", 4); + break; + case 9: + strncpy(out, "A>", 4); + break; + case 10: + strncpy(out, "Bb>", 4); + break; + case 11: + strncpy(out, "B>", 4); + break; + case 12: + strncpy(out, ">C<", 4); + break; + case 13: + strncpy(out, " 0)){ @@ -2182,7 +2333,7 @@ static bool idlePageUpdate(KeyState& __unused input, uint32_t __unused timeNow) } else if (pinkyKey && !specialKey){ //hold pinky key for rotator menu, and if too high touch sensing blocks regular menu, touching special key helps display.ssd1306_command(SSD1306_DISPLAYON); menuState= ROTATOR_MENU; - stateFirstRun = 1; + stateFirstRun = 1; } else { display.ssd1306_command(SSD1306_DISPLAYON); menuState = MAIN_MENU; @@ -2291,6 +2442,12 @@ void menu() { redraw |= updatePage((const MenuPage*)&aboutMenuPage, input, timeNow); } else if (menuState == EXTRAS_MENU) { redraw |= updatePage((const MenuPage*)&extrasMenuPage, input, timeNow); + } else if (menuState == ROTA_MENU) { + redraw |= updatePage((const MenuPage*)&rotSubAMenuPage, input, timeNow); + } else if (menuState == ROTB_MENU) { + redraw |= updatePage((const MenuPage*)&rotSubBMenuPage, input, timeNow); + } else if (menuState == ROTC_MENU) { + redraw |= updatePage((const MenuPage*)&rotSubCMenuPage, input, timeNow); } if(redraw) { diff --git a/NuEVI/menu.h b/NuEVI/menu.h index e65cc3e..17034f9 100644 --- a/NuEVI/menu.h +++ b/NuEVI/menu.h @@ -19,6 +19,9 @@ #define VIBRATO_MENU 7 #define ABOUT_MENU 8 #define EXTRAS_MENU 9 +#define ROTA_MENU 10 +#define ROTB_MENU 11 +#define ROTC_MENU 12 #define ARR_LEN(a) (sizeof (a) / sizeof (a[0])) diff --git a/NuEVI/settings.cpp b/NuEVI/settings.cpp index e836569..d58b843 100644 --- a/NuEVI/settings.cpp +++ b/NuEVI/settings.cpp @@ -179,6 +179,10 @@ void readEEPROM(const bool factoryReset) { writeSetting(CVRATE_ADDR, CVRATE_FACTORY); } + if(settingsVersion < 45) { + writeSetting(ROLLER_ADDR, ROLLER_FACTORY); + } + writeSetting(VERSION_ADDR, EEPROM_VERSION); } @@ -275,6 +279,7 @@ void readEEPROM(const bool factoryReset) { cvTune = readSettingBounded(CVTUNE_ADDR, 1, 199, CVTUNE_FACTORY); cvScale = readSettingBounded(CVSCALE_ADDR, 1, 199, CVSCALE_FACTORY); cvVibRate = readSettingBounded(CVRATE_ADDR, 0, 8, CVRATE_FACTORY); + rollerMode = readSettingBounded(ROLLER_ADDR, 0, 3, ROLLER_FACTORY); //Flags stored in bit field fastBoot = (dipSwBits & (1<