force small rx/tx buffer for usbmidi teensy 4

Status
Not open for further replies.

lokki

Well-known member
is there a way to force a teensy 4 (declared as usb-midi device) to use the small buffer instead of the big (512) buffer? i read the data in on a teensy 3.6 (via usb-host port) and i have to use the
Code:
MIDIDevice_BigBuffer
class, which i would like to avoid if at all possible.

since i don't know the port on the hub where the teensy 4 is plugged in i have to use the
Code:
MIDIDevice_BigBuffer
on every instance...

also i don't know if it affects latency. memory usage is also a concern...
 
The USB 2.0 spec requires bulk endpoints to use 512 bytes max packet size when the speed is 480 Mbit/sec. As a USB device, you can make a non-conforming endpoint (by editing the usb_desc.h) and it will work with nearly all USB hosts. I've never seen a host refuse to enumerate a USB device for this reason.

On host side, if you reduce the max buffer size, it won't work with virtually all high speed USB MIDI devices, because they all use 512 byte max packet size as the USB spec requires. If it probably would work together with a Teensy which has been edited to use a spec-violating smaller size.

You can also just use 12 MBit speed, where the only up to 64 bytes are allowed for bulk packets. Edit ehci.cpp in the USBHost_t36 library. Look for the commented out line with a comment about forcing 12 Mbit speed.

But in terms of actual communication speed, 512 bytes at 480 Mbit/sec takes less time than only 64 bytes at 12 Mbit/sec. Neither blocks your program on Teensy, in device or host mode, so it's hard to see how this really matters for latency.

If you're *very* tight on memory, restricting to only 12 Mbit/sec speed can help.
 
Hi Paul and lokki,

Wondering if this is along the same line as when I was adding support in USBHost for Serial objects that want a 512 byte communications instead of the 64.. When I added the bigger object, I added an optional setting to say what minimum size RX/TX size should this object accept, as maybe cases like this where the user may want multiple devices and one of them needs the larger buffers.

Not sure if adding something like this to the midi objects would make sense?
 
hi paul, hi KurtE

thanks for your answer.

i have up to 7 usb-midi devices attached to my usb2 hub, only the teensy4 reports at usb2 speed and needs the bigger buffer. so it seemed like a waste because i have to declare them all as big buffers as kurtE wrote. (since i don't know how they enumerate on startup) for now the memory is not an issue, and if you say that latency is not affected (somehow i remember reading that usb2 could actually increase usb-midi latency) i can leave it like this. if i'll add more code to the teensy 3.6 this could become an issue later..
 
sorry to resurrect this.

so i got a strange problem where my midi controller (a teensy 3.6 sending out via usb-host) becomes very sluggish as soon as i send midi to a connected teensy 4.0
receiving midi from the teensy 4.0 at the 3.6 side is no problem at all.

if i disconnect the teensy 4 from the hub, the sluggishness goes away immediately. so i think this is related to the teensy 4. i have
Code:
usbMIDI.setHandleNoteOn(bassNoteOn);
usbMIDI.setHandleNoteOff(bassNoteOff);
in setup and

Code:
void loop() {

  usbMIDI.read();
in loop. the helper functions are working but i have replaced them with empty ones.

i am a bit unsure where to search for here. the code on the teensy 3.6 works with all synths attached, and if i set it so that it never sends to the teensy 4, there is no sluggishness even with the teensy 4 (that still sends midi to the 3.6) connected.

so i guessed that it could be somehow related to the usb2 communication between the two. i edited ehci.cpp as per your suggestion, but now the teensy 4 is not recognised anymore by the 3.6 i guess because it is still using usb2. looking at the teensy4 usb_desc.h seems to indicate that it should actually switch now that i force 12mbit mode on the 3.6 but it does not seem to work. even if i edit the tx and rx size:

Code:
  #define MIDI_TX_SIZE_12       64
  #define MIDI_TX_SIZE_480      64
  #define MIDI_RX_ENDPOINT      3
  #define MIDI_RX_SIZE_12       64
  #define MIDI_RX_SIZE_480      64

it is not recognised by the teensy 3.6

so, can i somehow force the teensy 4 to use usb1 communication?
what could be the cause for a controller to get non responsive as soon as it sends to a specific midi device?
 
Last edited:
actually setting the tx and rx buffer in usb_desc.h is not a good idea :) usb-midi communication is also messed up when connected to a macbook air, messages come in as wrong types or simply don't come in at all.
 
so i got a strange problem where my midi controller (a teensy 3.6 sending out via usb-host) becomes very sluggish as soon as i send midi to a connected teensy 4.0

Can this problem be reproduced using unmodified USB code on both boards?

If so, can I talk you into posting 2 small but complete program I can copy into Arduino and upload to the 2 boards? It's possible you've found a previously unknown bug. But it probably won't ever be investigated and fixed if we don't have a pair of programs to reproduce it.
 
yes, it happened on unmodified USB code, which is why i started to modify it :)

for starters i can just upload the whole code of the two boards, and as time permits i will work on smaller versions. the teensy 3.6 code is a mess, it comes from an arduino micro where i optimised for speed by unrolling for loops etc.

teensy 3.6:

Code:
  /*
* Arduino Ribbon Synth MIDI controller
* ------------------------------------
* ©2014 Dean Miller
* ©2016-2018 Simon Iten many additions, 4 strings, 24 frets, fsr, channelmode, 
* midi message thinning, usb and din midi etc..
*/
#pragma GCC optimize ("-O3")
#include <EEPROM.h>
#include <Arduino.h>
#include <U8x8lib.h>
#include <MIDI.h>        // access to serial (5 pin DIN) MIDI
#include <USBHost_t36.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#include <Wire.h>
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI1);
U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE, /* clock=*/ 7, /* data=*/ 8);

// Create the ports for USB devices plugged into Teensy's 2nd USB port (via hubs)
USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
USBHub hub3(myusb);
USBHub hub4(myusb);
MIDIDevice_BigBuffer midi01(myusb);
MIDIDevice_BigBuffer midi02(myusb);
MIDIDevice_BigBuffer midi03(myusb);
MIDIDevice_BigBuffer midi04(myusb);
MIDIDevice_BigBuffer midi05(myusb);
MIDIDevice_BigBuffer midi06(myusb);
MIDIDevice_BigBuffer midi07(myusb);
MIDIDevice_BigBuffer * midilist[07] = {
  &midi01, &midi02, &midi03, &midi04, &midi05, &midi06, &midi07
};


//------- Constants -------//

#define PIN_LED 13
// the 4 strings softpots
#define PIN_SOFTPOT_1 A0
#define PIN_SOFTPOT_2 A1
#define PIN_SOFTPOT_3 A2
#define PIN_SOFTPOT_4 A3
//the 4 fsrs under the strings
#define PIN_STRINGFSR_1 A16
#define PIN_STRINGFSR_2 A17
#define PIN_STRINGFSR_3 A18
#define PIN_STRINGFSR_4 A19
//the 4 fsr's
#define PIN_FSR_1 A4
#define PIN_FSR_2 A5
#define PIN_FSR_3 A6
#define PIN_FSR_4 A7
#define PIN_FSR_5 A22

#define PIN_FSR_FOOT 29 //replace with midi fulllegato tapping command
#define PIN_BUTTON_CHANNEL 28
#define PIN_BUTTON_PANIC 27
#define PIN_OCTAVE_UP 24
#define PIN_OCTAVE_DOWN 25
#define PIN_BUTTON_FSR 26
//joystick
#define PIN_JOYSTICK_X A14
#define PIN_JOYSTICK_Y A15
//accelerometer
#define PIN_ACCEL_X A9
#define PIN_ACCEL_Y A10
#define PIN_ACCEL_Z A11
//hothand
#define PIN_HOTHAND_X A13
#define PIN_HOTHAND_Y A12
//lfo wheel
#define PIN_WHEEL A21
//arp softpot and fsr
#define PIN_ARP_SOFTPOT A8
#define PIN_ARP_FSR A20
#define UP 0
#define DOWN 1
#define FULLLEGATO 2


#define NUM_STRINGS 4
//resistance to change note when finger position not precise...
#define PADDING 2
#define MAXREADING 1300
#define MINVELOCITY 60
//where does the channelmode start, default mode starts on channel 2  general modulation happens on channel one (kind of mpe))
#define CHANNEL_OFFSET 4
//how long before a note stays on when you release the fsr in non-bowmode
#define ATTACK 1000
#define ATTACK_LEGATO 1000
//which cc numbers are used to save settings and change the modes via midi.
#define SAVE_CC 115
#define CHANNELMODE_CC 119
#define FULLLEGATO_CC 118
#define OCTAVE_CC 117
#define FSR_SLAVE_CC 116
#define ALLMUTE_CC 123
#define BOWMODE_CC 114
#define DUMMY_CC 113
//lowest open string to calculate midi note values on the neck
#define LOWEST_NOTE 4

// corrects false note splutter when softpot is released
#define STABLETIME 14

//buttonpresstime (detect multiple presses, debounce)
#define BUTTONPRESS 1000
//thin out cc messages
#define CONTROL_RATE 15
//thin out aftertouch messages
#define AFTERTOUCH_RATE 15

//------ Global Variables ---------//

/*
fret defs stored in EEPROM for calibration purposes.
Lower output voltages from USB ports result in different values read from
SoftPots and wonky fret definitions.
*/
 byte fret_Defs[4][25];
 
byte map_fsr_string[] = {
127,126,125,124,124,123,122,121,120,119,118,118,117,116,115,114,114,113,112,111,110,110,109,108,107,107,106,105,104,104,103,102,102,101,100,100,99,98,97,97,96,95,95,94,93,93,92,92,91,90,
90,89,88,88,87,87,86,85,85,84,84,83,82,82,81,81,80,80,79,79,78,77,77,76,76,75,75,74,74,73,73,72,72,71,71,70,70,69,69,68,68,67,67,66,66,66,65,65,64,64,
63,63,62,62,62,61,61,60,60,59,59,59,58,58,57,57,57,56,56,55,55,55,54,54,54,53,53,52,52,52,51,51,51,50,50,50,49,49,49,48,48,48,47,47,47,46,46,46,45,45,
45,44,44,44,43,43,43,43,42,42,42,41,41,41,41,40,40,40,39,39,39,39,38,38,38,38,37,37,37,37,36,36,36,36,35,35,35,35,34,34,34,34,33,33,33,33,32,32,32,32,
32,31,31,31,31,30,30,30,30,30,29,29,29,29,29,28,28,28,28,28,27,27,27,27,27,26,26,26,26,26,26,25,25,25,25,25,25,24,24,24,24,24,24,23,23,23,23,23,23,22,
22,22,22,22,22,22,21,21,21,21,21,21,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19,18,18,18,18,18,18,18,18,17,17,17,17,17,17,17,17,17,16,16,16,16,16,16,
16,16,15,15,15,15,15,15,15,15,15,15,14,14,14,14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,
11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,
};
byte map_fsr[] = {
127,126,126,125,124,124,123,123,122,121,121,120,120,119,118,118,117,117,116,116,115,114,114,113,113,112,112,111,110,110,109,109,108,108,107,107,106,106,105,105,104,104,103,103,102,102,101,101,100,100,
99,99,98,98,97,97,96,96,95,95,94,94,93,93,92,92,91,91,91,90,90,89,89,88,88,87,87,87,86,86,85,85,84,84,84,83,83,82,82,82,81,81,80,80,80,79,79,78,78,78,
77,77,76,76,76,75,75,75,74,74,73,73,73,72,72,72,71,71,71,70,70,70,69,69,69,68,68,68,67,67,67,66,66,66,65,65,65,64,64,64,63,63,63,62,62,62,61,61,61,61,
60,60,60,59,59,59,58,58,58,58,57,57,57,56,56,56,56,55,55,55,55,54,54,54,53,53,53,53,52,52,52,52,51,51,51,51,50,50,50,50,49,49,49,49,48,48,48,48,47,47,
47,47,46,46,46,46,46,45,45,45,45,44,44,44,44,44,43,43,43,43,43,42,42,42,42,41,41,41,41,41,40,40,40,40,40,39,39,39,39,39,38,38,38,38,38,38,37,37,37,37,
37,36,36,36,36,36,36,35,35,35,35,35,34,34,34,34,34,34,33,33,33,33,33,33,32,32,32,32,32,32,32,31,31,31,31,31,31,30,30,30,30,30,30,30,29,29,29,29,29,29,
29,28,28,28,28,28,28,28,27,27,27,27,27,27,27,26,26,26,26,26,26,26,26,25,25,25,25,25,25,25,25,24,24,24,24,24,24,24,24,24,23,23,23,23,23,23,23,23,22,22,
22,22,22,22,22,22,22,22,21,21,21,21,21,21,21,21,21,20,20,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19,19,19,19,19,18,18,18,18,18,18,18,18,18,18,18,17,
17,17,17,17,17,17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14,14,
14,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,
};

 byte map_hothand[] = {
0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,8,9,
9,9,9,9,9,10,10,10,11,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
48,49,50,51,52,53,53,54,55,56,57,58,58,59,59,60,60,61,61,62,62,63,63,64,64,65,65,66,66,67,67,68,68,69,69,70,70,71,71,72,72,73,73,74,74,75,75,76,76,77,77,
78,78,79,79,80,80,81,81,82,82,83,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90,90,91,91,91,92,92,92,93,93,93,94,94,94,95,95,95,96,96,
96,97,97,97,98,98,98,99,99,99,100,100,100,100,101,101,101,101,102,102,102,102,103,103,103,103,104,104,104,104,105,105,105,105,106,106,106,106,107,107,
107,107,108,108,108,108,109,109,109,110,110,110,111,111,112,112,112,112,112,113,113,113,113,114,114,114,114,114,114,115,115,115,115,
115,115,116,116,116,116,116,116,117,117,117,117,117,117,118,118,118,118,118,118,119,119,119,119,119,119,119,120,
120,120,120,121,122,123,124,
124,124,125,126,126,127 };
/*
byte map_wheel[] {
0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,
3,3,4,4,4,4,5,5,5,6,6,6,7,7,7,8,8,9,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,21,21,22,22,23,24,24,25,26,
26,27,27,28,29,29,30,31,32,32,33,34,34,35,36,36,37,38,39,39,40,41,42,42,43,44,45,45,46,47,48,48,49,50,51,52,52,53,54,55,56,56,57,58,59,60,60,61,62,63,64,64,65,66,67,67,68,69,70,71,71,72,73,74,75,75,76,77,78,79,79,80,81,82,82,83,84,85,85,86,87,88,88,89,90,91,91,92,93,93,94,95,95,96,97,98,98,99,100,100,
101,101,102,103,103,104,105,105,106,106,107,108,108,109,109,110,110,111,111,112,112,113,113,114,114,115,115,116,116,117,117,118,118,118,119,119,120,120,120,121,121,121,122,122,122,123,123,123,123,124,
124,124,124,125,125,125,125,125,126,126,126,126,126,126,126,126,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,126,126,126,126,126,126,126,126,125,125,125,125,125,124,124,
124,124,123,123,123,123,122,122,122,121,121,121,120,120,120,119,119,118,118,118,117,117,116,116,115,115,114,114,113,113,112,112,111,111,110,110,109,109,108,108,107,106,106,105,105,104,103,103,102,101,
101,100,100,99,98,98,97,96,95,95,94,93,93,92,91,91,90,89,88,88,87,86,85,85,84,83,82,82,81,80,79,79,78,77,76,75,75,74,73,72,71,71,70,69,68,67,67,66,65,64,
64,63,62,61,60,60,59,58,57,56,56,55,54,53,52,52,51,50,49,48,48,47,46,45,45,44,43,42,42,41,40,39,39,38,37,36,36,35,34,34,33,32,32,31,30,29,29,28,27,27,
26,26,25,24,24,23,22,22,21,21,20,19,19,18,18,17,17,16,16,15,15,14,14,13,13,12,12,11,11,10,10,9,9,9,8,8,7,7,7,6,6,6,5,5,5,4,4,4,4,3,
3,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
}; */

byte map_wheel[] {
0,3,5,7,10,12,14,17,
19,21,23,25,27,29,31,33,
35,37,38,40,42,44,45,47,
48,50,51,53,54,56,57,59,
60,61,63,64,65,66,68,69,
70,71,72,73,74,75,76,77,
78,79,80,81,82,83,84,85,
86,86,87,88,89,90,90,91,
92,92,93,94,94,95,96,96,
97,98,98,99,99,100,100,101,
101,102,102,103,103,104,104,105,
105,106,106,106,107,107,108,108,
108,109,109,109,110,110,110,111,
111,111,112,112,112,113,113,113,
113,114,114,114,115,115,115,115,
115,116,116,116,116,117,117,117,
117,117,118,118,118,118,118,118,
119,119,119,119,119,119,120,120,
120,120,120,120,120,121,121,121,121,121,121,121,121,122,122,122,122,122,122,122,122,122,122,122,123,123,123,123,123,123,123,123,
123,123,123,123,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,125,125,125,
125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,
126,126,126,126,126,126,126,126,126,126,126,127,127,127,127,127,127,127,127,127,126,126,126,126,126,126,126,126,125,125,125,125,125,124,124,
124,124,123,123,123,123,122,122,122,121,121,121,120,120,120,119,119,118,118,118,117,117,116,116,115,115,114,114,113,113,112,112,111,111,110,110,109,109,108,108,107,106,106,105,105,104,103,103,102,101,
101,100,100,99,98,98,97,96,95,95,94,93,93,92,91,91,90,89,88,88,87,86,85,85,84,83,82,82,81,80,79,79,78,77,76,75,75,74,73,72,71,71,70,69,68,67,67,66,65,64,
64,63,62,61,60,60,59,58,57,56,56,55,54,53,52,52,51,50,49,48,48,47,46,45,45,44,43,42,42,41,40,39,39,38,37,36,36,35,34,34,33,32,32,31,30,29,29,28,27,27,
26,26,25,24,24,23,22,22,21,21,20,19,19,18,18,17,17,16,16,15,15,14,14,13,13,12,12,11,11,10,10,9,9,9,8,8,7,7,7,6,6,6,5,5,5,4,4,4,4,3,
3,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,


 
};

