The synthesizer is now ready for its full code upload! Building upon the previous two tests of code with the MIDI to synth messages and the Trellis functions, this code adds a number of other features to make the synth really fun to play!

Look at the code below and you'll see a few key features:

First, we import the MIDI and Trellis libraries as before, this time creating the Trellis object with two matrices.

Then, we create a variable scaleMode to select which scale we'll use. The choices are defined by MIDI note numbers and are broken up into six scales: chromatic, major, minor, dorian, mixolydian, and harmonic minor.

Logical Pads

Next, we create the logicalPads[] array in order to map the physical buttons of two Trellis grids into one logical array that reads left to right from top to bottom. This makes the rest of the code much easier later on. Here you can see the mapping of physical button numbers with their functions below each button.

We assign a few variables including CC0_value through CC5_value to work with our potentiometers to send CC messages to the synth. CC0_bankPin0 throughCC0_bankPin3 and CC_bank0_value through CC_bank3_value  will be used to identify the position of the selector switch and used these values to choose which bank of parameters the knobs control at a give time.

Synthesizer Parameters

Here is the full list of parameters on the DSP-G1 that can be adjusted with CC messages, as well as the default values we'll use upon startup:

  MIDI.sendControlChange( 7, 119, 1);   //volume
  MIDI.sendControlChange( 1, 24, 1);   //LFO mod 24
  MIDI.sendControlChange(16,  6, 1);   //LFO rate 12
  MIDI.sendControlChange(20,  0, 1);    //LFO waveform 0-63 sine, 64-127 S/H
  MIDI.sendControlChange(74, 80, 1);  //DC Filter cutoff
  MIDI.sendControlChange(71, 70, 1);   //DC Filter resonance
  MIDI.sendControlChange(82, 32, 1);   //DC Filter envelope Attack
  MIDI.sendControlChange(83, 38, 1);   //DC Filter envelope Decay
  MIDI.sendControlChange(28, 64, 1);   //DC Filter envelope Sustain
  MIDI.sendControlChange(29, 32, 1);   //DC Filter envelope Release
  MIDI.sendControlChange(81, 57, 1);   //DC Filter envelope modulation
  MIDI.sendControlChange(76, 100, 1);  //DC Oscillator waveform* 100
  MIDI.sendControlChange( 4,  0, 1);   //DC Oscillator wrap
  MIDI.sendControlChange(21,  0, 1);    //DC Oscillator range
  MIDI.sendControlChange(93,  0, 1);    //DC Oscillator detune
  MIDI.sendControlChange(73,  0, 1);   //DC Oscillator envelope Attack
  MIDI.sendControlChange(75, 12, 1);   //DC Oscillator envelope Decay
  MIDI.sendControlChange(31, 60, 1);   //DC Oscillator envelope Sustain
  MIDI.sendControlChange(72, 80, 1);   //DC Oscillator envelope Release
/*Wavforms: 0 tri, 25 squarish, 50 pulse, 75 other squarish, 100 saw      */

Loop

The main loop of the code does these things:

  • Check position of the selector switch
  • Check the bottom right Trellis pad to see if we are in momentary or held (latching) mode when the MIDI notes are played on the first three rows of eight pads
  • Send MIDI note messages to the synth chip
  • When potentiometer values change, send CC parameter value messages to the synth chip

Knob Readings

At the bottom of the code is a procedure called read_CC_Knobs() that is where a few special things happen!

To avoid constantly spamming the DSP-G1 with MIDI CC messages when nothing is changing, the procedure checks to see if the current value of each knob is different that the last time it changed. If not, don't send a message!

When a knob is changed, it's value is compared to the last value that knob had when the current bank was previously selected. To avoid having values suddenly jump, the messages are only sent when the pot value reaches the last value within a small tolerance.

Code Download

Here is the full code. Copy it, create a new sketch, paste in the code, save it, and then upload to your Feather. When the board restarts your synthesizer is ready to be played!

#include <MIDI.h>
#include "Adafruit_Trellis.h"
//use Trellis 0-11 and 16-27 as input for notes.
//use Trellis 12-15 and 28-31 for input to modes, sequencer, patches
//six potentiometers as CC value input
//rotary switch to choose banks of CC numbers for knobs

