Need help with arrays for midi to cv

I'm very very very new to this and I tried updating some code for a midi to cv controller for synths off of another code I came across earlier. I got it to work but it was very long with way too many if statements. Someone told me to put it in an array and index it with a variable.

Originally I had something like this:

if (robin == 0) {
            notecv1 = MIDI_NOTES_ACTIVE.get(0);
            notecv2 = MIDI_NOTES_ACTIVE.get(1);
            notecv3 = MIDI_NOTES_ACTIVE.get(2);
            notecv4 = note;}
            if (robin == 1) {
            notecv2 = MIDI_NOTES_ACTIVE.get(0);
            notecv3 = MIDI_NOTES_ACTIVE.get(1);
            notecv4 = MIDI_NOTES_ACTIVE.get(2);
            notecv1 = note;}
            if (robin == 2) {
            notecv3 = MIDI_NOTES_ACTIVE.get(0);
            notecv4 = MIDI_NOTES_ACTIVE.get(1);
            notecv1 = MIDI_NOTES_ACTIVE.get(2);
            notecv2 = note;}
            if (robin == 3) {
            notecv4 = MIDI_NOTES_ACTIVE.get(0);
            notecv1 = MIDI_NOTES_ACTIVE.get(1);
            notecv2 = MIDI_NOTES_ACTIVE.get(2);
            notecv3 = note;}

which this worked and I tried putting some variables into an array and ended up with this:

byte notearray[4] = {notecv1, notecv2, notecv3, notecv4};

notearray[robin] = MIDI_NOTES_ACTIVE.get(0);
notearray[robincv2] = MIDI_NOTES_ACTIVE.get(1);
notearray[robincv3] = MIDI_NOTES_ACTIVE.get(2);
notearray[robincv4] = note;

No error message but it doesn't the value of notecv1 2 3 etc.

1 Like

Please use code tags when posting code

What are your variables robincv1 robincv2 etc. ??

Why do you initialize the array and just after allocate new values into those cells ?

1 Like

that probably would be "compressed" into something like this if arrays were used:

byte notecv[4];
int i;
for(i=robin; i<3+robin;++i){
notecv[i%4] = MIDI_NOTES_ACTIVE.get(i%3);
}
notecv[i%4] = note;

probably might be a bit over your head if ur still very new to coding! :stuck_out_tongue:

hope that helps...

EDIT
not sure on actual intention so IMHO, it could also be written as:

byte notecv[4];
int i,j;

for(i=robin,j=0;i<3+robin;++i,++j){
     notecv[i%4] = MIDI_NOTES_ACTIVE.get(j);
}
notecv[i%4] = note;

the 2 snippets outcomes are obviously different! :wink:

1 Like

oh my apologies. robincv2, robincv3. are the next steps in the round robin cycle. Robin + 1 and subtract 4 when its greater than 3. (its just a 4 poly midi to cv) but those send the gates out to the the same corresponding pitch cv. The robin mode cycles forward once when all the notes are released and notes are pressed again. I was not too sure on how arrays worked and that would make sense to why everythings midi note 0. I thought it would read the corresponding midi note value and assign the notecv value to the note value

A big big thank you and it is very very much over my head but It's going to give me a starting point to dig and figure out what all of this means. I need to figure out what all the i's (okay i see thats just a variable now) but and %s mean

the 'i' is just a variable used are to iterate within a 'for' loop

'%' is the modulo operator

1 Like

the code you have posted has this pattern

depending on value of variable "robin" the variables
notecv1, notecv2, notecv3, notecv4 are assigned values in a rotating manner

robin == 0 rotates not
robin == 1 rotates one step
robin == 2 rotates two steps
robin == 3 rotates three steps

to make it easier to see and analyse I shortened your variable-names functions

if (robin == 0) {
notecv0 = M.get(0);    
notecv1 = M.get(1);
notecv2 = M.get(2);
notecv3 = M.get(3);
}

if (robin == 1) {      
notecv0 = M.get(3);
notecv1 = M.get(0);
notecv2 = M.get(1);
notecv3 = M.get(2);
}

if (robin == 2) {      
notecv0 = M.get(2);
notecv1 = M.get(3)
notecv2 = M.get(0);
notecv3 = M.get(1);
}

if (robin == 3) {      
notecv0 = M.get(1);
notecv1 = M.get(2);
notecv2 = M.get(3);
notecv3 = M.get(0);
}

As you need not just a simple offset that "moves" always forward or backward
but instead you have to jump forward and backward with the "index" the only idea that I have is using a switch-case-break-statement

void myRoundRobinFunc(byte robin) {
  switch (robin) {
    case 0:
      notecv1 = MIDI_NOTES_ACTIVE.get(0);
      notecv2 = MIDI_NOTES_ACTIVE.get(1);
      notecv3 = MIDI_NOTES_ACTIVE.get(2);
      notecv4 = note;
      break;

    case 1:
      notecv2 = MIDI_NOTES_ACTIVE.get(0);
      notecv3 = MIDI_NOTES_ACTIVE.get(1);
      notecv4 = MIDI_NOTES_ACTIVE.get(2);
      notecv1 = note;
      break;

    case 2:
      notecv3 = MIDI_NOTES_ACTIVE.get(0);
      notecv4 = MIDI_NOTES_ACTIVE.get(1);
      notecv1 = MIDI_NOTES_ACTIVE.get(2);
      notecv2 = note;
      break;

    case 3:
      notecv4 = MIDI_NOTES_ACTIVE.get(0);
      notecv1 = MIDI_NOTES_ACTIVE.get(1);
      notecv2 = MIDI_NOTES_ACTIVE.get(2);
      notecv3 = note;
      break;
  }
}

If the values of