byte fsr_Touched[] = {false, false, false, false};
byte active_Note[] = {0,0,0,0};
byte arp_Note[] = {0,0,0,0};
//byte active_Velo[] = {0,0,0,0};
unsigned int fsr_Vals[] = {0, 0, 0, 0};
byte fsr_Read_Old[] = {0, 0, 0, 0};

byte fsr_Pins[] = {PIN_FSR_1, PIN_FSR_2, PIN_FSR_3, PIN_FSR_4};
unsigned int fsr_Init[] = {0, 0, 0, 0};

unsigned int soft_Pot_Vals[4];
unsigned int string_Fsr_Vals[4];
unsigned int string_Fsr_Old[4];
unsigned int string_Fsr_Init[4];

 byte soft_Pot_Pins[] = {PIN_SOFTPOT_1, PIN_SOFTPOT_2, PIN_SOFTPOT_3, PIN_SOFTPOT_4};
 byte string_Fsr_Pins[] = {PIN_STRINGFSR_1,PIN_STRINGFSR_2, PIN_STRINGFSR_3, PIN_STRINGFSR_4};
  bool string_fsr_active[] = {false, false, false, false};
byte soft_Pot_Vals_Old[] = {0, 0, 0, 0};

byte fret_Touched[4];
byte maybe_Note[] {0,0,0,0};
byte stable_Count[] = {0,0,0,0};
byte note_Fretted[4];
byte string_Active[] = {false, false, false, false};
//debug to print to serial every 2 seconds
elapsedMillis debugsession;
elapsedMillis hothand_on;


//unsigned int calibration_Max[] = {630, 630, 630, 630};
unsigned int calibration_Min[4];


//octave offset
byte octave = 2;

//default offsets for the 4 strings
byte offsets[] = {28, 33, 38, 43};

//states of control buttons
byte button_States[] = {false, false, false};
unsigned int stick_Zero_Y = 0;
unsigned int stick_Zero_X = 0;
// fifth fsr  mode, when off fifth fsr is fixed to fourth fsr sound otherwise dynamic (last hit fsr)
boolean fsr_Add_Slave_Mode = false;
//no need to press the fsr to trigger a note, simply press a finger on a softpot
boolean full_Legato_Mode = false;
// allows for 4 sounds to be triggered by the 4 fsr's.
boolean channel_Mode = false;
//toggle bowmode (hold sound only as long as fsr is touched) and regular mode (hold sound as long as string is pressed)
boolean bow_Mode = false;
// store which fsr has been hit in channelmode
byte c = 0;
byte old_c = 0;


int y_Pos_old = 0;
int y_Pos2_old = 0;

//accelerometer
int accel_y_old = 0;
int accel_z_old = 0;
int accel_x_old = 0;
int stick_x_old = 0;
int wheel_old = 0;
int wheel_older = 0;
int hothand_x_old = 0;
int hothand_y_old = 0;
int hothand_stable;
int hothand_counter = 0;
byte hothand_array[40];
unsigned int stick_average = 0;
unsigned int stick_average_y = 0;
unsigned int accel_average_y = 0;
unsigned int accel_average_z = 0;
unsigned int accel_average_x = 0;
unsigned int wheel_average = 0;
int wheel_counter = 0;
int old_wheel = 0;
int wheel_stable = 0;
byte wheel_array[40];
unsigned int hothand_average_x = 0;
unsigned int hothand_average_y = 0;

int attack_counter[] = {0,0,0,0};
byte running_byte = 0;
//midi in variables
byte state = 0;
byte save_Slot = 0;
byte status_Byte;
byte data_Byte1;
byte data_Byte2;

 byte button_read = 0;
 int button_count = 0;

 //make sure multimode program changes work on the blofeld!!
byte first_programchange = 0;

//joystick
bool is_Middle_stick_y = 0;
bool is_Middle_stick_x = 0;
// thin control data a little
byte control_counter = 0;
byte at_counter[] = {0,0,0,0};
byte fsr_counter[] = {0,0,0,0};
unsigned int fsr_Add_Init;
unsigned int fsr_Foot_Init;
unsigned int fsr_Arp_Init;
byte fsr_Add_Touched = 0;
bool fsr_Foot_Touched = 0;
bool fsr_Arp_Touched = 0;
byte fsr_Add_Old = 0;
byte fsr_Arp_Old = 0;
byte fsr_Foot_Old = 0;
byte at_counter_add = 0;
byte at_counter_foot = 0;
byte arp_counter_add = 0;
//arpeggiator softpot and fsr stuff
 byte temp_active;
 byte divider;
 byte old_pos_arp;
 byte arp_pos;
 byte old_arp;
//usb host stuff serials of attached devices
int serialNumbers[7];
//specific devices are saved to be able to send/receive to specific devices regardless of order they are plugged in
int blofeld;
int keysaxo;
int footpedal;

//sustain via midi cc
bool sustain_mode = 1;
//--------- Setup ----------------//
void setup() {
Wire.setSDA(8);
  Wire.setSCL(7);
MIDI1.begin(MIDI_CHANNEL_OMNI);
u8x8.begin();
  u8x8.setPowerSave(0);
  u8x8.setFont(u8x8_font_7x14B_1x2_f);
 // u8x8.drawString(0,0,"Booting");
 // digitalWrite(PIN_LED, HIGH);
  //read fret definitions from EEPROM
//

  
  for (byte i=NUM_STRINGS; i--;){
 
    fret_Defs[i][0] = 255;
    for (byte j=1; j<24; j++){
      fret_Defs[i][j] = EEPROM.read(j + (24*i));
    }
    fret_Defs[i][24]=0;
    calibration_Min[i] = EEPROM.read(24 + (24*i));
  }


  
  pinMode(PIN_BUTTON_PANIC, INPUT);  
  pinMode(PIN_BUTTON_FSR, INPUT);  
  pinMode(PIN_OCTAVE_UP, INPUT);  
  pinMode(PIN_OCTAVE_DOWN, INPUT);  
  pinMode(PIN_BUTTON_CHANNEL, INPUT); 
  analogReadResolution(11);

 // pinMode(PIN_LED, OUTPUT);
  while(millis() < 800) {
    for (byte i=NUM_STRINGS; i--;){
      fsr_Init[i] = analogRead(fsr_Pins[i])>>1;
      string_Fsr_Init[i] = analogRead(string_Fsr_Pins[i])>>1;
  //    unsigned int val = analogRead(soft_Pot_Pins[i]);
    //  if (val > calibration_Max[i]) calibration_Max[i] = val;
    }
    fsr_Add_Init = analogRead(PIN_FSR_5)>>1;
  //  fsr_Foot_Init = analogRead(PIN_FSR_FOOT);
    fsr_Arp_Init = analogRead(PIN_ARP_FSR)>>1;
    //calibrate joystick
    int temp_stick_y;
    for (int i=CONTROL_RATE; i--;){
    temp_stick_y = analogRead(PIN_JOYSTICK_Y);
    stick_Zero_Y = stick_Zero_Y + temp_stick_y;
    }
    stick_Zero_Y = stick_Zero_Y / (CONTROL_RATE);
    stick_Zero_X = analogRead(PIN_JOYSTICK_X);
    //calibrate accelerometer
    
    }
   
    myusb.begin();
     delay(1500);
for (int i=0; i<7; i++) {
  if (midilist[i]->manufacturer() != NULL && midilist[i]->serialNumber() != NULL) {
  
     Serial.println((char*)midilist[i]->serialNumber());
     Serial.println(midilist[i]->idProduct());
     if (!strcmp(midilist[i]->serialNumber(), "11390072173-1304284600")) { //Waldorf Blofeld Serial
      Serial.println("here is blofeld");
      blofeld = i;
     }

     if (!strcmp(midilist[i]->serialNumber(),"003600433435511733353932")) {//Axoloti for qunexus/vocoder serial
      Serial.println("here is axovocoder");
      keysaxo = i;
     }

     if (!strcmp(midilist[i]->serialNumber(),"EncoderFanel")) {//Axoloti for qunexus/vocoder serial
      Serial.println("here is the footcontroller");
      footpedal = i;
     }
  }
  
  }
  Serial.println(keysaxo);
  Serial.println(footpedal);
  midilist[footpedal]->setHandleProgramChange(footProgramChange);
  midilist[footpedal]->setHandleControlChange(footControlChange);
  midilist[footpedal]->setHandleNoteOn(footNoteOn);
  midilist[footpedal]->setHandleNoteOff(footNoteOff);  
    //send to blofeld to activate multi program change
       midilist[blofeld]->sendControlChange(0,127,6);
  midilist[blofeld]->sendControlChange(32,127,6);

  //load first program on all synths
  loadSettings(0);
    
  for (int i=0; i<7; i++) {
 if (i != footpedal) midilist[i]->sendProgramChange(0,1);
  }

 
 //   digitalWrite(PIN_LED, LOW);
    //press leftmost (from above) button during startup to calibrate
    if ( digitalRead(PIN_BUTTON_CHANNEL) == LOW ) {
      u8x8.drawString(0,0,"Calibration:");
        calibrate();
  }
  //write defaults to all program locations, overwriting everything
 /* if (digitalRead(PIN_BUTTON_FSR) == LOW && !button_States[BREATH]) {
    button_States[BREATH] = true;
    writeDefaults();
  } */
  if (!channel_Mode) u8x8.drawString(0,0,"MPE ");
  else u8x8.drawString(0,0,"POLY");
  u8x8.drawString(0,50,"OCT:");
  enum {BufSize=3}; // If a is short use a smaller number, eg 5 or 6 
            char buf[BufSize];
            snprintf (buf, BufSize, "%d", octave);
        u8x8.drawString(5,50,buf);
}