//John Park for Adafruit Industries

MIDI_CREATE_DEFAULT_INSTANCE();
Adafruit_Trellis matrix0 = Adafruit_Trellis(); //left Trellis
Adafruit_Trellis matrix1 = Adafruit_Trellis(); //right Trellis
Adafruit_TrellisSet trellis =  Adafruit_TrellisSet(&matrix0, &matrix1);
#define NUMTRELLIS 2
#define numKeys (NUMTRELLIS * 16)
//#define INTPIN A2
#define MOMENTARY 0
#define LATCHING 1
int holdMode = 0;
int lastHoldMode = 0;
static const unsigned LED = 13;      // LED pin on the Feather

/*********************/
//pick scale mode here:
//0=chromatic, 1=major, 2=minor, 3=dorian, 4=mixolydian, 5=harmonic minor
int scaleMode = 0; //Dorian
/*********************/
int octave = 1;
int transpose[6] = {0, 12, 24, 36, 48, 60}; //multiply notes depending on octave
//Trellis assignments
/*
//First three rows map to MIDI Notes, bottom row is special functions
-------------------------------------------------------------------------------
      0          1         2         3        16        17        18       19
     M16       M17        M18       M19       M20      M21       M22      M23


      4          5         6         7        20        21        22       23
     M8         M9        M10       M11       M12      M13       M14      M15


      8          9        10        11        24        25        26       27
     M0         M1        M2        M3        M4        M5        M6       M7
-------------------------------------------------------------------------------

    12         13        14        15        28        29        30       31
   seq       patch    pause/play  rec        I         II      III   hold mode
-------------------------------------------------------------------------------
*/

//Map physical Trellis grids to single logical grid
int logicalPads[32] = { 0,  1,  2,  3,  8,  9, 10, 11,
                 16, 17,  18,  19, 24, 25, 26, 27,
                 4,  5, 6, 7, 12, 13, 14, 15,
                20, 21, 22, 23, 28, 29, 30, 31 } ;

int padNoteMap[24] = { 16, 17, 18, 19, 20, 21, 22, 23,
                        8,  9, 10, 11, 12, 13, 14, 15,
                        0,  1,  2,  3,  4,  5,  6,  7};

int padFuncMap[8] = { //note, only hold mode is implemented currently
                      0, // sequencer
                      1, // patch
                      2, // pause/play / recall
                      3, // record / store
                      4, // sequence I / patch I
                      5, // seq. II / patch II
                      6, // seq. III / patch III
                      7 //hold mode: LATCHING or MOMENTARY
                    };
//Define Scales
int scalesMatrix[6][24] = {
//Chromatic
  { 0,  1,  2,  3,  4,  5,  6,  7,
    8,  9, 10, 11, 12, 13, 14, 15,
   16, 17, 18, 19, 20, 21, 22, 23 },

//Major
   { 0,  2,  4,  5,  7,  9, 11, 12,
    12, 14, 16, 17, 19, 21, 23, 24,
    24, 26, 28, 29, 31, 33, 35, 36 },

//Minor
   { 0,  2,  3,  5,  7,  8, 10, 12,
    12, 14, 15, 17, 19, 20, 22, 24,
    24, 26, 27, 29, 31, 32, 34, 36 },

//Dorian
   { 0,  2,  3,  5,  6,  9, 10, 12,
    12, 14, 15, 17, 18, 21, 22, 24,
    24, 26, 27, 29, 30, 33, 34, 36 },

//Mixolydian
   { 0,  2,  4,  5,  7,  9, 10, 12,
    12, 14, 16, 17, 19, 21, 22, 24,
    24, 26, 28, 29, 31, 33, 34, 36 },

//Harmonic Minor
   { 0,  2,  3,  5,  7,  8, 11, 12,
    12, 14, 15, 17, 19, 20, 23, 24,
    24, 26, 27, 29, 31, 32, 35, 36 }
};

//Set up selector switch pins to read digital input pins that set the CC bank
const int CC_bankPin0 = 9;
const int CC_bankPin1 = 10;
const int CC_bankPin2 = 11;
const int CC_bankPin3 = 12;

int CC_bankState0 = 0;
int CC_bankState1 = 0;
int CC_bankState2 = 0;
int CC_bankState3 = 0;

