diff --git a/NuEVI/NuEVI.ino b/NuEVI/NuEVI.ino index 50bfb81..21ff30c 100644 --- a/NuEVI/NuEVI.ino +++ b/NuEVI/NuEVI.ino @@ -66,10 +66,14 @@ unsigned short octave; unsigned short curve; unsigned short velSmpDl; // 0-30 ms unsigned short velBias; // 0-9 -unsigned short pinkySetting; // 0 - 11 (QuickTranspose -12 to -1), 12 (pb/2), 13 - 24 (QuickTranspose +1 to +12) +unsigned short pinkySetting; // 0 - 11 (QuickTranspose -12 to -1), 12 (pb/2), 13 - 24 (QuickTranspose +1 to +12), 25 (EC2), 26 (ECSW), 27 (LVL), 28 (LVLP) unsigned short dipSwBits; // virtual dip switch settings for special modes (work in progress) unsigned short priority; // mono priority for rotator chords +unsigned short extraCT2; // OFF:1-127 +unsigned short levelCC; // 0-127 +unsigned short levelVal; // 0-127 + unsigned short vibSens = 2; // vibrato sensitivity unsigned short vibRetn = 2; // vibrato return speed unsigned short vibSquelch = 12; //vibrato signal squelch @@ -158,7 +162,7 @@ int targetPitch; int exSensor=0; byte extracIsOn=0; int oldextrac=0; -int lastEx=0; +int oldextrac2=0; int pitchBend=8192; int oldpb=8192; @@ -226,6 +230,7 @@ byte halfPitchBendKey; byte specialKey; byte pinkyKey; byte lastSpecialKey = 0; +byte lastPinkyKey = 0; byte pitchlatch; int reverb; @@ -317,6 +322,10 @@ void setup() { doPatchUpdate=1; } + if ((pinkySetting == LVLP) && levelCC){ + midiSendControlChange(levelCC, levelVal); + } + activeMIDIchannel = MIDIchannel; midiInitialize(MIDIchannel); @@ -507,6 +516,21 @@ void loop() { parallelChord = 0; subOctaveDouble = 0; } + if ((pinkySetting == LVL) || (pinkySetting == LVLP)){ + if (pinkyKey){ + ledMeter(levelVal); + if (K5 && (levelVal < 127)){ + levelVal++; + if (levelCC) midiSendControlChange(levelCC, levelVal); + } else if (K1 && (levelVal > 0)){ + levelVal--; + if (levelCC) midiSendControlChange(levelCC, levelVal); + } + } else if (lastPinkyKey){ + writeSetting(LEVEL_VAL_ADDR,levelVal); + } + lastPinkyKey = pinkyKey; + } } else if (mainState == RISE_WAIT) { if ((pressureSensor > breathThrVal) || gateOpen) { // Has enough time passed for us to collect our second @@ -684,7 +708,9 @@ void loop() { } else { if (slowMidi) breath(); extraController(); - updateSensorLEDs(); + if (((pinkySetting == LVL) || (pinkySetting == LVLP)) && pinkyKey){ + // show LVL indication + } else updateSensorLEDs(); doorKnobCheck(); } ccSendTime = millis(); @@ -970,60 +996,103 @@ void doorKnobCheck() { //*********************************************************** void extraController() { + bool CC2sw; + bool CC1sw; + int extracCC; // Extra Controller is the lip touch sensor (proportional) in front of the mouthpiece exSensor = exSensor * 0.6 + 0.4 * touchRead(extraPin); // get sensor data, do some smoothing - SENSOR PIN 16 - PCB PIN "EC" (marked K4 on some prototype boards) + if (pinkySetting == EC2){ + //send 0 or 127 on extra controller CC2 depending on pinky key touch + if (pinkyKey && extraCT2) { + if (lastPinkyKey != pinkyKey){ + midiSendControlChange(extraCT2, 127); + lastPinkyKey = pinkyKey; + } + } else { + if (lastPinkyKey != pinkyKey){ + midiSendControlChange(extraCT2, 0); + lastPinkyKey = pinkyKey; + } + } + } else if (pinkySetting == ECSW){ + if (pinkyKey){ + //send extra controller CC2 only + CC2sw = 1; + CC1sw = 0; + } else { + //send extra controller primary CC only + CC2sw = 0; + CC1sw = 1; + } + } else { + //send both primary CC and CC2 + CC2sw = 1; + CC1sw = 1; + } if (extraCT && (exSensor >= extracThrVal)) { // if we are enabled and over the threshold, send data if (!extracIsOn) { extracIsOn = 1; - if (extraCT == 4) { //Sustain ON + if ((extraCT == 4) && CC1sw) { //Sustain ON midiSendControlChange(64, 127); } } - if (extraCT == 1) { //Send modulation - int extracCC = map(constrain(exSensor, extracThrVal, extracMaxVal), extracThrVal, extracMaxVal, 1, 127); + if ((extraCT == 1) && CC1sw) { //Send modulation + extracCC = map(constrain(exSensor, extracThrVal, extracMaxVal), extracThrVal, extracMaxVal, 1, 127); if (extracCC != oldextrac) { midiSendControlChange(1, extracCC); } oldextrac = extracCC; } - if (extraCT == 2) { //Send foot pedal (CC#4) - int extracCC = map(constrain(exSensor, extracThrVal, extracMaxVal), extracThrVal, extracMaxVal, 1, 127); + if ((extraCT == 2) && CC1sw) { //Send foot pedal (CC#4) + extracCC = map(constrain(exSensor, extracThrVal, extracMaxVal), extracThrVal, extracMaxVal, 1, 127); if (extracCC != oldextrac) { midiSendControlChange(4, extracCC); } oldextrac = extracCC; } - if ((extraCT == 3) && (breathCC != 9)) { //Send filter cutoff (CC#74) - int extracCC = map(constrain(exSensor, extracThrVal, extracMaxVal), extracThrVal, extracMaxVal, 1, 127); + if ((extraCT == 3) && (breathCC != 9) && CC1sw) { //Send filter cutoff (CC#74) + extracCC = map(constrain(exSensor, extracThrVal, extracMaxVal), extracThrVal, extracMaxVal, 1, 127); if (extracCC != oldextrac) { midiSendControlChange(74, extracCC); } oldextrac = extracCC; } + if ((extraCT2 ) && CC2sw){ //Send extra controller CC2 + extracCC = map(constrain(exSensor, extracThrVal, extracMaxVal), extracThrVal, extracMaxVal, 1, 127); + if (extracCC != oldextrac2) { + midiSendControlChange(extraCT2, extracCC); + } + oldextrac2 = extracCC; + } } else if (extracIsOn) { // we have just gone below threshold, so send zero value extracIsOn = 0; - if (extraCT == 1) { //MW + if ((extraCT == 1) && CC1sw) { //MW if (oldextrac != 0) { //send modulation 0 midiSendControlChange(1, 0); oldextrac = 0; } - } else if (extraCT == 2) { //FP + } else if ((extraCT == 2) && CC1sw) { //FP if (oldextrac != 0) { //send foot pedal 0 midiSendControlChange(4, 0); oldextrac = 0; } - } else if ((extraCT == 3) && (breathCC != 9)) { //CF + } else if ((extraCT == 3) && (breathCC != 9) && CC1sw) { //CF if (oldextrac != 0) { //send filter cutoff 0 midiSendControlChange(74, 0); oldextrac = 0; } - } else if (extraCT == 4) { //SP + } else if ((extraCT == 4) && CC1sw) { //SP //send sustain off midiSendControlChange(64, 0); } + if ((extraCT2 ) && CC2sw){ //CC2 + //send 0 for extra ctr CC2 + midiSendControlChange(extraCT2, 0); + oldextrac2 = 0; + } } } @@ -1127,7 +1196,7 @@ void readSwitches() { pinkyKey = (touchRead(halfPitchBendKeyPin) > touch_Thr); // SENSOR PIN 1 - PCB PIN "S1" - int qTransp = pinkyKey ? pinkySetting-12 : 0; + int qTransp = (pinkyKey && (pinkySetting < 25)) ? pinkySetting-12 : 0; // Calculate midi note number from pressed keys diff --git a/NuEVI/globals.h b/NuEVI/globals.h index 03fabd6..bccf687 100644 --- a/NuEVI/globals.h +++ b/NuEVI/globals.h @@ -20,6 +20,10 @@ //Magic value where pinky button means "pitch bend" #define PBD 12 +#define EC2 25 +#define ECSW 26 +#define LVL 27 +#define LVLP 28 //Vibrato direction #define UPWD 1 @@ -55,7 +59,7 @@ extern unsigned short octave; extern unsigned short curve; extern unsigned short velSmpDl; // 0-30 ms extern unsigned short velBias; // 0-9 -extern unsigned short pinkySetting; // 0 - 11 (QuickTranspose -12 to -1), 12 (pb/2), 13 - 24 (QuickTranspose +1 to +12) +extern unsigned short pinkySetting; // 0 - 11 (QuickTranspose -12 to -1), 12 (pb/2), 13 - 24 (QuickTranspose +1 to +12), 25 (EC2), 26 (ECSW), 27 (LVL), 28 (LVLP) extern unsigned short dipSwBits; // virtual dip switch settings for special modes (work in progress) extern unsigned short priority; // mono priority for rotator chords extern unsigned short vibSens; // vibrato sensitivity @@ -66,6 +70,9 @@ extern unsigned short vibSensBite; // vibrato sensitivity (bite) extern unsigned short vibSquelchBite; //vibrato signal squelch (bite) extern unsigned short vibControl; extern unsigned short fastPatch[7]; +extern unsigned short extraCT2; // OFF:1-127 +extern unsigned short levelCC; // 0-127 +extern unsigned short levelVal; // 0-127 extern uint16_t gateOpenEnable; extern uint16_t specialKeyEnable; extern byte rotatorOn; @@ -99,7 +106,6 @@ extern int lastBite; extern byte biteJumper; extern int exSensor; -extern int lastEx; extern int pitchBend; diff --git a/NuEVI/led.cpp b/NuEVI/led.cpp index 2412388..092af37 100644 --- a/NuEVI/led.cpp +++ b/NuEVI/led.cpp @@ -46,3 +46,8 @@ void updateSensorLEDs() { analogWrite(pLedPin, 0); } } + +void ledMeter(byte indicatedValue){ + analogWrite(bLedPin, map(constrain(indicatedValue, 0, 127), 0, 127, 0, BREATH_LED_BRIGHTNESS)); // full glow at maximum value + analogWrite(pLedPin, map(constrain(indicatedValue, 0, 127), 127, 0, 0, PORTAM_LED_BRIGHTNESS)); // full glow at minimum value +} diff --git a/NuEVI/led.h b/NuEVI/led.h index 4b43241..a5ccaa8 100644 --- a/NuEVI/led.h +++ b/NuEVI/led.h @@ -8,5 +8,6 @@ void statusLed(bool state); void statusLedFlash(uint16_t delayTime); void statusLedBlink(); void updateSensorLEDs(); +void ledMeter(byte indicatedValue); #endif diff --git a/NuEVI/menu.cpp b/NuEVI/menu.cpp index 5788e68..328ce2c 100644 --- a/NuEVI/menu.cpp +++ b/NuEVI/menu.cpp @@ -840,6 +840,16 @@ const MenuEntrySub extraMenu = { , nullptr }; +const MenuEntrySub extraCC2Menu = { + MenuType::ESub, "EXCTR CC2", "EXCTR CC2", &extraCT2, 0, 127, MenuEntryFlags::EMenuEntryWrap, + [](SubMenuRef __unused, char* out, const char** __unused unit) { + if(extraCT2) numToString(extraCT2, out); + else strncpy(out, "OFF", 4); + }, +[](const MenuEntrySub & __unused sub) { writeSetting(EXTRA2_ADDR,extraCT2); } + , nullptr +}; + const MenuEntryStateCh vibratoSubMenu = { MenuType::EStateChange, "VIBRATO", VIBRATO_MENU }; const MenuEntrySub deglitchMenu = { @@ -856,10 +866,18 @@ const MenuEntrySub deglitchMenu = { }; const MenuEntrySub pinkyMenu = { - MenuType::ESub, "PINKY KEY", "PINKY KEY", &pinkySetting, 0, 24, MenuEntryFlags::ENone, + MenuType::ESub, "PINKY KEY", "PINKY KEY", &pinkySetting, 0, 28, MenuEntryFlags::ENone, [](SubMenuRef __unused,char* textBuffer, const char** __unused unit) { if (pinkySetting == PBD) strncpy(textBuffer, "PBD", 4); + else if (pinkySetting == EC2) + strncpy(textBuffer, "EC2", 4); + else if (pinkySetting == ECSW) + strncpy(textBuffer, "ECS", 4); + else if (pinkySetting == LVL) + strncpy(textBuffer, "LVL", 4); + else if (pinkySetting == LVLP) + strncpy(textBuffer, "LVP", 4); else numToString(pinkySetting-12, textBuffer, true); }, @@ -867,13 +885,25 @@ const MenuEntrySub pinkyMenu = { , nullptr }; +const MenuEntrySub lvlCtrlCCMenu = { + MenuType::ESub, "LEVEL CC", "LEVEL CC", &levelCC, 0, 127, MenuEntryFlags::EMenuEntryWrap, + [](SubMenuRef __unused, char* out, const char** __unused unit) { + if(levelCC) numToString(levelCC, out); + else strncpy(out, "OFF", 4); + }, +[](const MenuEntrySub & __unused sub) { writeSetting(LEVEL_CC_ADDR,levelCC); } + , nullptr +}; + const MenuEntry* controlMenuEntries[] = { (MenuEntry*)&portMenu, (MenuEntry*)&pitchBendMenu, (MenuEntry*)&extraMenu, + (MenuEntry*)&extraCC2Menu, (MenuEntry*)&vibratoSubMenu, (MenuEntry*)°litchMenu, - (MenuEntry*)&pinkyMenu + (MenuEntry*)&pinkyMenu, + (MenuEntry*)&lvlCtrlCCMenu }; const MenuPage controlMenuPage = { diff --git a/NuEVI/settings.cpp b/NuEVI/settings.cpp index 913e06f..d8b3195 100644 --- a/NuEVI/settings.cpp +++ b/NuEVI/settings.cpp @@ -96,6 +96,12 @@ void readEEPROM() { writeSetting(DAC_MODE_ADDR, DAC_MODE_FACTORY); } + if(settingsVersion < 33) { + writeSetting(EXTRA2_ADDR, EXTRA2_FACTORY); + writeSetting(LEVEL_CC_ADDR, LEVEL_CC_FACTORY); + writeSetting(LEVEL_VAL_ADDR, LEVEL_VAL_FACTORY); + } + writeSetting(VERSION_ADDR, EEPROM_VERSION); } @@ -124,7 +130,7 @@ void readEEPROM() { curve = readSettingBounded(BREATHCURVE_ADDR, 0, 12, BREATHCURVE_FACTORY); velSmpDl = readSettingBounded(VEL_SMP_DL_ADDR, 0, 30, VEL_SMP_DL_FACTORY); velBias = readSettingBounded(VEL_BIAS_ADDR, 0, 9, VEL_BIAS_FACTORY); - pinkySetting = readSettingBounded(PINKY_KEY_ADDR, 0, 24, PINKY_KEY_FACTORY); + pinkySetting = readSettingBounded(PINKY_KEY_ADDR, 0, 28, PINKY_KEY_FACTORY); fastPatch[0] = readSettingBounded(FP1_ADDR, 0, 127, 0); fastPatch[1] = readSettingBounded(FP2_ADDR, 0, 127, 0); fastPatch[2] = readSettingBounded(FP3_ADDR, 0, 127, 0); @@ -150,6 +156,9 @@ void readEEPROM() { vibControl = readSettingBounded(VIB_CONTROL_ADDR, 0, 1, VIB_CONTROL_FACTORY); dacMode = readSettingBounded(DAC_MODE_ADDR, DAC_MODE_BREATH, DAC_MODE_PITCH, DAC_MODE_FACTORY); trill3_interval = readSettingBounded(TRILL3_INTERVAL_ADDR, 3, 4, TRILL3_INTERVAL_FACTORY); + extraCT2 = readSettingBounded(EXTRA2_ADDR, 0, 127, EXTRA2_FACTORY); + levelCC = readSettingBounded(LEVEL_CC_ADDR, 0, 127, LEVEL_CC_FACTORY); + levelVal = readSettingBounded(LEVEL_VAL_ADDR, 0, 127, LEVEL_VAL_FACTORY); //Flags stored in bit field fastBoot = (dipSwBits & (1<