//----------Main Loop---------------//
void loop() {
//------midi input from the qunexus keyboard-----------//
  if (MIDI1.read()) {
sendQunexus(MIDI1.getType(), MIDI1.getData1(), MIDI1.getData2(), MIDI1.getChannel() + 9);
  }
//---midi from the footpedal----//
myusb.Task();
midilist[footpedal]->read();

//-------------------start of the bass-midi controller code-------------------------------//
//reset fsr_Vals to zero
memset(fsr_Vals,0,sizeof(fsr_Vals));

//------------------------- READ ALL SENSORS (Softpots and FSRs)---------------//
 //read values of all sensors 
 
 unsigned int fsr_Read[4];
 unsigned int stringfsr_Read[4];

  byte fret_touch = fret_Touched[0] + fret_Touched[1] + fret_Touched[2] + fret_Touched[3];
  
unsigned int fsr_Add = analogRead(PIN_FSR_5)>>1;
unsigned int fsr_Arp = analogRead(PIN_ARP_FSR)>>1;
unsigned int softpot_Arp = analogRead(PIN_ARP_SOFTPOT);


//code for the "arpeggiator" softpot and fsr
if (channel_Mode) {
 
  if (fsr_Arp < (fsr_Arp_Init - 50) && !fsr_Arp_Touched) {
    fsr_Arp_Touched = 1;
    divider = 0;
    
    for (int i=0; i<NUM_STRINGS; i++) {
      arp_Note[i] = 0;
      if (fret_Touched[i]) {
        divider = divider + 1;
        arp_Note[divider - 1] = active_Note[i];
        noteOn(0x91 + c, active_Note[i],0);
      }
    }
   for (int i=divider; i<NUM_STRINGS; i++) {
          arp_Note[i] = arp_Note[i-divider] + 12;
        }
    }

  if (fsr_Arp < (fsr_Arp_Init - 30) && fsr_Arp_Touched) {
     

   fsr_Arp = map_fsr[constrain(int(fsr_Arp*1.6f) - 450,0,1005)];
     if ((fsr_Arp - fsr_Arp_Old)) {
      arp_counter_add = arp_counter_add + 1;
      if (arp_counter_add == AFTERTOUCH_RATE) {
 if (fret_touch)  aftertouchChange(0xD1 + c + CHANNEL_OFFSET, fsr_Arp);
   
      arp_counter_add = 0;
   
      }
     }
      
       
      
       fsr_Arp_Old = fsr_Arp; 

    }
    
    
 if ((softpot_Arp > 880) ) arp_pos = 0;
 if ((softpot_Arp > 740) && (softpot_Arp <= 852)) arp_pos = 1;
 if ((softpot_Arp > 692) && (softpot_Arp <= 730)) arp_pos = 0;
 if ((softpot_Arp > 540) && (softpot_Arp <= 682)) arp_pos = 2;
 if ((softpot_Arp > 500) && (softpot_Arp <= 530))arp_pos = 0;
 if ((softpot_Arp > 300) && (softpot_Arp <= 490))arp_pos = 3;
 if ((softpot_Arp > 250) && (softpot_Arp <= 295))arp_pos = 0;
 if ((softpot_Arp > 130) && (softpot_Arp <= 240))arp_pos = 4;
 if ((softpot_Arp > 0) && (softpot_Arp <= 120))arp_pos = 0;


   if (divider) { 
      if (arp_pos != old_arp) {
        old_arp = arp_pos;
      switch (arp_pos) {
          case 0:
      if (temp_active)noteOn(0x91 + c, temp_active, 0);
      temp_active = 0;
      break;
     case 1:
      if (temp_active)noteOn(0x91 + c, temp_active, 0);
      noteOn(0x91 + c, arp_Note[0] + 12, 80);
      temp_active = arp_Note[0] + 12;
      break;
     case 2: 
      if (temp_active)noteOn(0x91 + c, temp_active, 0);
      noteOn(0x91 + c, arp_Note[1] + 12, 80);
      temp_active = arp_Note[1] + 12;
      break;
     case 3:
     if (temp_active)noteOn(0x91 + c, temp_active, 0);
      noteOn(0x91 + c, arp_Note[2] + 12, 80);
      temp_active = arp_Note[2] + 12;
      break;
     case 4:
     if (temp_active)noteOn(0x91 + c, temp_active, 0);
      noteOn(0x91 + c, arp_Note[3] + 12, 80);
      temp_active = arp_Note[3] + 12;
      break;
   
    }
    }
    }
  if (fsr_Arp > (fsr_Arp_Init - 15) && fsr_Arp_Touched) {
     if (temp_active)noteOn(0x91 + c, temp_active, 0);
      temp_active = 0;
      old_arp = -1;
    fsr_Arp_Touched = 0;
    aftertouchChange(0xD1 + c + CHANNEL_OFFSET, 0);
  }
}
if (!fsr_Foot_Touched && !fsr_Arp_Touched) {
if (channel_Mode) {
   
   //  if (fret_touch) {
    if (fsr_Add < (fsr_Add_Init - 30) && !fsr_Add_Touched) {
      if (!fsr_Add_Slave_Mode) c = 3;
      attack_counter[c] = 0;
   //  fsr_Vals[c] = map(fsr_Add, fsr_Add_Init - 30, 60, MINVELOCITY, 127);
   fsr_Vals[c] = 80;
      fsr_Add_Touched = 1;
      fsr_Touched[c] = 1;
    }
    if (fsr_Add < (fsr_Add_Init - 20) && fsr_Add_Touched) {
     

   fsr_Add = map_fsr[constrain(fsr_Add - 20,0,1005)];
     if ((fsr_Add - fsr_Add_Old) && attack_counter[c]) {
      at_counter_add = at_counter_add + 1;
      if (at_counter_add == AFTERTOUCH_RATE) {
 if (fret_touch)  aftertouchChange(0xD1 + c + CHANNEL_OFFSET, fsr_Add);
   
      at_counter_add = 0;
   
      }
     }
      
       if (attack_counter[c] < ATTACK) attack_counter[c] = attack_counter[c] + 1;
      
       fsr_Add_Old = fsr_Add; 

    }
    if (fsr_Add > (fsr_Add_Init - 15) && fsr_Add_Touched) {
  if (fret_touch)   aftertouchChange(0xD1 + c + CHANNEL_OFFSET, 0);
      fsr_Add_Touched = 0;   
      fsr_Touched[c] = 0;
    } 
   
//} else fsr_Add_Touched = 0;
} else {
    if (fsr_Add < (fsr_Add_Init - 30) && !fsr_Add_Touched) {
      memset(attack_counter,0,sizeof(attack_counter));
   //   fsr_Vals[0] = map(fsr_Add, fsr_Add_Init - 30, 60, MINVELOCITY, 127);
   fsr_Vals[0] = 80;
      fsr_Vals[1] = fsr_Vals[0];
      fsr_Vals[2] = fsr_Vals[0];
      fsr_Vals[3] = fsr_Vals[0];
      fsr_Add_Touched = 1;
      memset(fsr_Touched,1,sizeof(fsr_Touched));
    }
    if (fsr_Add < (fsr_Add_Init - 20) && fsr_Add_Touched) {
     

   fsr_Add = map_fsr[constrain(fsr_Add - 20,0,1005) ];
     if ((fsr_Add - fsr_Add_Old) && attack_counter[0]) {
      at_counter_add = at_counter_add + 1;
      if (at_counter_add == AFTERTOUCH_RATE) {
  if (fret_Touched[0]) aftertouchChange(0xD1 , fsr_Add);
   if (fret_Touched[1]) aftertouchChange(0xD2 , fsr_Add);
   if (fret_Touched[2]) aftertouchChange(0xD3 , fsr_Add);
  if (fret_Touched[3]) aftertouchChange(0xD4 , fsr_Add);
    at_counter_add = 0;
      }
     }
      
       if (attack_counter[0] < ATTACK) {
        attack_counter[0] = attack_counter[0] + 1;
         attack_counter[1] = attack_counter[0];
          attack_counter[2] = attack_counter[0];
           attack_counter[3] = attack_counter[0];
        
       }
      
       fsr_Add_Old = fsr_Add; 

    }
    if (fsr_Add > (fsr_Add_Init - 15) && fsr_Add_Touched) {
  if (fret_Touched[0])  aftertouchChange(0xD1 , 0);
 if (fret_Touched[1])   aftertouchChange(0xD2 , 0);
  if (fret_Touched[2]) aftertouchChange(0xD3 , 0);
  if (fret_Touched[3])  aftertouchChange(0xD4 , 0);
      fsr_Add_Touched = 0;   
      memset(fsr_Touched,0,sizeof(fsr_Touched));
    }    
}
}
//bool fsr_Foot = digitalRead(PIN_FSR_FOOT);
bool fsr_Foot = sustain_mode;
if (!fsr_Add_Touched && !fsr_Arp_Touched) {

    
if (channel_Mode) {


 
 
   
   //  if (fret_touch) {
    if (fsr_Foot == LOW && !fsr_Foot_Touched) {
   // if (!fsr_Add_Slave_Mode) c = 3;
      attack_counter[c] = ATTACK;
    //  fsr_Vals[c] = map(fsr_Foot, fsr_Foot_Init - 450, 60, MINVELOCITY, 127);
    fsr_Vals[c] = 80;
      fsr_Foot_Touched = 1;
      fsr_Touched[c] = 1;
    }

    if (fsr_Foot_Touched) {
      int c_temp = c;
       fsr_Read[0] = analogRead(fsr_Pins[0])>>1;
     
    if (fsr_Read[0] < (fsr_Init[0] - 30)) {
      fsr_Touched[c] = 0;
    //  fsr_Vals[c] = 0;
      fsr_Touched[0] = 1;
     // fsr_Vals[0] = 80;
      c = 0;

    }
      fsr_Read[1] = analogRead(fsr_Pins[1])>>1;
     
    if (fsr_Read[1] < (fsr_Init[1] - 30)) {
      fsr_Touched[c] = 0;
      fsr_Touched[1] = 1;
      c = 1;
    }
      fsr_Read[2] = analogRead(fsr_Pins[2])>>1;
     
    if (fsr_Read[2] < (fsr_Init[2] - 30)) {
      fsr_Touched[c] = 0;
      fsr_Touched[2] = 1;
      c = 2;
    }
      fsr_Read[3] = analogRead(fsr_Pins[3])>>1;
     
    if (fsr_Read[3] < (fsr_Init[3] - 30)) {
      fsr_Touched[c] = 0;
      fsr_Touched[3] = 1;
      c = 3;
    }
    if (c_temp != c) {
      if (fret_Touched[0]) {
         noteOn(0x91 + c, active_Note[0], 80);
        noteOn(0x91 + c_temp, active_Note[0], 0);
       
      }
      if (fret_Touched[1]) {
        noteOn(0x91 + c, active_Note[1], 80);
        noteOn(0x91 + c_temp, active_Note[1], 0);
         
      }
      if (fret_Touched[2]) {
         noteOn(0x91 + c, active_Note[2], 80);
        noteOn(0x91 + c_temp, active_Note[2], 0);
        
      }
      if (fret_Touched[3]) {
        noteOn(0x91 + c, active_Note[3], 80);
        noteOn(0x91 + c_temp, active_Note[3], 0);
         
      }
    }
    }
 
    if (fsr_Foot == HIGH && fsr_Foot_Touched) {
// if (fret_touch) aftertouchChange(0xD1 + c + CHANNEL_OFFSET, 0);
      fsr_Foot_Touched = 0;   
      fsr_Touched[c] = 0;
    } 
} else {
  
    if (fsr_Foot == LOW && !fsr_Foot_Touched) {
      
      memset(attack_counter,ATTACK,sizeof(attack_counter));
    //  fsr_Vals[0] = map(fsr_Foot, fsr_Foot_Init - 450, 60, MINVELOCITY, 127);
    fsr_Vals[0] = 80;
      fsr_Vals[1] = fsr_Vals[0];
      fsr_Vals[2] = fsr_Vals[0];
      fsr_Vals[3] = fsr_Vals[0];
      fsr_Foot_Touched = 1;
      memset(fsr_Touched,1,sizeof(fsr_Touched));
    }
 
    if (fsr_Foot == HIGH && fsr_Foot_Touched) {
    
 
      fsr_Foot_Touched = 0;   
      memset(fsr_Touched,0,sizeof(fsr_Touched));
    }
 }
}
    //-STRING ONE-//
    //read fsr vals
 if(!fsr_Add_Touched && !fsr_Foot_Touched && !fsr_Arp_Touched) {
if (!channel_Mode) fret_touch = fret_Touched[0];
    fsr_Read[0] = analogRead(fsr_Pins[0])>>1;
     if (fret_touch) {
    if (fsr_Read[0] < (fsr_Init[0] - 50) && !fsr_Touched[0]) {
      attack_counter[0] = 0;
    //  fsr_Vals[0] = map((fsr_Read[0]), fsr_Init[0] - 30, 60, MINVELOCITY, 127);
    fsr_Vals[0] = 80;
      fsr_Touched[0] = 1;
      c= 0;
    }
    if (fsr_Read[0] < (fsr_Init[0] - 35) && fsr_Touched[0]) {
     

   fsr_Read[0] = map_fsr[constrain(fsr_Read[0] - 30,0,1005) ];
     if ((fsr_Read[0] - fsr_Read_Old[0]) && attack_counter[0]) {
      at_counter[0] = at_counter[0] + 1;
      if (at_counter[0] == AFTERTOUCH_RATE) {
        
      if (channel_Mode)  aftertouchChange(0xD1 + CHANNEL_OFFSET, fsr_Read[0]);
      else aftertouchChange(0xD1 ,fsr_Read[0]);
      at_counter[0] = 0;
        
      }
     }
      
       if (attack_counter[0] < ATTACK) attack_counter[0] = attack_counter[0] + 1;
      
       fsr_Read_Old[0] = fsr_Read[0]; 

    }
    if (fsr_Read[0] > (fsr_Init[0] - 30) && fsr_Touched[0]) {
 
      if (channel_Mode)  aftertouchChange(0xD1 + CHANNEL_OFFSET, 0);
      else aftertouchChange(0xD1 ,0);
 
      fsr_Touched[0] = 0;   
  
    } 
} else {
  fsr_Touched[0] = 0;
  if (fsr_Read[0] < (fsr_Init[0] - 30)) c = 0;
}
 }
    //read the value of all the softPots
    soft_Pot_Vals[0] = analogRead(soft_Pot_Pins[0]);
    soft_Pot_Vals[0] = map(soft_Pot_Vals[0], calibration_Min[0], MAXREADING, 0, 255);
   soft_Pot_Vals[0] = constrain(soft_Pot_Vals[0], 0, 255);
   
   // read the string_fsr and process it...send on string channel poly aftertouch
   string_Fsr_Vals[0] = analogRead(string_Fsr_Pins[0])>>1;
  
   if ((string_Fsr_Vals[0] < (string_Fsr_Init[0] - 30)) && string_Active[0]) {
    string_fsr_active[0] = 1;
    unsigned int map_string_Fsr = map_fsr_string[constrain(string_Fsr_Vals[0] - 30,0,1005)];
    if (map_string_Fsr - string_Fsr_Old[0]) {
      fsr_counter[0] = fsr_counter[0] + 1;
      if (fsr_counter[0] == AFTERTOUCH_RATE) {
    if (channel_Mode) {
      usbMIDI.sendPolyPressure(active_Note[0],map_string_Fsr, c + CHANNEL_OFFSET + 2);
      for (int i=0; i<7; i++) {
        if (i != footpedal) {
midilist[i]->sendPolyPressure(active_Note[0],map_string_Fsr, c + CHANNEL_OFFSET + 2);
midilist[i]->send_now();
        }
}
    }
    else {
      usbMIDI.sendPolyPressure(active_Note[0],map_string_Fsr, 2);
    for (int i=0; i<7; i++) {
      if (i != footpedal) {
midilist[i]->sendPolyPressure(active_Note[0],map_string_Fsr, 2);
midilist[i]->send_now();
      }
}
    }
   
        fsr_counter[0] = 0;
      }
      string_Fsr_Old[0] = map_string_Fsr;
    }
   } else string_fsr_active[0] = 0;

//--STRING TWO--//
 if(!fsr_Add_Touched && !fsr_Foot_Touched && !fsr_Arp_Touched) {
  if (!channel_Mode) fret_touch = fret_Touched[1];
   fsr_Read[1] = analogRead(fsr_Pins[1])>>1;
     if (fret_touch) {
    if (fsr_Read[1] < (fsr_Init[1] - 50) && !fsr_Touched[1]) {
      attack_counter[1] = 0;
    //  fsr_Vals[1] = map((fsr_Read[1]), fsr_Init[1] - 30, 60, MINVELOCITY, 127);
    fsr_Vals[1] = 80;
      fsr_Touched[1] = 1;
      c= 1;
    }
    if (fsr_Read[1] < (fsr_Init[1] - 35) && fsr_Touched[1]) {
     
   fsr_Read[1] = map_fsr[constrain(fsr_Read[1] - 30,0,1005) ];
       if ((fsr_Read[1] - fsr_Read_Old[1]) && attack_counter[1]) {
         at_counter[1] = at_counter[1] + 1;
      if (at_counter[1] == AFTERTOUCH_RATE) {
      
      if (channel_Mode)  aftertouchChange(0xD2 + CHANNEL_OFFSET, fsr_Read[1]);
      else aftertouchChange(0xD2 ,fsr_Read[1]);
      at_counter[1] = 0;
        
      }
       }
      
       if (attack_counter[1] < ATTACK) attack_counter[1] = attack_counter[1] + 1;
        
       fsr_Read_Old[1] = fsr_Read[1]; 
    }
    if (fsr_Read[1] > (fsr_Init[1] - 30) && fsr_Touched[1]) {
    
        if (channel_Mode)  aftertouchChange(0xD2 + CHANNEL_OFFSET, 0);
      else aftertouchChange(0xD2 ,0);
     
      fsr_Touched[1] = 0;
    }    
} else {
  fsr_Touched[1] = 0;
  if (fsr_Read[1] < (fsr_Init[1] - 30)) c = 1;
}
 }
    //read the value of all the softPots
    soft_Pot_Vals[1] = analogRead(soft_Pot_Pins[1]);
    soft_Pot_Vals[1] = map(soft_Pot_Vals[1], calibration_Min[1], MAXREADING, 0, 255);
   soft_Pot_Vals[1] = constrain(soft_Pot_Vals[1], 0, 255);
   string_Fsr_Vals[1] = analogRead(string_Fsr_Pins[1])>>1;

// read the string_fsr and process it...send on string channel poly aftertouch
   string_Fsr_Vals[1] = analogRead(string_Fsr_Pins[1])>>1;
  
   if ((string_Fsr_Vals[1] < (string_Fsr_Init[1] - 30)) && string_Active[1]) {
    string_fsr_active[1] = 1;
    unsigned int map_string_Fsr = map_fsr_string[constrain(string_Fsr_Vals[1] - 30,0,1005)];
    if (map_string_Fsr - string_Fsr_Old[1]) {
      fsr_counter[1] = fsr_counter[1] + 1;
      if (fsr_counter[1] == AFTERTOUCH_RATE) {
    if (channel_Mode) {
      usbMIDI.sendPolyPressure(active_Note[1],map_string_Fsr, c + CHANNEL_OFFSET + 2);
    for (int i=0; i<7; i++) {
      if (i != footpedal) {
midilist[i]->sendPolyPressure(active_Note[1],map_string_Fsr, c + CHANNEL_OFFSET + 2);
midilist[i]->send_now();
}
    }
    }
    else {
      usbMIDI.sendPolyPressure(active_Note[1],map_string_Fsr, 3);
     for (int i=0; i<7; i++) {
      if (i != footpedal) {
midilist[i]->sendPolyPressure(active_Note[1],map_string_Fsr, 3);
midilist[i]->send_now();
}
     }
    }
   
        fsr_counter[1] = 0;
      }
      string_Fsr_Old[1] = map_string_Fsr;
    }
   } else string_fsr_active[1] = 0;

//-STRING THREE--//
 if(!fsr_Add_Touched && !fsr_Foot_Touched && !fsr_Arp_Touched) {
 if (!channel_Mode) fret_touch = fret_Touched[2];
 fsr_Read[2] = analogRead(fsr_Pins[2])>>1;
     if (fret_touch) {
    if (fsr_Read[2] < (fsr_Init[2] - 50) && !fsr_Touched[2]) {
      attack_counter[2] = 0;
     
     // fsr_Vals[2] = map((fsr_Read[2]), fsr_Init[2] - 30, 60, MINVELOCITY, 127);
     fsr_Vals[2] = 80;
      fsr_Touched[2] = 1;
      c= 2;
    }
    if (fsr_Read[2] < (fsr_Init[2] - 35) && fsr_Touched[2]) {
     
   fsr_Read[2] = map_fsr[constrain(fsr_Read[2] - 30,0,1005) ];
        if ((fsr_Read[2] - fsr_Read_Old[2]) && attack_counter[2]) {
           at_counter[2] = at_counter[2] + 1;
      if (at_counter[2] == AFTERTOUCH_RATE) {
     
      if (channel_Mode)  aftertouchChange(0xD3 + CHANNEL_OFFSET, fsr_Read[2]);
      else aftertouchChange(0xD3 ,fsr_Read[2]);
      at_counter[2] = 0;
      
      }
        }
      
       if (attack_counter[2] < ATTACK) attack_counter[2] = attack_counter[2] + 1;
        
       fsr_Read_Old[2] = fsr_Read[2]; 
    }
    if (fsr_Read[2] > (fsr_Init[2] - 30) && fsr_Touched[2]) {
   
        if (channel_Mode)  aftertouchChange(0xD2 + CHANNEL_OFFSET, 0);
      else aftertouchChange(0xD2 ,0);
   
      fsr_Touched[2] = 0;
    }  
} else {
  fsr_Touched[2] = 0;
  if (fsr_Read[2] < (fsr_Init[2] - 30)) c = 2;
}
 }
    //read the value of all the softPots
    soft_Pot_Vals[2] = analogRead(soft_Pot_Pins[2]);
    soft_Pot_Vals[2] = map(soft_Pot_Vals[2], calibration_Min[2], MAXREADING, 0, 255);
   soft_Pot_Vals[2] = constrain(soft_Pot_Vals[2], 0, 255);
      string_Fsr_Vals[2] = analogRead(string_Fsr_Pins[2])>>1;

// read the string_fsr and process it...send on string channel poly aftertouch
   string_Fsr_Vals[2] = analogRead(string_Fsr_Pins[2])>>1;
  
   if ((string_Fsr_Vals[2] < (string_Fsr_Init[2] - 30)) && string_Active[2]) {
    string_fsr_active[2] = 1;
    unsigned int map_string_Fsr = map_fsr_string[constrain(string_Fsr_Vals[2] - 30,0,1005)];
    if (map_string_Fsr - string_Fsr_Old[2]) {
      fsr_counter[2] = fsr_counter[2] + 1;
      if (fsr_counter[2] == AFTERTOUCH_RATE) {
    if (channel_Mode) {
      usbMIDI.sendPolyPressure(active_Note[2],map_string_Fsr, c + CHANNEL_OFFSET + 2);
    for (int i=0; i<7; i++) {
      if (i != footpedal) {
midilist[i]->sendPolyPressure(active_Note[2],map_string_Fsr, c + CHANNEL_OFFSET + 2);
midilist[i]->send_now();
}
    }
    }
    else {
      usbMIDI.sendPolyPressure(active_Note[2],map_string_Fsr,4);
   for (int i=0; i<7; i++) {
    if (i != footpedal) {
midilist[i]->sendPolyPressure(active_Note[2],map_string_Fsr,4);
midilist[i]->send_now();
}
   }
    }
   
        fsr_counter[2] = 0;
      }
      string_Fsr_Old[2] = map_string_Fsr;
    }
   } else string_fsr_active[2] = 0;

//-- STRING FOUR--//
if(!fsr_Add_Touched && !fsr_Foot_Touched && !fsr_Arp_Touched) {
  if (!channel_Mode) fret_touch = fret_Touched[3];
 fsr_Read[3] = analogRead(fsr_Pins[3])>>1;
    if (fret_touch) {
    if (fsr_Read[3] < (fsr_Init[3] - 50) && !fsr_Touched[3]) {
      attack_counter[3] = 0;
      
   //   fsr_Vals[3] = map((fsr_Read[3]), fsr_Init[3] - 30, 60, MINVELOCITY, 127);
   fsr_Vals[3] = 80;
      fsr_Touched[3] = 1;
      c=3;
    }
    if (fsr_Read[3] < (fsr_Init[3] - 35) && fsr_Touched[3]) {
     
   fsr_Read[3] = map_fsr[constrain(fsr_Read[3] - 30,0,1005) ];
       if ((fsr_Read[3] - fsr_Read_Old[3]) && attack_counter[3]) {
         at_counter[3] = at_counter[3] + 1;
      if (at_counter[3] == AFTERTOUCH_RATE) {
       
      if (channel_Mode)  aftertouchChange(0xD4 + CHANNEL_OFFSET, fsr_Read[3]);
      else aftertouchChange(0xD4 ,fsr_Read[3]);
      at_counter[3] = 0;
        
      }
       }
       
       if (attack_counter[3] < ATTACK) attack_counter[3] = attack_counter[3] + 1;
      
      fsr_Read_Old[3] = fsr_Read[3];
    }
    if (fsr_Read[3] > (fsr_Init[3] - 30) && fsr_Touched[3]) {
   
        if (channel_Mode)  aftertouchChange(0xD3 + CHANNEL_OFFSET, 0);
      else aftertouchChange(0xD3 ,0);
     
      fsr_Touched[3] = 0;
    } 
    }  else {
  fsr_Touched[3] = 0;
  if (fsr_Read[3] < (fsr_Init[3] - 30)) c = 3;
}
}
    //read the value of all the softPots
    soft_Pot_Vals[3] = analogRead(soft_Pot_Pins[3]);
    soft_Pot_Vals[3] = map(soft_Pot_Vals[3], calibration_Min[3], MAXREADING, 0, 255);
   soft_Pot_Vals[3] = constrain(soft_Pot_Vals[3], 0, 255);
      string_Fsr_Vals[3] = analogRead(string_Fsr_Pins[3])>>1;

// read the string_fsr and process it...send on string channel poly aftertouch
   string_Fsr_Vals[3] = analogRead(string_Fsr_Pins[3])>>1;
  
   if ((string_Fsr_Vals[3] < (string_Fsr_Init[3] - 30)) && string_Active[3]) {
    string_fsr_active[3] = 1;
    unsigned int map_string_Fsr = map_fsr_string[constrain(string_Fsr_Vals[3] - 30,0,1005)];
    if (map_string_Fsr - string_Fsr_Old[3]) {
      fsr_counter[3] = fsr_counter[3] + 1;
      if (fsr_counter[3] == AFTERTOUCH_RATE) {
    if (channel_Mode) {
      usbMIDI.sendPolyPressure(active_Note[3],map_string_Fsr, c + CHANNEL_OFFSET + 2);
      for (int i=0; i<7; i++) {
        if (i != footpedal) {
midilist[i]->sendPolyPressure(active_Note[3],map_string_Fsr, c + CHANNEL_OFFSET + 2);
midilist[i]->send_now();
}
      }
    }
    else {
      usbMIDI.sendPolyPressure(active_Note[3],map_string_Fsr, 5);
      for (int i=0; i<7; i++) {
        if (i != footpedal) {
midilist[i]->sendPolyPressure(active_Note[3],map_string_Fsr, 5);
midilist[i]->send_now();
}
      }
    }
   
        fsr_counter[3] = 0;
      }
      string_Fsr_Old[3] = map_string_Fsr;
    }
   } else string_fsr_active[3] = 0;

//}
  
 //------------------DETERMINE FRETS----------------------//
 
    //---------Get Fret Numbers------//

    //--STRING ONE--//
 
   byte soft_Pot_Val = soft_Pot_Vals[0];
   
    //check for open strings
    if (soft_Pot_Val == 255) {
      soft_Pot_Vals_Old[0] = soft_Pot_Val;
      fret_Touched[0]=0;
    }
    
    //loop through the array of fret definitions
    for (byte j=1; j<24; j++) {
      
      byte k = j-1;
     if (soft_Pot_Val <= fret_Defs[0][k] && 
          soft_Pot_Val > fret_Defs[0][j] ) {
            
if (((uint8_t)(abs( (int8_t) (soft_Pot_Val-soft_Pot_Vals_Old[0]))) > PADDING)) {
  soft_Pot_Vals_Old[0] = soft_Pot_Val;
            fret_Touched[0] = j;
    
            break;
  
  } 
    }
    }
    
    if (soft_Pot_Val <= fret_Defs[0][23]) {
      soft_Pot_Vals_Old[0] = soft_Pot_Val;
      fret_Touched[0]=24;
    
    }

//--STRING TWO--//

   soft_Pot_Val = soft_Pot_Vals[1];
    
    //check for open strings
    if (soft_Pot_Val == 255) {
      soft_Pot_Vals_Old[1] = soft_Pot_Val;
      fret_Touched[1]=0;
    }
    
    //loop through the array of fret definitions
    for (byte j=1; j<24; j++) {
      
      byte k = j-1;
     if (soft_Pot_Val <= fret_Defs[1][k] && 
          soft_Pot_Val > fret_Defs[1][j] ) {
if (((uint8_t)(abs( (int8_t) (soft_Pot_Val-soft_Pot_Vals_Old[1]))) > PADDING)) {
  
  soft_Pot_Vals_Old[1] = soft_Pot_Val;
            fret_Touched[1] = j;

            break;
} 
  }
    }
    
    if (soft_Pot_Val <= fret_Defs[1][23]) {
      soft_Pot_Vals_Old[1] = soft_Pot_Val;
      fret_Touched[1]=24;
     
    }

    //--STRING THREE--//

       soft_Pot_Val = soft_Pot_Vals[2];
   
    //check for open strings
    if (soft_Pot_Val == 255) {
      soft_Pot_Vals_Old[2] = soft_Pot_Val;
      fret_Touched[2]=0;
    }
    
    //loop through the array of fret definitions
    for (byte j=1; j<24; j++) {
      
      byte k = j-1;
     if (soft_Pot_Val <= fret_Defs[2][k] && 
          soft_Pot_Val > fret_Defs[2][j]) {
            
         
if(((uint8_t)(abs( (int8_t) (soft_Pot_Val-soft_Pot_Vals_Old[2]))) > PADDING)) {
  
  soft_Pot_Vals_Old[2] = soft_Pot_Val;
            fret_Touched[2] = j;
 
            break;
} 

  }
    }
    
    if (soft_Pot_Val <= fret_Defs[2][23]) {
      soft_Pot_Vals_Old[2] = soft_Pot_Val;
      fret_Touched[2]=24;
  
  
      
    }

    //---STRING FOUR--//

       soft_Pot_Val = soft_Pot_Vals[3];
   
    //check for open strings
    if (soft_Pot_Val == 255) {
      soft_Pot_Vals_Old[3] = soft_Pot_Val;
      fret_Touched[3]=0;
    }
    
    //loop through the array of fret definitions
    for (byte j=1; j<24; j++) {
      
      byte k = j-1;
     if (soft_Pot_Val <= fret_Defs[3][k] && 
          soft_Pot_Val > fret_Defs[3][j] ) {
if (((uint8_t)(abs( (int8_t) (soft_Pot_Val-soft_Pot_Vals_Old[3]))) > PADDING)) {
  
  soft_Pot_Vals_Old[3] = soft_Pot_Val;
            fret_Touched[3] = j;
           
            break;
} 

  }
    }
    
    if (soft_Pot_Val <= fret_Defs[3][23]) {
      soft_Pot_Vals_Old[3] = soft_Pot_Val;
      fret_Touched[3]=24;
     
      
    }
  
 
   //test for legato action
   byte enable_legato;
   if (channel_Mode) {
    if(attack_counter[c] < ATTACK_LEGATO && fsr_Add_Touched) enable_legato = 0;
    else enable_legato = 1;
   }
 //----STRING ONE--//
 
      if (!channel_Mode) {
       if(attack_counter[0] < ATTACK_LEGATO && fsr_Add_Touched) enable_legato = 0;
    else enable_legato = 1;
    c = 0;
    old_c = 0;
    }
  
    if (string_Active[0] ) {
      if (enable_legato ) {
       if (fret_Touched[0]) note_Fretted[0] = fret_Touched[0] + offsets[0];
  
   if (note_Fretted[0] > active_Note[0]) {
   
      //turn on new note
   noteOn(0x91 + c, note_Fretted[0], 80);
        noteOn(0x91 + old_c, active_Note[0], 0);
     
      
      //register new note as the active one
      active_Note[0] = note_Fretted[0];
     
     
   } 
  else if ((note_Fretted[0] < active_Note[0]) && string_fsr_active[0]) {
    if (note_Fretted[0] == maybe_Note[0]) stable_Count[0] += 1;
    if (stable_Count[0] == STABLETIME) {
   noteOn(0x91 + c, note_Fretted[0], 80);
        noteOn(0x91 + old_c, active_Note[0], 0);
     
      
      //register new note as the active one
      active_Note[0] = note_Fretted[0];
      stable_Count[0] = 0;
   //  maybe_Note[0] = 0;
    }
   maybe_Note[0] = note_Fretted[0];
   } 
    }
    }
    
else if (fret_Touched[0] && fsr_Touched[c] && !fsr_Vals[c]) {
   
          note_Fretted[0] = fret_Touched[0] + offsets[0];
   

      

    noteOn(0x91 +c, note_Fretted[0], 80);
   
        //register new note as the active one
        active_Note[0] = note_Fretted[0];
      
        string_Active[0] = true;

    }
 
  //----STRING TWO--//
 
      if (!channel_Mode) {
         if(attack_counter[1] < ATTACK_LEGATO && fsr_Add_Touched) enable_legato = 0;
    else enable_legato = 1;
    c = 1;
    old_c = 1;
    }
   
    if (string_Active[1] ) {
       if (enable_legato ) {
     if (fret_Touched[1])   note_Fretted[1] = fret_Touched[1] + offsets[1];
 
   if (note_Fretted[1] > active_Note[1]) {
    
      //turn on new note

     noteOn(0x91 + c, note_Fretted[1], 80);
        noteOn(0x91 + old_c, active_Note[1], 0);
    
      
      //register new note as the active one
      active_Note[1] = note_Fretted[1];
    
      
   } 
   else if ((note_Fretted[1] < active_Note[1]) && string_fsr_active[1]) {
    if (note_Fretted[1] == maybe_Note[1]) stable_Count[1] += 1;
    if (stable_Count[1] == STABLETIME) {
   noteOn(0x91 + c, note_Fretted[1], 80);
        noteOn(0x91 + old_c, active_Note[1], 0);
     
      
      //register new note as the active one
      active_Note[1] = note_Fretted[1];
     stable_Count[1] = 0;
  //    maybe_Note[1] = 0;
    }
    maybe_Note[1] = note_Fretted[1];
   }
    }
    }
else if (fret_Touched[1] && fsr_Touched[c] && !fsr_Vals[c]) {
   
          note_Fretted[1] = fret_Touched[1] + offsets[1];
 
    noteOn(0x91 +c, note_Fretted[1], 80);
   
        //register new note as the active one
        active_Note[1] = note_Fretted[1];
       
        string_Active[1] = true;

    }
  
    //----STRING THREE--//
 
      if (!channel_Mode) {
         if(attack_counter[2] < ATTACK_LEGATO && fsr_Add_Touched) enable_legato = 0;
    else enable_legato = 1;
    c = 2;
    old_c = 2;
    }
  
    if (string_Active[2] ) {
       if (enable_legato) {
      if (fret_Touched[2])    note_Fretted[2] = fret_Touched[2] + offsets[2];

   if (note_Fretted[2] > active_Note[2]) {
    
      //turn on new note

    noteOn(0x91 + c, note_Fretted[2], 80);
        noteOn(0x91 + old_c, active_Note[2], 0);
   
      
      //register new note as the active one
      active_Note[2] = note_Fretted[2];
   
     
   } 
   
  else if ((note_Fretted[2] < active_Note[2]) && string_fsr_active[2]) {
    if (note_Fretted[2] == maybe_Note[2]) stable_Count[2] += 1;
    if (stable_Count[2] == STABLETIME) {
      noteOn(0x91 + c, note_Fretted[2], 80);
        noteOn(0x91 + old_c, active_Note[2], 0);
     
      
      //register new note as the active one
      active_Note[2] = note_Fretted[2];
      stable_Count[2] = 0;
    //  maybe_Note[2] = 0;
    }
    maybe_Note[2] = note_Fretted[2];
   }
    }
    }
 else if (fret_Touched[2] && fsr_Touched[c] && !fsr_Vals[c] ) {
   
          note_Fretted[2] = fret_Touched[2] + offsets[2];
   

      noteOn(0x91 +c, note_Fretted[2], 80);
      
        //register new note as the active one
        active_Note[2] = note_Fretted[2];
      
        string_Active[2] = true;

    }
      
    //----STRING FOUR--//
 
      if (!channel_Mode) {
         if(attack_counter[3] < ATTACK_LEGATO && fsr_Add_Touched) enable_legato = 0;
    else enable_legato = 1;
    c = 3;
    old_c = 3;
      }
   
    if (string_Active[3] ) {
       if (enable_legato) {
        if (fret_Touched[3])  note_Fretted[3] = fret_Touched[3] + offsets[3];

   if (note_Fretted[3] > active_Note[3]) {
    
      //turn on new note

    noteOn(0x91 + c, note_Fretted[3], 80);
        noteOn(0x91 + old_c, active_Note[3], 0);
    
      
      //register new note as the active one
      active_Note[3] = note_Fretted[3];
    
     
   } 
   else if ((note_Fretted[3] < active_Note[3]) && string_fsr_active[3]) {
    if (note_Fretted[3] == maybe_Note[3]) stable_Count[3] += 1;
    if (stable_Count[3] == STABLETIME) {
       noteOn(0x91 + c, note_Fretted[3], 80);
        noteOn(0x91 + old_c, active_Note[3], 0);
     
      
      //register new note as the active one
      active_Note[3] = note_Fretted[3];
      stable_Count[3] = 0;
  //   maybe_Note[3] = 0;
    }
    maybe_Note[3] = note_Fretted[3];
   }
    }
    }
 else if (fret_Touched[3] && fsr_Touched[c] && !fsr_Vals[c]) {
   
          note_Fretted[3] = fret_Touched[3] + offsets[3];
   
  
   noteOn(0x91 +c, note_Fretted[3], 80);
  
        //register new note as the active one
        active_Note[3] = note_Fretted[3];
       
        string_Active[3] = true;
    }
     
  //------------PICK NOTES--------------------//
  
   //use this info to determine which notes to pluck

  
  //---STRING ONE----//

    if (!channel_Mode) {
    c = 0;
    old_c = 0;
    }
    //if the fsr was hit, play the fretted note
    if ((fsr_Vals[c] && fret_Touched[0]) ){
          note_Fretted[0] = fret_Touched[0] + offsets[0];
   
      
      if (string_Active[0]){
 if (!fsr_Foot_Touched) noteOn(0x91 + old_c , active_Note[0], 0);
      
        }
      
      if (!string_Active[0]) {
        
        //mark string as active
        string_Active[0] = true;
      }
        //register with active notes
        
        active_Note[0] = note_Fretted[0];
       // active_Velo[0] = fsr_Vals[c];
    
       
      
        //turn on fretted note
  if (!fsr_Foot_Touched)  noteOn(0x91 + c, active_Note[0], 80);
      
      }

      //---STRING TWO----//
    if (!channel_Mode) {
    c = 1;
    old_c = 1;
    }
    //if the fsr was hit, play the fretted note
    if ((fsr_Vals[c] && fret_Touched[1]) ){
          note_Fretted[1] = fret_Touched[1] + offsets[1];
   
      
      if (string_Active[1]){
      if (!fsr_Foot_Touched)  noteOn(0x91 + old_c , active_Note[1], 0);
      
        }
      
      if (!string_Active[1]) {
        
        //mark string as active
        string_Active[1] = true;
      }
        //register with active notes
        
        active_Note[1] = note_Fretted[1];
     //   active_Velo[1] = fsr_Vals[c];
    
     
        
        //turn on fretted note
     if (!fsr_Foot_Touched)   noteOn(0x91 + c, active_Note[1], 80);
      
      }

      //---STRING THREE----//
    if (!channel_Mode) {
    c = 2;
    old_c = 2;
    }
    //if the fsr was hit, play the fretted note
    if ((fsr_Vals[c] && fret_Touched[2]) ){
          note_Fretted[2] = fret_Touched[2] + offsets[2];
   
      
      if (string_Active[2]){
       if (!fsr_Foot_Touched) noteOn(0x91 + old_c , active_Note[2], 0);
       
        }
      
      if (!string_Active[2]) {
        
        //mark string as active
        string_Active[2] = true;
      }
        //register with active notes
        
        active_Note[2] = note_Fretted[2];
     //   active_Velo[2] = fsr_Vals[c];
    
      
        
        //turn on fretted note
       if (!fsr_Foot_Touched)  noteOn(0x91 + c, active_Note[2], 80);
      
      }

      //---STRING FOUR----//
    if (!channel_Mode) {
    c = 3;
    old_c = 3;
    }
    //if the fsr was hit, play the fretted note
    if ((fsr_Vals[c] && fret_Touched[3]) ){
          note_Fretted[3] = fret_Touched[3] + offsets[3];
   
      
      if (string_Active[3]){
      if (!fsr_Foot_Touched)  noteOn(0x91 + old_c , active_Note[3], 0);
      
        }
      
      if (!string_Active[3]) {
        
        //mark string as active
        string_Active[3] = true;
      }
        //register with active notes
        
        active_Note[3] = note_Fretted[3];
    //    active_Velo[3] = fsr_Vals[c];
    
       
        
        //turn on fretted note
     if (!fsr_Foot_Touched)    noteOn(0x91 + c, active_Note[3], 80);
      
      }
    
  
    //------------------CLEAN UP------------------------//
    
  //send not off messages and reset necessary things

//---STRING ONE----//
       if (!channel_Mode) {
    c = 0;
    old_c = 0;
    }

    //no fret is touched and the string is marked active
    if (!fret_Touched[0] && string_Active[0]) {
     
          noteOn(0x91 + old_c, active_Note[0], 0);
 
      string_Active[0] = false;
     
    }
    if (!fsr_Touched[c] && string_Active[0] && (attack_counter[c] < ATTACK || bow_Mode)) {
       noteOn(0x91 + old_c, active_Note[0], 0);
      string_Active[0] = false;
      
    }

//---STRING TWO----//
       if (!channel_Mode) {
    c = 1;
    old_c = 1;
    }

    //no fret is touched and the string is marked active
    if (!fret_Touched[1] && string_Active[1]) { 
     
          noteOn(0x91 + old_c, active_Note[1], 0);
   
      string_Active[1] = false;
     
    }
if (!fsr_Touched[c] && string_Active[1] && (attack_counter[c] < ATTACK || bow_Mode)){
    noteOn(0x91 + old_c, active_Note[1], 0);
      string_Active[1] = false;
     
}
//---STRING THREE----//
       if (!channel_Mode) {
    c = 2;
    old_c = 2;
    }

    //no fret is touched and the string is marked active
    if (!fret_Touched[2] && string_Active[2]) { 
       
   
          noteOn(0x91 + old_c, active_Note[2], 0);
  
      string_Active[2] = false;
     
    }
if (!fsr_Touched[c] && string_Active[2] && (attack_counter[c] < ATTACK || bow_Mode)) {
     noteOn(0x91 + old_c, active_Note[2], 0);
      string_Active[2] = false;
      
}
//---STRING FOUR----//
       if (!channel_Mode) {
    c = 3;
    old_c = 3;
    }

    //no fret is touched and the string is marked active
    if (!fret_Touched[3] && string_Active[3]) { 
       
          noteOn(0x91 + old_c, active_Note[3], 0);
  
      string_Active[3] = false;
     
    }
if (!fsr_Touched[c] && string_Active[3] && (attack_counter[c] < ATTACK || bow_Mode)) {
        noteOn(0x91 + old_c, active_Note[3], 0);
      string_Active[3] = false;
     
}
// }
 old_c = c;
 
 //------------------READ CONTROLS-----------------//
 byte is_Hit = fsr_Vals[0] + fsr_Vals[1] + fsr_Vals[2] + fsr_Vals[3]; 
 byte any_Active = string_Active[0] + string_Active[1] + string_Active[2] + string_Active[3];
 //check for control changes
byte channel_button = !digitalRead(PIN_BUTTON_CHANNEL);
byte panic_button = !digitalRead(PIN_BUTTON_PANIC);
byte fsr_button = !digitalRead(PIN_BUTTON_FSR);
 button_read = (channel_button << 2) | (panic_button << 1) | fsr_button;
 
 if (button_read){
  if(button_count < (BUTTONPRESS + 2)) {
 
  button_count = button_count + 1;
 }
 }else {
  button_count = 0;
 }

 if (button_count == BUTTONPRESS) {
  switch (button_read) {
    case 1: 
    fsr_Add_Slave_Mode = !fsr_Add_Slave_Mode;
    if (!fsr_Add_Slave_Mode) u8x8.drawString(7,0,"FIX");
    else u8x8.drawString(7,0,"DYN");   
    break;
    case 2:
    //mute all midi, release hanging notes etc.
    controllerAllChannels(123,0);
    break;
    case 3:
 //calibrate accelerometer
  
    break;
    case 4:
    channel_Mode = !channel_Mode;
      if (!channel_Mode) u8x8.drawString(0,0,"MPE ");
  else u8x8.drawString(0,0,"POLY");
    break;
    case 5:
    saveSettings();
    break;
    case 6:
    bow_Mode = !bow_Mode;
    break;
 
  }
 }

  
//---- CHANGING THE OCTAVE -------//
  //UP and down buttons to change offset/octave.
  
  //---- UP BUTTON ----
  if (digitalRead(PIN_OCTAVE_UP) == LOW) {
     if (!button_States[UP]) {
      if (octave < 1) octave = 1;
        octave = octave - 1;
        byte string_base = 12*octave + LOWEST_NOTE;
        offsets[0] = string_base; 
        offsets[1] = string_base + 5; 
        offsets[2] = string_base + 10; 
        offsets[3] = string_base + 15; 
        enum {BufSize=3}; // If a is short use a smaller number, eg 5 or 6 
            char buf[BufSize];
            snprintf (buf, BufSize, "%d", octave);
        u8x8.drawString(5,50,buf);          
    }
    
    button_States[UP] = true;
       
  
  }
  //reset state once button is no longer being pressed
  if (digitalRead(PIN_OCTAVE_UP) == HIGH && button_States[UP]) button_States[UP] = false;
  
  //----DOWN BUTTON----
  if (digitalRead(PIN_OCTAVE_DOWN) == LOW) {
    if (!button_States[DOWN]) {
      
      octave = octave + 1;
      if (octave > 7) octave = 7;
      byte string_base = 12*octave + LOWEST_NOTE;
        offsets[0] = string_base; 
        offsets[1] = string_base + 5; 
        offsets[2] = string_base + 10; 
        offsets[3] = string_base + 15;           
   enum {BufSize=3}; // If a is short use a smaller number, eg 5 or 6 
            char buf[BufSize];
            snprintf (buf, BufSize, "%d", octave);
        u8x8.drawString(5,50,buf);  
    }
    
    button_States[DOWN] = true;
  }
  //reset state once button is no longer being pressed
  if (digitalRead(PIN_OCTAVE_DOWN) == HIGH && button_States[DOWN]) button_States[DOWN] = false;


  if (!is_Hit && any_Active) {
      int stick_x = analogRead(PIN_JOYSTICK_X);
      int stick_y = analogRead(PIN_JOYSTICK_Y);
      int accel_y = analogRead(PIN_ACCEL_Y);
      int accel_z = analogRead(PIN_ACCEL_Z);
      int accel_x = analogRead(PIN_ACCEL_X);
      int wheel = analogRead(PIN_WHEEL);
      int read_Hothand_x = analogRead(PIN_HOTHAND_X);
      int read_Hothand_y = analogRead(PIN_HOTHAND_Y);
     
      accel_average_y = accel_average_y + accel_y;
      accel_average_z = accel_average_z + accel_z;
      accel_average_x = accel_average_x + accel_x;
      wheel_average = wheel_average + wheel;

      stick_average = stick_average + stick_x;
      stick_average_y = stick_average_y + stick_y;

      hothand_average_x = hothand_average_x + read_Hothand_x;
      hothand_average_y = hothand_average_y + read_Hothand_y;
      
    if (control_counter == CONTROL_RATE) {
     stick_x = stick_average / CONTROL_RATE; //actually wrong but i did all the math later already...
     stick_y = stick_average_y / CONTROL_RATE;
     accel_y = accel_average_y / (CONTROL_RATE);
     accel_z = accel_average_z / (CONTROL_RATE);
     accel_x = accel_average_x / (CONTROL_RATE);
     wheel = wheel_average / (CONTROL_RATE + 1);
     read_Hothand_x = hothand_average_x / CONTROL_RATE;
     read_Hothand_y = hothand_average_y / CONTROL_RATE;
     
     stick_average = 0;
     stick_average_y = 0;
     accel_average_y = 0;
     accel_average_z = 0;
     accel_average_x = 0;
     wheel_average = 0;
     hothand_average_x = 0;
     hothand_average_y = 0;
     
     
    control_counter = 0;
    //read positions from joystick center
    
    int bend;
    if (abs(stick_x - stick_Zero_X) > 70) {
      is_Middle_stick_x = 0;
      bend = map(stick_x, 60, 2040, -8192, 8191);
      bend = constrain(bend, -8192,8191);
      bend = bend;

       if (abs(stick_x - stick_x_old)>1) {
        usbMIDI.sendPitchBend(bend, 1);
        for (int i=0; i<7; i++) {
          if (i != footpedal) {
          if (!channel_Mode) {
midilist[i]->sendPitchBend(bend, 2);
midilist[i]->sendPitchBend(bend, 3);
midilist[i]->sendPitchBend(bend, 4);
midilist[i]->sendPitchBend(bend, 5);
midilist[i]->send_now();
          } else {
midilist[i]->sendPitchBend(bend, 2 + c + CHANNEL_OFFSET);
midilist[i]->send_now();
          }
}
        }
       }
         
    stick_x_old = stick_x;
    } else {
      if (!is_Middle_stick_x) {
        usbMIDI.sendPitchBend(0, 1);
        for (int i=0; i<7; i++) {
          if (i != footpedal) {
          if (!channel_Mode) {
midilist[i]->sendPitchBend(0, 2);
midilist[i]->sendPitchBend(0, 3);
midilist[i]->sendPitchBend(0, 4);
midilist[i]->sendPitchBend(0, 5);
midilist[i]->send_now();
          } else {
midilist[i]->sendPitchBend(0, 2 + c + CHANNEL_OFFSET);
midilist[i]->send_now();
          }
          
}
        }
        is_Middle_stick_x = 1;
      }
    }

    
    
    byte yPos;
    byte yPos2;
    if (stick_y > (stick_Zero_Y + 4)) {
      yPos2 = 0;
      yPos = map(stick_y, stick_Zero_Y+4, 2020, 0, 127);
    if (yPos >= 127) yPos = 127;
    }
    else if (stick_y < (stick_Zero_Y - 4)) { 
      yPos = 0;
      yPos2 = map(stick_y,stick_Zero_Y - 4,20, 0, 127);
    if (yPos2 >= 127) yPos2 = 127;
    } else {
      yPos = 0;
      yPos2 = 0; 
    }

       if (yPos - y_Pos_old)    controllerChange(1, yPos);  
    y_Pos_old = yPos;
        if (yPos2 - y_Pos2_old) controllerChange(2, yPos2);
    y_Pos2_old = yPos2;

    //accelerometer y
    accel_y = map(accel_y,840,1168,0,127);
    accel_y = constrain(accel_y,0,127); 
    if (accel_y - accel_y_old) controllerChange(3, accel_y);
        accel_y_old = accel_y;
        
    //accelerometer_z    
accel_z = map(accel_z,800,1300,0,127);
    accel_z = constrain(accel_z,0,127); 
    if (accel_z - accel_z_old) controllerChange(4, accel_z);
        accel_z_old = accel_z;
        
//accelerometer x
accel_x = map(accel_x,300,1300,0,127);
    accel_x = constrain(accel_x,0,127); 
    if (accel_x - accel_x_old) controllerChange(6, accel_x);
        accel_x_old = accel_x;
        
//lfo wheel  
//int wheel_full = wheel;
wheel = map(wheel,0,1935,0,2000);
wheel = constrain(wheel,0,2000);

wheel_counter = (wheel_counter + 1) % 40;
int wheel_midi = map_wheel[wheel%500];

wheel_array[wheel_counter] = wheel_midi;
wheel_stable = 0;
for (int i=0; i<40; i++) {
  if (abs(wheel_midi - wheel_array[i]) < 4) wheel_stable = wheel_stable + 1;
}

if ((wheel_midi - wheel_old) && (wheel_stable < 39)) {

 if ((wheel_midi > 10) && (wheel_old<4)) {
 } else {
 if (hothand_stable > 20) controllerChange(8, wheel_midi);
  
 }
 }
 
wheel_old = wheel_midi;
wheel_older = old_wheel;
wheel = old_wheel;
int fsr_temp_touch = fsr_Touched[0] + fsr_Touched[1] + fsr_Touched[2] + fsr_Touched[3];
// hothand...x axis sends aftertouch y axis on cc 9
if (fsr_temp_touch && sustain_mode) hothand_on = 0;
if (hothand_on > 50) {
  
  

read_Hothand_x = map(read_Hothand_x,1400,700,-310,310); //was 1200 to 900
read_Hothand_x = constrain(read_Hothand_x,-310,310);
read_Hothand_x = abs(read_Hothand_x);
//read_Hothand_x = 310-read_Hothand_x;
int hothand_midi = map_hothand[read_Hothand_x];
//"debounce" analog readings, so there is less splutter on meandring values...
hothand_counter = (hothand_counter + 1) % 40;
hothand_array[hothand_counter] = hothand_midi;
  hothand_stable = 0;
for (int i=0; i<40; i++) {
  if (abs(hothand_midi - hothand_array[i]) < 4) hothand_stable = hothand_stable + 2;
  if (hothand_array[i] < 6) hothand_stable = hothand_stable + 1;
}
if (read_Hothand_x != hothand_x_old) {
  hothand_x_old = read_Hothand_x;
 if (hothand_stable < 20) controllerChange(8, hothand_midi);
}
}


read_Hothand_y = map(read_Hothand_y,1170,970,0,127);
read_Hothand_y = constrain(read_Hothand_y,0,127);

if (read_Hothand_y != hothand_y_old) {
  hothand_y_old = read_Hothand_y;
  controllerChange(9, read_Hothand_y);
}

  } else if (control_counter < CONTROL_RATE) control_counter = control_counter + 1;
  } 
  }