//current bank per knob. assume not on 0-3
int currentBank[6] = {4, 4, 4, 4, 4, 4};
//last bank per knob. assume not on 0-3
int lastBank[6]    = {5, 5, 5, 5, 5, 5};

//Set up potentiometer pins
const int CC0_pin = A0; //potentiometer pin
int CC0_value; //store pot value
const int CC1_pin = A1;
int CC1_value;
const int CC2_pin = A2;
int CC2_value;
const int CC3_pin = A3;
int CC3_value;
const int CC4_pin = A4;
int CC4_value;
const int CC5_pin = A5;
int CC5_value;

int CC_read[4] ;

//Store previous values to enable hysteresis and pick-up mode for knobs
int CC_bank0_lastValue[6] = {32, 32, 32, 32, 32, 32};
int CC_bank1_lastValue[6] = {32, 32, 32, 32, 32, 32};
int CC_bank2_lastValue[6] = {32, 32, 32, 32, 32, 32};
int CC_bank3_lastValue[6] = {32, 32, 32, 32, 32, 32};

int CC_bank0_value[6] = {0, 0, 0, 0, 0, 0};
int CC_bank1_value[6] = {0, 0, 0, 0, 0, 0};
int CC_bank2_value[6] = {0, 0, 0, 0, 0, 0};
int CC_bank3_value[6] = {0, 0, 0, 0, 0, 0};

void setup() {
  Serial.begin(115200);
  pinMode(LED, OUTPUT);
  digitalWrite(LED, HIGH); //turn this on as a system power indicator
  pinMode(CC_bankPin0, INPUT_PULLUP); //loop this
  pinMode(CC_bankPin1, INPUT_PULLUP);
  pinMode(CC_bankPin2, INPUT_PULLUP);
  pinMode(CC_bankPin3, INPUT_PULLUP);

  // Default Arduino I2C speed is 100 KHz, but the HT16K33 supports
  // 400 KHz.  We can force this for faster read & refresh, but may
  // break compatibility with other I2C devices...so be prepared to
  // comment this out, or save & restore value as needed.
#ifdef ARDUINO_ARCH_SAMD
  Wire.setClock(400000L);
#endif
#ifdef __AVR__
  TWBR = 12; // 400 KHz I2C on 16 MHz AVR
#endif

  trellis.begin(0x70, 0x71);
  for (uint8_t i=0; i<numKeys; i++) {
    trellis.setLED(i);
    trellis.writeDisplay();
    delay(15);
  }
  // then turn them off
  for (uint8_t i=0; i<numKeys; i++) {
    trellis.clrLED(i);
    trellis.writeDisplay();
    delay(15);
  }

  MIDI.begin(1);

  //All notes off MIDI panic if reset
  for(int n=0; n<128; n++){
    MIDI.sendNoteOff(n, 127, 1);  //DC Filter cutoff
  }

/////////////DSP-G1 CC Parameter Settings Defaults (to be changed with knobs)
  MIDI.sendControlChange( 7, 119, 1);   //volume
  MIDI.sendControlChange( 1, 24, 1);   //LFO mod 24
  MIDI.sendControlChange(16,  6, 1);   //LFO rate 12
  MIDI.sendControlChange(20,  0, 1);    //LFO waveform 0-63 sine, 64-127 S/H
  MIDI.sendControlChange(74, 80, 1);  //DC Filter cutoff
  MIDI.sendControlChange(71, 70, 1);   //DC Filter resonance
  MIDI.sendControlChange(82, 32, 1);   //DC Filter envelope Attack
  MIDI.sendControlChange(83, 38, 1);   //DC Filter envelope Decay
  MIDI.sendControlChange(28, 64, 1);   //DC Filter envelope Sustain
  MIDI.sendControlChange(29, 32, 1);   //DC Filter envelope Release
  MIDI.sendControlChange(81, 57, 1);   //DC Filter envelope modulation
  MIDI.sendControlChange(76, 100, 1);  //DC Oscillator waveform* 100
  MIDI.sendControlChange( 4,  0, 1);   //DC Oscillator wrap
  MIDI.sendControlChange(21,  0, 1);    //DC Oscillator range
  MIDI.sendControlChange(93,  0, 1);    //DC Oscillator detune
  MIDI.sendControlChange(73,  0, 1);   //DC Oscillator envelope Attack
  MIDI.sendControlChange(75, 12, 1);   //DC Oscillator envelope Decay
  MIDI.sendControlChange(31, 60, 1);   //DC Oscillator envelope Sustain
  MIDI.sendControlChange(72, 80, 1);   //DC Oscillator envelope Release
/*Wavforms: 0 tri, 25 squarish, 50 pulse, 75 other squarish, 100 saw      */
}

