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.

This commit is contained in:
Johan Berglund 2020-07-19 13:52:06 +02:00
parent c7c1825b62
commit cc188f2196
8 changed files with 11365 additions and 57 deletions

View file

@ -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,6 +971,36 @@ void loop() {
}
}
if (rotatorOn) {
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;
@ -830,6 +1011,29 @@ void loop() {
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 (!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 (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 (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,6 +1207,36 @@ void loop() {
}
}
if (rotatorOn) {
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;
@ -939,6 +1247,29 @@ void loop() {
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 (!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;

View file

@ -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;

View file

@ -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", &parallel, 0, 48, MenuEntryFlags::ENone,
MenuType::ESub, "RTA PARAL", "SEMITONES", &parallel, 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", &parallelb, 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", &parallelc, 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,
};

View file

@ -121,6 +121,33 @@ void readEEPROM(const bool factoryReset) {
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<<DIPSW_FASTBOOT))?1:0;

View file

@ -63,8 +63,24 @@
#define BATTYPE_ADDR 112
#define HARMSET_ADDR 114
#define HARMSEL_ADDR 116
#define PARAB_ADDR 118
#define ROTB1_ADDR 120
#define ROTB2_ADDR 122
#define ROTB3_ADDR 124
#define ROTB4_ADDR 126
#define PARAC_ADDR 128
#define ROTC1_ADDR 130
#define ROTC2_ADDR 132
#define ROTC3_ADDR 134
#define ROTC4_ADDR 136
#define POLYSEL_ADDR 138
#define FWCTYPE_ADDR 140
#define HMZKEY_ADDR 150
#define FWCLCH_ADDR 152
#define FWCDP2_ADDR 154
#define HMZLIMIT_ADDR 156
#define EEPROM_SIZE 118
#define EEPROM_SIZE 158 //Last address +2
//DAC output modes
@ -81,7 +97,7 @@
//"factory" values for settings
#define EEPROM_VERSION 35
#define EEPROM_VERSION 38
#define BREATH_THR_FACTORY 1400
#define BREATH_MAX_FACTORY 4000
#define PORTAM_THR_FACTORY 2600
@ -135,6 +151,22 @@
#define BATTYPE_FACTORY 0
#define HARMSET_FACTORY 0
#define HARMSEL_FACTORY 0
#define PARAB_FACTORY 31 // 7 (+ 24) Rotator parallel
#define ROTB1_FACTORY 19 // -5 (+24) Rotation 1
#define ROTB2_FACTORY 14 // -10 (+24) Rotation 2
#define ROTB3_FACTORY 17 // -7 (+24) Rotation 3
#define ROTB4_FACTORY 10 // -14 (+24) Rotation 4
#define PARAC_FACTORY 31 // 7 (+ 24) Rotator parallel
#define ROTC1_FACTORY 19 // -5 (+24) Rotation 1
#define ROTC2_FACTORY 14 // -10 (+24) Rotation 2
#define ROTC3_FACTORY 17 // -7 (+24) Rotation 3
#define ROTC4_FACTORY 10 // -14 (+24) Rotation 4
#define POLYSEL_FACTORY 0
#define FWCTYPE_FACTORY 1
#define HMZKEY_FACTORY 0
#define FWCLCH_FACTORY 0
#define FWCDP2_FACTORY 0
#define HMZLIMIT_FACTORY 5
#define NO_CHECKSUM 0x7F007F00

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,64 @@
POLY PLAY
In the Poly Play menu you configure everything having to do with polyphonic playing functions.
POLY PLAY POLY MODE
Here you select which type of harmonization or which rotator setup will be activated by touching/holding MOD key (NuRAD) or Pinky Key (NuEVI) and then touching Special Key(s). Deactivate by just touching Special Key(s).
OFF disables all Special Key functionality, including the Parallel Chord, Slur Sustain and Sub Octave functions
MGR Major Gospel Root a gospel type triad voicing
MGD Major Gospel Dominant same as MGR, but with a dominant on V instead of an inversion of the root
MA9 Major add9 pop style add9 harmonization
MND minor Dorian jazz type minor
MNA minor Aeolian classical minor
MNH minor 4-voice Hip a more hip dorian minor
FWC Four Way Close old school block chord harmony (with additional options further down in the Poly Play menu)
RTA Rotator A
RTB Rotator B
RTC - Rotator C
POLY PLAY HMZ KEY
Selects the key you are playing in for the key based harmonizations.
POLY PLAY HMZ LIMIT
Limits the number of voices to be played, starting elimination from lowest note and up. Applies to the key based harmonizations only, not Rotator, Parallel Chord or Slur Sustain.
POLY PLAY FWC TYPE
Type of block chord for the Four Way Close harmonization. (6, m6, 7 or m7)
POLY PLAY FWC LOCKH
"Lock Hands" (double melody) adds another melody note one octave down for the Four Way Close harmonizations. (OFF/ON)
POLY PLAY FWC DROP2
"Drop 2" moves the second note (the one below melody note) one octave down for the FWC. (OFF/ON)
POLY PLAY PRIORITY
Sets which note will get priority when playing mono patches (sounds really great to layer a mono patch with a poly patch for use with with the Poly Play functions). MEL will play the melody note as the mono lead and ROT will play the rotated note or last note of other poly modes.
POLY PLAY RTA PARAL
POLY PLAY RTA ROT 1
POLY PLAY RTA ROT 2
POLY PLAY RTA ROT 3
POLY PLAY RTA ROT 4
POLY PLAY RTB PARAL
POLY PLAY RTB ROT 1
POLY PLAY RTB ROT 2
POLY PLAY RTB ROT 3
POLY PLAY RTB ROT 4
POLY PLAY RTC PARAL
POLY PLAY RTC ROT 1
POLY PLAY RTC ROT 2
POLY PLAY RTC ROT 3
POLY PLAY RTC ROT 4
This last section of settings is for the three rotators. They create a three note chord using the melody note, a fixed interval parallel note and a third note taken from a rotating selection of four notes. For every new note triggered, the rotation is advanced one step, and a new combination of notes is played. For each uf the three selectable rotator setups you can configure the fixed interval with RTx PARAL and the four intervals to be rotated for the third note with RTx ROT 1 to RTx ROT4, where x represents rotators A through C.