MIDI_NOTES_ACTIVE.get(0);
MIDI_NOTES_ACTIVE.get(1);
MIDI_NOTES_ACTIVE.get(2);

are completely constant all the time
it might be possible to fill an array with the values
But I guess these values are changing

1 Like

@sherzaad maybe I have made a typo. If then I don't see it

I took your code as a base to test it with this demo-code

char notecv[4];
char getVal[4] = {'1', '2', '3', '4'};

byte i;

void myRobinFunc(byte robin) {
  Serial.print("Robin=");
  Serial.println(robin);

  for ( i = robin; i < 3 + robin; i++) {
    notecv[i % 4] = getVal[i % 3];
  }
  notecv[i % 4] = getVal[3]; // equals to "note"

  for (byte j = 0; j < 4; j++) {
    Serial.print("notecv[");
    Serial.print(j);
    Serial.print("]=");
    Serial.println(notecv[j]);
  }
  Serial.println();
  Serial.println();
}


void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");

  myRobinFunc(0);
  myRobinFunc(1);
  myRobinFunc(2);
  myRobinFunc(3);
}

void loop() {
}

and got this output

Setup-Start
Robin=0
notecv[0]=1
notecv[1]=2
notecv[2]=3
notecv[3]=4


Robin=1
notecv[0]=4  correct   4
notecv[1]=2  should be 1
notecv[2]=3  should be 2
notecv[3]=1  should be 3


Robin=2
notecv[0]=2 should be 3
notecv[1]=4 should be 4
notecv[2]=3 should be 1
notecv[3]=1 should be 2


Robin=3
notecv[0]=2 correct   2
notecv[1]=3 should be 3
notecv[2]=4 should be 4
notecv[3]=1 should be 1

which is not correct in all details

what do you think?
best regards Stefan

1 Like

I update my post with and alternate version as well as it is not clear to me what is required.

from my perspective, depending on the intent either snippet should do the trick...

void setup() {
  Serial.begin(115200);

  Serial.println("___VERSION A___");
  for (int robin = 0; robin < 4; ++robin) {
    Serial.print("robin");
    Serial.print(robin);
    Serial.print(": ");

    int i, j;

    for (i = robin, j = 0; i < 3 + robin; ++i, ++j) {
      Serial.print(i % 4);
      Serial.print("/");
      Serial.print(j);
      Serial.print(" ");
    }
    Serial.print(i % 4);
    Serial.println("/note");
  }

  Serial.println("\n___VERSION B___");
  for (int robin = 0; robin < 4; ++robin) {
    Serial.print("robin");
    Serial.print(robin);
    Serial.print(": ");

    int i;

    for (i = robin; i < 3 + robin; ++i) {
      Serial.print(i % 4);
      Serial.print("/");
      Serial.print(i % 3);
      Serial.print(" ");
    }
    Serial.print(i % 4);
    Serial.println("/note");
  }

}

void loop() {
  // put your main code here, to run repeatedly:

}

VERSION A
robin0: 0/0 1/1 2/2 3/note
robin1: 1/0 2/1 3/2 0/note
robin2: 2/0 3/1 0/2 1/note
robin3: 3/0 0/1 1/2 2/note

VERSION B
robin0: 0/0 1/1 2/2 3/note
robin1: 1/1 2/2 3/0 0/note
robin2: 2/2 3/0 0/1 1/note
robin3: 3/0 0/1 1/2 2/note

I don't understand this output because some numbers in the line are repeating
change it to use numbers 0,1,2,3 or 1,2,3,4 for everything

The pattern is pure round robin
robin 0 = no round robin
the sequence is

notecv1 = MIDI_NOTES_ACTIVE.get(0);
notecv2 = MIDI_NOTES_ACTIVE.get(1);
notecv3 = MIDI_NOTES_ACTIVE.get(2);
notecv4 = MIDI_NOTES_ACTIVE.get(3); // note;}

changed numbers on the left from 1...4 to 0..3

notecv0 = MIDI_NOTES_ACTIVE.get(0);
notecv1 = MIDI_NOTES_ACTIVE.get(1);
notecv2 = MIDI_NOTES_ACTIVE.get(2);
notecv3 = MIDI_NOTES_ACTIVE.get(3); // note;}

which makes thing smuch more easier to recognise as the number on the left and on the right are the same for robin = 0

robin == 1 means

just changed order on the left to be 0..3 again
if (robin == 1) {
notecv0 = MIDI_NOTES_ACTIVE.get(3) //;note;} // formely last gets assigned to first
notecv1 = MIDI_NOTES_ACTIVE.get(0); // all other slip down one step
notecv2 = MIDI_NOTES_ACTIVE.get(1);
notecv3 = MIDI_NOTES_ACTIVE.get(2);
.
.

if (robin == 2) {
notecv0 = MIDI_NOTES_ACTIVE.get(2);
notecv1 = MIDI_NOTES_ACTIVE.get(3);//note;}
notecv2 = MIDI_NOTES_ACTIVE.get(0);
notecv3 = MIDI_NOTES_ACTIVE.get(1);

if (robin == 3) {
notecv0 = MIDI_NOTES_ACTIVE.get(1);
notecv1 = MIDI_NOTES_ACTIVE.get(2);
notecv2 = MIDI_NOTES_ACTIVE.get(3); //note;}
notecv3 = MIDI_NOTES_ACTIVE.get(0);

This numbering 1..4 get(0); get(1); get(2); note and the changed order on the left in the original code is confusing

best regards Stefan

1 Like

Apologies but I fail to understand the issue you have.

From what I can see, VERSION A code that I demonstrated, tallies with OP's requirements.
I've tried to reformat the output result in the hopes that it is now more understandable

robin0: 	
j<-i	
0<-0	notecv1 = MIDI_NOTES_ACTIVE.get(0);
1<-1	notecv2 = MIDI_NOTES_ACTIVE.get(1);
2<-2	notecv3 = MIDI_NOTES_ACTIVE.get(2);
note<-3	notecv4 = note;}
	
robin1: 	
j<-i	
0<-1	notecv2 = MIDI_NOTES_ACTIVE.get(0);
1<-2	notecv3 = MIDI_NOTES_ACTIVE.get(1);
2<-3	notecv4 = MIDI_NOTES_ACTIVE.get(2);
note<-0	notecv1 = note;}
	
robin2: 	
j<-i	
0<-2	notecv3 = MIDI_NOTES_ACTIVE.get(0);
1<-3	notecv4 = MIDI_NOTES_ACTIVE.get(1);
2<-0	notecv1 = MIDI_NOTES_ACTIVE.get(2);
note<-1	notecv2 = note;}
	