void loop(){
  //read selector switch pins to find CC knob bank
  CC_bankState0 = digitalRead(CC_bankPin0);//loop this
  CC_bankState1 = digitalRead(CC_bankPin1);
  CC_bankState2 = digitalRead(CC_bankPin2);
  CC_bankState3 = digitalRead(CC_bankPin3);
  int b; //to increment through current bank state values
  if (CC_bankState0 == LOW){ //low means it's the selected bank
    for (b=0;b<6;b++){currentBank[b] = 0;}
    read_CC_Knobs(0);
  }
  else if (CC_bankState1 == LOW){
    for (b=0;b<6;b++){currentBank[b] = 1;}
    read_CC_Knobs(1);
  }
  else if (CC_bankState2 == LOW){
    for (b=0;b<6;b++){currentBank[b] = 2;}
    read_CC_Knobs(2);
  }
  else if (CC_bankState3 == LOW){
    for (b=0;b<6;b++){currentBank[b] = 3;}
    read_CC_Knobs(3);
  }
  else { //4-7 have been picked, not connected
    for (b=0;b<6;b++){currentBank[b] = 4;}
  }

  //Trellis MIDI out Keyboard
  delay(30); // 30ms delay is required, dont remove me!

  if (holdMode == MOMENTARY) {
    if (trellis.readSwitches()) { // If a button was just pressed or released...
      for (uint8_t i=0; i<numKeys; i++) { // go through every button
        if (trellis.justPressed(i)) { // if it was pressed, map what it actually does
          //remap the physical button to logical button. 'p' is logical pad, i is physical pad. these names stink.
          int p = logicalPads[i];
          // Serial.print("logical pad: "); Serial.println(p);
          if(p<24){ //it's a MIDI note pad, play a note
            int padNote = logicalPads[i];
            MIDI.sendNoteOn((scalesMatrix[scaleMode][padNoteMap[padNote]] + transpose[octave]), 127, 1);
            //uncomment for debugging:
            /*
            Serial.print("v"); Serial.println(p); //print which button pressed
            trellis.setLED(i); //light stuff up
            Serial.print("OUT: "); //print MIDI out command
            Serial.print("\tChannel: "); Serial.print(1);
            Serial.print("\tNote: "); Serial.print(scalesMatrix[scaleMode][padNoteMap[padNote]] + transpose[octave]);
            Serial.print("\tValue: "); Serial.println("127");
            */
          }
          else if (p==31){ // last button on bottom row swaps hold modes
            holdMode = !holdMode;
            lastHoldMode = holdMode;
            //Serial.println("Hold mode switch to Latching.");
            for (uint8_t n=0; n<24; n++) { //clear note LEDs
              trellis.clrLED(n);
              trellis.writeDisplay();
            }
            trellis.setLED(i); //light stuff up
            trellis.writeDisplay();
            delay(30);
          }
          else{
            Serial.println("not a note");
          }
        }
        if (trellis.justReleased(i)) { // if it was released, turn it off
          int p = logicalPads[i];
          //Serial.print("logical pad: "); Serial.println(p);
          if(p<24){ //it's a MIDI note pad, play a note
            int padNote=logicalPads[i];
            MIDI.sendNoteOff((scalesMatrix[scaleMode][padNoteMap[padNote]] + transpose[octave]), 127, 1);
            //Serial.print("^"); Serial.println(p);
            for (uint8_t i=0; i<numKeys; i++) {
               trellis.clrLED(i);
               trellis.writeDisplay();
            }
            trellis.setLED(i); //keep last one that was pressed turned on
            //uncomment for debugging
            /*
            Serial.print("OUT: ");
            Serial.print("\tChannel: "); Serial.print(1);
            Serial.print("\tNote: "); Serial.print(scalesMatrix[scaleMode][padNoteMap[padNote]]+ transpose[octave]);
            */

            //Serial.print("\tValue: "); Serial.println("0");
          }
          else if (p==31){ // last button on bottom row swaps hold modes
          }
          else{
            Serial.println("not a note");
          }
        }
      }
      trellis.writeDisplay(); // tell the trellis to set the LEDs we requested
    }
  }

  if (holdMode == LATCHING) {
    if (trellis.readSwitches()) {
      for (uint8_t i=0; i<numKeys; i++) {
        if (trellis.justPressed(i)) {
          int p = logicalPads[i];
          //Serial.print("logical pad: "); Serial.println(p);
          if(p<24){
            int padNote = logicalPads[i];
            //Serial.print("pad note: "); Serial.println(padNote);
            //Serial.print("v"); Serial.println(i);
            if (trellis.isLED(i)){ // Alternate the button
              MIDI.sendNoteOff((scalesMatrix[scaleMode][padNoteMap[padNote]] + transpose[octave]), 127, 1);
              trellis.clrLED(i);
            }
            else{
              MIDI.sendNoteOn((scalesMatrix[scaleMode][padNoteMap[padNote]] + transpose[octave]), 127, 1);
              trellis.setLED(i);
            }
          }
          else if (i==31){ // last button on bottom row swaps hold modes
            holdMode = !holdMode;
            lastHoldMode = holdMode;
            for(int n=0; n<128; n++){
              MIDI.sendNoteOff(n, 127, 1);  //DC Filter cutoff
            }
            for (uint8_t j=0; j<24; j++) { //clear all note pads
              trellis.clrLED(j);
            }
            trellis.clrLED(i); //clear holdMode pad
            trellis.writeDisplay();
            //Serial.println("holdMode switch to Momentary.");
            delay(30);
          }
          else{
            Serial.println("not a note");
          }
        }
        trellis.writeDisplay();
      }
    }
  }
  //clear key LEDs after a hold mode change
  if(holdMode != lastHoldMode){
    //Serial.print("Hold mode: "); Serial.println(holdMode);
    //Serial.print("Last hold mode: "); Serial.println(lastHoldMode);
    for (uint8_t j=0; j<24; j++) { //clear all note pads
      trellis.clrLED(j);
    }
    trellis.writeDisplay();
  }
}