//----CALIBRATION----//
/* Likely will only have to calibrate once. This is done by activating calibration mode and
* "plucking" each note on each string starting with the upper bound (after the 24st fret) and descending down
* to just after the 1st fret. Starts with the low E string, then the A string and then the D string.
* fret definitions are stored in EEPROM. Once it is calibrated for the voltage put out by the MIDI --> USB board
* you can just have the calibration button do something else because you probably won't need it again.
*/

void calibrate() {
  for (byte i=0; i<NUM_STRINGS; i++) {
    switch (i) {
      case 0:
       u8x8.drawString(0,50,"E:");
       break;
       case 1:
       u8x8.drawString(0,50,"A:");
       break;
       case 2:
       u8x8.drawString(0,50,"D:");
       break;
       case 3:
       u8x8.drawString(0,50,"G:");
       break;
    }
    
   
    int sensorMin = 1023;
    int val;
    
      //loop through the array of fret definitions
      for (byte j=24; j>0; j--) {
      enum {BufSize=3}; // If a is short use a smaller number, eg 5 or 6 
            char buf[BufSize];
            snprintf (buf, BufSize, "%d", j);
        u8x8.drawString(8,50,buf);
        int response = false;
        int fsrHit = 0;
        //wait for response
        while (!response) {
        
          //read fsr val
          int fsrVal = analogRead(fsr_Pins[i])>>1;
          //get the sensor min value (highest fret) on the first round
          if (j==24) {
            enum {BufSize=3}; // If a is short use a smaller number, eg 5 or 6 
            char buf[BufSize];
            snprintf (buf, BufSize, "%d", j);
            u8x8.drawString(8,50,buf);
            int fretVal = analogRead(soft_Pot_Pins[i]);
      //      if (fretVal > sensorMax) (sensorMax = fretVal);
       
            //if the fsr is hit, register this as the definition for this fret
            if (fsrVal < (fsr_Init[i] - 180) && fsrHit == 0) {
              
              int fretVal = analogRead(soft_Pot_Pins[i]);
              sensorMin = fretVal;
              val = fretVal;
              response = true;
              fsrHit = 1;
            }
            if (fsrVal > (fsr_Init[i] - 100) && fsrHit == 1) fsrHit = 0;
          }
        
          else {
            //get the rest of the fret definitions
            //if the piezo is hit, register this as the definition for this fret
            if (fsrVal < (fsr_Init[i] - 180) && fsrHit == 0) {
              int fretVal = analogRead(soft_Pot_Pins[i]);
              fretVal = map(fretVal, sensorMin, MAXREADING, 0, 255);
              if (fretVal > 255) fretVal = 255;
              val = fretVal;
              response = true;
              fsrHit = 1;
            } 
            if (fsrVal >  (fsr_Init[i] -100) && fsrHit == 1) fsrHit = 0;
          }
        }
      
        //write to memory
    //    digitalWrite(PIN_LED, LOW);
        EEPROM.write(j + (24*i), val);
        
        delay(100);
    //    digitalWrite(PIN_LED, HIGH);
      }
    
    //update global definitions
    calibration_Min[i] = EEPROM.read(24 + (24*i));

    for (byte j=1; j<24; j++) {
      fret_Defs[i][j] = EEPROM.read(j + (i*24));
    }
  }
  
//  digitalWrite(PIN_LED, LOW);
}