robin3: 	
j<-i	
0<-3	notecv4 = MIDI_NOTES_ACTIVE.get(0);
1<-0	notecv1 = MIDI_NOTES_ACTIVE.get(1);
2<-1	notecv2 = MIDI_NOTES_ACTIVE.get(2);
note<-2	notecv3 = note;}

where 'j' is used for the MIDI_NOTES_ACTIVE and 'i' selects the notecv array element

1 Like

This code

char notecv[4];
char getVal[4] = {'1', '2', '3', '4'};

byte i;

void myRobinFunc(byte robin) {
  Serial.print("Robin=");
  Serial.println(robin);

  for ( i = robin; i < 3 + robin; i++) {
    notecv[i % 4] = getVal[i % 3];
  }
  notecv[i % 4] = getVal[3]; // equals to "note"

  for (byte j = 0; j < 4; j++) {
    Serial.print("notecv[");
    Serial.print(j);
    Serial.print("]=");
    Serial.println(notecv[j]);
  }
  Serial.println();
  Serial.println();
}


void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");

  myRobinFunc(0);
  myRobinFunc(1);
  myRobinFunc(2);
  myRobinFunc(3);
}

void loop() {
}

uses exactly your for loop

 for ( i = robin; i < 3 + robin; i++) {
    notecv[i % 4] = getVal[i % 3];
  }
  notecv[i % 4] = getVal[3]; // equals to "note"

explain to me: why does the output of your code NOT do a real round robin?

1 Like

finally here is a code-version that compares the two algorithms
both functions use the same values

char sherzaad_notecv[4];
char sherzaad_getVal[4] = {'1', '2', '3', '4'};

char armouredsteele_notecv[4];
char armouredsteele_getVal[4] = {'1', '2', '3', '4'};

armouredsteeles code.version with if-conditions produces a pure round robin of the values
your code-version does mixing up some of the values.
What do you need more as prooving?
Do I have to code a comparising or are are you able to compare the serial-output yourself?

I simply made armouredsteeles original code as comments so you can compare it line for line
the only thing that I changed is the numbering from 1..4 to 0..3

char sherzaad_notecv[4];
char sherzaad_getVal[4] = {'1', '2', '3', '4'};

char armouredsteele_notecv[4];
char armouredsteele_getVal[4] = {'1', '2', '3', '4'};

byte i;

void compareSherzaadWithArmouredsteele(byte robin) {
  Serial.print("robin=");
  Serial.println(robin);

  if (robin == 0) {
    armouredsteele_notecv[0] = armouredsteele_getVal[0];//notecv1 = MIDI_NOTES_ACTIVE.get(0);
    armouredsteele_notecv[1] = armouredsteele_getVal[1];//notecv2 = MIDI_NOTES_ACTIVE.get(1);
    armouredsteele_notecv[2] = armouredsteele_getVal[2];//notecv3 = MIDI_NOTES_ACTIVE.get(2);
    armouredsteele_notecv[3] = armouredsteele_getVal[3];//notecv4 = note;
  }
  
  if (robin == 1) {
    armouredsteele_notecv[1] = armouredsteele_getVal[0];//notecv2 = MIDI_NOTES_ACTIVE.get(0);
    armouredsteele_notecv[2] = armouredsteele_getVal[1];//notecv3 = MIDI_NOTES_ACTIVE.get(1);
    armouredsteele_notecv[3] = armouredsteele_getVal[2];//notecv4 = MIDI_NOTES_ACTIVE.get(2);
    armouredsteele_notecv[0] = armouredsteele_getVal[3];//notecv1 = note;
  }
  
  if (robin == 2) {
    armouredsteele_notecv[2] = armouredsteele_getVal[0];//notecv3 = MIDI_NOTES_ACTIVE.get(0);
    armouredsteele_notecv[3] = armouredsteele_getVal[1];//notecv4 = MIDI_NOTES_ACTIVE.get(1);
    armouredsteele_notecv[0] = armouredsteele_getVal[2];//notecv1 = MIDI_NOTES_ACTIVE.get(2);
    armouredsteele_notecv[1] = armouredsteele_getVal[3];//notecv2 = note;
  }
  
  if (robin == 3) {
    armouredsteele_notecv[3] = armouredsteele_getVal[0];//notecv4 = MIDI_NOTES_ACTIVE.get(0);
    armouredsteele_notecv[0] = armouredsteele_getVal[1];//notecv1 = MIDI_NOTES_ACTIVE.get(1);
    armouredsteele_notecv[1] = armouredsteele_getVal[2];//notecv2 = MIDI_NOTES_ACTIVE.get(2);
    armouredsteele_notecv[2] = armouredsteele_getVal[3];//notecv3 = note;
  }

  for ( i = robin; i < 3 + robin; i++) {
    sherzaad_notecv[i % 4] = sherzaad_getVal[i % 3];
  }
  sherzaad_notecv[i % 4] = sherzaad_getVal[3];

  
  for (byte j = 0; j < 4; j++) {

    Serial.print("arm[");
    Serial.print(j);
    Serial.print("]=");
    Serial.print(armouredsteele_notecv[j]);

    Serial.print(" sher[");
    Serial.print(j);
    Serial.print("]=");
    Serial.print(sherzaad_notecv[j]);

    if (armouredsteele_notecv[j] == sherzaad_notecv[j]) {
      Serial.println("  same value");
    }
    else {
      Serial.println("  !!! DIFFERENT values !!!");      
    }
  }
  
  Serial.println();
  Serial.println();
}

  


