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<