//write default programs to eeprom, so unused slots don't output garbage values, restore defaults
//likely will only have to write defaults once
void writeDefaults() {
  for (byte i=100; i<228; i++) {
    EEPROM.write(i, 2);
  }

}


//-------------MIDI OUT FUNCTIONS-----------------//

//note-on (and off) message
inline void noteOn(byte cmd, byte pitch, byte velocity) {
  if (channel_Mode){ cmd = cmd + CHANNEL_OFFSET;
  }
  
    //kind of mpe, starting at channel 2, channel 1 is for general modulation only
  usbMIDI.sendNoteOn(pitch, velocity, cmd + 1);
for (int i=0; i<7; i++) {
if (i != footpedal) {
  midilist[i]->sendNoteOn(pitch,velocity, cmd + 1);
midilist[i]->send_now();
}
}
midilist[footpedal]->sendNoteOn(pitch,velocity,1);
}



//Sends controller change to the specified controller
inline void controllerChange(byte controller, byte value) {
   //kind of mpe, channel 1 is for general modulation only 

usbMIDI.sendControlChange(controller,value,1);
for (int i=0; i<7; i++) {
  if (i != footpedal) {
  if (channel_Mode) {

  midilist[i]->sendControlChange(controller,value, 2 + CHANNEL_OFFSET + c);

midilist[i]->send_now();

  } else {
    midilist[i]->sendControlChange(controller,value, 2);
    midilist[i]->sendControlChange(controller,value, 3);
    midilist[i]->sendControlChange(controller,value, 4);
    midilist[i]->sendControlChange(controller,value, 5);
    midilist[i]->send_now();
  }
  }
}
}