void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");

  compareSherzaadWithArmouredsteele(0);
  compareSherzaadWithArmouredsteele(1);
  compareSherzaadWithArmouredsteele(2);
  compareSherzaadWithArmouredsteele(3);
}


void loop() {

}

This is the serial output

Setup-Start
robin=0
arm[0]=1 sher[0]=1  same value
arm[1]=2 sher[1]=2  same value
arm[2]=3 sher[2]=3  same value
arm[3]=4 sher[3]=4  same value


robin=1
arm[0]=4 sher[0]=4  same value
arm[1]=1 sher[1]=2  !!! DIFFERENT values !!!
arm[2]=2 sher[2]=3  !!! DIFFERENT values !!!
arm[3]=3 sher[3]=1  !!! DIFFERENT values !!!


robin=2
arm[0]=3 sher[0]=2  !!! DIFFERENT values !!!
arm[1]=4 sher[1]=4  same value
arm[2]=1 sher[2]=3  !!! DIFFERENT values !!!
arm[3]=2 sher[3]=1  !!! DIFFERENT values !!!


robin=3
arm[0]=2 sher[0]=2  same value
arm[1]=3 sher[1]=3  same value
arm[2]=4 sher[2]=4  same value
arm[3]=1 sher[3]=1  same value

test it yourself
best regards Stefan

1 Like

Thank you, I woke up a few moments ago and I'm going to try and learn and take some tries at it with this. This was me trying to learn from an existing project that has several modules in it. I took the advice to change all of the 1-4s to 0-3s but this was the original code which ended up working but is hard for me to read and I feel like it could be a lot more simplified:

byte notecv0;
byte notecv1;
byte notecv2;
byte notecv3;
bool robinhasrun = false;
byte robin0;
byte robin1;
byte robin2;
byte robin3;


result handleMidi2CV(eventMask event, navNode& nav, prompt &item) {
  if (event == enterEvent) {
    startMidi2CV();
    activeModule = &loopMidi2CV;
  }
  if (event == exitEvent) {
    activeModule = {};
    endMidi2CV();
  }
  return proceed;
}

// called once on module enter
void startMidi2CV() {
  robin0 = 0;
}

// called once on module exit
void endMidi2CV() {
  resetCVOut();
  resetGateOut();
}