void read_CC_Knobs(int CC_bank){
  int AnalogPin[6] = {A0, A1, A2, A3, A4, A5}; //define the analog pins
  int CCKnob[6] = {0, 1, 2, 3, 4, 5}; //define knobs
  // choose which CC numbers are on each knob per bank
  // definitions are at bottom of code
  //Note: can set knobs to "never change" by repeating CC numbers per array
  int CCNumber[6]; //variable array to store the CC numbers
  if(CC_bank == 0){ //set the CC numbers per knob per bank
    //OSC
    int CCNumberChoice[6] = {71, //Filter resonance bottom of left knobs
                             74, //Filter cutoff top of left two knobs
                             21, //DCO range upper row
                             93, //DCO detune
                              4,  //DCO wrap
                             76 //DCO waveform

                       };
    for(int n=0; n<6; n++){
      CCNumber[n] = CCNumberChoice[n];
    }
  }
  else if(CC_bank == 1){
    //Envelope (for main oscillators)
    int CCNumberChoice[6] = {71, //Filter resonance
                             74, //Filter cutoff top of left two knobs
                             82, //VCA Attack
                             83, //VCA Decay
                             28, //VCA Sustain
                             29  //VCA Release
                       };
    for(int n=0; n<6; n++){
      CCNumber[n] = CCNumberChoice[n];
    }
  }
  else if(CC_bank == 2){
    //LFO low frequency oscillator for main OSC
    int CCNumberChoice[6] = {71, //Filter resonance
                             74, //Filter cutoff top of left two knobs
                              1, //LFO mod
                             16, //LFO rate
                             20, //LFO waveform shape
                             81  //Filter mod
                       };
    for(int n=0; n<6; n++){
      CCNumber[n] = CCNumberChoice[n];
    }
  }

  else if(CC_bank == 3){
    //Envelope (for filter)
    int CCNumberChoice[6] = {71,  //Filter resonance
                             74, //Filter cutoff top of left two knobs
                              1, //Filter A
                             16, //Filter D
                             20, //Filter S
                             81 //Filter R
                       };
    for(int n=0; n<6; n++){
      CCNumber[n] = CCNumberChoice[n];
    }
  }
  //Knob pick-up mode -- to deal with multiple knob banks,
  //value doesn't get sent until knob reaches pravious ("last") position
  //NOTE: ugly way to do this, clean it up so a matrix is used instead
  //per bank loop currently

  //Send CC values only when they change beyond last value to avoid getting stuck between two values
  //thanks to Groovesizer Foxtrot code for this idea: https://groovesizer.com/foxtrot/
  //thanks to Todbot for the delta hysteresis idea

  if(CC_bank == 0){ //first bank is selected
    for(int k=0; k<6; k++){ //loop through each of six pots
      if(currentBank[k] != lastBank[k]){ //if the current bank for current knob
        //digitalWrite(LED, LOW);
        //is different than the last bank for the current knob:
       //read CC values from potentiometers
        CC_read[CC_bank] = analogRead(AnalogPin[k]);
        CC_bank0_value[k] = map(CC_read[CC_bank], 0, 1023, 0, 127); // remap range to 0-127
        //check against last read when we were on this bank, only send CC if value
        //of knob is withing a certain delta of the last value
        if((abs(CC_bank0_lastValue[k] - CC_bank0_value[k])) < 3){ //hysteresis for spinning knob too fast
          Serial.println("PICKUP ACHIEVED");
          //digitalWrite(LED, HIGH);
          Serial.print("\nCC_bank0_value for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank0_value[k]);
          Serial.print("CC_bank0_lastValue for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank0_lastValue[k]);
          lastBank[k] = 0;
        }
      }
      else if(currentBank[k] == lastBank[k]){
        //read CC values from potentiometers
        CC_read[CC_bank] = analogRead(AnalogPin[k]);
        CC_bank0_value[k] = map(CC_read[CC_bank], 0, 1023, 0, 127); // remap range to 0-127
        //check against last read, only send CC if value has changed since last read by a certain delta
        if((abs(CC_bank0_lastValue[k] - CC_bank0_value[k])) > 3){ //hysteresis for spinning knob too fast
          Serial.print("\nCC_bank0_value for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank0_value[k]);
          Serial.print("CC_bank0_lastValue for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank0_lastValue[k]);
          MIDI.sendControlChange(CCNumber[k], CC_bank0_value[k], 1);
          //Serial.print("CC number: "); Serial.println(CCNumber[k]);
          CC_bank0_lastValue[k] = CC_bank0_value[k];
          lastBank[k] = 0;
        }
      }
    }
  }

  if(CC_bank == 1){ //second bank is selected
    for(int k=0; k<6; k++){ //loop through each of six pots
      if(currentBank[k] != lastBank[k]){
       //read CC values from potentiometers
        CC_read[CC_bank] = analogRead(AnalogPin[k]);
        CC_bank1_value[k] = map(CC_read[CC_bank], 0, 1023, 0, 127); // remap range to 0-127
        //check against last read when we were on this bank, only send CC if value
        //of knob is withing a certain delta of the last value
        if((abs(CC_bank1_lastValue[k] - CC_bank1_value[k])) < 3){ //hysteresis for spinning knob too fast
          Serial.println("Pickup achieved.");
          Serial.print("\nCC_bank1_value for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank1_value[k]);
          Serial.print("CC_bank1_lastValue for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank1_lastValue[k]);
          lastBank[k] = 1;
        }
      }
      else if(currentBank[k] == lastBank[k]){
        //read CC values from potentiometers
          CC_read[CC_bank] = analogRead(AnalogPin[k]);
          CC_bank1_value[k] = map(CC_read[CC_bank], 0, 1023, 0, 127); // remap range to 0-127
          //check against last read, only send CC if value has changed since last read by a certain delta
        if((abs(CC_bank1_lastValue[k] - CC_bank1_value[k])) > 3){ //hysteresis for spinning knob too fast
          Serial.print("\nCC_bank1_value for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank1_value[k]);
          Serial.print("CC_bank1_lastValue for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank1_lastValue[k]);
          MIDI.sendControlChange(CCNumber[k], CC_bank1_value[k], 1);
          //Serial.print("CC number: "); Serial.println(CCNumber[k]);
          CC_bank1_lastValue[k] = CC_bank1_value[k];
          lastBank[k] = 1;
        }
      }
    }
  }
  if(CC_bank == 2){ //third bank is selected
    for(int k=0; k<6; k++){ //loop through each of six pots
      if(currentBank[k] != lastBank[k]){
        //read CC values from potentiometers
        CC_read[CC_bank] = analogRead(AnalogPin[k]);
        CC_bank2_value[k] = map(CC_read[CC_bank], 0, 1023, 0, 127); // remap range to 0-127
        //check against last read when we were on this bank, only send CC if value
        //of knob is withing a certain delta of the last value
        if((abs(CC_bank2_lastValue[k] - CC_bank2_value[k])) < 3){ //hysteresis for spinning knob too fast
          Serial.println("Pickup achieved.");
          Serial.print("\nCC_bank2_value for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank2_value[k]);
          Serial.print("CC_bank2_lastValue for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank2_lastValue[k]);
          lastBank[k] = 2;
        }
      }
      else if(currentBank[k] == lastBank[k]){
        //read CC values from potentiometers
          CC_read[CC_bank] = analogRead(AnalogPin[k]);
          CC_bank2_value[k] = map(CC_read[CC_bank], 0, 1023, 0, 127); // remap range to 0-127
          //check against last read, only send CC if value has changed since last read by a certain delta
        if((abs(CC_bank2_lastValue[k] - CC_bank2_value[k])) > 3){ //hysteresis for spinning knob too fast
          Serial.print("\nCC_bank2_value for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank2_value[k]);
          Serial.print("CC_bank2_lastValue for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank2_lastValue[k]);
          MIDI.sendControlChange(CCNumber[k], CC_bank2_value[k], 1);
          //Serial.print("CC number: "); Serial.println(CCNumber[k]);
          CC_bank2_lastValue[k] = CC_bank2_value[k];
          lastBank[k] = 2;
        }
      }
    }
  }
  if(CC_bank == 3){ //fourth bank is selected
    for(int k=0; k<6; k++){ //loop through each of six pots
      if(currentBank[k] != lastBank[k]){
       //read CC values from potentiometers
        CC_read[CC_bank] = analogRead(AnalogPin[k]);
        CC_bank3_value[k] = map(CC_read[CC_bank], 0, 1023, 0, 127); // remap range to 0-127
        //check against last read when we were on this bank, only send CC if value
        //of knob is withing a certain delta of the last value
        if((abs(CC_bank3_lastValue[k] - CC_bank3_value[k])) < 3){ //hysteresis for spinning knob too fast
          Serial.println("Pickup achieved.");
          Serial.print("\nCC_bank3_value for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank3_value[k]);
          Serial.print("CC_bank3_lastValue for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank3_lastValue[k]);
          lastBank[k] = 3;
        }
      }
      else if(currentBank[k] == lastBank[k]){
        //read CC values from potentiometers
          CC_read[CC_bank] = analogRead(AnalogPin[k]);
          CC_bank3_value[k] = map(CC_read[CC_bank], 0, 1023, 0, 127); // remap range to 0-127
          //check against last read, only send CC if value has changed since last read by a certain delta
        if((abs(CC_bank3_lastValue[k] - CC_bank3_value[k])) > 3){ //hysteresis for spinning knob too fast
          Serial.print("\nCC_bank3_value for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank3_value[k]);
          Serial.print("CC_bank3_lastValue for knob: "); Serial.print(k); Serial.print("\t"); Serial.println(CC_bank3_lastValue[k]);
          MIDI.sendControlChange(CCNumber[k], CC_bank3_value[k], 1);
          //Serial.print("CC number: "); Serial.println(CCNumber[k]);
          CC_bank3_lastValue[k] = CC_bank3_value[k];
          lastBank[k] = 3;
        }
      }
    }
  }
}

This guide was first published on Apr 30, 2018. It was last updated on Apr 30, 2018.

This page (Code the Synthesizer) was last updated on Sep 15, 2021.

Text editor powered by tinymce.