inline void controllerChangeChannel(byte controller, byte value, byte channel) {
    if (channel_Mode) {     
   usbMIDI.sendControlChange(controller,value,channel + CHANNEL_OFFSET);
  for (int i=0; i<7; i++) {
    if (i != footpedal) {
midilist[i]->sendControlChange(controller,value, channel + CHANNEL_OFFSET);
midilist[i]->send_now();
}
  }
  } else {
 usbMIDI.sendControlChange(controller,value,channel);
 for (int i=0; i<7; i++) {
  if (i != footpedal) {
midilist[i]->sendControlChange(controller,value, channel);
midilist[i]->send_now();
  }
}
  }
}

inline void controllerAllChannels(byte controller, byte value) {
    if (channel_Mode) {
  
   usbMIDI.sendControlChange(controller,value, 2 + CHANNEL_OFFSET);
  
usbMIDI.sendControlChange(controller,value, 3 + CHANNEL_OFFSET);
  
usbMIDI.sendControlChange(controller,value, 4 + CHANNEL_OFFSET);
 
usbMIDI.sendControlChange(controller,value, 5 + CHANNEL_OFFSET);
for (int i=0; i<7; i++) {
  if (i != footpedal) {
midilist[i]->sendControlChange(controller,value, 2 + CHANNEL_OFFSET);
midilist[i]->sendControlChange(controller,value, 3 + CHANNEL_OFFSET);
midilist[i]->sendControlChange(controller,value, 4 + CHANNEL_OFFSET);
midilist[i]->sendControlChange(controller,value, 5 + CHANNEL_OFFSET);
midilist[i]->send_now();
}
}
  } else {
 
usbMIDI.sendControlChange(controller,value, 2);
  
 
usbMIDI.sendControlChange(controller,value, 3);
 
usbMIDI.sendControlChange(controller,value, 4);
 
usbMIDI.sendControlChange(controller,value, 5);
for (int i=0; i<7; i++) {
  if (i != footpedal) {
midilist[i]->sendControlChange(controller,value, 2);
midilist[i]->sendControlChange(controller,value, 3);
midilist[i]->sendControlChange(controller,value, 4);
midilist[i]->sendControlChange(controller,value, 5);
midilist[i]->send_now();
  }
}
  }
}

inline void aftertouchChange(byte cmd, byte value) {
 
   //kind of mpe, starting at channel 2, channel 1 is for general modulation only
usbMIDI.sendAfterTouch(value, cmd + 1);
for (int i=0; i<7; i++) {
  if (i != footpedal) {
midilist[i]->sendAfterTouch(value, cmd + 1);
midilist[i]->send_now();
  }
}
}

//-------------------OTHER FUNCTIONS---------------//

//save settings to eeprom on cc SAVE_CC (slot is last received program change)
 void saveSettings() {
 // if (octave < 0) octave = 0;
  byte settings = (channel_Mode << 7) | (full_Legato_Mode << 6) | (fsr_Add_Slave_Mode << 5) | (bow_Mode << 4) | octave;
  EEPROM.write(save_Slot + 100, settings);
}

// load settings from eeprom on program change
void loadSettings(byte prgCh) {

  
  byte settings = EEPROM.read(prgCh + 100);
  if (((settings >> 7) & 1) != channel_Mode) {
     if (string_Active[0]) {
              if (!channel_Mode) old_c = 0;
        noteOn(0x91 + old_c, active_Note[0], 0);    
        }

       if (string_Active[1]) {
              if (!channel_Mode) old_c = 1;
        noteOn(0x91 + old_c, active_Note[1], 0);    
        }

       if (string_Active[2]) {
              if (!channel_Mode) old_c = 2;
        noteOn(0x91 + old_c, active_Note[2], 0);    
        }

        if (string_Active[3]) {
              if (!channel_Mode) old_c = 3;
        noteOn(0x91 + old_c, active_Note[3], 0);    
        }     
  c = 0;
  }
  channel_Mode = (settings >> 7) & 1;
  full_Legato_Mode = (settings >> 6) & 1;
  fsr_Add_Slave_Mode = (settings >> 5) & 1;
  bow_Mode = (settings >> 4) & 1;
  octave = settings & 15;
  if (octave > 7) octave = 7;
  byte string_base = 12*octave + LOWEST_NOTE;
        offsets[0] = string_base; 
        offsets[1] = string_base + 5; 
        offsets[2] = string_base + 10; 
        offsets[3] = string_base + 15;
        u8x8.drawString(11,50,"P:");
    enum {BufSize=4}; 
            char buf[BufSize];
            snprintf (buf, BufSize, "%03d", prgCh);
            u8x8.drawString(13,50,buf);
            if (!channel_Mode) u8x8.drawString(0,0,"MPE ");
  else u8x8.drawString(0,0,"POLY");
  if (bow_Mode)  u8x8.drawString(12,0,"BOW ");
  else u8x8.drawString(12,0,"PIZZ");
  enum {BufSize2=3}; // If a is short use a smaller number, eg 5 or 6 
            char buf2[BufSize2];
            snprintf (buf2, BufSize2, "%d", octave);
        u8x8.drawString(5,50,buf2);  
        if (!fsr_Add_Slave_Mode) u8x8.drawString(7,0,"FIX");
    else u8x8.drawString(7,0,"DYN");   
  
}

void sendQunexus(byte type, byte data1, byte data2, byte channel )
{
    midilist[keysaxo]->send(type, data1, data2, channel);

}


void footProgramChange(byte channel, byte program) {
  save_Slot = program;
    loadSettings(program);
    
  for (int i=0; i<7; i++) {
 if (i != footpedal) midilist[i]->sendProgramChange(program,1);
  }
}

void footControlChange(byte channel, byte control, byte value) {
  switch (control) {
    case 11:
    case 12:
    case 14:
    case 15:
    case 16:
    midilist[keysaxo]->sendControlChange(control,value, 1);
    midilist[keysaxo]->send_now();
    break;
    case 114:
    bow_Mode = !bow_Mode;
  if (bow_Mode)  u8x8.drawString(12,0,"BOW ");
  else u8x8.drawString(12,0,"PIZZ");
  break;
  case 115:
  saveSettings();
  u8x8.drawString(11,50,"SAVED");
  break;
    case 119:
     if (string_Active[0]) {
              if (!channel_Mode) old_c = 0;
        noteOn(0x91 + old_c, active_Note[0], 0);    
        }

       if (string_Active[1]) {
              if (!channel_Mode) old_c = 1;
        noteOn(0x91 + old_c, active_Note[1], 0);    
        }

       if (string_Active[2]) {
              if (!channel_Mode) old_c = 2;
        noteOn(0x91 + old_c, active_Note[2], 0);    
        }

        if (string_Active[3]) {
              if (!channel_Mode) old_c = 3;
        noteOn(0x91 + old_c, active_Note[3], 0);    
        }     
      c = 0;
      channel_Mode = !channel_Mode;
      if (!channel_Mode) u8x8.drawString(0,0,"MPE ");
  else u8x8.drawString(0,0,"POLY");
      break; 
      case 123:
      controllerAllChannels(123,0);
      break;
      case 124:
      if (value) sustain_mode = 0;
      else sustain_mode = 1;
  }
}

void footNoteOn(byte channel, byte note, byte velocity) {
    usbMIDI.sendNoteOn(note, velocity, channel);
for (int i=0; i<7; i++) {
if (i != footpedal) {
  midilist[i]->sendNoteOn(note,velocity, channel);
midilist[i]->send_now();
}
}
}

void footNoteOff(byte channel, byte note, byte velocity) {
   usbMIDI.sendNoteOn(note, 0, channel);
for (int i=0; i<7; i++) {
if (i != footpedal) {
  midilist[i]->sendNoteOn(note,0, channel);
midilist[i]->send_now();
}
}
}

teensy 4.0:

Code:
// midi foot controller, 56 button matrix
#include <i2c_driver_wire.h> //Library for I2C interface
#include "U8g2lib.h"

//#include <SPI.h>
#include <MIDI.h>

MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI1);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial2, MIDI2);
//MIDI_CREATE_INSTANCE(HardwareSerial, Serial3, MIDI3);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial5, MIDI4);


U8G2_SH1106_128X64_NONAME_F_HW_I2C OLED_1(U8G2_R0, U8X8_PIN_NONE);
U8G2_SH1106_128X64_NONAME_F_HW_I2C OLED_2(U8G2_R0, U8X8_PIN_NONE);
U8G2_SH1106_128X64_NONAME_F_2ND_HW_I2C OLED_3(U8G2_R0, U8X8_PIN_NONE);
U8G2_SH1106_128X64_NONAME_F_2ND_HW_I2C OLED_4(U8G2_R0, U8X8_PIN_NONE);

//display 1 first and second line 

const char d1f_1[]  = "OCT:-2";
const char d1f_2[]  = "OCT:-1";
const char d1f_3[]  = "OCT: 0";
const char d1f_4[]  = "OCT: 1";
const char d1f_5[]  = "OCT: 2";
const char d1f_6[]  = "OCT: 3";
const char d1f_7[]  = "OCT: 4";
const char* const disp1f[]  = {d1f_1, d1f_2, d1f_3,d1f_4, d1f_5, d1f_6,d1f_7};

const char d1s_1[]  = "SPLT";
const char d1s_2[]  = "NOTE";
const char d1s_3[]  = "PROG";
const char* const disp1s[]  = {d1s_1, d1s_2, d1s_3};
//display 3
const char d3f_1[]  = "VoxOct";
const char d3f_2[]  = "Vox2FX";
const char d3f_3[]  = "Vox3FX";
const char d3f_4[]  = "CH: 4";
const char d3f_5[]  = "CH: 5";
const char d3f_6[]  = "CH: 6";
const char d3f_7[]  = "CH: 7";
const char d3f_8[]  = "CH: 8";
const char d3f_9[]  = "CH: 9";
const char d3f_10[]  = "CH:10";
const char d3f_11[]  = "CH:11";
const char d3f_12[]  = "CH:12";
const char d3f_13[]  = "CH:13";
const char d3f_14[]  = "CH:14";
const char d3f_15[]  = "CH:15";
const char d3f_16[]  = "CH:16";
const char* const disp3f[]  = {d3f_1, d3f_2, d3f_3,d3f_4, d3f_5, d3f_6,d3f_7,d3f_8, d3f_9, d3f_10,d3f_11, d3f_12, d3f_13,d3f_14, d3f_15, d3f_16};
const char d3f_active[] = "__";
const char d2f_active[] = "______";
//display 4...
const char d4f_1[]  = "VOX NOTE";
const char d4f_2[]  = "VOX PROG";
const char d4f_3[]  = "GLB PROG";
const char* const disp4f[]  = {d4f_1, d4f_2, d4f_3};

//display 3 alternative mode for autotune and vocal fxs

const char mode1[] = "C/W/D";
const char mode2[] = "Major";
const char mode3[] = "Minor";
const char mode4[] = "Pemin";
const char mode5[] = "Pemaj";
const char* const disp3modes[] = { mode1, mode2, mode3, mode4, mode5};

const char note0[]= "__";
const char note1[]= "C ";
const char note2[]= "C#";
const char note3[]= "D ";
const char note4[]= "Eb";
const char note5[]= "E ";
const char note6[]= "F ";
const char note7[]= "F#";
const char note8[]= "G ";
const char note9[]= "Ab";
const char note10[]= "A ";
const char note11[]= "Bb";
const char note12[]= "B ";
const char note13[]= "Ch";
const char note14[]= "WC";
const char note15[]= "WF";
const char note16[]= "DC";
const char note17[]= "DE";
const char note18[]= "DF";
const char note19[]= "SCL";
const char* const disp3notes[] = {note0, note1, note2, note3, note4, note5, note6, note7, note8, note9, note10, note11, note12, note13, note14, note15, note16, note17, note18, note19 };
int rootnote = 0;


int modes;
int atmodes = 0;
bool pentaswitch = 0;
bool pentamode = 0;
int voxpreset = 0;
char dispbuf[8];
char disp2buf[8];

//display 1
byte disp1_firstline = 0;
byte disp1_secondline = 0;
byte change_disp1 = 4;

//display 2
byte disp2_firstline = 0;
byte disp2_secondline = 0;
byte change_disp2 = 4;

//display 3
byte change_disp3 = 4;
byte voxfx;
byte program;
//display 4
byte disp4_firstline = 0;
byte disp4_secondline = 0;
byte change_disp4 = 4;

//toggle variables
bool pd_autotune = 0;
bool bytebeat_1 = 0;
bool bytebeat_2 = 0;
bool bytebeat_3 = 0;
bool vocoder = 0;
bool autotune_on = 0;
bool clean_on = 0;
bool octaver_on = 0;
bool subsynth_on = 0;
bool scale_pressed = 0;
#define DEBOUNCE_TIME 80
#define DEBOUNCE_ON 5
// pin setup
byte rows[] = {2,3,4, 5, 6, 9, 10, 11};
const int rowCount = 8;
byte cols[] = {27, 29, 31, 33, 28, 30, 32};
const int colCount = 7;


//setup the arrays for button state, previous state and debounce handling
bool buttonState[colCount][rowCount];
bool prevButtonState[colCount][rowCount];
byte debounceButtons[colCount][rowCount];
byte buttoncounter[colCount][rowCount];
//notice the switched row and col for easier midifying...
//layouts:
byte allNotes[rowCount][colCount] = {
  {128, 129, 25, 27, 30, 32, 34}, //two function keys, and 5 black keys
  {24, 26, 28, 29, 31, 33, 35}, //7 white keys
  {130, 131, 37, 39, 42, 44, 46}, //two function keys and 5 black keys
  {36, 38, 40, 41, 43, 45, 47}, // 7 white keys
  {169, 133, 49, 51, 54, 56, 58}, // you
  {48, 50, 52, 53, 55, 57, 59}, // get
  {134, 135, 61, 63, 66, 68, 70}, // the
  {60, 62, 64, 65, 67, 69, 71}, // idea
};


byte controllerMode[rowCount][colCount] = {
  {128, 129, 25, 27, 30, 32, 34}, //two function keys, and 5 black keys
  {24, 26, 28, 29, 31, 33, 35}, //7 white keys
  {130, 131, 37, 39, 42, 44, 46}, //two function keys and 5 black keys
  {36, 38, 40, 41, 43, 45, 47}, // 7 white keys
  {132, 133, 137, 139, 142, 144, 146}, // alternate
  {136, 138, 140, 141, 143, 145, 147}, // mode for program changes
  {160, 161, 149, 151, 154, 156, 158}, // etc.
  {148, 150, 152, 153, 155, 157, 159}, // we will see...
};

byte basscontrolMode[rowCount][colCount] = {
  {128, 129, 25, 27, 30, 32, 34}, //two function keys, and 5 black keys
  {24, 26, 28, 29, 31, 33, 35}, //7 white keys
  {130, 131, 37, 39, 42, 44, 46}, //two function keys and 5 black keys
  {36, 38, 40, 41, 43, 45, 47}, // 7 white keys
  {132, 133, 163, 165, 168, 144, 146}, // alternate
  {162, 164, 166, 167, 143, 145, 147}, // mode for program changes
  {160, 161, 149, 151, 154, 156, 158}, // etc.
  {148, 150, 152, 153, 155, 157, 159}, // we will see...
};
byte *mode = &controllerMode[0][0];

// other variables
bool channelMode = 1;
byte modeCount = 0;
byte routeKey = 0;
byte midichannel = 0;
byte analogsend = 0; 
byte analog_retain[20];
byte lastBoard = 0;
byte blinkcount = 8;
int pcOffset = 0;
byte tapCount = 0;
bool sustain = 0;
bool oldsustain = 0;
bool toggleSustain = 0;
float tempo = 1000;
unsigned long mtcTempo = tempo * 24;
elapsedMicros clocktimer;
elapsedMicros clockontimer;
bool blinker = 0;
//sysex for xr18 taptempo
uint8_t setdelaytime[] = {0xF0, 0x00, 0x20, 0x32, 0x32, 0x2F, 0x66, 0x78, 0x2F, 0x33, 0x2F, 0x70, 0x61, 0x72, 0x2F, 0x30, 0x31, 0x20, 0x32, 0x30, 0x32, 0x30, 0xF7}; //fx3 parameter 1
//sysex for mute/unmute ch1...
const uint8_t mutech1[] = {0xF0, 0x00, 0x20, 0x32, 0x32, 0x2F, 0x63, 0x68, 0x2F, 0x30, 0x31, 0x2F, 0x6D, 0x69, 0x78, 0x2F, 0x6F, 0x6E, 0x20, 0x4F, 0x46, 0x46, 0xF7};
const uint8_t unmutech1[] = {0xF0, 0x00, 0x20, 0x32, 0x32, 0x2F, 0x63, 0x68, 0x2F, 0x30, 0x31, 0x2F, 0x6D, 0x69, 0x78, 0x2F, 0x6F, 0x6E, 0x20, 0x4F, 0x4E, 0xF7};

//time measurements...sustain toggle, blinking, tapping...
elapsedMillis holdsustain;
elapsedMicros taptime;
elapsedMillis blinktime;
elapsedMillis blinktap;
//debug
elapsedMillis debugtime;
//cc-rate
#define CCRATE 40
int cc_counter = 0; 
int old_pedal;
int pedal_acc = 0;
int old_joymidi_x = 0;
int old_joymidi_y = 0;
int middle_joyy;
int joyy_acc = 0;
int joyx_acc = 0;
int octave = 0;

//sustain mode
int currentNote = 128;
bool sustainFoot = 0;
bool sameRelease = 0;