// called constantly from main loop
void loopMidi2CV() {
  //note is the last note played
  byte note = MIDI_NOTES_ACTIVE.get(MIDI_NOTES_ACTIVE.size() - 1);

  //starts when any note is played midi 0 is no notes
  if (note > 0) {

    //round robin movement
    if (robinhasrun == false) {
      robin0 ++;
      robin1 = (robin0 + 1);
      robin2 = (robin0 + 2);
      robin3 = (robin0 + 3);
      robinhasrun = true;
    }

    //returns individual robin positions back to 0 if they exceed 3
    if (robin0 > 3) {
      robin0 = 0;
    }
    if (robin1 > 3) {
      robin1 = (robin1 - 4);
    }
    if (robin2 > 3) {
      robin2 = (robin2 - 4);
    }
    if (robin3 > 3) {
      robin3 = (robin3 - 4);
    }

    ///mono only 1 note can be played
    if (midi2CVpoly == 0) {
      if (roundrobin == 0) {
        notecv0 = note;
        setGateOutDuration(0, 10);
      }
      if (roundrobin == 1) {
        if (robin0 == 0) {
          notecv0 = note;
        }
        if (robin0 == 1) {
          notecv1 = note;
        }
        if (robin0 == 2) {
          notecv2 = note;
        }
        if (robin0 == 3) {
          notecv3 = note;
        }
        setGateOutDuration(robin0, 10);
      }
    }

    ///duo only 2 notes can be played
    if (midi2CVpoly == 1) {
      if (MIDI_NOTES_ACTIVE.size() == 1) {
        if (roundrobin == 0) {
          notecv0 = note;
          setGateOutDuration(0, 10);
        }
        if (roundrobin == 1) {
          if (robin0 == 0) {
            notecv0 = note;
          }
          if (robin0 == 1) {
            notecv1 = note;
          }
          if (robin0 == 2) {
            notecv2 = note;
          }
          if (robin0 == 3) {
            notecv3 = note;
          }
          setGateOutDuration(robin0, 10);
        }
      }
      if (MIDI_NOTES_ACTIVE.size() > 1) {
        if (roundrobin == 0) {
          notecv0 = MIDI_NOTES_ACTIVE.get(0);
          notecv1 = note;
          setGateOutDuration(0, 10);
          setGateOutDuration(1, 10);
        }
        if (roundrobin == 1) {
          if (robin0 == 0) {
            notecv0 = MIDI_NOTES_ACTIVE.get(0);
            notecv1 = note;
          }
          if (robin0 == 1) {
            notecv1 = MIDI_NOTES_ACTIVE.get(0);
            notecv2 = note;
          }
          if (robin0 == 2) {
            notecv2 = MIDI_NOTES_ACTIVE.get(0);
            notecv3 = note;
          }
          if (robin0 == 3) {
            notecv3 = MIDI_NOTES_ACTIVE.get(0);
            notecv0 = note;
          }
          setGateOutDuration(robin0, 10);
          setGateOutDuration(robin1, 10);
        }
      }
    }

    ///poly all 4 notes can be played no polyphonic restrictions
    if (midi2CVpoly == 2) {
      if (MIDI_NOTES_ACTIVE.size() == 1) {
        if (roundrobin == 0) {
          notecv0 = note;
          setGateOutDuration(0, 10);
        }
        if (roundrobin == 1) {
          if (robin0 == 0) {
            notecv0 = note;
          }
          if (robin0 == 1) {
            notecv1 = note;
          }
          if (robin0 == 2) {
            notecv2 = note;
          }
          if (robin0 == 3) {
            notecv3 = note;
          }

          setGateOutDuration(robin0, 10);
        }
      }
      if (MIDI_NOTES_ACTIVE.size() == 2) {
        if (roundrobin == 0) {
          notecv0 = MIDI_NOTES_ACTIVE.get(0);
          notecv1 = note;
          setGateOutDuration(0, 10);
          setGateOutDuration(1, 10);
        }
        if (roundrobin == 1) {
          if (robin0 == 0) {
            notecv0 = MIDI_NOTES_ACTIVE.get(0);
            notecv1 = note;
          }
          if (robin0 == 1) {
            notecv1 = MIDI_NOTES_ACTIVE.get(0);
            notecv2 = note;
          }
          if (robin0 == 2) {
            notecv2 = MIDI_NOTES_ACTIVE.get(0);
            notecv3 = note;
          }
          if (robin0 == 3) {
            notecv3 = MIDI_NOTES_ACTIVE.get(0);
            notecv0 = note;
          }

          setGateOutDuration(robin0, 10);
          setGateOutDuration(robin1, 10);
        }
      }
      if (MIDI_NOTES_ACTIVE.size() == 3) {
        if (roundrobin == 0) {
          notecv0 = MIDI_NOTES_ACTIVE.get(0);
          notecv1 = MIDI_NOTES_ACTIVE.get(1);
          notecv2 = note;
          setGateOutDuration(0, 10);
          setGateOutDuration(1, 10);
          setGateOutDuration(2, 10);
        }
        if (roundrobin == 1) {
          if (robin0 == 0) {
            notecv0 = MIDI_NOTES_ACTIVE.get(0);
            notecv1 = MIDI_NOTES_ACTIVE.get(1);
            notecv2 = note;
          }
          if (robin0 == 1) {
            notecv1 = MIDI_NOTES_ACTIVE.get(0);
            notecv2 = MIDI_NOTES_ACTIVE.get(1);
            notecv3 = note;
          }
          if (robin0 == 2) {
            notecv2 = MIDI_NOTES_ACTIVE.get(0);
            notecv3 = MIDI_NOTES_ACTIVE.get(1);
            notecv0 = note;
          }
          if (robin0 == 3) {
            notecv3 = MIDI_NOTES_ACTIVE.get(0);
            notecv0 = MIDI_NOTES_ACTIVE.get(1);
            notecv1 = note;
          }

          setGateOutDuration(robin0, 10);
          setGateOutDuration(robin1, 10);
          setGateOutDuration(robin2, 10);
        }
      }
      if (MIDI_NOTES_ACTIVE.size() > 3) {
        if (roundrobin == 0) {
          notecv0 = MIDI_NOTES_ACTIVE.get(0);
          notecv1 = MIDI_NOTES_ACTIVE.get(1);
          notecv2 = MIDI_NOTES_ACTIVE.get(2);
          notecv3 = note;
          setGateOutDuration(0, 10);
          setGateOutDuration(1, 10);
          setGateOutDuration(2, 10);
          setGateOutDuration(3, 10);
        }
        if (roundrobin == 1) {
          if (robin0 == 0) {
            notecv0 = MIDI_NOTES_ACTIVE.get(0);
            notecv1 = MIDI_NOTES_ACTIVE.get(1);
            notecv2 = MIDI_NOTES_ACTIVE.get(2);
            notecv3 = note;
          }
          if (robin0 == 1) {
            notecv1 = MIDI_NOTES_ACTIVE.get(0);
            notecv2 = MIDI_NOTES_ACTIVE.get(1);
            notecv3 = MIDI_NOTES_ACTIVE.get(2);
            notecv0 = note;
          }
          if (robin0 == 2) {
            notecv2 = MIDI_NOTES_ACTIVE.get(0);
            notecv3 = MIDI_NOTES_ACTIVE.get(1);
            notecv0 = MIDI_NOTES_ACTIVE.get(2);
            notecv1 = note;
          }
          if (robin0 == 3) {
            notecv3 = MIDI_NOTES_ACTIVE.get(0);
            notecv0 = MIDI_NOTES_ACTIVE.get(1);
            notecv1 = MIDI_NOTES_ACTIVE.get(2);
            notecv2 = note;
          }

          setGateOutDuration(robin0, 10);
          setGateOutDuration(robin1, 10);
          setGateOutDuration(robin2, 10);
          setGateOutDuration(robin3, 10);
        }
      }
    }

    ///uni 2 This plays the same note in unison twice to two different synth voices
    if (midi2CVpoly == 3) {
      if (MIDI_NOTES_ACTIVE.size() == 1) {
        if (roundrobin == 0) {
          notecv0 = note;
          notecv1 = note;
          setGateOutDuration(0, 10);
          setGateOutDuration(1, 10);
        }
        if (roundrobin == 1) {
          if (robin0 == 0) {
            notecv0 = note;
            notecv1 = note;
          }
          if (robin0 == 1) {
            notecv1 = note;
            notecv2 = note;
          }
          if (robin0 == 2) {
            notecv2 = note;
            notecv3 = note;
          }
          if (robin0 == 3) {
            notecv3 = note;
            notecv0 = note;
          }
          setGateOutDuration(robin0, 10);
          setGateOutDuration(robin1, 10);
        }
      }
      if (MIDI_NOTES_ACTIVE.size() > 1) {
        if (roundrobin == 0) {
          notecv0 = MIDI_NOTES_ACTIVE.get(0);
          notecv1 = MIDI_NOTES_ACTIVE.get(0);
          notecv2 = note;
          notecv3 = note;
          setGateOutDuration(0, 10);
          setGateOutDuration(1, 10);
          setGateOutDuration(2, 10);
          setGateOutDuration(3, 10);
        }
        if (roundrobin == 1) {
          if (robin0 == 0) {
            notecv0 = MIDI_NOTES_ACTIVE.get(0);
            notecv1 = MIDI_NOTES_ACTIVE.get(0);
            notecv2 = note;
            notecv3 = note;
          }
          if (robin0 == 1) {
            notecv1 = MIDI_NOTES_ACTIVE.get(0);
            notecv2 = MIDI_NOTES_ACTIVE.get(0);
            notecv3 = note;
            notecv0 = note;
          }
          if (robin0 == 2) {
            notecv2 = MIDI_NOTES_ACTIVE.get(0);
            notecv3 = MIDI_NOTES_ACTIVE.get(0);
            notecv0 = note;
            notecv1 = note;
          }
          if (robin0 == 3) {
            notecv3 = MIDI_NOTES_ACTIVE.get(0);
            notecv0 = MIDI_NOTES_ACTIVE.get(0);
            notecv1 = note;
            notecv2 = note;
          }
          setGateOutDuration(robin0, 10);
          setGateOutDuration(robin1, 10);
          setGateOutDuration(robin2, 10);
          setGateOutDuration(robin3, 10);
        }
      }
    }

    ///uni 4 this plays all 4 voices on the same note. no round robin option neccesary here
    if (midi2CVpoly == 4) {
      notecv0 = note;
      notecv1 = note;
      notecv2 = note;
      notecv3 = note;
      setGateOutDuration(0, 10);
      setGateOutDuration(1, 10);
      setGateOutDuration(2, 10);
      setGateOutDuration(3, 10);
    }

    //CV values this converts the midi data into voltage for the synths using floats
    float cv0 = getCVFromNote(notecv0 + 12 * midi2CVOctave);
    float cv1 = getCVFromNote(notecv1 + 12 * midi2CVOctave);
    float cv2 = getCVFromNote(notecv2 + 12 * midi2CVOctave);
    float cv3 = getCVFromNote(notecv3 + 12 * midi2CVOctave);
    setCVOut(0, cv0, true);
    setCVOut(1, cv1, true);
    setCVOut(2, cv2, true);
    setCVOut(3, cv3, true);

  }
  //this returns robinhasrun to false when no notes are pressed
  else {
    robinhasrun = false;
  }
}

