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!
// SPDX-FileCopyrightText: 2018 John Edgar Park for Adafruit Industries // // SPDX-License-Identifier: MIT #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; } } } } }
Page last edited January 22, 2025
Text editor powered by tinymce.