void setup() {
analogReadResolution(12);
  //Serial1.begin(31250);
  MIDI1.begin(MIDI_CHANNEL_OMNI);
  MIDI2.begin(MIDI_CHANNEL_OMNI);
 // Send Clock to Blofeld on Serial 3, "Midi Clock info is easier to do in straight serial"
 Serial3.begin(31250);
 
  MIDI4.begin(MIDI_CHANNEL_OMNI);

  OLED_1.setI2CAddress(0x3C * 2);        //<- SOLVED it works
  OLED_2.setI2CAddress(0x3D * 2);        //<- SOLVED it works
  OLED_3.setI2CAddress(0x3D * 2);        //<- SOLVED it works
  OLED_4.setI2CAddress(0x3C * 2);        //<- SOLVED it works
  
//  u8g2_SetI2CAddress(OLED_1.GetU8g2(), 0x3C * 2); This did not work for me
 // u8g2_SetI2CAddress(OLED_2.GetU8g2(), 0x3D * 2); This did not work for me
  OLED_1.setBusClock(1000000);
  OLED_2.setBusClock(1000000);
  OLED_3.setBusClock(1000000);
  OLED_4.setBusClock(1000000);
  OLED_1.begin();
  OLED_2.begin();
  OLED_3.begin();
  OLED_4.begin();
  
  OLED_1.setFont(u8g2_font_inb19_mf);
  OLED_2.setFont(u8g2_font_inb19_mf);
  OLED_3.setFont(u8g2_font_inb16_mf);
  OLED_4.setFont(u8g2_font_inb19_mf);
  
  Serial.begin(9600);
//while (!Serial);
  for(int x=0; x<rowCount; x++) {
    
    pinMode(rows[x], INPUT_PULLUP);
  }

  for (int x=0; x<colCount; x++) {
    
    pinMode(cols[x], INPUT_PULLUP);
    
  }
  //sustain LED
  pinMode(12, OUTPUT);
  //taptempo LED and output
  pinMode(13, OUTPUT);
  for (int colIndex=0; colIndex < colCount; colIndex++) {
    
  for (int rowIndex=0; rowIndex < rowCount; rowIndex++) {
    prevButtonState[colIndex][rowIndex] = 1;
    debounceButtons[colIndex][rowIndex] = 0;
    buttoncounter[colCount][rowCount] = 0;
  }
  
  }
/*  int acc_middle = 0;
  for (int i=0; i < 40; i++) {
  middle_joyy = analogRead(A10);
  acc_middle = middle_joyy + acc_middle;
}
middle_joyy = acc_middle / 40;
Serial.println(middle_joyy); */
usbMIDI.setHandleNoteOn(bassNoteOn);
usbMIDI.setHandleNoteOff(bassNoteOff);
}


void loop() {
 // usbMIDI.Task();
  usbMIDI.read();
 /* if (usbMIDI.read()) {
    processMIDI();
  }*/
  readMatrix();
  evalMatrix();
 if (sustain != oldsustain) digitalWrite(12, sustain);
 oldsustain = sustain;
 if (blinkcount < 8) blinkSustainLed();
 
 if (change_disp1)  drawOLED_1();
 if (change_disp2) drawOLED_2();

 if (change_disp4) drawOLED_4();

 if (change_disp3) drawOLED_3();
 if (blinktap >= tempo/2.0f) {
  blinktap = 0;
  blinker = !blinker;
  digitalWrite(13, blinker);

 }
 if (( clocktimer >= mtcTempo) && (clockontimer < 500000)) {
  Serial3.write(byte(248));
  clocktimer = 0;
 }

 //analog Readings
int pedal = analogRead(A8);
pedal_acc = pedal_acc + pedal;
int joystick_y = analogRead(A10);
int joystick_x = analogRead(A12);
joyx_acc = joyx_acc + joystick_x;
joyy_acc = joyy_acc + joystick_y;

if (cc_counter < CCRATE) cc_counter = cc_counter + 1;
if (cc_counter == CCRATE) {
  
int midipedal = pedal_acc / (CCRATE);
midipedal = constrain(midipedal,5,4090);
midipedal = map(midipedal,5,4090,0,127);
  if (midipedal != old_pedal) {
    MIDI1.sendControlChange(analogsend + 6,midipedal,1);
    analog_retain[analogsend] = midipedal;
    change_disp2 = 1;
  }
  old_pedal = midipedal;
  pedal_acc = 0;
 
  
int joymidi_y = joyy_acc / (CCRATE);
/*if (debugtime > 1000) {
    Serial.println(joymidi_y);
    debugtime = 0;
  } */
joymidi_y = constrain(joymidi_y,1570,2560);
if ((2052 - joymidi_y) > 75) joymidi_y = map(joymidi_y,1570,2052 - 75,0,62);
else if ((joymidi_y - 2052) > 75) joymidi_y = map(joymidi_y,2052 + 75, 2560,64,127);
else joymidi_y = 63;
  if (joymidi_y != old_joymidi_y) {
    usbMIDI.sendControlChange(30,joymidi_y,1);
   // analog_retain[analogsend] = midipedal;
   // change_disp2 = 1;
  }
  old_joymidi_y = joymidi_y;
  joyy_acc = 0;

  int joymidi_x = joyx_acc / (CCRATE);
  //if (debugtime > 1000) {
    //Serial.println(joymidi_x);
   // debugtime = 0;
 // }
  
joymidi_x = constrain(joymidi_x,1613,2517);
joymidi_x = map(joymidi_x,2517,1613,0,127);
  if (joymidi_x != old_joymidi_x) {
    usbMIDI.sendControlChange(31,joymidi_x,1);
   // analog_retain[analogsend] = midipedal;
   // change_disp2 = 1;
  }
  old_joymidi_x = joymidi_x;
  joyx_acc = 0;
   cc_counter = 0;
}
/*if (debugtime > 1000) {
  debugtime = 0;
  Serial.println(pedal);
} */
}

void readMatrix() {
  // iterate the columns
  for (int colIndex=0; colIndex < colCount; colIndex++) {
    // col: set to output to low
    byte curCol = cols[colIndex];
    pinMode(curCol, OUTPUT);
    digitalWrite(curCol, LOW);

    // row: interate through the rows
    for (int rowIndex=0; rowIndex < rowCount; rowIndex++) {
      byte rowCol = rows[rowIndex];
      pinMode(rowCol, INPUT_PULLUP);
      buttonState[colIndex][rowIndex] = digitalRead(rowCol);
    //  pinMode(rowCol, INPUT_PULLUP);
      
    }
    // disable the column
  //  digitalWrite(curCol, HIGH);
    pinMode(curCol, INPUT_PULLUP);
    //adjust accordingly if you still get false positives or lower the value if you feel the keybed lagging
    delayMicroseconds(80);
  }
}

void evalMatrix() {
  for (int rowIndex=0; rowIndex < rowCount; rowIndex++) {

    for (int colIndex=0; colIndex < colCount; colIndex++) {
      int currentButton = *(mode + (rowCount -1)*rowIndex + colIndex); 
      if(!buttonState[colIndex][rowIndex] && prevButtonState[colIndex][rowIndex]) {
        if ( buttoncounter[colCount][rowCount] < DEBOUNCE_ON) {
      buttoncounter[colCount][rowCount]++;
      buttonState[colIndex][rowIndex] = 1;
     } else {
          buttoncounter[colCount][rowCount] = 0;
        // button pressed
        Serial.print("pressed:");
      Serial.println(currentButton);
      if(currentButton < 128) {
      if (currentNote != currentButton) {
        usbMIDI.sendNoteOn( currentButton + octave, 127, midichannel + 1, 0);
        sameRelease = 0;
      }
      else if ((currentNote < 128) && !sameRelease) {
        usbMIDI.sendNoteOff( currentNote + octave, 0, midichannel + 1, 0);
        Serial.println("same noteoff");
        Serial.println(currentNote);
        currentNote = 128;
        sameRelease = 1;
        
      }
      if (sustainFoot) {
      if (currentNote < 128) usbMIDI.sendNoteOff( currentNote + octave, 0, midichannel + 1, 0);
     if (!sameRelease) currentNote = currentButton;
      } else currentNote = 128;
      
      } else {
        
        switch (currentButton) {
          case 128:
          modeCount = (modeCount + 1)%3;
          Serial.print("Mode:");
      Serial.println(modeCount);
      if (!modeCount) {
        
        mode = &controllerMode[0][0];
        disp1_secondline = 0;
        Serial.println("Controller Mode");
      } else if (modeCount == 1) {
        mode = &allNotes[0][0];
        disp1_secondline = 1;
        Serial.println("Note Mode");
      } else if (modeCount == 2) {
        Serial.println("BassSettings Mode");
        mode = &basscontrolMode[0][0];
        disp1_secondline = 2;
      }
      change_disp1 = 1;
          break; 
       case 129:
          sustain = !sustain;
          usbMIDI.sendControlChange(124,sustain*127,0);
          holdsustain = 0;
          toggleSustain = 0;
          Serial.print("Sustain:");
      Serial.println(sustain);
      break;  
      
      case 133:
      routeKey = (routeKey + 1)%3;
       change_disp1 = 1;
       change_disp2 = 1;
      Serial.print("Midirouting:");
      Serial.println(routeKey);
      break;
      case 130:
          channelMode = !channelMode;
      usbMIDI.sendControlChange(119,127,0);    
          Serial.print("channelMode:");
      Serial.println(channelMode);
          break;
          
      case 131:
      Serial.println("All Notes OFF");
      usbMIDI.sendControlChange(123,127,0);
      break;
      
      case 132:
      
      tapCount = (tapCount + 1)%5;
      if (taptime > 8000000) tapCount = 0;
      Serial.println(tapCount);
      if (!tapCount) taptime = 0;
      if (tapCount == 4) {
        tempo = taptime / 4000.0f;
        mtcTempo = taptime / (4.0f*24.0f);
        Serial3.write(byte(248));
        blinktap = tempo;
        blinker = 0;
        setdelaytime[18] = 0x30 + tempo / 1000;
      setdelaytime[19] = 0x30 + (tempo - (tempo/1000) * 1000) / 100;
      setdelaytime[20] = 0x30 + (tempo - (tempo/100) * 100) / 10;
      setdelaytime[21] = 0x30 + (tempo - (tempo/10) * 10);
      MIDI2.sendSysEx(sizeof(setdelaytime),setdelaytime,true);
       Serial.println(tempo);
       clockontimer = 0;
       
      }
      break;
          
      case 134:
          octave = octave - 12;
          if (octave < -24) octave = -24;
          change_disp1 = 1;
          break;
      case 135:
          octave = octave + 12;
          if (octave > 48) octave = 48;
          change_disp1 = 1;
          break;
      case 136:
      //vocoder on (switch to vocoder and send sound to bela) when released switch back to previous mode
      MIDI1.sendControlChange(11, 127,1); //send to bela (switch on vocoder)
      usbMIDI.sendControlChange(11, 127,1); //send to axoloti to turn on vocoder modulator
      vocoder = 1;
      change_disp4 = 1;
      break;
      case 137:
      MIDI1.sendControlChange(12, 127,1); // send to bela (switch on vocoder)
      usbMIDI.sendControlChange(12, 127,1); //to axoloti to turn on vocoder one octave below
      //vocoder on one octave below (switch to vocoder and send sound to bela) when released switch back to previous mode
      vocoder = 1;
      change_disp4 = 1;
      break;
       case 138:
       
       if (!pd_autotune) {
        MIDI1.sendControlChange(13, 127,1); //toggle pd synth and autotune
        pd_autotune = 1;
       } else {
         MIDI1.sendControlChange(13, 0,1); //toggle pd synth and autotune
        pd_autotune = 0;
       }
       change_disp3 = 1;
       change_disp4 = 1;
      //switch between autotune and synth ("toggle") (vocoder via vocoder switches "momentary")
      break;
      case 139: 
      if (!bytebeat_1) {
      usbMIDI.sendControlChange(14, 127,1);
      bytebeat_1 = 1;
      } else {
      usbMIDI.sendControlChange(14, 0,1);
      bytebeat_1 = 0;  
      }
      change_disp4 = 1;
      //byte beat loop 1
      break;
      case 140:
      //byte beat loop 2
      if (!bytebeat_2) {
      usbMIDI.sendControlChange(15, 127,1);
      bytebeat_2 = 1;
      } else {
      usbMIDI.sendControlChange(15, 0,1);
      bytebeat_2 = 0;  
      }
      change_disp4 = 1;
      break;
      case 141:
      //byte beat loop 3
      if (!bytebeat_3) {
      usbMIDI.sendControlChange(16, 127,1);
      bytebeat_3 = 1;
      } else {
      usbMIDI.sendControlChange(16, 0,1);
      bytebeat_3 = 0;  
      }
      change_disp4 = 1;
      break;
     
      case 142:
      // still free...
      break;   
      case 143:
      lastBoard = (lastBoard + 1)%3;
      change_disp4 = 1;
      change_disp3 = 1;
      Serial.print("LastBoardMode:");
      Serial.println(lastBoard);
      break;
      case 160:
      pcOffset = pcOffset - 16;
      if (pcOffset < 0) pcOffset = 0;
      change_disp3 = 1;
      break;
      case 161:
      pcOffset = pcOffset + 16;
      if (pcOffset > 112) pcOffset = 112;
      change_disp3 = 1;
      break;
      case 162:
      //bowmode
      usbMIDI.sendControlChange(114, 127,1);
      //bowmode
      break;
      case 163:
      //save cc
      usbMIDI.sendControlChange(115, 127,1);
      break;
      case 164:
      if (!autotune_on) {
        MIDI1.sendControlChange(14, 127,1); //toggle pd synth and autotune
        autotune_on = 1;
       } else {
         MIDI1.sendControlChange(14, 0,1); //toggle pd synth and autotune
        autotune_on = 0;
       }
      break;
      case 165:
      if (!clean_on) {
        MIDI1.sendControlChange(15, 127,1); //toggle pd synth and autotune
        clean_on = 1;
       } else {
         MIDI1.sendControlChange(15, 0,1); //toggle pd synth and autotune
        clean_on = 0;
       }
      break;
      case 166:
      if (!octaver_on) {
        MIDI1.sendControlChange(16, 127,1); //toggle pd synth and autotune
        octaver_on = 1;
       } else {
         MIDI1.sendControlChange(16, 0,1); //toggle pd synth and autotune
        octaver_on = 0;
       }
      break;
      case 167:
      if (!subsynth_on) {
        MIDI1.sendControlChange(17, 127,1); //toggle pd synth and autotune
        subsynth_on = 1;
       } else {
         MIDI1.sendControlChange(17, 0,1); //toggle pd synth and autotune
        pd_autotune = 0;
       }
      break;
      case 168:
      //still free
      break;
      case 169:
      sustainFoot = !sustainFoot;
      if (sustainFoot) currentNote = 128;
      if (!sustainFoot && (currentNote < 128)) usbMIDI.sendNoteOff( currentNote + octave, 0, midichannel + 1, 0);
      change_disp1 = 1;
      break;
        }
       if ((currentButton < 160) && (currentButton > 143) ) {
         if (routeKey == 0) {
          
          //send notes for autotune root and scale...and pd synth fast preset changes 16
          if (!lastBoard) {
            if (pd_autotune && ((currentButton < 148) && (currentButton > 143)) ) {
            atmodes = currentButton - 144;
            if (currentButton == 147) {
              if (pentaswitch) pentamode = !pentamode;
              else pentaswitch = 1;
              if (pentamode) atmodes = 4;
            } else pentaswitch = 0;
            scale_pressed = 1;
            rootnote = 0;
            Serial.println(atmodes);
          }
            if (pentamode && pd_autotune && (currentButton == 147)) {
              MIDI1.sendNoteOn(35, 127,1); 
         //     Serial.println("Should send noteOn 35");
            }
            else {
              MIDI1.sendNoteOn(currentButton - 108, 127,1); 
           //   Serial.println(modes);
            }
            if (!pd_autotune) voxpreset = currentButton - 144;
            if (pd_autotune && (currentButton > 147)) {
              Serial.println(atmodes);
              if (atmodes != 0) rootnote = currentButton - 147;
              else rootnote = currentButton - 135;
              if (rootnote > 19) rootnote = 13;
            }
            change_disp3 = 1;     
          }
         if (lastBoard == 1) {
          //program change to bela (voxsynth)
          MIDI1.sendProgramChange(currentButton - 144, 1); 
          voxfx = currentButton - 144; 
          change_disp3 = 1;
         }
         if (lastBoard == 2) {
          //send program change to bass and other synths
          usbMIDI.sendProgramChange( currentButton - 144 + pcOffset, 1, 0);
          program = currentButton - 144 + pcOffset;
          change_disp3 = 1;
         }
         }
         if (routeKey == 1) {
          //select midichannel for keymode...
        midichannel =  (currentButton - 144);
        routeKey = 0;
        change_disp1 = 1;
         }
        if (routeKey == 2) {
          //select midichannel for keymode...
        analogsend =  (currentButton - 144);
        routeKey = 0;
        change_disp2 = 1;
         }
       }

      }
      
     }
    }
//Handle Button releases if necessary 
   if(buttonState[colIndex][rowIndex] && !prevButtonState[colIndex][rowIndex]) {  
     if ( debounceButtons[colIndex][rowIndex] < DEBOUNCE_TIME) {
      debounceButtons[colIndex][rowIndex]++;
      buttonState[colIndex][rowIndex] = 0;
     } else {
      //button is released
      Serial.print("released:");
      Serial.println(currentButton);
       if((currentButton < 128) && !sustainFoot) {
      usbMIDI.sendNoteOff( currentButton + octave, 0, midichannel + 1, 0);
       }
      else {
        switch (currentButton) {
          case 129:
          if (!toggleSustain) {
          sustain = 0;
          usbMIDI.sendControlChange(124,0,0);
          }  
          Serial.print("Sustain:");
      Serial.println(sustain);
      break;
      case 136:
      //vocoder on (switch to vocoder and send sound to bela) when released switch back to previous mode
      MIDI1.sendControlChange(11, 0,1); //send to bela (switch off vocoder)
      usbMIDI.sendControlChange(11, 0,1); //send to axoloti to turn off vocoder modulator
      vocoder = 0;
      change_disp4 = 1;
      break;
      case 137:
      MIDI1.sendControlChange(12, 0,1); // send to bela (switch off vocoder)
      usbMIDI.sendControlChange(12, 0,1); //to axoloti to turn off vocoder one octave below
      //vocoder off one octave below (switch to vocoder and send sound to bela) when released switch back to previous mode
      vocoder = 0;
      change_disp4 = 1;
      break;
        }
        if ((currentButton < 160) && (currentButton > 143) ) {
          if (pd_autotune && ((currentButton < 148) && (currentButton > 143)) ) {
            scale_pressed = 0;
            
          }
          if (!lastBoard) {
            if (pentamode && pd_autotune && (currentButton == 147)) {
              MIDI1.sendNoteOff(35, 0,1); 
           //   Serial.println("Should send noteOff 35");
            }
            else MIDI1.sendNoteOff(currentButton - 108, 0,1);
          }
        }
      }
      debounceButtons[colIndex][rowIndex] = 0;
     }

      
      
    } 
    prevButtonState[colIndex][rowIndex] = buttonState[colIndex][rowIndex];
  }
  
}
if (sustain && !toggleSustain && (holdsustain > 3000)) {
  blinkcount = 0;
  Serial.println("Hold Sustain");
  toggleSustain = 1;
}
}
//non blocking led blink
void blinkSustainLed(void) {
  if (blinktime > 80) {
    
    digitalWrite(12, blinkcount%2);
    blinkcount++;
    blinktime = 0;
  }
}
void drawOLED_1(void) {
  OLED_1.clearBuffer(); // clear the internal memory
  OLED_1.drawStr(0, 25, disp1s[disp1_secondline]);
  if (sustainFoot) OLED_1.drawStr(110, 55, "S");
  else OLED_1.drawStr(110, 55, " "); 
  OLED_1.drawStr(0, 55, disp1f[(octave/12) +2]);
  enum {BufSize=4}; // If a is short use a smaller number, eg 5 or 6 
            char buf[BufSize];
            snprintf (buf, BufSize, "%02d", midichannel + 1);
        
  OLED_1.drawStr(95, 25, buf);
 if (routeKey == 1) {
  OLED_1.drawStr(95, 25, d3f_active); 
 }
  OLED_1.sendBuffer(); // transfer internal memory to the display
  change_disp1 = 0;
}