There is also separate lines of code for the menu and I added a few options to it to get where I am at now. Random is my next goal to select random voices for each note played but to not repeat them into existing voices played. (IE, press 1st key and it picks a random voice and sends out data to it. While that note is held if I press a 2nd note it chooses any of the 3 remaining notes to play. The note played has to line up with the gate out sent) This is the menu code:

int midi2CVOctave = 0;
byte midi2CVpoly = 0;
byte roundrobin = 0;

result handleMidi2CV(eventMask event, navNode& nav, prompt &item);

SELECT(midi2CVOctave,midi2CVOctaveMenu,"OCTAVE",doNothing,noEvent,noStyle
  ,VALUE("-3",-3,doNothing,noEvent)
  ,VALUE("-2",-2,doNothing,noEvent)
  ,VALUE("-1",-1,doNothing,noEvent)
  ,VALUE("0",0,doNothing,noEvent)
  ,VALUE("1",1,doNothing,noEvent)
  ,VALUE("2",2,doNothing,noEvent)
  ,VALUE("3",3,doNothing,noEvent)
);

SELECT(midi2CVpoly,midi2CVpolyMenu,"VOICES",doNothing,noEvent,noStyle
  ,VALUE("MONO",0,doNothing,noEvent)
  ,VALUE("DUO",1,doNothing,noEvent)
  ,VALUE("POLY",2,doNothing,noEvent)
  ,VALUE("UNI 2",3,doNothing,noEvent)
  ,VALUE("UNI 4",4,doNothing,noEvent)
);

SELECT(roundrobin,roundrobinMenu,"ROBIN",doNothing,noEvent,noStyle
  ,VALUE("OFF",0,doNothing,noEvent)
  ,VALUE("ON",1,doNothing,noEvent)
  ,VALUE("RAND",2,doNothing,noEvent)
);


MENU(subMenuMidi2CV,"CHURRO MIDI",handleMidi2CV,(Menu::eventMask)(enterEvent|exitEvent),wrapStyle
  ,SUBMENU(midi2CVOctaveMenu)
  ,SUBMENU(midi2CVpolyMenu)
  ,SUBMENU(roundrobinMenu)
  ,EXIT("<BACK")
  
);

There is another code for the whole program front page that calls on the various libraries and gives all the menus, submenus, midi instances meaning. The menu sub menu and everything is working good to my knowledge it's just a very long code and gets all the added libraries like midi.h Theres alot more code in the front page but all the menu values and things end up looking something like this edit*** i just dropped the entire menu code because I didn't realize arduino had a nice neat scrollbar function. Most of this isn't neccessary i'm certain but It's everything:

