From cc188f2196e840452f6eaecb9bd8c93471230f81 Mon Sep 17 00:00:00 2001 From: Johan Berglund Date: Sun, 19 Jul 2020 13:52:06 +0200 Subject: [PATCH] For NuRAD: Fix for SAX fingering (LH2+RH2 now plays Bb). Added Gate Hold functionality from NuEVI, using thumb folded in over R2 through R5 in place of the "doorknob" grip on the EVI. For NuRAD and NuEVI: New POLY PLAY functionality with a number of harmonizer settings and additional rotator setups. --- NuEVI/NuEVI.ino | 424 +- NuEVI/globals.h | 22 + NuEVI/menu.cpp | 295 +- NuEVI/settings.cpp | 43 + NuEVI/settings.h | 36 +- .../NuEVI-polyplay-beta3.ino.hex | 5213 ++++++++++++++++ .../NuRAD-polyplay-beta3.ino.hex | 5325 +++++++++++++++++ user guides/poly play user guide section.txt | 64 + 8 files changed, 11365 insertions(+), 57 deletions(-) create mode 100644 uploadable hex files/NuEVI-polyplay-beta3.ino.hex create mode 100644 uploadable hex files/NuRAD-polyplay-beta3.ino.hex create mode 100644 user guides/poly play user guide section.txt diff --git a/NuEVI/NuEVI.ino b/NuEVI/NuEVI.ino index d38d461..246b229 100644 --- a/NuEVI/NuEVI.ino +++ b/NuEVI/NuEVI.ino @@ -93,6 +93,12 @@ unsigned short lpinky3; // 0-25 (OFF, -12 - MOD - +12) unsigned short batteryType; // 0-2 ALK,NIM,LIP unsigned short harmSetting; // 0-7 unsigned short harmSelect; // 0-4 +unsigned short polySelect; // OFF, MGR, MGD, MND, MNH, FWC, RTA, RTB or RTC +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 hmzLimit; // 2-5: unsigned short vibSens = 2; // vibrato sensitivity unsigned short vibRetn = 2; // vibrato return speed @@ -113,6 +119,10 @@ byte rotatorOn = 0; byte currentRotation = 0; uint16_t rotations[4]; // semitones { -5, -10, -7, -14 }; uint16_t parallel; // = 7; // semitones +uint16_t rotationsb[4]; +uint16_t parallelb; // semitones +uint16_t rotationsc[4]; +uint16_t parallelc; // semitones byte gateOpen = 0; // setting for gate always open, note on sent for every time fingering changes, no matter the breath status uint16_t gateOpenEnable = 0; @@ -241,10 +251,10 @@ const unsigned short* const curves[] = { }; // NuRAD Sax fingering -// LH1, LHb, LH2, LH3, LHp1, -LHp2-, -RHsx-, RH1, RH2, RH3, RHp1, RHp2, RHp3 -excluded- LHp2 always -1, RHs always +1 +// LH1, LHb, LH2, LH3, LHp1, -LHp2-, -RHs-, RH1, RH2, RH3, RHp1, -RHp2-, RHp3 -excluded- LHp2 always -1, RHs always +1, RHp2 disabled // 0 = not touched, 1 = touched, 2 = whatever -const byte saxFingerMatch[15][10] = +const byte saxFingerMatch[16][10] = { {1, 2, 1, 1, 0, 1, 1, 1, 2, 1}, // C (-13 semis) {1, 2, 1, 1, 1, 1, 1, 1, 2, 1}, // C# (-12 semis) @@ -256,13 +266,159 @@ const byte saxFingerMatch[15][10] = {1, 2, 1, 1, 0, 0, 0, 2, 2, 2}, // G (-6 semis) {1, 2, 1, 1, 1, 0, 0, 2, 2, 2}, // G# (-5 semis) {1, 2, 1, 0, 2, 2, 2, 2, 2, 2}, // A (-4 semis) - {1, 2, 0, 2, 2, 1, 2, 2, 2, 2}, // A# (-3 semis) - {1, 1, 0, 2, 2, 2, 2, 2, 2, 2}, // A# (-3 semis) + {1, 2, 0, 2, 2, 1, 2, 2, 2, 2}, // A# (-3 semis) RH1 for Bb + {1, 2, 0, 2, 2, 2, 1, 2, 2, 2}, // A# (-3 semis) RH2 for Bb + {1, 1, 0, 2, 2, 2, 2, 2, 2, 2}, // A# (-3 semis) bis for Bb {1, 0, 0, 2, 2, 0, 2, 2, 2, 2}, // B (-2 semis) {0, 2, 1, 2, 2, 2, 2, 2, 2, 2}, // C (-1 semis) {0, 2, 0, 2, 2, 2, 2, 2, 2, 2}, // C# (-0 semis) }; +int saxFingerResult[16] = +{-13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -3, -3, -2, -1, 0}; + +byte saxFinger[10]; + +byte bottom = 1; + +// Four Way Close variants (FWC), http://www.thejazzpianosite.com/jazz-piano-lessons/jazz-chord-voicings/four-way-close/ +// 6 +const int blockFWC[4][12][3] = {{{ -3, -5, -8 }, // C or key base + { -3, -5, -8 }, // C# or base +1 + { -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, -5, -8 }, // F# or base +6 + { -3, -5, -8 }, // G or base +7 + { -3, -6, -9 }, // G# or base +8 + { -4, -5, -9 }, // A or base +9 + { -3, -5, -9 }, // Bb or base +10 + { -3, -6, -9 }}, // B or base +11 +// m6 + {{ -3, -5, -9 }, // C or key base + { -3, -5, -9 }, // C# or base +1 + { -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, -8 }, // F# or base +6 + { -3, -6, -8 }, // G or base +7 + { -3, -6, -9 }, // G# or base +8 + { -4, -5, -9 }, // A or base +9 + { -3, -6, -9 }, // Bb or base +10 + { -3, -6, -9 }}, // B or base +11 +// 7 + {{ -2, -5, -8 }, // C or key base + { -2, -5, -8 }, // C# or base +1 + { -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, -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 +// 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 + { -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 + +// Major Gospel Root (MGR), Bert Lochs +const int majGosRootHmz[12][3] = {{ -5, -8, -12 }, // C or key base + { -6, -9, -12 }, // C# or base +1 + { -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 + { -3, -6, -12 }, // F# or base +6 + { -3, -7, -12 }, // G or base +7 + { -3, -8, -12 }, // G# or base +8 + { -4, -9, -12 }, // A or base +9 + { -5, -8, -12 }, // Bb or base +10 + { -4, -9, -12 }}; // B or base +11 + +// Major Gospel Dominant (MGD), Bert Lochs +const int majGosDomHmz[12][3] = {{ -5, -8, -12 }, // C or key base + { -6, -9, -12 }, // C# or base +1 + { -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 + { -3, -6, -12 }, // F# or base +6 + { -5, -8, -12 }, // G or base +7 + { -3, -8, -12 }, // G# or base +8 + { -4, -9, -12 }, // A or base +9 + { -5, -8, -12 }, // Bb or base +10 + { -4, -9, -12 }}; // B or base +11 + +// Major add9 (MA9), Bert Lochs +const int majAdd9Hmz[12][3] = {{ -5, -8, -10 }, // C or key base + { -6, -8, -10 }, // C# or base +1 + { -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 + { -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 + +// Minor Dorian (MND), Bert Lochs +const int minDorHmz[12][3] = {{ -5, -9, -12 }, // C or key base + { -5, -9, -12 }, // C# or base +1 + { -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 + { -5, -9, -12 }, // F# or base +6 + { -5, -9, -12 }, // G or base +7 + { -5, -8, -12 }, // G# or base +8 + { -4, -7, -12 }, // A or base +9 + { -3, -8, -12 }, // Bb or base +10 + { -4, -9, -12 }}; // B or base +11 + +// Minor Aeolian (MNA), Bert Lochs +const int minAeoHmz[12][3] = {{ -5, -9, -12 }, // C or key base + { -5, -9, -12 }, // C# or base +1 + { -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 +6 + { -5, -9, -12 }, // G or base +7 + { -3, -8, -12 }, // G# or base +8 + { -3, -8, -12 }, // A or base +9 + { -3, -8, -12 }, // Bb or base +10 + { -6, -8, -12 }}; // B or base +11 + +// 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 + { -5, -9, -10 }, // F# or base +6 + { -5, -9, -10 }, // G or base +7 + { -5, -6, -8 }, // G# or base +8 + { -4, -7, -8 }, // A or base +9 + { -3, -4, -8 }, // Bb or base +10 + { -4, -6, -9 }}; // B or base +11 + const int harmonicResult[5][7] = {{ 0, 7, 12, 16, 19, 24, 28 }, //HRM { 0, 7, 12, 19, 24, 31, 36 }, //5TH @@ -276,11 +432,6 @@ const int rollerHarmonic[2][7] = {{ 0, 7, 12, 16, 19, 24, 26 }, //F horn 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 saxFingerResult[15] = -{-13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -3, -2, -1, 0}; - -byte saxFinger[10]; - int vibThr; // this gets auto calibrated in setup int vibThrLo; @@ -704,7 +855,7 @@ void loop() { #else specialKey = (touchRead(specialKeyPin) > touch_Thr); //S2 on pcb #endif - if (specialKeyEnable) { + if (polySelect) { if (lastSpecialKey != specialKey) { if (specialKey) { // special key just pressed, check other keys @@ -820,16 +971,69 @@ void loop() { } } if (rotatorOn) { - if (parallel-24) midiSendNoteOn(noteValueCheck(fingeredNote + parallel-24), velocitySend); // send Note On message for new note - if (currentRotation < 3) currentRotation++; - else currentRotation = 0; - int allCheck=4; - while ((0 == rotations[currentRotation]-24) && allCheck){ - if (currentRotation < 3) currentRotation++; - else currentRotation = 0; - allCheck--; + if (MGR == polySelect){ // Triad Major Gospel Root + midiSendNoteOn(noteValueCheck(fingeredNote+majGosRootHmz[(fingeredNote-hmzKey)%12][0]), velocitySend); + if (hmzLimit>2) midiSendNoteOn(noteValueCheck(fingeredNote+majGosRootHmz[(fingeredNote-hmzKey)%12][1]), velocitySend); + if (hmzLimit>3) midiSendNoteOn(noteValueCheck(fingeredNote+majGosRootHmz[(fingeredNote-hmzKey)%12][2]), velocitySend); + } else if (MGD == polySelect){ // Triad Major Gospel Dominant + midiSendNoteOn(noteValueCheck(fingeredNote+majGosDomHmz[(fingeredNote-hmzKey)%12][0]), velocitySend); + if (hmzLimit>2) midiSendNoteOn(noteValueCheck(fingeredNote+majGosDomHmz[(fingeredNote-hmzKey)%12][1]), velocitySend); + if (hmzLimit>3) midiSendNoteOn(noteValueCheck(fingeredNote+majGosDomHmz[(fingeredNote-hmzKey)%12][2]), velocitySend); + } else if (MA9 == polySelect){ // Major add9 + midiSendNoteOn(noteValueCheck(fingeredNote+majAdd9Hmz[(fingeredNote-hmzKey)%12][0]), velocitySend); + if (hmzLimit>2) midiSendNoteOn(noteValueCheck(fingeredNote+majAdd9Hmz[(fingeredNote-hmzKey)%12][1]), velocitySend); + if (hmzLimit>3) midiSendNoteOn(noteValueCheck(fingeredNote+majAdd9Hmz[(fingeredNote-hmzKey)%12][2]), velocitySend); + } else if (MND == polySelect){ // Minor Dorian + midiSendNoteOn(noteValueCheck(fingeredNote+minDorHmz[(fingeredNote-hmzKey)%12][0]), velocitySend); + if (hmzLimit>2) midiSendNoteOn(noteValueCheck(fingeredNote+minDorHmz[(fingeredNote-hmzKey)%12][1]), velocitySend); + if (hmzLimit>3) midiSendNoteOn(noteValueCheck(fingeredNote+minDorHmz[(fingeredNote-hmzKey)%12][2]), velocitySend); + } else if (MNA == polySelect){ // Minor Aeolian + midiSendNoteOn(noteValueCheck(fingeredNote+minAeoHmz[(fingeredNote-hmzKey)%12][0]), velocitySend); + if (hmzLimit>2) midiSendNoteOn(noteValueCheck(fingeredNote+minAeoHmz[(fingeredNote-hmzKey)%12][1]), velocitySend); + if (hmzLimit>3) midiSendNoteOn(noteValueCheck(fingeredNote+minAeoHmz[(fingeredNote-hmzKey)%12][2]), velocitySend); + } else if (MNH == polySelect){ // Minor 4-voice Hip + midiSendNoteOn(noteValueCheck(fingeredNote+minHipHmz[(fingeredNote-hmzKey)%12][0]), velocitySend); + if (hmzLimit>2) midiSendNoteOn(noteValueCheck(fingeredNote+minHipHmz[(fingeredNote-hmzKey)%12][1]), velocitySend); + if (hmzLimit>3) midiSendNoteOn(noteValueCheck(fingeredNote+minHipHmz[(fingeredNote-hmzKey)%12][2]), velocitySend); + } else if (FWC == polySelect){ // Four Way Close Harmonizer + if (!fwcDrop2 || (hmzLimit>(3+fwcLockH))) midiSendNoteOn(noteValueCheck(fingeredNote+blockFWC[fwcType][(fingeredNote-hmzKey)%12][0]-12*fwcDrop2), velocitySend); + if ((hmzLimit+fwcDrop2)>2) midiSendNoteOn(noteValueCheck(fingeredNote+blockFWC[fwcType][(fingeredNote-hmzKey)%12][1]), velocitySend); + if ((hmzLimit+fwcDrop2)>3) midiSendNoteOn(noteValueCheck(fingeredNote+blockFWC[fwcType][(fingeredNote-hmzKey)%12][2]), velocitySend); + if (((hmzLimit+fwcDrop2)>4) && (1 == fwcLockH)) midiSendNoteOn(noteValueCheck(fingeredNote-12), velocitySend); + } else if (RT1 == polySelect) { // Rotator A + if (parallel-24) midiSendNoteOn(noteValueCheck(fingeredNote + parallel-24), velocitySend); // send Note On message for new note + if (currentRotation < 3) currentRotation++; + else currentRotation = 0; + int allCheck=4; + while ((0 == rotations[currentRotation]-24) && allCheck){ + if (currentRotation < 3) currentRotation++; + else currentRotation = 0; + allCheck--; + } + if (rotations[currentRotation]-24) midiSendNoteOn(noteValueCheck(fingeredNote + rotations[currentRotation]-24), velocitySend); // send Note On message for new note + } else if (RT2 == polySelect) { // Rotator B + if (parallelb-24) midiSendNoteOn(noteValueCheck(fingeredNote + parallelb-24), velocitySend); // send Note On message for new note + if (currentRotation < 3) currentRotation++; + else currentRotation = 0; + int allCheck=4; + while ((0 == rotationsb[currentRotation]-24) && allCheck){ + if (currentRotation < 3) currentRotation++; + else currentRotation = 0; + allCheck--; + } + if (rotationsb[currentRotation]-24) midiSendNoteOn(noteValueCheck(fingeredNote + rotationsb[currentRotation]-24), velocitySend); // send Note On message for new note + } else if (RT3 == polySelect) { // Rotator C + if (parallelc-24) midiSendNoteOn(noteValueCheck(fingeredNote + parallelc-24), velocitySend); // send Note On message for new note + if (currentRotation < 3) currentRotation++; + else currentRotation = 0; + int allCheck=4; + while ((0 == rotationsc[currentRotation]-24) && allCheck){ + if (currentRotation < 3) currentRotation++; + else currentRotation = 0; + allCheck--; + } + if (rotationsc[currentRotation]-24) midiSendNoteOn(noteValueCheck(fingeredNote + rotationsc[currentRotation]-24), velocitySend); // send Note On message for new note } - if (rotations[currentRotation]-24) midiSendNoteOn(noteValueCheck(fingeredNote + rotations[currentRotation]-24), velocitySend); // send Note On message for new note } if (!priority) { // mono prio to base note midiSendNoteOn(fingeredNote, velocitySend); // send Note On message for new note @@ -863,8 +1067,45 @@ void loop() { } } if (rotatorOn) { - if (parallel - 24) midiSendNoteOff(noteValueCheck(activeNote + parallel-24 )); // send Note Off message for old note - if (rotations[currentRotation]-24) midiSendNoteOff(noteValueCheck(activeNote + rotations[currentRotation]-24)); // send Note Off message for old note + if (MGR == polySelect){ // Triad Major Gospel Root + midiSendNoteOff(noteValueCheck(activeNote+majGosRootHmz[(activeNote-hmzKey)%12][0])); + if (hmzLimit>2) midiSendNoteOff(noteValueCheck(activeNote+majGosRootHmz[(activeNote-hmzKey)%12][1])); + if (hmzLimit>3) midiSendNoteOff(noteValueCheck(activeNote+majGosRootHmz[(activeNote-hmzKey)%12][2])); + } else if (MGD == polySelect){ // Triad Major Gospel Dominant + midiSendNoteOff(noteValueCheck(activeNote+majGosDomHmz[(activeNote-hmzKey)%12][0])); + if (hmzLimit>2) midiSendNoteOff(noteValueCheck(activeNote+majGosDomHmz[(activeNote-hmzKey)%12][1])); + if (hmzLimit>3) midiSendNoteOff(noteValueCheck(activeNote+majGosDomHmz[(activeNote-hmzKey)%12][2])); + } else if (MA9 == polySelect){ // Major add9 + midiSendNoteOff(noteValueCheck(activeNote+majAdd9Hmz[(activeNote-hmzKey)%12][0])); + if (hmzLimit>2) midiSendNoteOff(noteValueCheck(activeNote+majAdd9Hmz[(activeNote-hmzKey)%12][1])); + if (hmzLimit>3) midiSendNoteOff(noteValueCheck(activeNote+majAdd9Hmz[(activeNote-hmzKey)%12][2])); + } else if (MND == polySelect){ // Minor Dorian + midiSendNoteOff(noteValueCheck(activeNote+minDorHmz[(activeNote-hmzKey)%12][0])); + if (hmzLimit>2) midiSendNoteOff(noteValueCheck(activeNote+minDorHmz[(activeNote-hmzKey)%12][1])); + if (hmzLimit>3) midiSendNoteOff(noteValueCheck(activeNote+minDorHmz[(activeNote-hmzKey)%12][2])); + } else if (MNA == polySelect){ // Minor Dorian + midiSendNoteOff(noteValueCheck(activeNote+minAeoHmz[(activeNote-hmzKey)%12][0])); + if (hmzLimit>2) midiSendNoteOff(noteValueCheck(activeNote+minAeoHmz[(activeNote-hmzKey)%12][1])); + if (hmzLimit>3) midiSendNoteOff(noteValueCheck(activeNote+minAeoHmz[(activeNote-hmzKey)%12][2])); + } else if (MNH == polySelect){ // Minor 4-voice Hip + midiSendNoteOff(noteValueCheck(activeNote+minHipHmz[(activeNote-hmzKey)%12][0])); + if (hmzLimit>2) midiSendNoteOff(noteValueCheck(activeNote+minHipHmz[(activeNote-hmzKey)%12][1])); + if (hmzLimit>3) midiSendNoteOff(noteValueCheck(activeNote+minHipHmz[(activeNote-hmzKey)%12][2])); + } else if (FWC == polySelect){ // Four Way Close Harmonizer + if (!fwcDrop2 || (hmzLimit>(3+fwcLockH))) midiSendNoteOff(noteValueCheck(activeNote+blockFWC[fwcType][(activeNote-hmzKey)%12][0]-12*fwcDrop2)); + if ((hmzLimit+fwcDrop2)>2) midiSendNoteOff(noteValueCheck(activeNote+blockFWC[fwcType][(activeNote-hmzKey)%12][1])); + if ((hmzLimit+fwcDrop2)>3) midiSendNoteOff(noteValueCheck(activeNote+blockFWC[fwcType][(activeNote-hmzKey)%12][2])); + if (((hmzLimit+fwcDrop2)>4) && (1 == fwcLockH)) midiSendNoteOff(noteValueCheck(activeNote-12)); + } else if (RT1 == polySelect){ // Rotator A + if (parallel - 24) midiSendNoteOff(noteValueCheck(activeNote + parallel-24 )); // send Note Off message for old note + if (rotations[currentRotation]-24) midiSendNoteOff(noteValueCheck(activeNote + rotations[currentRotation]-24)); // send Note Off message for old note + } else if (RT2 == polySelect){ // Rotator B + if (parallelb - 24) midiSendNoteOff(noteValueCheck(activeNote + parallelb-24 )); // send Note Off message for old note + if (rotationsb[currentRotation]-24) midiSendNoteOff(noteValueCheck(activeNote + rotationsb[currentRotation]-24)); // send Note Off message for old note + } else if (RT3 == polySelect){ // Rotator C + if (parallelc - 24) midiSendNoteOff(noteValueCheck(activeNote + parallelc-24 )); // send Note Off message for old note + if (rotationsc[currentRotation]-24) midiSendNoteOff(noteValueCheck(activeNote + rotationsc[currentRotation]-24)); // send Note Off message for old note + } } if (!priority) { midiSendNoteOff(activeNote); // send Note Off message @@ -904,8 +1145,45 @@ void loop() { } } if (rotatorOn) { - if (parallel-24) midiSendNoteOff(noteValueCheck(activeNote + parallel-24)); // send Note Off message for old note - if (rotations[currentRotation]-24) midiSendNoteOff(noteValueCheck(activeNote + rotations[currentRotation]-24)); // send Note Off message for old note + if (MGR == polySelect){ // Triad Major Gospel Root + midiSendNoteOff(noteValueCheck(activeNote+majGosRootHmz[(activeNote-hmzKey)%12][0])); + if (hmzLimit>2) midiSendNoteOff(noteValueCheck(activeNote+majGosRootHmz[(activeNote-hmzKey)%12][1])); + if (hmzLimit>3) midiSendNoteOff(noteValueCheck(activeNote+majGosRootHmz[(activeNote-hmzKey)%12][2])); + } else if (MGD == polySelect){ // Triad Major Gospel Dominant + midiSendNoteOff(noteValueCheck(activeNote+majGosDomHmz[(activeNote-hmzKey)%12][0])); + if (hmzLimit>2) midiSendNoteOff(noteValueCheck(activeNote+majGosDomHmz[(activeNote-hmzKey)%12][1])); + if (hmzLimit>3) midiSendNoteOff(noteValueCheck(activeNote+majGosDomHmz[(activeNote-hmzKey)%12][2])); + } else if (MA9 == polySelect){ // Major add9 + midiSendNoteOff(noteValueCheck(activeNote+majAdd9Hmz[(activeNote-hmzKey)%12][0])); + if (hmzLimit>2) midiSendNoteOff(noteValueCheck(activeNote+majAdd9Hmz[(activeNote-hmzKey)%12][1])); + if (hmzLimit>3) midiSendNoteOff(noteValueCheck(activeNote+majAdd9Hmz[(activeNote-hmzKey)%12][2])); + } else if (MND == polySelect){ // Minor Dorian + midiSendNoteOff(noteValueCheck(activeNote+minDorHmz[(activeNote-hmzKey)%12][0])); + if (hmzLimit>2) midiSendNoteOff(noteValueCheck(activeNote+minDorHmz[(activeNote-hmzKey)%12][1])); + if (hmzLimit>3) midiSendNoteOff(noteValueCheck(activeNote+minDorHmz[(activeNote-hmzKey)%12][2])); + } else if (MNA == polySelect){ // Minor Dorian + midiSendNoteOff(noteValueCheck(activeNote+minAeoHmz[(activeNote-hmzKey)%12][0])); + if (hmzLimit>2) midiSendNoteOff(noteValueCheck(activeNote+minAeoHmz[(activeNote-hmzKey)%12][1])); + if (hmzLimit>3) midiSendNoteOff(noteValueCheck(activeNote+minAeoHmz[(activeNote-hmzKey)%12][2])); + } else if (MNH == polySelect){ // Minor 4-voice Hip + midiSendNoteOff(noteValueCheck(activeNote+minHipHmz[(activeNote-hmzKey)%12][0])); + if (hmzLimit>2) midiSendNoteOff(noteValueCheck(activeNote+minHipHmz[(activeNote-hmzKey)%12][1])); + if (hmzLimit>3) midiSendNoteOff(noteValueCheck(activeNote+minHipHmz[(activeNote-hmzKey)%12][2])); + } else if (FWC == polySelect){ // Four Way Close Harmonizer + if (!fwcDrop2 || (hmzLimit>(3+fwcLockH))) midiSendNoteOff(noteValueCheck(activeNote+blockFWC[fwcType][(activeNote-hmzKey)%12][0]-12*fwcDrop2)); + if ((hmzLimit+fwcDrop2)>2) midiSendNoteOff(noteValueCheck(activeNote+blockFWC[fwcType][(activeNote-hmzKey)%12][1])); + if ((hmzLimit+fwcDrop2)>3) midiSendNoteOff(noteValueCheck(activeNote+blockFWC[fwcType][(activeNote-hmzKey)%12][2])); + if (((hmzLimit+fwcDrop2)>4) && (1 == fwcLockH)) midiSendNoteOff(noteValueCheck(activeNote-12)); + } else if (RT1 == polySelect){ // Rotator A + if (parallel - 24) midiSendNoteOff(noteValueCheck(activeNote + parallel-24 )); // send Note Off message for old note + if (rotations[currentRotation]-24) midiSendNoteOff(noteValueCheck(activeNote + rotations[currentRotation]-24)); // send Note Off message for old note + } else if (RT2 == polySelect){ // Rotator B + if (parallelb - 24) midiSendNoteOff(noteValueCheck(activeNote + parallelb-24 )); // send Note Off message for old note + if (rotationsb[currentRotation]-24) midiSendNoteOff(noteValueCheck(activeNote + rotationsb[currentRotation]-24)); // send Note Off message for old note + } else if (RT3 == polySelect){ // Rotator C + if (parallelc - 24) midiSendNoteOff(noteValueCheck(activeNote + parallelc-24 )); // send Note Off message for old note + if (rotationsc[currentRotation]-24) midiSendNoteOff(noteValueCheck(activeNote + rotationsc[currentRotation]-24)); // send Note Off message for old note + } } if ((parallelChord || subOctaveDouble || rotatorOn) && !priority) { // poly playing, send old note off before new note on midiSendNoteOff(activeNote); // send Note Off message for old note @@ -929,16 +1207,69 @@ void loop() { } } if (rotatorOn) { - if (parallel-24) midiSendNoteOn(noteValueCheck(fingeredNote + parallel-24), velocitySend); // send Note On message for new note - if (currentRotation < 3) currentRotation++; - else currentRotation = 0; - int allCheck=4; - while ((0 == rotations[currentRotation]-24) && allCheck){ - if (currentRotation < 3) currentRotation++; - else currentRotation = 0; - allCheck--; + if (MGR == polySelect){ // Triad Major Gospel Root + midiSendNoteOn(noteValueCheck(fingeredNote+majGosRootHmz[(fingeredNote-hmzKey)%12][0]), velocitySend); + if (hmzLimit>2) midiSendNoteOn(noteValueCheck(fingeredNote+majGosRootHmz[(fingeredNote-hmzKey)%12][1]), velocitySend); + if (hmzLimit>3) midiSendNoteOn(noteValueCheck(fingeredNote+majGosRootHmz[(fingeredNote-hmzKey)%12][2]), velocitySend); + } else if (MGD == polySelect){ // Triad Major Gospel Dominant + midiSendNoteOn(noteValueCheck(fingeredNote+majGosDomHmz[(fingeredNote-hmzKey)%12][0]), velocitySend); + if (hmzLimit>2) midiSendNoteOn(noteValueCheck(fingeredNote+majGosDomHmz[(fingeredNote-hmzKey)%12][1]), velocitySend); + if (hmzLimit>3) midiSendNoteOn(noteValueCheck(fingeredNote+majGosDomHmz[(fingeredNote-hmzKey)%12][2]), velocitySend); + } else if (MA9 == polySelect){ // Major add9 + midiSendNoteOn(noteValueCheck(fingeredNote+majAdd9Hmz[(fingeredNote-hmzKey)%12][0]), velocitySend); + if (hmzLimit>2) midiSendNoteOn(noteValueCheck(fingeredNote+majAdd9Hmz[(fingeredNote-hmzKey)%12][1]), velocitySend); + if (hmzLimit>3) midiSendNoteOn(noteValueCheck(fingeredNote+majAdd9Hmz[(fingeredNote-hmzKey)%12][2]), velocitySend); + } else if (MND == polySelect){ // Minor Dorian + midiSendNoteOn(noteValueCheck(fingeredNote+minDorHmz[(fingeredNote-hmzKey)%12][0]), velocitySend); + if (hmzLimit>2) midiSendNoteOn(noteValueCheck(fingeredNote+minDorHmz[(fingeredNote-hmzKey)%12][1]), velocitySend); + if (hmzLimit>3) midiSendNoteOn(noteValueCheck(fingeredNote+minDorHmz[(fingeredNote-hmzKey)%12][2]), velocitySend); + } else if (MNA == polySelect){ // Minor Aeolian + midiSendNoteOn(noteValueCheck(fingeredNote+minAeoHmz[(fingeredNote-hmzKey)%12][0]), velocitySend); + if (hmzLimit>2) midiSendNoteOn(noteValueCheck(fingeredNote+minAeoHmz[(fingeredNote-hmzKey)%12][1]), velocitySend); + if (hmzLimit>3) midiSendNoteOn(noteValueCheck(fingeredNote+minAeoHmz[(fingeredNote-hmzKey)%12][2]), velocitySend); + } else if (MNH == polySelect){ // Minor 4-voice Hip + midiSendNoteOn(noteValueCheck(fingeredNote+minHipHmz[(fingeredNote-hmzKey)%12][0]), velocitySend); + if (hmzLimit>2) midiSendNoteOn(noteValueCheck(fingeredNote+minHipHmz[(fingeredNote-hmzKey)%12][1]), velocitySend); + if (hmzLimit>3) midiSendNoteOn(noteValueCheck(fingeredNote+minHipHmz[(fingeredNote-hmzKey)%12][2]), velocitySend); + } else if (FWC == polySelect){ // Four Way Close Harmonizer + if (!fwcDrop2 || (hmzLimit>(3+fwcLockH))) midiSendNoteOn(noteValueCheck(fingeredNote+blockFWC[fwcType][(fingeredNote-hmzKey)%12][0]-12*fwcDrop2), velocitySend); + if ((hmzLimit+fwcDrop2)>2) midiSendNoteOn(noteValueCheck(fingeredNote+blockFWC[fwcType][(fingeredNote-hmzKey)%12][1]), velocitySend); + if ((hmzLimit+fwcDrop2)>3) midiSendNoteOn(noteValueCheck(fingeredNote+blockFWC[fwcType][(fingeredNote-hmzKey)%12][2]), velocitySend); + if (((hmzLimit+fwcDrop2)>4) && (1 == fwcLockH)) midiSendNoteOn(noteValueCheck(fingeredNote-12), velocitySend); + } else if (RT1 == polySelect) { // Rotator A + if (parallel-24) midiSendNoteOn(noteValueCheck(fingeredNote + parallel-24), velocitySend); // send Note On message for new note + if (currentRotation < 3) currentRotation++; + else currentRotation = 0; + int allCheck=4; + while ((0 == rotations[currentRotation]-24) && allCheck){ + if (currentRotation < 3) currentRotation++; + else currentRotation = 0; + allCheck--; + } + if (rotations[currentRotation]-24) midiSendNoteOn(noteValueCheck(fingeredNote + rotations[currentRotation]-24), velocitySend); // send Note On message for new note + } else if (RT2 == polySelect) { // Rotator B + if (parallelb-24) midiSendNoteOn(noteValueCheck(fingeredNote + parallelb-24), velocitySend); // send Note On message for new note + if (currentRotation < 3) currentRotation++; + else currentRotation = 0; + int allCheck=4; + while ((0 == rotationsb[currentRotation]-24) && allCheck){ + if (currentRotation < 3) currentRotation++; + else currentRotation = 0; + allCheck--; + } + if (rotationsb[currentRotation]-24) midiSendNoteOn(noteValueCheck(fingeredNote + rotationsb[currentRotation]-24), velocitySend); // send Note On message for new note + } else if (RT3 == polySelect) { // Rotator C + if (parallelc-24) midiSendNoteOn(noteValueCheck(fingeredNote + parallelc-24), velocitySend); // send Note On message for new note + if (currentRotation < 3) currentRotation++; + else currentRotation = 0; + int allCheck=4; + while ((0 == rotationsc[currentRotation]-24) && allCheck){ + if (currentRotation < 3) currentRotation++; + else currentRotation = 0; + allCheck--; + } + if (rotationsc[currentRotation]-24) midiSendNoteOn(noteValueCheck(fingeredNote + rotationsc[currentRotation]-24), velocitySend); // send Note On message for new note } - if (rotations[currentRotation]-24) midiSendNoteOn(noteValueCheck(fingeredNote + rotations[currentRotation]-24), velocitySend); // send Note On message for new note } if (!priority) { @@ -977,10 +1308,7 @@ void loop() { ccSendTime2 = currentTime; } if (currentTime - ccSendTime3 > CC_INTERVAL3) { - #if defined(NURAD) - #else if (gateOpenEnable || gateOpen) doorKnobCheck(); - #endif battCheck(); if (((pinkySetting == LVL) || (pinkySetting == LVLP) || (pinkySetting == GLD)) && pinkyKey && (mainState == NOTE_OFF)){ // show LVL indication @@ -1245,6 +1573,21 @@ void pitch_bend() { void doorKnobCheck() { if (gateOpenEnable){ + #if defined(NURAD) + if (R2 && R3 && R4 && R5) { // fold thumb in to cover R2 through R5 + if (!gateOpen && (pbUp > ((pitchbMaxVal + pitchbThrVal) / 2))) { + gateOpen = 1; + statusLedFlash(100); + } else if (gateOpen && (pbDn > ((pitchbMaxVal + pitchbThrVal) / 2))) { + gateOpen = 0; + midiPanic(); + statusLedFlash(100); + statusLedFlash(100); + statusLedFlash(100); + delay(600); + } + } + #else if (K4 && R1 && R2 && R3) { // doorknob grip on canister if (!gateOpen && (pbUp > ((pitchbMaxVal + pitchbThrVal) / 2))) { gateOpen = 1; @@ -1258,6 +1601,7 @@ void doorKnobCheck() { delay(600); } } + #endif } else if (gateOpen) { gateOpen = 0; midiPanic(); @@ -1503,10 +1847,10 @@ void readSwitches() { // 6-pin version octaveR = 0; if (touchValueRollers[rPin6] < ctouchThrVal) octaveR = 6; //R6 - else if (touchValueRollers[rPin5] < ctouchThrVal) octaveR = 5; //R5 - else if (touchValueRollers[rPin4] < ctouchThrVal) octaveR = 4; //R4 - else if (touchValueRollers[rPin3] < ctouchThrVal) octaveR = 3; //R3 - else if (touchValueRollers[rPin2] < ctouchThrVal) octaveR = 2; //R2 + 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 /* //5-pin version @@ -1587,7 +1931,7 @@ void readSwitches() { byte matched = 0; byte combo = 0; - while (matched<10 && combo<15) + while (matched<10 && combo<16) { combo++; matched = 0; diff --git a/NuEVI/globals.h b/NuEVI/globals.h index fe359e5..a4b3523 100644 --- a/NuEVI/globals.h +++ b/NuEVI/globals.h @@ -27,6 +27,18 @@ #define GLD 29 #define ECH 30 +#define HOF 0 +#define MGR 1 +#define MGD 2 +#define MA9 3 +#define MND 4 +#define MNA 5 +#define MNH 6 +#define FWC 7 +#define RT1 8 +#define RT2 9 +#define RT3 10 + #define MOD 13 @@ -89,12 +101,22 @@ extern unsigned short lpinky3; // 0-25 (OFF, -12 - MOD - +12) extern unsigned short batteryType; // 0-2 ALK,NIM,LIP extern unsigned short harmSetting; // 0-7 extern unsigned short harmSelect; // 0-4 +extern unsigned short polySelect; // OFF, MGR, MGD, MND, MNH, FWC, RTA, RTB or RTC +extern unsigned short fwcType; // 6, m6, 7, m7 +extern unsigned short fwcLockH; // OFF:ON +extern unsigned short fwcDrop2; // OFF:ON +extern unsigned short hmzKey; // 0-11 (0 is C) +extern unsigned short hmzLimit; // 2-5 extern uint16_t gateOpenEnable; extern uint16_t specialKeyEnable; extern byte rotatorOn; extern byte currentRotation; extern uint16_t rotations[4]; extern uint16_t parallel; // semitones +extern uint16_t rotationsb[4]; +extern uint16_t parallelb; // semitones +extern uint16_t rotationsc[4]; +extern uint16_t parallelc; // semitones extern uint16_t bcasMode; //Legacy CASSIDY compile flag extern uint16_t trill3_interval; diff --git a/NuEVI/menu.cpp b/NuEVI/menu.cpp index a64e9da..eb09de6 100644 --- a/NuEVI/menu.cpp +++ b/NuEVI/menu.cpp @@ -510,7 +510,7 @@ static void clearFPS(int trills) { //*********************************************************** -// Rotator menu +// Poly Play menu static void rotatorSave(const MenuEntrySub& __unused sub) { int16_t stored; @@ -521,6 +521,25 @@ static void rotatorSave(const MenuEntrySub& __unused sub) { } } +static void rotatorBSave(const MenuEntrySub& __unused sub) { + int16_t stored; + for(int i = 0; i < 4; ++i) { + stored = readSetting(ROTB1_ADDR+2*i); + if(stored != rotationsb[i]) + writeSetting(ROTB1_ADDR+2*i,(rotationsb[i])); + } +} + +static void rotatorCSave(const MenuEntrySub& __unused sub) { + int16_t stored; + for(int i = 0; i < 4; ++i) { + stored = readSetting(ROTC1_ADDR+2*i); + if(stored != rotationsc[i]) + writeSetting(ROTC1_ADDR+2*i,(rotationsc[i])); + } +} + + static void rotatorOptionGet(SubMenuRef sub, char *out, const char** __unused unit) { numToString((*sub.valuePtr) - 24, out, true); } @@ -529,38 +548,104 @@ static void parallelOptionGet(SubMenuRef __unused, char *out, const char** __unu numToString(parallel-24, out, true); } +static void parallelBOptionGet(SubMenuRef __unused, char *out, const char** __unused unit) { + numToString(parallelb-24, out, true); +} + +static void parallelCOptionGet(SubMenuRef __unused, char *out, const char** __unused unit) { + numToString(parallelc-24, out, true); +} + static void parallelSave(SubMenuRef __unused) { writeSetting(PARAL_ADDR, parallel); } +static void parallelBSave(SubMenuRef __unused) { + writeSetting(PARAB_ADDR, parallelb); +} + +static void parallelCSave(SubMenuRef __unused) { + writeSetting(PARAC_ADDR, parallelc); +} + const MenuEntrySub rotatorParaMenu = { - MenuType::ESub, "PARALLEL", "SEMITONES", ¶llel, 0, 48, MenuEntryFlags::ENone, + MenuType::ESub, "RTA PARAL", "SEMITONES", ¶llel, 0, 48, MenuEntryFlags::ENone, parallelOptionGet, parallelSave, nullptr }; const MenuEntrySub rotator1Menu = { - MenuType::ESub, "ROTATE 1", "SEMITONES", &rotations[0], 0, 48, MenuEntryFlags::ENone, + MenuType::ESub, "RTA ROT 1", "SEMITONES", &rotations[0], 0, 48, MenuEntryFlags::ENone, rotatorOptionGet, rotatorSave, nullptr }; const MenuEntrySub rotator2Menu = { - MenuType::ESub, "ROTATE 2", "SEMITONES", &rotations[1], 0, 48, MenuEntryFlags::ENone, + MenuType::ESub, "RTA ROT 2", "SEMITONES", &rotations[1], 0, 48, MenuEntryFlags::ENone, rotatorOptionGet, rotatorSave, nullptr }; const MenuEntrySub rotator3Menu = { - MenuType::ESub, "ROTATE 3", "SEMITONES", &rotations[2], 0, 48, MenuEntryFlags::ENone, + MenuType::ESub, "RTA ROT 3", "SEMITONES", &rotations[2], 0, 48, MenuEntryFlags::ENone, rotatorOptionGet, rotatorSave, nullptr }; const MenuEntrySub rotator4Menu = { - MenuType::ESub, "ROTATE 4", "SEMITONES", &rotations[3], 0, 48, MenuEntryFlags::ENone, + MenuType::ESub, "RTA ROT 4", "SEMITONES", &rotations[3], 0, 48, MenuEntryFlags::ENone, rotatorOptionGet, rotatorSave, nullptr }; +const MenuEntrySub rotatorParaBMenu = { + MenuType::ESub, "RTB PARAL", "SEMITONES", ¶llelb, 0, 48, MenuEntryFlags::ENone, + parallelBOptionGet, parallelBSave, nullptr +}; + +const MenuEntrySub rotatorB1Menu = { + MenuType::ESub, "RTB ROT 1", "SEMITONES", &rotationsb[0], 0, 48, MenuEntryFlags::ENone, + rotatorOptionGet, rotatorBSave, nullptr +}; + +const MenuEntrySub rotatorB2Menu = { + MenuType::ESub, "RTB ROT 2", "SEMITONES", &rotationsb[1], 0, 48, MenuEntryFlags::ENone, + rotatorOptionGet, rotatorBSave, nullptr +}; + +const MenuEntrySub rotatorB3Menu = { + MenuType::ESub, "RTB ROT 3", "SEMITONES", &rotationsb[2], 0, 48, MenuEntryFlags::ENone, + rotatorOptionGet, rotatorBSave, nullptr +}; + +const MenuEntrySub rotatorB4Menu = { + MenuType::ESub, "RTB ROT 4", "SEMITONES", &rotationsb[3], 0, 48, MenuEntryFlags::ENone, + rotatorOptionGet, rotatorBSave, nullptr +}; +const MenuEntrySub rotatorParaCMenu = { + MenuType::ESub, "RTC PARAL", "SEMITONES", ¶llelc, 0, 48, MenuEntryFlags::ENone, + parallelCOptionGet, parallelCSave, nullptr +}; + +const MenuEntrySub rotatorC1Menu = { + MenuType::ESub, "RTC ROT 1", "SEMITONES", &rotationsc[0], 0, 48, MenuEntryFlags::ENone, + rotatorOptionGet, rotatorCSave, nullptr +}; + +const MenuEntrySub rotatorC2Menu = { + MenuType::ESub, "RTC ROT 2", "SEMITONES", &rotationsc[1], 0, 48, MenuEntryFlags::ENone, + rotatorOptionGet, rotatorCSave, nullptr +}; + +const MenuEntrySub rotatorC3Menu = { + MenuType::ESub, "RTC ROT 3", "SEMITONES", &rotationsc[2], 0, 48, MenuEntryFlags::ENone, + rotatorOptionGet, rotatorCSave, nullptr +}; + +const MenuEntrySub rotatorC4Menu = { + MenuType::ESub, "RTC ROT 4", "SEMITONES", &rotationsc[3], 0, 48, MenuEntryFlags::ENone, + rotatorOptionGet, rotatorCSave, nullptr +}; + + static void rotatorPrioOptionGet(SubMenuRef __unused, char* out, const char** __unused) { - if (priority) strncpy(out, "ROT", 4); - else strncpy(out, "MEL", 4); + if (priority) strncpy(out, "LO", 4); + else strncpy(out, "HI", 4); } static void rotatorPrioSave(SubMenuRef __unused) { @@ -572,13 +657,194 @@ const MenuEntrySub rotatorPrioMenu = { rotatorPrioOptionGet, rotatorPrioSave, nullptr, }; + +static void fwcTypeOptionGet(SubMenuRef __unused, char* out, const char** __unused) { + switch (fwcType){ + case 0: + strncpy(out, "6", 4); + break; + case 1: + strncpy(out, "m6", 4); + break; + case 2: + strncpy(out, "7", 4); + break; + case 3: + strncpy(out, "m7", 4); + } +} + +static void fwcTypeSave(SubMenuRef __unused) { + writeSetting(FWCTYPE_ADDR,fwcType); +} + +const MenuEntrySub fwcTypeMenu = { + MenuType::ESub, "FWC TYPE", "CHORD", &fwcType, 0,3, MenuEntryFlags::EMenuEntryWrap, + fwcTypeOptionGet, fwcTypeSave, nullptr, +}; + +static void fwcLockHOptionGet(SubMenuRef __unused, char* out, const char** __unused) { + if (fwcLockH) strncpy(out, "ON", 4); + else strncpy(out, "OFF", 4); +} + +static void fwcLockHSave(SubMenuRef __unused) { + writeSetting(FWCLCH_ADDR,fwcLockH); +} + +const MenuEntrySub fwcLockHMenu = { + MenuType::ESub, "FWC LOCKH", "LH MELODY", &fwcLockH, 0,1, MenuEntryFlags::EMenuEntryWrap, + fwcLockHOptionGet, fwcLockHSave, nullptr, +}; + +static void fwcDrop2OptionGet(SubMenuRef __unused, char* out, const char** __unused) { + if (fwcDrop2) strncpy(out, "ON", 4); + else strncpy(out, "OFF", 4); +} + +static void fwcDrop2Save(SubMenuRef __unused) { + writeSetting(FWCDP2_ADDR,fwcDrop2); +} + +const MenuEntrySub fwcDrop2Menu = { + MenuType::ESub, "FWC DROP2", "DROP 2", &fwcDrop2, 0,1, MenuEntryFlags::EMenuEntryWrap, + fwcDrop2OptionGet, fwcDrop2Save, nullptr, +}; + +static void hmzKeyOptionGet(SubMenuRef __unused, char* out, const char** __unused) { + switch (hmzKey){ + 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; + } +} + +static void hmzKeySave(SubMenuRef __unused) { + writeSetting(HMZKEY_ADDR,hmzKey); +} + +const MenuEntrySub hmzKeyMenu = { + MenuType::ESub, "HMZ KEY", "KEY PLAYED", &hmzKey, 0,11, MenuEntryFlags::EMenuEntryWrap, + hmzKeyOptionGet, hmzKeySave, nullptr, +}; + + +static void polySelectOptionGet(SubMenuRef __unused, char* out, const char** __unused) { + switch (polySelect){ + case 0: + strncpy(out, "OFF", 4); + break; + case 1: + strncpy(out, "MGR", 4); + break; + case 2: + strncpy(out, "MGD", 4); + break; + case 3: + strncpy(out, "MA9", 4); + break; + case 4: + strncpy(out, "MND", 4); + break; + case 5: + strncpy(out, "MNA", 4); + break; + case 6: + strncpy(out, "MNH", 4); + break; + case 7: + strncpy(out, "FWC", 4); + break; + case 8: + strncpy(out, "RTA", 4); + break; + case 9: + strncpy(out, "RTB", 4); + break; + case 10: + strncpy(out, "RTC", 4); + break; + } +} + +static void polySelectSave(SubMenuRef __unused) { + writeSetting(POLYSEL_ADDR,polySelect); +} + +const MenuEntrySub polySelectMenu = { + MenuType::ESub, "POLY MODE", "SELECT", &polySelect, 0,10, MenuEntryFlags::EMenuEntryWrap, + polySelectOptionGet, polySelectSave, nullptr, +}; + +static void hmzLimitOptionGet(SubMenuRef sub, char *out, const char** __unused unit) { + numToString((*sub.valuePtr), out, false); +} + +static void hmzLimitSave(SubMenuRef __unused) { + writeSetting(HMZLIMIT_ADDR,hmzLimit); +} + +const MenuEntrySub hmzLimitMenu = { + MenuType::ESub, "HMZ LIMIT", "VOICES", &hmzLimit, 2,5, MenuEntryFlags::EMenuEntryWrap, + hmzLimitOptionGet, hmzLimitSave, nullptr, +}; + const MenuEntry* rotatorMenuEntries[] = { + (MenuEntry*)&polySelectMenu, + (MenuEntry*)&hmzKeyMenu, + (MenuEntry*)&hmzLimitMenu, + (MenuEntry*)&fwcTypeMenu, + (MenuEntry*)&fwcLockHMenu, + (MenuEntry*)&fwcDrop2Menu, + (MenuEntry*)&rotatorPrioMenu, (MenuEntry*)&rotatorParaMenu, (MenuEntry*)&rotator1Menu, (MenuEntry*)&rotator2Menu, (MenuEntry*)&rotator3Menu, (MenuEntry*)&rotator4Menu, - (MenuEntry*)&rotatorPrioMenu + (MenuEntry*)&rotatorParaBMenu, + (MenuEntry*)&rotatorB1Menu, + (MenuEntry*)&rotatorB2Menu, + (MenuEntry*)&rotatorB3Menu, + (MenuEntry*)&rotatorB4Menu, + (MenuEntry*)&rotatorParaCMenu, + (MenuEntry*)&rotatorC1Menu, + (MenuEntry*)&rotatorC2Menu, + (MenuEntry*)&rotatorC3Menu, + (MenuEntry*)&rotatorC4Menu }; /* const MenuPage rotatorMenuPage = { @@ -590,7 +856,7 @@ const MenuPage rotatorMenuPage = { }; */ const MenuPage rotatorMenuPage = { - "ROTATOR SETUP", + "POLY PLAY SETUP", 0, CursorIdx::ERotator, MAIN_MENU, @@ -760,7 +1026,7 @@ const MenuEntrySub batteryTypeMenu = { const MenuEntry* extrasMenuEntries[] = { (MenuEntry*)&legacyPBMenu, (MenuEntry*)&legacyBRMenu, - (MenuEntry*)&specialKeyMenu, + (MenuEntry*)&gateOpenMenu, (MenuEntry*)&dacModeMenu, (MenuEntry*)&batteryTypeMenu, (MenuEntry*)&fastBootMenu, @@ -772,7 +1038,6 @@ const MenuEntry* extrasMenuEntries[] = { (MenuEntry*)&legacyPBMenu, (MenuEntry*)&legacyBRMenu, (MenuEntry*)&gateOpenMenu, - (MenuEntry*)&specialKeyMenu, (MenuEntry*)&trill3Menu, (MenuEntry*)&bcasModeMenu, (MenuEntry*)&dacModeMenu, @@ -812,7 +1077,7 @@ const MenuEntrySub midiMenu = { const MenuEntryStateCh adjustMenu = { MenuType::EStateChange, "ADJUST", ADJUST_MENU }; const MenuEntryStateCh breathMenu = { MenuType::EStateChange, "SETUP BR", SETUP_BR_MENU }; const MenuEntryStateCh controlMenu = { MenuType::EStateChange, "SETUP CTL", SETUP_CT_MENU }; -const MenuEntryStateCh rotatorMenu = { MenuType::EStateChange, "ROTATOR", ROTATOR_MENU }; +const MenuEntryStateCh rotatorMenu = { MenuType::EStateChange, "POLY PLAY", ROTATOR_MENU }; const MenuEntryStateCh extrasMenu = { MenuType::EStateChange, "EXTRAS", EXTRAS_MENU }; const MenuEntryStateCh aboutMenu = { MenuType::EStateChange, "ABOUT", ABOUT_MENU }; @@ -820,10 +1085,10 @@ const MenuEntry* mainMenuEntries[] = { (MenuEntry*)&transposeMenu, (MenuEntry*)&octaveMenu, (MenuEntry*)&midiMenu, - (MenuEntry*)&adjustMenu, + (MenuEntry*)&rotatorMenu, (MenuEntry*)&breathMenu, (MenuEntry*)&controlMenu, - (MenuEntry*)&rotatorMenu, + (MenuEntry*)&adjustMenu, (MenuEntry*)&extrasMenu, (MenuEntry*)&aboutMenu, }; diff --git a/NuEVI/settings.cpp b/NuEVI/settings.cpp index f0767fe..76e197d 100644 --- a/NuEVI/settings.cpp +++ b/NuEVI/settings.cpp @@ -120,6 +120,33 @@ void readEEPROM(const bool factoryReset) { writeSetting(HARMSET_ADDR, HARMSET_FACTORY); writeSetting(HARMSEL_ADDR, HARMSEL_FACTORY); } + + if(settingsVersion < 36) { + writeSetting(PARAB_ADDR, PARAB_FACTORY); + writeSetting(ROTB1_ADDR, ROTB1_FACTORY); + writeSetting(ROTB2_ADDR, ROTB2_FACTORY); + writeSetting(ROTB3_ADDR, ROTB3_FACTORY); + writeSetting(ROTB4_ADDR, ROTB4_FACTORY); + writeSetting(PARAC_ADDR, PARAC_FACTORY); + writeSetting(ROTC1_ADDR, ROTC1_FACTORY); + writeSetting(ROTC2_ADDR, ROTC2_FACTORY); + writeSetting(ROTC3_ADDR, ROTC3_FACTORY); + writeSetting(ROTC4_ADDR, ROTC4_FACTORY); + writeSetting(POLYSEL_ADDR, POLYSEL_FACTORY); + writeSetting(FWCTYPE_ADDR, FWCTYPE_FACTORY); + writeSetting(HMZKEY_ADDR, HMZKEY_FACTORY); + } + + if(settingsVersion < 37) { + writeSetting(FWCLCH_ADDR, FWCLCH_FACTORY); + writeSetting(FWCDP2_ADDR, FWCDP2_FACTORY); + } + + + if(settingsVersion < 38) { + writeSetting(HMZLIMIT_ADDR, HMZLIMIT_FACTORY); + } + writeSetting(VERSION_ADDR, EEPROM_VERSION); } @@ -187,6 +214,22 @@ void readEEPROM(const bool factoryReset) { batteryType = readSettingBounded(BATTYPE_ADDR, 0, 2, BATTYPE_FACTORY); harmSetting = readSettingBounded(HARMSET_ADDR, 0, 6, HARMSET_FACTORY); harmSelect = readSettingBounded(HARMSEL_ADDR, 0, 4, HARMSEL_FACTORY); + polySelect = readSettingBounded(POLYSEL_ADDR, 0, 10, POLYSEL_FACTORY); + fwcType = readSettingBounded(FWCTYPE_ADDR, 0, 4, FWCTYPE_FACTORY); + fwcLockH = readSettingBounded(FWCLCH_ADDR, 0, 1, FWCLCH_FACTORY); + fwcDrop2 = readSettingBounded(FWCDP2_ADDR, 0, 1, FWCDP2_FACTORY); + hmzKey = readSettingBounded(HMZKEY_ADDR, 0, 11, HMZKEY_FACTORY); + hmzLimit = readSettingBounded(HMZLIMIT_ADDR, 2, 5, HMZLIMIT_FACTORY); + parallelb = readSettingBounded(PARAB_ADDR, 0, 48, PARAB_FACTORY); + rotationsb[0] = readSettingBounded(ROTB1_ADDR, 0, 48, ROTB1_FACTORY); + rotationsb[1] = readSettingBounded(ROTB2_ADDR, 0, 48, ROTB2_FACTORY); + rotationsb[2] = readSettingBounded(ROTB3_ADDR, 0, 48, ROTB3_FACTORY); + rotationsb[3] = readSettingBounded(ROTB4_ADDR, 0, 48, ROTB4_FACTORY); + parallelc = readSettingBounded(PARAC_ADDR, 0, 48, PARAC_FACTORY); + rotationsc[0] = readSettingBounded(ROTC1_ADDR, 0, 48, ROTC1_FACTORY); + rotationsc[1] = readSettingBounded(ROTC2_ADDR, 0, 48, ROTC2_FACTORY); + rotationsc[2] = readSettingBounded(ROTC3_ADDR, 0, 48, ROTC3_FACTORY); + rotationsc[3] = readSettingBounded(ROTC4_ADDR, 0, 48, ROTC4_FACTORY); //Flags stored in bit field fastBoot = (dipSwBits & (1<