void drawOLED_2(void) {
 // char buffer[10];
  OLED_2.clearBuffer(); // clear the internal memory
    
        

  OLED_2.drawStr(0, 25, disp3f[analogsend]);
  if (routeKey == 2) {
    OLED_2.drawStr(0, 25, d2f_active); 
  }
  enum {BufSize=4}; // If a is short use a smaller number, eg 5 or 6 
            char buf[BufSize];
  snprintf (buf, BufSize, "%03d", analog_retain[analogsend]);
  OLED_2.drawStr(0,55, buf);
  
  OLED_2.sendBuffer(); // transfer internal memory to the display
  change_disp2 = 0;
}

void drawOLED_3(void) {
  OLED_3.clearBuffer(); 
  if (lastBoard == 2) {
  // clear the internal memory
  OLED_3.setFont(u8g2_font_inb19_mf);
  OLED_3.drawStr(0,25,"P:");
  enum {BufSize=4}; // If a is short use a smaller number, eg 5 or 6 
            char buf[BufSize];
            snprintf (buf, BufSize, "%03d", program);
        
  OLED_3.drawStr(30, 25, buf);
  }
  if (lastBoard == 1) {
    OLED_3.setFont(u8g2_font_inb19_mf);
  OLED_3.drawStr(0, 25, "VOX:");
  enum {BufSize2=4}; // If a is short use a smaller number, eg 5 or 6 
            char buf2[BufSize2];
            snprintf (buf2, BufSize2, "%02d", voxfx);
   OLED_3.drawStr(64, 25, buf2); 
  }  
  if (lastBoard == 2) {
    enum {BufSize2=4}; // If a is short use a smaller number, eg 5 or 6 
            char buf2[BufSize2];
  snprintf (buf2, BufSize2, "%03d", pcOffset);
  OLED_3.setFont(u8g2_font_inb16_mf);
  OLED_3.drawStr(88,25,buf2);   
  }   
  if (!lastBoard) {
   enum {BufSize2=4}; // If a is short use a smaller number, eg 5 or 6 
            char buf2[BufSize2];
  snprintf (buf2, BufSize2, "%03d", program);
  OLED_3.drawStr(88,25,buf2);
  if (pd_autotune) {
    OLED_3.drawStr(0,55,disp3notes[rootnote] );
    OLED_3.drawStr(50,55,disp3modes[atmodes]);
  } else {
    enum {BufSize2=4}; // If a is short use a smaller number, eg 5 or 6 
            char buf2[BufSize2];
  snprintf (buf2, BufSize2, "%02d", voxpreset);
    OLED_3.drawStr(0,55,"Preset:");
    OLED_3.drawStr(100,55,buf2);
  }
  }
  OLED_3.sendBuffer(); // transfer internal memory to the display
  change_disp3 = 0;
}

void drawOLED_4(void) {
 // char buffer[10];
  OLED_4.clearBuffer(); // clear the internal memory
  OLED_4.drawStr(0, 25, disp4f[lastBoard]);
 if (bytebeat_1) OLED_4.drawStr(70, 55, "1");
 else OLED_4.drawStr(70, 55, "   ");
 if (bytebeat_2) OLED_4.drawStr(110, 55, "2");
 else OLED_4.drawStr(110, 55, "   ");
 if (bytebeat_3) OLED_4.drawStr(40, 55, "B");
 else OLED_4.drawStr(40, 55, "K"); 
  if (pd_autotune) OLED_4.drawStr(0, 55, "AT");
 else OLED_4.drawStr(0, 55, "PD");
 if (vocoder) OLED_4.drawStr(0, 55, "VC");
 
  OLED_4.sendBuffer(); // transfer internal memory to the display
  change_disp4 = 0;
  
}

void bassNoteOn(byte channel, byte note, byte velocity) {
/*note = note % 12;
if (scale_pressed && (atmodes != 0)) {
  MIDI1.sendNoteOn(note + 40, 127,1);
  MIDI1.sendNoteOff(note + 40, 127,1); 
  rootnote = note + 1;
  change_disp3 = 1;
} */
}
void bassNoteOff(byte channel, byte note, byte velocity) {

   /* Serial.print("Note On, ch=");
      Serial.print(channel, DEC);
      Serial.print(", note=");
      Serial.print(note, DEC);
      Serial.print(", velocity=");
      Serial.println(velocity, DEC); */

}

the teensy 4 also has a name.c in a separate tab to change the usb-name, but i doubt it has anything to do with it:

Code:
// To give your project a unique name, this code must be
// placed into a .c file (its own tab).  It can not be in
// a .cpp file or your main sketch (the .ino file).

#include "usb_names.h"

// Edit these lines to create your own name.  The length must
// match the number of characters in your custom name.

#define MANUFACTURER_NAME   {'L','o','k','k','i','L','a','b','s'}
#define MANUFACTURER_NAME_LEN  9
#define MIDI_NAME   {'F','O','O','T'}
#define MIDI_NAME_LEN  4
#define SERIAL_NUM {'E','n','c','o','d','e','r','F','a','n','e','l'}
#define SERIAL_NUM_LEN 12

// Do not change this part.  This exact format is required by USB.

struct usb_string_descriptor_struct usb_string_manufacturer_name = {
        2 + MANUFACTURER_NAME_LEN * 2,
        3,
        MANUFACTURER_NAME
};

struct usb_string_descriptor_struct usb_string_product_name = {
        2 + MIDI_NAME_LEN * 2,
        3,
        MIDI_NAME
};


struct usb_string_descriptor_struct usb_string_serial_number = {
        2 + SERIAL_NUM_LEN * 2,
        3,
        SERIAL_NUM
};

it is a bit hard for me to imagine how i would create smaller versions of the programs that exhibit the problem in a way you could observe. the sluggishness in playing is really apparent when i play the instrument, but the code is still working so...

what would be your suggestions to make a small version? just a simple program that sends note on and off from a teensy 3.6 to a teensy 4 via usb host? you would then measure the lag somehow?

it is the midi bass i posted here: https://forum.pjrc.com/threads/64462-Midi-Bass-Controller
 
Please try to trim these to small programs.

If possible, please eliminate the dependency on U8x8lib.h, i2c_driver_wire.h and any other libraries not part of a clean Arduino + Teensyduino install. If there really is no way to reproduce the problem without these other pieces of software, I need very clear info about where to get the exact versions you used.

For now, I'm not putting this onto my list of issues to investigate. I really need a clearer and hopefully simpler path to quickly reproduce the problem.
 
well, this was much simpler then i thought it would be.
here are two simple programs that show the problem quite well. an ascending set of notes sent out to all ports on a hub and a teensy 4 with some simple code and a delay(10); to emulate a bigger sketch that takes some time to execute. you can also decrease the delay, but like this it is very apparent.

attach at least one other synth with usb-midi to check the code. it sends on channel 6. look at the serial output of the teensy 3.6 to see the time it takes to send out notes. it should be every 11ms but it depends on the delay set in teensy4! so the teensy4 slows down the teensy 3.6! if i have no delay(); in the teensy 4 code it actually performs at 11ms as expected. but in my real sketch the teensy4 takes some time to read my key-matrix and this seems enough to cause readings of 162ms instead of 11ms in my teensy 3.6 test patch.

i hope i am doing something simple wrong and you can tell me how to fix it :)

teensy 3.6 program:

Code:
#pragma GCC optimize ("-O3")

#include <Arduino.h>
       
#include <USBHost_t36.h>

// Create the ports for USB devices plugged into Teensy's 2nd USB port (via hubs)
USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
USBHub hub3(myusb);
USBHub hub4(myusb);
MIDIDevice_BigBuffer midi01(myusb);
MIDIDevice_BigBuffer midi02(myusb);
MIDIDevice_BigBuffer midi03(myusb);
MIDIDevice_BigBuffer midi04(myusb);
MIDIDevice_BigBuffer midi05(myusb);
MIDIDevice_BigBuffer midi06(myusb);
MIDIDevice_BigBuffer midi07(myusb);
MIDIDevice_BigBuffer * midilist[07] = {
  &midi01, &midi02, &midi03, &midi04, &midi05, &midi06, &midi07
};




//testing midi from teensy 3.6 to teensy 4 via host...
elapsedMillis noteOff_Time;

int footpedal = 7;

int note_counter = 40;
//--------- Setup ----------------//
void setup() {
    myusb.begin();
     delay(1500);
for (int i=0; i<7; i++) {
  if (midilist[i]->manufacturer() != NULL && midilist[i]->serialNumber() != NULL) {
  
     Serial.println((char*)midilist[i]->serialNumber());
     Serial.println(midilist[i]->idProduct());

     if (!strcmp(midilist[i]->serialNumber(),"EncoderFanel")) {//teensy 4 enumeration
      Serial.println("here is the footcontroller");
      footpedal = i;
     }
  }
  
  }
//  Serial.println(keysaxo);
  Serial.println(footpedal);
  midilist[footpedal]->setHandleProgramChange(footProgramChange);
  midilist[footpedal]->setHandleControlChange(footControlChange);
  midilist[footpedal]->setHandleNoteOn(footNoteOn);
  midilist[footpedal]->setHandleNoteOff(footNoteOff);  

}

//----------Main Loop---------------//
void loop() {

//---midi from the footpedal----//
myusb.Task();
midilist[footpedal]->read();

if (noteOff_Time > 10) {
  Serial.println(noteOff_Time); //i get readings of about 2560 ms when it should be 11, clearly something slows the teensy down...
  noteOff_Time = 0;
noteOn(0x95,note_counter, 100);
if (note_counter > 40) noteOn(0x95,note_counter -1,0);
note_counter++;

if (note_counter > 90) note_counter = 40;
}
  }




//-------------MIDI OUT FUNCTIONS-----------------//

//note-on (and off) message
inline void noteOn(byte cmd, byte pitch, byte velocity) {

  
    //kind of mpe, starting at channel 2, channel 1 is for general modulation only
  usbMIDI.sendNoteOn(pitch, velocity, 6);
for (int i=0; i<7; i++) {
if (i != footpedal) {
  midilist[i]->sendNoteOn(pitch,velocity, 6);
midilist[i]->send_now();
}
}
midilist[footpedal]->sendNoteOn(pitch,velocity,6);
}


void footProgramChange(byte channel, byte program) {
 
  for (int i=0; i<7; i++) {
 if (i != footpedal) midilist[i]->sendProgramChange(program,1);
  }
}

void footControlChange(byte channel, byte control, byte value) {
 //empty for test
  }


void footNoteOn(byte channel, byte note, byte velocity) {
    usbMIDI.sendNoteOn(note, velocity, channel);
for (int i=0; i<7; i++) {
if (i != footpedal) {
  midilist[i]->sendNoteOn(note,velocity, channel);
midilist[i]->send_now();
}
}
}

void footNoteOff(byte channel, byte note, byte velocity) {
   usbMIDI.sendNoteOn(note, 0, channel);
for (int i=0; i<7; i++) {
if (i != footpedal) {
  midilist[i]->sendNoteOn(note,0, channel);
midilist[i]->send_now();
}
}
}

teensy 4, two tabs.. the program:

Code:
elapsedMillis send_something;
void setup() {
  // put your setup code here, to run once:
usbMIDI.setHandleNoteOn(bassNoteOn);
usbMIDI.setHandleNoteOff(bassNoteOff);
Serial.println("this is teensy 4");
}

void loop() {
   usbMIDI.read();
  // put your main code here, to run repeatedly:
  if (send_something > 100) {
    
  send_something = 0;
usbMIDI.sendControlChange(31,100,1);
  }
  delay(10); //adjust this to adjust the delay on the other teensy!!! with delay 10 i get 2560ms delay on the other teensy
}


void bassNoteOn(byte channel, byte note, byte velocity) {
/*note = note % 12;
if (scale_pressed && (atmodes != 0)) {
  MIDI1.sendNoteOn(note + 40, 127,1);
  MIDI1.sendNoteOff(note + 40, 127,1); 
  rootnote = note + 1;
  change_disp3 = 1;
} */
}
void bassNoteOff(byte channel, byte note, byte velocity) {

   /* Serial.print("Note On, ch=");
      Serial.print(channel, DEC);
      Serial.print(", note=");
      Serial.print(note, DEC);
      Serial.print(", velocity=");
      Serial.println(velocity, DEC); */

}

and name.c

Code:
// To give your project a unique name, this code must be
// placed into a .c file (its own tab).  It can not be in
// a .cpp file or your main sketch (the .ino file).

#include "usb_names.h"

// Edit these lines to create your own name.  The length must
// match the number of characters in your custom name.

#define MANUFACTURER_NAME   {'L','o','k','k','i','L','a','b','s'}
#define MANUFACTURER_NAME_LEN  9
#define MIDI_NAME   {'F','O','O','T'}
#define MIDI_NAME_LEN  4
#define SERIAL_NUM {'E','n','c','o','d','e','r','F','a','n','e','l'}
#define SERIAL_NUM_LEN 12

// Do not change this part.  This exact format is required by USB.

struct usb_string_descriptor_struct usb_string_manufacturer_name = {
        2 + MANUFACTURER_NAME_LEN * 2,
        3,
        MANUFACTURER_NAME
};

struct usb_string_descriptor_struct usb_string_product_name = {
        2 + MIDI_NAME_LEN * 2,
        3,
        MIDI_NAME
};


struct usb_string_descriptor_struct usb_string_serial_number = {
        2 + SERIAL_NUM_LEN * 2,
        3,
        SERIAL_NUM
};
 
ok, since i will need this to be working rather soonish... i thought about using serial communication instead of midi to send data from teensy 3.6 to teensy 4. could this be a workaround for now? at least my code executes at the expected speed if i send the variable via serial out of the hub.

i am not sure how to find the teensy4 serial port on the hub though. both boards, teensy 3.6. and teensy4 are configured as serial + midi.

i have this on teensy 3.6:

Code:
// Create the ports for USB devices plugged into Teensy's 2nd USB port (via hubs)
USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
USBHub hub3(myusb);
USBHub hub4(myusb);
USBSerial userial(myusb);
MIDIDevice_BigBuffer midi01(myusb);
MIDIDevice_BigBuffer midi02(myusb);
MIDIDevice_BigBuffer midi03(myusb);
MIDIDevice_BigBuffer midi04(myusb);
MIDIDevice_BigBuffer midi05(myusb);
MIDIDevice_BigBuffer midi06(myusb);
MIDIDevice_BigBuffer midi07(myusb);

since the teensy4 will be the only serial device attached to this hub (along several other usb-midi synths) should this code in setup not print the serial of the teensy4?

Code:
Serial.println((char*)userial.serialNumber());

or do i need seven usbserial ports (like with midi) and scan them all?

sorry if this is all obvious, but i have until now not been able to find the teensy4 with the teensy 3.6 on the hub.

so to summarise: i have a hub with many connected usb-midi devices. one of them is a teensy4 to which i would like to send data not thru midi but straight serial. how do i have to create the ports for serial? and how do i "find" the teensy4 so that i can make sure my data is sent to this device?
 
i was able to find the teensy4 on the hub, i had to use the USBSerial_BigBuffer userial() statement, which is part of the newest USBHost library (but not jet included in 1.53). just in case anyone hits the same problem...the problem with midi still persist though.
 
Status
Not open for further replies.
Back
Top