#include <Arduino.h>
#include <EEPROM.h>
#include <Wire.h>

#include <Adafruit_ADS1X15.h>
#include <Adafruit_MCP4728.h>
#include <MIDI.h>
#include <menu.h>
#include <menuIO/U8x8Out.h>
#include <U8x8lib.h>
#include <RotaryEncoder.h>
#include <Bounce2.h>
#include <LinkedList.h>

//#include "example_module.h"
#include "adsr.h"
#include "arp.h"
#include "midi2cv.h"
#include "multiple.h"
#include "quantizer.h"

#define DEBUG 1
#define CALIBRATE_CV_IN 0
#define CALIBRATE_CV_OUT 0

float CV_IN_CORRECTION[4] = {1.0079f, 1.0086f, 1.0088f, 1.0085f};
unsigned int CV_OUT_LUT[4][21];
int LED_PINS[2] = {13, A3};
int GATE_IN_PINS[4] = {6, 7, 8, 9};
int GATE_OUT_PINS[4] = {2, 3, 4, 5};
unsigned long GATE_OUT_DURATION[4];
int SWITCH_PINS[4] = {A0, A1, A2, 12};
Bounce2::Button SWITCHES[4];
int MIDI_CHANNEL = 1;
int OCTAVE_OFFSET = 3;
LinkedList<byte> MIDI_NOTES_ACTIVE;
void (*activeModule)(void);

Adafruit_ADS1115 ads;
Adafruit_MCP4728 mcp;
U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
RotaryEncoder encoder(10, 11, RotaryEncoder::LatchMode::TWO03);

// menu
MENU(mainMenu,"KOSMO MULTITOOL",doNothing,noEvent,wrapStyle
  //,SUBMENU(subMenuExample)
  ,SUBMENU(subMenuADSR)
  ,SUBMENU(subMenuArp)
  ,SUBMENU(subMenuMidi2CV)
  ,SUBMENU(subMenuMultiple)
  ,SUBMENU(subMenuQuantizer)
);
#define MAX_DEPTH 3
noInput in;
MENU_OUTPUTS(out,MAX_DEPTH,U8X8_OUT(u8x8,{0,0,17,8}),NONE);
NAVROOT(nav,mainMenu,MAX_DEPTH,in,out);

void setup(void) {
  if (DEBUG) {
    Serial.begin(9600);
    Serial.println("Polykit Multitool. Initializing...");
  }
  
  // initialize adc
  ads.setGain(GAIN_TWOTHIRDS);
  ads.begin();

  // initialize dac
  mcp.begin();

  // init midi
  MIDI.setHandleNoteOn(handleNoteOn);
  MIDI.setHandleNoteOff(handleNoteOff);
  MIDI.begin(MIDI_CHANNEL);

  // init display
  u8x8.begin();
  u8x8.setFont(u8x8_font_chroma48medium8_u);
  
  for (int i=0; i<2; i++) {
    pinMode(LED_PINS[i], OUTPUT);
  }

  for (int i=0; i<4; i++) {
    pinMode(GATE_IN_PINS[i], INPUT);
    pinMode(GATE_OUT_PINS[i], OUTPUT);
    GATE_OUT_DURATION[i] = 0;
  }

  for (int i=0; i<4; i++) {
    SWITCHES[i] = Bounce2::Button();
    SWITCHES[i].attach(SWITCH_PINS[i], INPUT_PULLUP);
    SWITCHES[i].interval(10); 
    SWITCHES[i].setPressedState(LOW); 
  } 

  if (CALIBRATE_CV_IN) {
    u8x8.drawString(0,0,"CALIBRATING...");
    calibrateCVIn();
    u8x8.drawString(0,1,"DONE");
    while (1);
  } 

  if (CALIBRATE_CV_OUT) {
    u8x8.drawString(0,0,"CALIBRATING...");
    calibrateCVOut();
    u8x8.drawString(0,1,"DONE");
    while (1);
  } else {
    u8x8.drawString(0,0,"LOADING...");
    int addr = 0;
    for (int c=0; c<4; c++) {
      CV_OUT_LUT[c][0] = 0;
      for (int i=1; i<=20; i++) {
        EEPROM.get(addr, CV_OUT_LUT[c][i]);
        addr += sizeof(unsigned int);
      }
    }
  }

  for (int i=0; i<4; i++) {
    setLEDOn(0);
    setLEDOff(1);
    delay(100);
    setLEDOn(1);
    setLEDOff(0);
    delay(100);
  }
  setLEDOff(1);
}

void loop(void) {
  MIDI.read();
  encoder.tick();
  nav.poll();
  handleMenu();
  handleGateOutDurations();
  handleSwitches();
  if (activeModule) {
    activeModule();
  }
}

void handleNoteOn(byte channel, byte note, byte velocity) {
  if (channel != MIDI_CHANNEL) return;
  MIDI_NOTES_ACTIVE.add(note);
}

void handleNoteOff(byte channel, byte note, byte velocity) {
  if (channel != MIDI_CHANNEL) return;
  for (int i=0; i<MIDI_NOTES_ACTIVE.size(); i++) {
    if (MIDI_NOTES_ACTIVE.get(i) == note) {
      MIDI_NOTES_ACTIVE.remove(i);
      return;
    }
  }
}

float getCVFromNote(byte note) {
  return (note-12*OCTAVE_OFFSET)/12.0f;
}

void handleMenu() {
  int dir = getEncoderDir();
  if (dir == (int)RotaryEncoder::Direction::COUNTERCLOCKWISE) {
    nav.doNav(navCmd(downCmd));
  } else if(dir == (int)RotaryEncoder::Direction::CLOCKWISE) {
    nav.doNav(navCmd(upCmd));    
  }
  if (isSwitchOn(3)) {
    nav.doNav(navCmd(enterCmd));
  }
}

int getEncoderDir() {
  return (int)encoder.getDirection();
}

int getEncoderPos() {
  return encoder.getPosition();
}

float getCVIn(int n, bool correct) {
  if (n>3) return -1;
  
  int16_t adc = ads.readADC_SingleEnded(n);
  float cv = ads.computeVolts(adc)*2;
  
  if (correct) {
    cv = cv*CV_IN_CORRECTION[n];
  }
  
  return cv;
}

void setCVOut(int n, float v, bool correct) {
  if (n>3) return;
  if (v>10) return;
  
  MCP4728_channel_t ch;
  if (n==0) ch = MCP4728_CHANNEL_A;
  if (n==1) ch = MCP4728_CHANNEL_B;
  if (n==2) ch = MCP4728_CHANNEL_C;
  if (n==3) ch = MCP4728_CHANNEL_D;
  int nv = map(v*1000, 0, 10000, 0, 4095);

  if (correct) {
    int pos = round(2*v);
    nv = nv*(CV_OUT_LUT[n][pos]/1000.0f);
  }

  mcp.setChannelValue(ch, nv, MCP4728_VREF_INTERNAL, MCP4728_GAIN_2X);
}

void calibrateCVIn() {
  if (DEBUG) Serial.println("ADC calibration started.");
  int numSamples = 20;
  for (int n=0; n<4; n++) {
    if (DEBUG) {
      Serial.print("CV");
      Serial.print(n);
      Serial.print("CV");
    }
    float cv = 0;
    for (int i=0; i<numSamples; i++) {
      cv += getCVIn(n, false);
    }
    if (DEBUG) Serial.println((cv/numSamples), 4);
  }
  if (DEBUG) Serial.println("ADC calibration ended.");
}

void calibrateCVOut() {
  if (DEBUG) Serial.println("DAC calibration started.");
  int numSamples = 20;
  float cv;
  int addr = 0;
  for (int c=0; c<4; c++) {
    if (DEBUG) {
      Serial.print("Channel: ");
      Serial.println(c);
    }
    CV_OUT_LUT[c][0] = 0;
    for (int i=1; i<=20; i++) {
      setCVOut(c, i*0.5f, false);
      delay(100);
      cv = 0;
      for (int j=0; j<numSamples; j++) {
        cv += getCVIn(c, true);
      }
      cv = cv/numSamples;
      CV_OUT_LUT[c][i] = round(1000*i*0.5f/cv);
      if (DEBUG) {
        Serial.print("Wanted: ");
        Serial.println(i*0.5f, 4);
        Serial.print("Real: ");
        Serial.println(cv, 4);
        Serial.print("LUT: ");
        Serial.println(CV_OUT_LUT[c][i]/1000.0f, 4);
      }
      EEPROM.put(addr, CV_OUT_LUT[c][i]);
      addr += sizeof(unsigned int);
    }
  }
  if (DEBUG) Serial.println("DAC calibration ended.");
}

void setGateOutDuration(int n, unsigned long duration_ms) {
  if (n>3) return;
  GATE_OUT_DURATION[n] = millis()+duration_ms;
  setGateOutHigh(n);
}

void handleGateOutDurations() {
  for (int n=0; n<4; n++) {
    if (GATE_OUT_DURATION[n] > 0) {
      long d = GATE_OUT_DURATION[n]-millis();
      if (d < 0) {
        setGateOutLow(n);
        GATE_OUT_DURATION[n] = 0;
      }
    }
  }
}

void setGateOutHigh(int n) {
  if (n>3) return;
  digitalWrite(GATE_OUT_PINS[n], HIGH);
}

void setGateOutLow(int n) {
  if (n>3) return;
  digitalWrite(GATE_OUT_PINS[n], LOW);
}

void setGateOut(int n, bool b) {
  if (n>3) return;
  digitalWrite(GATE_OUT_PINS[n], b);
}

bool getGateIn(int n) {
  if (n>3) return -1;
  return (bool)digitalRead(GATE_IN_PINS[n]);
}

void handleSwitches() {
  for (int n=0; n<4; n++) {
    SWITCHES[n].update();
  }
}

bool isSwitchOn(int n) {
  if (n>3) return 0;
  bool pressed = SWITCHES[n].pressed();
  return pressed;
}

void setLEDOn(int n) {
  if (n>1) return;
  digitalWrite(LED_PINS[n], HIGH);
}

void setLEDOff(int n) {
  if (n>1) return;
  digitalWrite(LED_PINS[n], LOW);
}

void resetCVOut() {
  for(int i=0; i<4; i++) {
    setCVOut(i, 0, false);
  }
}

void resetGateOut() {
  for(int i=0; i<4; i++) {
    setGateOutLow(i);
  }
}

Thank you all for all of the help and advice and I'm going to look through this and continue on my studying

Oh wow a big thank you I'm still going to do a whole bunch of work on it but it's miles upon miles shorter now

if (noteSize > 3) {
        if (roundrobin == 0) {
          notecv[0] = notePlayed[0];
          notecv[1] = notePlayed[1];
          notecv[2] = notePlayed[2];
          notecv[3] = notePlayed[3];
        }
        if (roundrobin == 1) {
          notecv[robin0] = notePlayed[0];
          notecv[robin1] = notePlayed[1];
          notecv[robin2] = notePlayed[2];
          notecv[robin3] = notePlayed[3];
        }
        setGateOutDuration(0, 10);
        setGateOutDuration(1, 10);
        setGateOutDuration(2, 10);
        setGateOutDuration(3, 10);
      }

I also got rid of the robin gates if all 4 notes were played because it's the exact same. Code functions the exact same as it did originally

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.