Having problems with digitalRead()

lsrichard

Active member
I have been trying to write a program for a Teensy 3.6 using USB host and building off the MIDI input functions example.
It uses the USBHost_t36.h library.
In trouble shooting my code using the serial monitor I discovered in some parts of my code I am getting wrong readings from digitalRead().
Most of the time it normally reads the 6 pins I am reading fine.
When the code is doing a more complex sustain or hold functions it starts reading input pin 3 as pin 2 and pin 4 as pin 3 ect.
I tried disabling interrupts. that did not help.
There was one thing I tried that worked but is unusable in my code but is was useful to prove the error.

Serial.println( "gate 2 retriggered");
noInterrupts();
Serial.println(digitalRead(2));// why is this reading as pin 3
Serial.println(digitalRead(3));// why is this reading as pin 4
delay(3); // makes program get stuck for 7.5 seconds for some reason.
Serial.println(digitalRead(2));// gets stuck for 7.5 seconds then comes back with the correct readings for the last two and shows all four pin readings?
Serial.println(digitalRead(3));
interrupts();

Any advice would be greatly appreciated.
Thanks
Richard
 
I doubt whether you will get any useful output from Serial.println() while interrupts are disabled
 
…or delay()

We’d need to see your wiring (schematic and image, ideally), and more / all of your code, posted in </> code tags to preserve the formatting, if the problem persists after fixing that. If your code is too big, please write a small self-contained example that can be compiled using just the Arduino IDE.
 
it starts reading input pin 3 as pin 2
How can you tell that it is doing this?
Just to be sure, you add, for example,
Serial.print("p2 ");
in front of
Serial.println(digitalRead(2));
and similarly for the other pins.

a more complex sustain or hold functions
What is "complex" about it? If it involves more delays and/or turning interrupts on and off, it could make a mess of any output that is being generated during that time.

And I second @h4yn0nnym0u5e's request for code.

Pete
 
I tried running your program by putting into loop() and adding my best guess for the setup() function.

Indeed there is a strange long delay is you disable interrupts. Both Serial and delay() need interrupts to function properly.

With noInterrupts() commented out, I also noticed the printing in Arduino 1.8.19 serial monitor seems to be an exact multiple of my computer's screen refresh. Because exactly the same info is printed every time, it visually appears like nothing is happening, when in fact it's scrolling very fast at an exact multiple of the monitor refresh rate. I added a couple more lines to print an incrementing number, so it's easy to visually confirm the printing really is happening.

Here's the complete program I ran.

Code:
void setup() {
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  Serial.begin(9600);
}

unsigned int loopcount = 0;

void loop() {
  Serial.print("gate 2 retriggered ");
  Serial.println(loopcount);
  loopcount = loopcount + 1;
  //noInterrupts();
  Serial.println(digitalRead(2));// why is this reading as pin 3
  Serial.println(digitalRead(3));// why is this reading as pin 4
  delay(3); // makes program get stuck for 7.5 seconds for some reason.
  Serial.println(digitalRead(2));// gets stuck for 7.5 seconds then comes back with the correct readings for the last two and shows all four pin readings?
  Serial.println(digitalRead(3));
  //interrupts();
}

While running this program, I tried touching a wire between GND and either pin 2, 3, or 4. I can't reproduce the problem where the incorrect pin is measured.

If you're still having trouble, maybe try copying this complete program into Arduino and run it on your Teensy.

Likewise, if you want me to try more, please give a complete program I can copy into Arduino and run on Teensy here. I tried my best with the partial code you gave, but without a complete program to copy as-is into Arduino, there's always some guesswork.
 
I am actually using a teensy 4.0
My mistake.
The program uses USB Host and The MIDI callback functions example that I built off of.
It has a Pitch Bend part of it that works perfectly using two PWM outputs.
It had 6 Gate inputs that I am reading and 6 Gate outputs.
When I am not using the hold or sustain function it is just passing the gate inputs to the gate outputs.
When I do use the hold function that where the coding gets complex.
When in hold I am trying to make the gate outputs stay HIGH and at the same add a retrigger that responds to the gate inputs.
Here is my code.
It is sloppy with a ton of comments and a lot of commented out code that I have tried to make work or I am just not using.

<
```cpp
// * MIDIsustainPitchbendv5
// This probably needs to be on MIDI ch 1 only to match JCS module in poly mode.

//#include <Wire.h>// maybe not needed
//#include <WireIMXRT.h>// maybe not needed
//#include <WireKinetis.h>// maybe not needed

//#include <antplusdefs.h>// maybe not needed// it compiles without them fine
#include <USBHost_t36.h>
// maybe add PWM frequency ? now running at 500hz could be much higher

//File myFile;
USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
MIDIDevice midi1(myusb);

byte mc=1;// MIDI channel // 0 is omni mode //global // Saved in EEPROM
// mc probably needs to be on ch 1 to match JCS module
byte spp=0;// sustain pedal polarity 0 or 1// global // can be Saved in EEPROM
byte hv=0;// use to set pedal polarity
byte nhv=127;// to use other polarity swap values of hv and nhv.
byte mds=false;// modulation switch state
//byte EEPmode = false; // save to eeprom mode
byte sustainp = false;// sustain or hold mode
byte onegate = false; // gate 1 input
byte twogate = false;
byte threegate = false;
byte fourgate = false;
byte fivegate = false;
byte sixgate = false;
byte gateout1 = false; //gate 1 output
byte gateout2 = false;
byte gateout3 = false;
byte gateout4 = false;
byte gateout5 = false;
byte gateout6 = false;
int bndp;// bender right or positive
int bndn;// bender left or negative
byte sph1;//send retrigger gate pulse on next main loop
byte sph2;
byte sph3;
byte sph4;
byte sph5;
byte sph6;
unsigned long p1;// retigger pulse duration and timing
unsigned long p2;
unsigned long p3;
unsigned long p4;
unsigned long p5;
unsigned long p6;
byte onelht = false; // low to high transition of gate
byte twolht = false;
byte threelht = false;
byte fourlht = false;
byte fivelht = false;
byte sixlht = false;
byte setlht = false;// flag set to detect low to high gate transition in main loop.

void setup() {
Serial.begin(115200);
// maybe add PWM frequency ? now running at 500hz could be much higher
analogWriteResolution(12);// maybee add write frequency and frequencytimer2 library
pinMode(0, INPUT_PULLUP); // Sustain pedal polarity switch
//pinMode(13, INPUT_PULLUP); // maybe parellel sustain pedal input ?
pinMode(1, INPUT);
pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(4, INPUT);
pinMode(5, INPUT);
pinMode(6, INPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
pinMode(22, OUTPUT);
pinMode(23, OUTPUT);
delay(300);
myusb.begin();
midi1.setHandleNoteOn(myNoteOn);
midi1.setHandleNoteOff(myNoteOff);
//midi1.setHandleAfterTouchPoly(myAfterTouchPoly);
midi1.setHandleControlChange(myControlChange);
//midi1.setHandleProgramChange(myProgramChange);
//midi1.setHandleAfterTouchChannel(myAfterTouchChannel);
midi1.setHandlePitchChange(myPitchChange);
// Only one of these System Exclusive handlers will actually be
// used. See the comments below for the difference between them.
//midi1.setHandleSystemExclusive(mySystemExclusiveChunk);
//midi1.setHandleSystemExclusive(mySystemExclusive);
//midi1.setHandleTimeCodeQuarterFrame(myTimeCodeQuarterFrame);
//midi1.setHandleSongPosition(mySongPosition);
//midi1.setHandleSongSelect(mySongSelect);
//midi1.setHandleTuneRequest(myTuneRequest);
//midi1.setHandleClock(myClock);
//midi1.setHandleStart(myStart);
//midi1.setHandleContinue(myContinue);
//midi1.setHandleStop(myStop);
//midi1.setHandleActiveSensing(myActiveSensing);
//midi1.setHandleSystemReset(mySystemReset);
// This generic System Real Time handler is only used if the
// more specific ones are not set.
//midi1.setHandleRealTimeSystem(myRealTimeSystem);

Serial.println("MIDI Sustain and Pitch Bend v6");
Serial.println("Firmware File: MIDIsustainPitchbendv6");
Serial.println("Teensy 4.0 board with MIDI host.");
//analogReadResolution(12); // maybee not needed // no analogRead()
PedPol();
digitalWrite(7, LOW);
digitalWrite(8, LOW);
digitalWrite(9, LOW);
digitalWrite(10, LOW);
digitalWrite(11, LOW);
digitalWrite(12, LOW);
}// setup

void loop() {
// The handler functions are called when midi1 reads data. They
// will not be called automatically. You must call midi1.read()
// regularly from loop() for midi1 to actually read incoming
// data and run the handler functions as messages arrive.
//AudioNoInterrupts();
myusb.Task();
midi1.read();

spp = digitalRead(0);

//if (setlht == 0) {// made sustain not work at all and crashed.
sixgate = digitalRead(6);
fivegate = digitalRead(5);
fourgate = digitalRead(4);
threegate = digitalRead(3);
twogate = digitalRead(2);
onegate = digitalRead(1);// this can only do a digitalRead Here.
// these digital reads are for when sustain or hold is not on




///}
// problem is program can not tell what gate was retriggered.
// with hold on most of the retriggers heard are for the wrong gate// fixed
// JCS Gate 1 making MIDI box gate 2 go on.// fixed
// Problems mostly fixed by moving low to high transition detection into main loop in lhtSet() routine and not in myNoteOn() routine.

if ( onegate ){
if ( sustainp ){ //why is this only working if a note is held down ?// fixed by moving lht to main loop// gate/ triggers still sometimes get mixed up in sustain mode
if (setlht) lhtSet();// set low to high detection
if (onelht) { // gate 1 retrigger set low and start 1ms timer
gateout1 = false;
digitalWrite(7, gateout1);// maybe use real port address // it is faster
p1 = micros() + 900;// 1ms
sph1 = true; // flag to set gate 1 high again after 1ms
onelht = false;// reset low to high transistion flag to low
//Serial.println( "gate 1 retrigger flag");
} // lht1
if ((p1 < micros())&& (sph1)){ // gate 1 retrigger, 1ms has past , set gate 1 high again
gateout1 = true;
digitalWrite(7, gateout1);// maybe use real port address // it is faster
sph1 = false;// reset flag low because Gate 1 has been set high again
onelht= false;// reset flag low for next low to high transition of gate 1
/*
Serial.println( "gate 1 retriggered");
Serial.print("RT Gate , 1 to 6 =");
//Serial.print(digitalRead(1));
Serial.print(onegate);//reading wrong gate here // JCS gate 2 is triggering onegate variable
Serial.print(twogate);
Serial.print(threegate);
Serial.print(fourgate);
Serial.print(fivegate);
Serial.println(sixgate);
*/
}// micros
// Retrigger here once
// setup pulse timer 1ms ? low using loop
}// if sustinp
else { // gate 1 on without hold// reads correctly here but recycles continuisly // seems to be no problem for digitalWrite() to recycle
gateout1 = true;
//Serial.println( gatein1 );
//Serial.print(digitalRead(1));
//Serial.print("ON Gate IN , 1 to 6 =");
//Serial.print(onegate);
//Serial.print(twogate);
//Serial.print(threegate);
//Serial.print(fourgate);
//Serial.print(fivegate);
//Serial.println(sixgate);
digitalWrite(7, gateout1);
} // else sustain
} // if gate
else {
if ( sustainp == false ){// gate 1 off without hold
gateout1 = false;
digitalWrite(7, gateout1);
//Serial.println( gatein1 );
}// if sustainp
}// else

if ( twogate ){
if ( sustainp ){
if (setlht) lhtSet();
if (twolht) {
gateout2 = false;
digitalWrite(8, gateout2);// maybe use real port address // it is faster
p2 = micros() + 900;// 1ms
sph2 = true;
twolht = false;
//Serial.println( "gate 2 retrigger flag");
} // lht1
if ((p2 < micros())&& (sph2)){
gateout2 = true;
digitalWrite(8, gateout2);// maybe use real port address // it is faster
sph2 = false;
twolht= false;

//Serial.println( "gate 2 retriggered");
// critical, time-sensitive code here
//noInterrupts();
//Serial.println(digitalRead(2));
//Serial.println(digitalRead(3));
//delay(3);
//Serial.println(digitalRead(2));// gets stuck for 7.5 seconds then comes back with the correct readings for the last two and shows all four ?
//Serial.println(digitalRead(3));
//interrupts();

}// micros
// Retrigger here once
// setup pulse timer 1ms ? low using loop
}// if sustinp
else {
gateout2 = true;
digitalWrite(8, gateout2);
} // else sustain
}// if gate
else {
if ( sustainp == false ){
gateout2 = false;
digitalWrite(8, gateout2);
}// if sustainp
}// else

if ( threegate ){
if ( sustainp ){
if (setlht) lhtSet();
if (threelht) {
gateout3 = false;
digitalWrite(9, gateout3);// maybe use real port address // it is faster
p3 = micros() + 900;// 1ms
sph3 = true;
threelht = false;
} // lht1
if ((p3 < micros())&& (sph3)){
gateout3 = true;
digitalWrite(9, gateout3);// maybe use real port address // it is faster
sph3 = false;
threelht= false;
}// micros
// Retrigger here once
// setup pulse timer 1ms ? low using loop
}// if sustinp
else {
gateout3 = true;
digitalWrite(9, gateout3);
} // else sustain
}// if gate
else {
if ( sustainp == false ){
gateout3 = false;
digitalWrite(9, gateout3);
}// if sustainp
}// else

if ( fourgate ){
if ( sustainp ){
if (fourlht) {
gateout4 = false;
digitalWrite(10, gateout4);// maybe use real port address // it is faster
p4 = micros() + 900;// 1ms
sph4 = true;
fourlht = false;
} // lht1
if ((p4 < micros())&& (sph4)){
gateout4 = true;
digitalWrite(10, gateout4);// maybe use real port address // it is faster
sph4 = false;
fourlht= false;
}// micros
// Retrigger here once
// setup pulse timer 1ms ? low using loop
}// if sustinp
else {
gateout4 = true;
digitalWrite(10, gateout4);
} // else sustain
}// if gate
else {
if ( sustainp == false ){
gateout4 = false;
digitalWrite(10, gateout4);
}// if sustainp
}// else

if ( fivegate ){
if ( sustainp ){
if (setlht) lhtSet();
if (fivelht) {
gateout5 = false;
digitalWrite(11, gateout5);// maybe use real port address // it is faster // was coming out of 6 ?
p5 = micros() + 900;// 1ms
sph5 = true;
fivelht = false;
} // lht1
if ((p5 < micros())&& (sph5)){
gateout5 = true;
digitalWrite(11, gateout5);// maybe use real port address // it is faster
sph5 = false;
fivelht= false;
}// micros
}// if sustinp
else {
gateout5 = true;
digitalWrite(11, gateout5);
} // else sustain
}// if gate
else {
if ( sustainp == false ){
gateout5 = false;
digitalWrite(11, gateout5);
}// if sustainp
}// else

if ( sixgate ){
if ( sustainp ){
if (setlht) lhtSet();
if (sixlht) {
gateout6 = false;
digitalWrite(12, gateout6);// maybe use real port address // it is faster // was coming out of 5 ?
p6 = micros() + 900;// 1ms
sph6 = true;
sixlht = false;
} // lht1
if ((p6 < micros())&& (sph6)){
gateout6 = true;
digitalWrite(12, gateout6);// maybe use real port address // it is faster
sph6 = false;
sixlht= false;
}// micros
}// if sustinp
else {
gateout6 = true;
digitalWrite(12, gateout6);
} // else sustain
}// if gate
else {
if ( sustainp == false ){
gateout6 = false;
digitalWrite(12, gateout6);
}// if sustainp
}// else
}// Main loop

void myNoteOn(byte channel, byte note, byte velocity) {// will only retrigger with hold on if at least one note is held down.// problem fixxed
// you cannot do a digitalRead relilibly within This myNoteOn Routine
if (( mc == channel ) || ( mc == 0 )) {// problem is no voice related gate alicaton is possible
if ( sustainp ){// adding this keeps it from retriggering as sustain or hold is turned on
//sustainp = false; // did not work caused no sustain at all
setlht = true;//sets to detect low to high gate transitions in main loop// low to high transition detection will be done in main loop and needs to be.
// myNoteOn() has strainge problems// vaiables do not get set correctly sometimes and digitalRead() also has problems in this.
}// if sustinp
//Serial.print(", note=");
//Serial.print(note, DEC);
//Serial.print(", velocity=");
//Serial.println(velocity, DEC);
}//mc
}//my


void myNoteOff(byte channel, byte note, byte velocity) {// adding note off seem to change things the most// sometimes will not sound until note is release in sustain mode// fixed
if (( mc == channel ) || ( mc == 0 )) {
if ( onegate == 0) {// detect gate off
onelht = false;// reset gate 1 low to high detaction flag
sph1 = false;// reset send retrigger pulse on flag
}
if ( twogate == 0) {
twolht = false;
sph2 = false;
}
if ( threegate == 0) {
threelht = false;
sph3 = false;
}
if ( fourgate == 0) {
fivelht = false;
sph4 = false;
}
if ( sixgate == 0) {
sixlht = false;// not sure how this works but swapping 5 and 6 it fixed it for the most part // probably strainge compiler error // more unique varable names could help// error seems to be gone now
sph6 = false;
}
if ( fivegate == 0) {
fivelht = false;
sph5 = false;
}
// */
//Serial.print("Note Off, ch=");
//Serial.print(channel, DEC);
//Serial.print(", note=");
//Serial.print(note, DEC);
//Serial.print(", velocity=");
//Serial.println(velocity, DEC);
}//mc
}//my
/*
//void myAfterTouchPoly(byte channel, byte note, byte velocity) {// Nothing on the S-10
// Serial.print("AfterTouch Change, ch=");
// Serial.print(channel, DEC);
// Serial.print(", note=");
//Serial.print(note, DEC);
//Serial.print(", velocity=");
//Serial.println(velocity, DEC);
//}
*/
void myControlChange(byte channel, byte control, byte value) { //This works With the S-10 joystick switch as control #1 value on #127 off #0
//Serial.print("Control Change, ch=");// control #123 may be all notes off ?
//Serial.print(channel, DEC); // bender will need to take value, do math with bender range, and recall newsineshigh.
//Serial.print(", control=");
//Serial.print(control, DEC);
//Serial.print(", value=");
//Serial.println(value, DEC); // need to add sustain pedal function, control 64, value off 0, on 127// will need to give polarity option.
if (( mc == channel ) || ( mc == 0 )) {//read gates here also
if ( control == 64 ){ // Maybe even get strainge and invert the fuction touching notes to turn them off ? just an Idea.
PedPol(); // pedal works perfect with no changes needed.
if ( value == hv ){// had to use reverse polarity pedal/0 = hold or hv/ 127= not hold or nhv.
sustainp = true;
}//value==hv
if ( value == nhv ){
sustainp = false;
}//value==nhv
}//control==64

if ( control == 1 ){
if ( value == 127 ){// could be dynamic on some keyboard controllers // check it // Triton LE it is dynamic
//Serial.println("Modulation Switch Full On 127");
mds=true;
}//value=127
else{//else of value==127
//Serial.print(value);
//Serial.println(" Modulation Switch Off");
mds=false;
}//else of value==127
}//control
}//mc
}//my

/*
void myProgramChange(byte channel, byte program) {
//Serial.print("Program Change, ch=");// Programs start on 0 // channel starts on 1
//Serial.print(channel, DEC);
//Serial.print(", program=");
//Serial.println(program, DEC);
if (( mc == channel ) || ( mc == 0 )) {// ch 0 is omni mode
if (mp){ // Only act if MIDI program change is set to ON
}//mp
}//mc
}//my

//void myAfterTouchChannel(byte channel, byte pressure) { // Nothing on the S-10
// Serial.print("After Touch, ch=");
// Serial.print(channel, DEC);
// Serial.print(", pressure=");
// Serial.println(pressure, DEC);
//}
*/
void myPitchChange(byte channel, int pitch) { // This works with the joystick on the S-10
//Serial.print("Pitch Change, ch=");
//Serial.print(channel, DEC);
//Serial.print(", pitch=");
//Serial.println(pitch, DEC);
if (( mc == channel ) || ( mc == 0 )) {// pitch has a range of +/-8192 then converted to +/- 100 and multiplied by bender range
if ( pitch > -1 ) {
//Serial.println(abs(pitch));
//Serial.println(pitch);
bndp = pitch / 2;// bender right side or +
bndn = 0;
//Serial.println(bndp);
analogWrite(22,bndp);// maybe add PWM frequency ? now running at 500hz could be much higher
analogWrite(23,bndn);// seems to work ok without PWM frequency// there are two stages of 10uf filtering and it is not too slow.
}// if pitch
else{
bndn = ( abs( pitch ) / 2 ) - 1;// bender left side or -
bndp = 0;
//Serial.println(abs(pitch));
//Serial.println(bndn);
analogWrite(23,bndn);
analogWrite(22,bndp);
}// else
}//mc
}//my

/*
// This 3-input System Exclusive function is more complex, but allows you to
// process very large messages which do not fully fit within the midi1's
// internal buffer. Large messages are given to you in chunks, with the
// 3rd parameter to tell you which is the last chunk. This function is
// a Teensy extension, not available in the Arduino MIDI library.
//
//void mySystemExclusiveChunk(const byte *data, uint16_t length, bool last) {
//Serial.print("SysEx Message: ");
//printBytes(data, length);
// if (last) {
// Serial.println(" (end)");
//} else {
// Serial.println(" (to be continued)");
//}
//}

// This simpler 2-input System Exclusive function can only receive messages
// up to the size of the internal buffer. Larger messages are truncated, with
// no way to receive the data which did not fit in the buffer. If both types
// of SysEx functions are set, the 3-input version will be called by midi1.
//
//void mySystemExclusive(byte *data, unsigned int length) {
//Serial.print("SysEx Message: ");
//printBytes(data, length);
//Serial.println();
//}

//void myTimeCodeQuarterFrame(byte data) {
//static char SMPTE[8]={'0','0','0','0','0','0','0','0'};
//static byte fps=0;
//byte index = data >> 4;
//byte number = data & 15;
//if (index == 7) {
// fps = (number >> 1) & 3;
// number = number & 1;
// }
//if (index < 8 || number < 10) {
// SMPTE[index] = number + '0';
// Serial.print("TimeCode: "); // perhaps only print when index == 7
//Serial.print(SMPTE[7]);
// Serial.print(SMPTE[6]);
// Serial.print(':');
// Serial.print(SMPTE[5]);
// Serial.print(SMPTE[4]);
// Serial.print(':');
// Serial.print(SMPTE[3]);
// Serial.print(SMPTE[2]);
//Serial.print('.');
//Serial.print(SMPTE[1]); // perhaps add 2 to compensate for MIDI latency?
//Serial.print(SMPTE[0]);
// switch (fps) {
// case 0: Serial.println(" 24 fps"); break;
// case 1: Serial.println(" 25 fps"); break;
// case 2: Serial.println(" 29.97 fps"); break;
// case 3: Serial.println(" 30 fps"); break;
// }
// } else {
// Serial.print("TimeCode: invalid data = ");
// Serial.println(data, HEX);
// }
//}

//void mySongPosition(uint16_t beats) {
// Serial.print("Song Position, beat=");
// Serial.println(beats);
//}

//void mySongSelect(byte songNumber) {
// Serial.print("Song Select, song=");
// Serial.println(songNumber, DEC);
//}

//void myTuneRequest() { // nothing on the S-10
// Serial.println("Tune Request");
//}

//void myClock() {
// Serial.println("Clock");
//}

//void myStart() {// nothing on the S-10
// Serial.println("Start");
//}

//void myContinue() {
// Serial.println("Continue");
//}

//void myStop() {
// Serial.println("Stop");
//}

//void myActiveSensing() {
// Serial.println("Actvice Sensing");
//}

//void mySystemReset() {
// Serial.println("System Reset");
//}

//void myRealTimeSystem(uint8_t realtimebyte) {//nothing on the S-10
// Serial.print("Real Time Message, code=");
// Serial.println(realtimebyte, HEX);
//}

//void printBytes(const byte *data, unsigned int size) {
// while (size > 0) {
// byte b = *data++;
// if (b < 16) Serial.print('0');
// Serial.print(b, HEX);
// if (size > 1) Serial.print(' ');
// size = size - 1;
//}
//}
*/

void PedPol(void){
if ( spp == 0) {
hv=0; // could be pure math hv=spp*127; with no if
nhv=127; // could be pure math nhv= ~spp*127; with no if
}//spp==0
if ( spp == 1) {
hv=127;
nhv=0;
}//spp==1
}//PedPol

void lhtSet(void){// this is starting to work but now retriggers when hold is activated // Retrigger problem fixed by adding if(sustainp) to myNoteOn()
onegate = digitalRead(1);// this can only do a digitalRead Here, not in myNoteOn().
twogate = digitalRead(2);// lhtSet is used when hold or sustain is activated
threegate = digitalRead(3);// detect low to high transition
fourgate = digitalRead(4);// make this only if the lht variable is not allready set
fivegate = digitalRead(5);
sixgate = digitalRead(6);// maybe try removing these digitalRead()'s
if ( onegate ) onelht = true;// sets that a low to high transition has happend
if ( twogate ) twolht = true;// this still sounds better even if it retriggers every note being held down
if ( threegate ) threelht = true;
if ( fourgate ) fourlht = true;
if ( fivegate ) fivelht = true;
if ( sixgate ) sixlht = true;
setlht = false; //reset read low to high detections flag for next Note on.
/*
Serial.print("lhtSet Gate IN , 1 to 6 =");// only active with sustain on
Serial.print(onegate);//reading wrong gate here // JCS gate 2 is triggering onegate variable
Serial.print(twogate);
Serial.print(threegate);
Serial.print(fourgate);
Serial.print(fivegate);
Serial.println(sixgate);
*/
}// lhtSet()
// is it still mixing up variables ? if so fix that first. gate 1 ID correct gate 3 IDed as gate 2 ? // not recycling
// digitalRead() is miss IDing gate 3 as gate 2, proven// try disable interups ? // did not help
// also reading gate 4 as gate 3 at this point.//

// maybe try to make a single 6 bit number to track what notes are being held down (gates on) and not to rertrigger them
// make new and old versions of that variable to detect changes.
// another idea is to do hold down stream in the Decay of the Hexsynator. R70 or R76 is the decay discharge resistor and the cap is C24 and is 1uf.
// maybe use a BS170 MOSFET.
// if (( sixgate ) && ( sixlht == 0 )) {
// if (( fivegate ) && ( fivelht == 0 )) {
// if (( fourgate ) && ( fourlht == 0 )) {
// if (( threegate ) && ( threelht == 0 )) {
// if (( twogate ) && ( twolht == 0 )) {
// if (( onegate ) && ( onelht == 0 )) {
/*
if ( sixgate ) { // got worse with sustain on // not knowing what gate to retrigger
sixlht = true; // sets that a low to high transition has happend
setlht = false; //reset read low to high detections flag for next Note on.
return;
} //6
if ( fivegate ) {
fivelht = true;
setlht = false; //reset read low to high detections flag for next Note on.
return;
}//5
if ( fourgate ) {
fourlht = true;
setlht = false; //reset read low to high detections flag for next Note on.
return;
}//4
if ( threegate ) {
threelht = true;
setlht = false; //reset read low to high detections flag for next Note on.
return;
}//3
if ( twogate ) {
twolht = true;
setlht = false; //reset read low to high detections flag for next Note on.
return;
}//2
if ( onegate ) {
onelht = true; // sets that a low to high transition has happend
setlht = false; //reset read low to high detections flag for next Note on.
return;
}//1
*/
/>
```

Thanks
 
The Gate signals I am passing thru the Teensy 4.0 come from two MIDI to CV converter modules made by Jakes Custom House.
They have 5 volt gate outputs so I am using a simple level converter to bring them down to 3.3 volts.
Attached is the schematic.
I do not think I am getting any crosstalk between the input pins but have considered the possibility of it.
If that is happening the results would probably be way more random and it would be a problem all of the time.
Thanks
 

Attachments

  • Teensy40 gate circuit.jpg
    Teensy40 gate circuit.jpg
    121.7 KB · Views: 74
Your posted code is unreadable! Could you please edit your post to put it in the code tags (circled in red), and check using the preview (green). The toolbar may look a bit different, I‘m on a tablet…
1749101204818.jpeg
 
Sorry, I will repost the code here the correct way.
C++:
```cpp
// * MIDIsustainPitchbendv5
// This probably needs to be on MIDI ch 1 only to match JCS module in poly mode.

//#include <Wire.h>// maybe not needed
//#include <WireIMXRT.h>// maybe not needed
//#include <WireKinetis.h>// maybe not needed

//#include <antplusdefs.h>// maybe not needed// it compiles without them fine
#include <USBHost_t36.h>
// maybe add PWM frequency ? now running at 500hz could be much higher

//File myFile;
USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
MIDIDevice midi1(myusb);

byte mc=1;// MIDI channel // 0 is omni mode //global // Saved in EEPROM
// mc probably needs to be on ch 1 to match JCS module
byte spp=0;// sustain pedal polarity 0 or 1// global // can be Saved in EEPROM
byte hv=0;// use to set pedal polarity
byte nhv=127;// to use other polarity swap values of hv and nhv.
byte mds=false;// modulation switch state
//byte EEPmode = false; // save to eeprom mode
byte sustainp = false;// sustain or hold mode
byte onegate = false; // gate 1 input
byte twogate = false;
byte threegate = false;
byte fourgate = false;
byte fivegate = false;
byte sixgate = false;
byte gateout1 = false; //gate 1 output
byte gateout2 = false;
byte gateout3 = false;
byte gateout4 = false;
byte gateout5 = false;
byte gateout6 = false;
int bndp;// bender right or positive
int bndn;// bender left or negative
byte sph1;//send retrigger gate pulse on next main loop
byte sph2;
byte sph3;
byte sph4;
byte sph5;
byte sph6;
unsigned long p1;// retigger pulse duration and timing
unsigned long p2;
unsigned long p3;
unsigned long p4;
unsigned long p5;
unsigned long p6;
byte onelht = false; // low to high transition of gate
byte twolht = false;
byte threelht = false;
byte fourlht = false;
byte fivelht = false;
byte sixlht = false;
byte setlht = false;// flag set to detect low to high gate transition in main loop.
 
void setup() {
  Serial.begin(115200);
  // maybe add PWM frequency ? now running at 500hz could be much higher
  analogWriteResolution(12);// maybee add write frequency and frequencytimer2 library
  pinMode(0, INPUT_PULLUP); // Sustain pedal polarity switch
  //pinMode(13, INPUT_PULLUP); // maybe parellel sustain pedal input ?
  pinMode(1, INPUT);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(22, OUTPUT);
  pinMode(23, OUTPUT);
  delay(300); 
  myusb.begin();
  midi1.setHandleNoteOn(myNoteOn);
  midi1.setHandleNoteOff(myNoteOff);
  //midi1.setHandleAfterTouchPoly(myAfterTouchPoly);
  midi1.setHandleControlChange(myControlChange);
  //midi1.setHandleProgramChange(myProgramChange);
  //midi1.setHandleAfterTouchChannel(myAfterTouchChannel);
  midi1.setHandlePitchChange(myPitchChange);
  // Only one of these System Exclusive handlers will actually be
  // used.  See the comments below for the difference between them.
  //midi1.setHandleSystemExclusive(mySystemExclusiveChunk);
  //midi1.setHandleSystemExclusive(mySystemExclusive);
  //midi1.setHandleTimeCodeQuarterFrame(myTimeCodeQuarterFrame);
  //midi1.setHandleSongPosition(mySongPosition);
  //midi1.setHandleSongSelect(mySongSelect);
  //midi1.setHandleTuneRequest(myTuneRequest);
  //midi1.setHandleClock(myClock);
  //midi1.setHandleStart(myStart);
  //midi1.setHandleContinue(myContinue);
  //midi1.setHandleStop(myStop);
  //midi1.setHandleActiveSensing(myActiveSensing);
  //midi1.setHandleSystemReset(mySystemReset);
  // This generic System Real Time handler is only used if the
  // more specific ones are not set.
  //midi1.setHandleRealTimeSystem(myRealTimeSystem);
 
  Serial.println("MIDI Sustain and Pitch Bend v6");
  Serial.println("Firmware File: MIDIsustainPitchbendv6");
  Serial.println("Teensy 4.0 board with MIDI host.");
  //analogReadResolution(12); // maybee not needed // no analogRead() 
  PedPol();
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
  digitalWrite(12, LOW);
}// setup

void loop() {
  // The handler functions are called when midi1 reads data.  They
  // will not be called automatically.  You must call midi1.read()
  // regularly from loop() for midi1 to actually read incoming
  // data and run the handler functions as messages arrive.
  //AudioNoInterrupts();
  myusb.Task();
  midi1.read();

  spp = digitalRead(0);

  //if (setlht == 0) {// made sustain not work at all and crashed.
  sixgate = digitalRead(6);
  fivegate = digitalRead(5);
  fourgate = digitalRead(4);
  threegate = digitalRead(3);
  twogate = digitalRead(2);
  onegate = digitalRead(1);// this can only do a digitalRead Here.
 // these digital reads are for when sustain or hold is not on
 
 
 
 
 ///}
  // problem is program can not tell what gate was retriggered.
  // with hold on most of the retriggers heard are for the wrong gate// fixed
  // JCS Gate 1 making MIDI box gate 2 go on.// fixed
  // Problems mostly fixed by moving low to high transition detection into main loop in lhtSet() routine and not in myNoteOn() routine.

  if ( onegate ){
    if ( sustainp ){ //why is this only working if a note is held down ?// fixed by moving lht to main loop// gate/ triggers still sometimes get mixed up in sustain mode
    if (setlht) lhtSet();// set low to high detection
      if (onelht) { // gate 1 retrigger set low and start 1ms timer
        gateout1 = false;
        digitalWrite(7, gateout1);// maybe use real port address // it is faster
        p1 = micros() + 900;// 1ms
        sph1 = true; // flag to set gate 1 high again after 1ms
        onelht = false;// reset low to high transistion flag to low
        //Serial.println( "gate 1 retrigger flag");
        } // lht1 
      if ((p1 < micros())&& (sph1)){ // gate 1 retrigger, 1ms has past , set gate 1 high again
        gateout1 = true;   
        digitalWrite(7, gateout1);// maybe use real port address // it is faster
        sph1 = false;// reset flag low because Gate 1 has been set high again
        onelht= false;// reset flag low for next low to high transition of gate 1
        /*
        Serial.println( "gate 1 retriggered");
        Serial.print("RT Gate , 1 to 6 =");
        //Serial.print(digitalRead(1));
        Serial.print(onegate);//reading wrong gate here // JCS gate 2 is triggering onegate variable
        Serial.print(twogate);
        Serial.print(threegate);
        Serial.print(fourgate);
        Serial.print(fivegate);
        Serial.println(sixgate);
        */
        }// micros
     // Retrigger here once
     // setup pulse timer 1ms ? low using loop
    }// if sustinp
    else { // gate 1 on without hold// reads correctly here but recycles continuisly // seems to be no problem for digitalWrite() to recycle
    gateout1 = true;
    //Serial.println( gatein1 );
    //Serial.print(digitalRead(1));
    //Serial.print("ON Gate IN , 1 to 6 =");
    //Serial.print(onegate);
    //Serial.print(twogate);
    //Serial.print(threegate);
    //Serial.print(fourgate);
    //Serial.print(fivegate);
    //Serial.println(sixgate);
    digitalWrite(7, gateout1);
      } // else sustain
    } // if gate
  else {
    if ( sustainp == false ){// gate 1 off without hold
      gateout1 = false;
      digitalWrite(7, gateout1);
      //Serial.println( gatein1 );     
    }// if sustainp
  }// else

  if ( twogate ){
    if ( sustainp ){
      if (setlht) lhtSet();
      if (twolht) {
        gateout2 = false;
        digitalWrite(8, gateout2);// maybe use real port address // it is faster
        p2 = micros() + 900;// 1ms
        sph2 = true;
        twolht = false;
         //Serial.println( "gate 2 retrigger flag");
        } // lht1 
      if ((p2 < micros())&& (sph2)){
        gateout2 = true;   
        digitalWrite(8, gateout2);// maybe use real port address // it is faster
        sph2 = false;
        twolht= false;
        
        //Serial.println( "gate 2 retriggered");       
      // critical, time-sensitive code here
      //noInterrupts();
        //Serial.println(digitalRead(2));
        //Serial.println(digitalRead(3));
        //delay(3);
        //Serial.println(digitalRead(2));// gets stuck for 7.5 seconds then comes back with the correct readings for the last two and shows all four ?
        //Serial.println(digitalRead(3));
      //interrupts();
      
        }// micros
     // Retrigger here once
     // setup pulse timer 1ms ? low using loop
    }// if sustinp
    else {
    gateout2 = true;
    digitalWrite(8, gateout2);
    } // else sustain
    }// if gate
  else {
    if ( sustainp == false ){
      gateout2 = false;
      digitalWrite(8, gateout2);     
    }// if sustainp
  }// else

  if ( threegate ){
    if ( sustainp ){
      if (setlht) lhtSet();
      if (threelht) {
        gateout3 = false;
        digitalWrite(9, gateout3);// maybe use real port address // it is faster
        p3 = micros() + 900;// 1ms
        sph3 = true;
        threelht = false;
        } // lht1 
      if ((p3 < micros())&& (sph3)){
        gateout3 = true;   
        digitalWrite(9, gateout3);// maybe use real port address // it is faster
        sph3 = false;
        threelht= false;
        }// micros
     // Retrigger here once
     // setup pulse timer 1ms ? low using loop
    }// if sustinp
    else {
    gateout3 = true;
    digitalWrite(9, gateout3);
    } // else sustain
    }// if gate
  else {
    if ( sustainp == false ){
      gateout3 = false;
      digitalWrite(9, gateout3);     
    }// if sustainp
  }// else

  if ( fourgate ){
    if ( sustainp ){
      if (fourlht) {
        gateout4 = false;
        digitalWrite(10, gateout4);// maybe use real port address // it is faster
        p4 = micros() + 900;// 1ms
        sph4 = true;
        fourlht = false;
        } // lht1 
      if ((p4 < micros())&& (sph4)){
        gateout4 = true;   
        digitalWrite(10, gateout4);// maybe use real port address // it is faster
        sph4 = false;
        fourlht= false;
        }// micros
     // Retrigger here once
     // setup pulse timer 1ms ? low using loop
    }// if sustinp
    else {
    gateout4 = true;
    digitalWrite(10, gateout4);
      } // else sustain
    }// if gate
  else {
    if ( sustainp == false ){
      gateout4 = false;
      digitalWrite(10, gateout4);     
    }// if sustainp
  }// else

  if ( fivegate ){
    if ( sustainp ){
      if (setlht) lhtSet();
      if (fivelht) {
        gateout5 = false;
        digitalWrite(11, gateout5);// maybe use real port address // it is faster // was coming out of 6 ?
        p5 = micros() + 900;// 1ms
        sph5 = true;
        fivelht = false;
        } // lht1 
      if ((p5 < micros())&& (sph5)){
        gateout5 = true;   
        digitalWrite(11, gateout5);// maybe use real port address // it is faster
        sph5 = false;
        fivelht= false;
        }// micros
    }// if sustinp
    else {
    gateout5 = true;
    digitalWrite(11, gateout5);
     } // else sustain
    }// if gate
  else {
    if ( sustainp == false ){
      gateout5 = false;
      digitalWrite(11, gateout5);     
    }// if sustainp
  }// else

  if ( sixgate ){
    if ( sustainp ){
      if (setlht) lhtSet();
      if (sixlht) {
        gateout6 = false;
        digitalWrite(12, gateout6);// maybe use real port address // it is faster // was coming out of 5 ?
        p6 = micros() + 900;// 1ms
        sph6 = true;
        sixlht = false;
        } // lht1 
      if ((p6 < micros())&& (sph6)){
        gateout6 = true;   
        digitalWrite(12, gateout6);// maybe use real port address // it is faster
        sph6 = false;
        sixlht= false;
        }// micros
    }// if sustinp
    else {
    gateout6 = true;
    digitalWrite(12, gateout6);
     } // else sustain
    }// if gate
  else {
    if ( sustainp == false ){
      gateout6 = false;
      digitalWrite(12, gateout6);     
    }// if sustainp
  }// else
}// Main loop

void myNoteOn(byte channel, byte note, byte velocity) {// will only retrigger with hold on if at least one note is held down.// problem fixxed
// you cannot do a digitalRead relilibly within This myNoteOn Routine
  if (( mc == channel ) || ( mc == 0 )) {// problem is no voice related gate alicaton is possible
    if ( sustainp ){// adding this keeps it from retriggering as sustain or hold is turned on
    //sustainp = false; // did not work caused no sustain at all
    setlht = true;//sets to detect low to high gate transitions in main loop// low to high transition detection will be done in main loop and needs to be.
    // myNoteOn() has strainge problems// vaiables do not get set correctly sometimes and digitalRead() also has problems in this.
    }// if sustinp
  //Serial.print(", note=");
  //Serial.print(note, DEC);
  //Serial.print(", velocity=");
  //Serial.println(velocity, DEC); 
  }//mc
}//my


void myNoteOff(byte channel, byte note, byte velocity) {// adding note off seem to change things the most// sometimes will not sound until note is release in sustain mode// fixed
  if (( mc == channel ) || ( mc == 0 )) {
    if ( onegate == 0) {// detect gate off
      onelht = false;// reset gate 1 low to high detaction flag
      sph1 = false;// reset send retrigger pulse on flag
    }
    if ( twogate == 0) {
      twolht = false;
      sph2 = false;
    }
    if ( threegate == 0) {
      threelht = false;
      sph3 = false;
    }
    if ( fourgate == 0) {
      fivelht = false;
      sph4 = false;
    }
    if ( sixgate == 0) {
      sixlht = false;// not sure how this works but swapping 5 and 6 it fixed it for the most part // probably strainge compiler error // more unique varable names could help// error seems to be gone now
      sph6 = false;
    }
    if ( fivegate == 0) {
      fivelht = false;
      sph5 = false;
    }
   // */
  //Serial.print("Note Off, ch=");
  //Serial.print(channel, DEC);
  //Serial.print(", note=");
  //Serial.print(note, DEC);
  //Serial.print(", velocity=");
  //Serial.println(velocity, DEC);   
  }//mc
}//my
/*
//void myAfterTouchPoly(byte channel, byte note, byte velocity) {// Nothing on the  S-10
// Serial.print("AfterTouch Change, ch=");
// Serial.print(channel, DEC);
// Serial.print(", note=");
 //Serial.print(note, DEC);
 //Serial.print(", velocity=");
 //Serial.println(velocity, DEC);
//}
*/
void myControlChange(byte channel, byte control, byte value) { //This works With the S-10 joystick switch as control #1 value on #127 off #0
  //Serial.print("Control Change, ch=");// control #123 may be all notes off ?
  //Serial.print(channel, DEC); // bender will need to take value, do math with bender range, and recall newsineshigh.
  //Serial.print(", control=");
  //Serial.print(control, DEC);
  //Serial.print(", value=");
  //Serial.println(value, DEC); // need to add sustain pedal function, control 64, value off 0, on 127// will need to give polarity option.
  if (( mc == channel ) || ( mc == 0 )) {//read gates here also
  if ( control == 64 ){ // Maybe even get strainge and invert the fuction touching notes to turn them off ? just an Idea.
    PedPol(); // pedal works perfect with no changes needed.
   if ( value == hv ){// had to use reverse polarity pedal/0 = hold or hv/ 127= not hold or nhv.
    sustainp = true;
   }//value==hv
   if ( value == nhv ){
    sustainp = false;
   }//value==nhv
  }//control==64
 
  if ( control == 1 ){
    if ( value == 127 ){// could be dynamic on some keyboard controllers // check it // Triton LE it is dynamic
      //Serial.println("Modulation Switch Full On 127");
      mds=true;
     }//value=127     
    else{//else of value==127
      //Serial.print(value); 
      //Serial.println(" Modulation Switch Off");
      mds=false;
    }//else of value==127
  }//control
 }//mc
}//my

/*
void myProgramChange(byte channel, byte program) {
 //Serial.print("Program Change, ch=");// Programs start on 0 // channel starts on 1
 //Serial.print(channel, DEC);
 //Serial.print(", program=");
 //Serial.println(program, DEC);
 if (( mc == channel ) || ( mc == 0 )) {// ch 0 is omni mode
    if (mp){ // Only act if MIDI program change is set to ON     
    }//mp
  }//mc     
}//my
 
//void myAfterTouchChannel(byte channel, byte pressure) { // Nothing on the  S-10
 // Serial.print("After Touch, ch=");
 // Serial.print(channel, DEC);
 // Serial.print(", pressure=");
 // Serial.println(pressure, DEC);
//}
*/
void myPitchChange(byte channel, int pitch) { // This works with the joystick on the S-10
  //Serial.print("Pitch Change, ch=");
  //Serial.print(channel, DEC);
  //Serial.print(", pitch=");
  //Serial.println(pitch, DEC);
  if (( mc == channel ) || ( mc == 0 )) {// pitch has a range of +/-8192 then converted to +/- 100 and multiplied by bender range   
  if ( pitch > -1 ) {     
    //Serial.println(abs(pitch));   
    //Serial.println(pitch);
    bndp = pitch / 2;// bender right side or +
    bndn = 0;
    //Serial.println(bndp);
    analogWrite(22,bndp);// maybe add PWM frequency ? now running at 500hz could be much higher
    analogWrite(23,bndn);// seems to work ok without PWM frequency// there are two stages of 10uf filtering and it is not too slow.
  }// if pitch
  else{
    bndn = ( abs( pitch ) / 2 ) - 1;// bender left side or -
    bndp = 0;
    //Serial.println(abs(pitch));
    //Serial.println(bndn);
    analogWrite(23,bndn);
    analogWrite(22,bndp); 
  }// else         
 }//mc 
}//my
 
/*
// This 3-input System Exclusive function is more complex, but allows you to
// process very large messages which do not fully fit within the midi1's
// internal buffer.  Large messages are given to you in chunks, with the
// 3rd parameter to tell you which is the last chunk.  This function is
// a Teensy extension, not available in the Arduino MIDI library.
//
//void mySystemExclusiveChunk(const byte *data, uint16_t length, bool last) {
  //Serial.print("SysEx Message: ");
  //printBytes(data, length);
 // if (last) {
  //  Serial.println(" (end)");
  //} else {
   // Serial.println(" (to be continued)");
  //}
//}

// This simpler 2-input System Exclusive function can only receive messages
// up to the size of the internal buffer.  Larger messages are truncated, with
// no way to receive the data which did not fit in the buffer.  If both types
// of SysEx functions are set, the 3-input version will be called by midi1.
//
//void mySystemExclusive(byte *data, unsigned int length) {
  //Serial.print("SysEx Message: ");
  //printBytes(data, length);
  //Serial.println();
//}

//void myTimeCodeQuarterFrame(byte data) {
  //static char SMPTE[8]={'0','0','0','0','0','0','0','0'};
  //static byte fps=0;
  //byte index = data >> 4;
  //byte number = data & 15;
  //if (index == 7) {
  //  fps = (number >> 1) & 3;
   // number = number & 1;
 // }
  //if (index < 8 || number < 10) {
   // SMPTE[index] = number + '0';
   // Serial.print("TimeCode: ");  // perhaps only print when index == 7
    //Serial.print(SMPTE[7]);
   // Serial.print(SMPTE[6]);
   // Serial.print(':');
   // Serial.print(SMPTE[5]);
   // Serial.print(SMPTE[4]);
   // Serial.print(':');
   // Serial.print(SMPTE[3]);
   // Serial.print(SMPTE[2]);
    //Serial.print('.');
    //Serial.print(SMPTE[1]);  // perhaps add 2 to compensate for MIDI latency?
    //Serial.print(SMPTE[0]);
   // switch (fps) {
   //   case 0: Serial.println(" 24 fps"); break;
   //   case 1: Serial.println(" 25 fps"); break;
    //  case 2: Serial.println(" 29.97 fps"); break;
    //  case 3: Serial.println(" 30 fps"); break;
   // }
 // } else {
  //  Serial.print("TimeCode: invalid data = ");
  //  Serial.println(data, HEX);
 // }
//}

//void mySongPosition(uint16_t beats) {
 // Serial.print("Song Position, beat=");
 // Serial.println(beats);
//}

//void mySongSelect(byte songNumber) {
//  Serial.print("Song Select, song=");
 // Serial.println(songNumber, DEC);
//}

//void myTuneRequest() { // nothing on the S-10
//  Serial.println("Tune Request");
//}

//void myClock() {
//  Serial.println("Clock");
//}

//void myStart() {// nothing on the S-10
//  Serial.println("Start");
//}

//void myContinue() {
 // Serial.println("Continue");
//}

//void myStop() {
 // Serial.println("Stop");
//}

//void myActiveSensing() {
 // Serial.println("Actvice Sensing");
//}

//void mySystemReset() {
 // Serial.println("System Reset");
//}

//void myRealTimeSystem(uint8_t realtimebyte) {//nothing on the S-10
 // Serial.print("Real Time Message, code=");
 // Serial.println(realtimebyte, HEX);
//}

//void printBytes(const byte *data, unsigned int size) {
 // while (size > 0) {
 //   byte b = *data++;
  //  if (b < 16) Serial.print('0');
  //  Serial.print(b, HEX);
   // if (size > 1) Serial.print(' ');
   // size = size - 1;
  //}
//}
*/

void PedPol(void){
  if ( spp == 0) {
    hv=0; // could be pure math hv=spp*127; with no if
    nhv=127; // could be pure math nhv= ~spp*127; with no if
  }//spp==0
  if ( spp == 1) {
    hv=127;
    nhv=0;
  }//spp==1
}//PedPol

void lhtSet(void){// this is starting to work but now retriggers when hold is activated // Retrigger problem fixed by adding if(sustainp) to myNoteOn()
  onegate = digitalRead(1);// this can only do a digitalRead Here, not in myNoteOn().
  twogate = digitalRead(2);// lhtSet is used when hold or sustain is activated
  threegate = digitalRead(3);// detect low to high transition
  fourgate = digitalRead(4);// make this only if the lht variable is not allready set
  fivegate = digitalRead(5);
  sixgate = digitalRead(6);// maybe try removing these digitalRead()'s
  if ( onegate ) onelht = true;// sets that a low to high transition has happend
  if ( twogate ) twolht = true;// this still sounds better even if it retriggers every note being held down
  if ( threegate ) threelht = true;
  if ( fourgate ) fourlht = true;
  if ( fivegate ) fivelht = true;
  if ( sixgate ) sixlht = true;
  setlht = false; //reset read low to high detections flag for next Note on.
  /*
  Serial.print("lhtSet Gate IN , 1 to 6 =");// only active with sustain on
  Serial.print(onegate);//reading wrong gate here // JCS gate 2 is triggering onegate variable
  Serial.print(twogate);
  Serial.print(threegate);
  Serial.print(fourgate);
  Serial.print(fivegate);
  Serial.println(sixgate);
  */
}// lhtSet()
// is it still mixing up variables ? if so fix that first. gate 1 ID correct gate 3 IDed as gate 2 ? // not recycling
// digitalRead() is miss IDing gate 3 as gate 2, proven// try disable interups ? // did not help
// also reading gate 4 as gate 3 at this point.//

// maybe try to make a single 6 bit number to track what notes are being held down (gates on) and not to rertrigger them
// make new and old versions of that variable to detect changes.
// another idea is to do hold down stream in the Decay of the Hexsynator. R70 or R76 is the decay discharge resistor and the cap is C24 and is 1uf.
// maybe use a BS170 MOSFET.
// if (( sixgate ) && ( sixlht == 0 )) {
// if (( fivegate ) && ( fivelht == 0 )) {
// if (( fourgate ) && ( fourlht == 0 )) {
// if (( threegate ) && ( threelht == 0 )) { 
// if (( twogate ) && ( twolht == 0 )) {
// if (( onegate ) && ( onelht == 0 )) {
/*
  if ( sixgate ) { // got worse with sustain on // not knowing what gate to retrigger
    sixlht = true; // sets that a low to high transition has happend
    setlht = false; //reset read low to high detections flag for next Note on.
    return;
  } //6
  if ( fivegate ) {
    fivelht = true;
    setlht = false; //reset read low to high detections flag for next Note on.
    return;
  }//5
  if ( fourgate ) {
    fourlht = true;
    setlht = false; //reset read low to high detections flag for next Note on.
    return;
  }//4
  if ( threegate ) {
    threelht = true;
    setlht = false; //reset read low to high detections flag for next Note on.
    return;
  }//3 
  if ( twogate ) {
    twolht = true;
    setlht = false; //reset read low to high detections flag for next Note on.
    return;
  }//2
  if ( onegate ) {
    onelht = true; // sets that a low to high transition has happend
    setlht = false; //reset read low to high detections flag for next Note on.
    return;
  }//1
  */

```
 
I copied your code into Arduino IDE. It compiles without error.

But I have no idea what steps I should perform to reproduce the problem. I'm guessing I need some sort of USB MIDI instrument? Are 6 of that special CV hardware also needed? Please keep in mind I'm not a musician, so even if I get the right gear... what do I need to do with it to cause the problem to occur and what specific thing do I watch to see the problem happen?
 
I do not expect anyone to go that far to reproduce the problem.
You could rem out or bypass the myNoteOn(), myNoteNoteOff() and myControlChange() and use some other way of setting the variables involved.
Then the MIDI gear would not be needed to reproduce it.
This would probably get way too involved.

Are there any special considerations for the use of digitalRead() ?
Is the USBHost_t36.h library and the MIDI input functions example reliable ?
Any Idea of things I could try with this setup on my own ?

I was thinking of rewriting the code to use the Bounce.h library instead of the MIDI callbacks just for the gate input part of it to read the input pins.
It would still use the MIDI callbacks for the other functions.
It would use risingEdge() detection instead of the myNoteOn()
and fallingEdge() detection instead of myNoteOff().

Some background on the device this is for:

I have repaired and restored a prototype 6 voice synth called the Hexsynator that was designed and built about 1980.
It never went into production and is a one of a kind 6 voice synth prototype.
It originally only worked with Roland GR700 synth guitar.
We wanted it to work as a keyboard synth also.
That is when I was given the ok to build the MIDI converter box for it.
After much work most of it works very well.
It sounds like an early analog polyphonic synth from the 80's similar to the Prophet 5 or Roland Juno 106.
The sustain function will never be perfect on it but i was trying to improve upon it anyway.
The photo attached is just the MIDI control box part of it with none of the cables attached.
It also uses a Roland A49 MIDI keyboard controller.
 

Attachments

  • IMG_20240915_003751.jpg
    IMG_20240915_003751.jpg
    794.9 KB · Views: 73
If you don't have physical pull-up resistors on your inputs, you might want to set your input pins to INPUT_PULLUP, eg:
Code:
pinMode(2, INPUT_PULLUP);
Floating input pins can pickup the state of nearby pins, which could explain the behaviour described initially

Marc
 
I think I have tried the internal INPUT_PULLUP on this.
I may try it again.

I think another possibility is that I am just trying to read the pins before the gate input signals arrive.
I need to investigate this more.

Thanks
 
Usually I do try to reproduce a problem when complete code is shown. If you're still stuck, please consider reducing the program to something I and others can try running to reproduce the problem without needing special hardware.

Here's an attempt to try answering your 3 recent questions.

Are there any special considerations for the use of digitalRead() ?

You need to use pinMode() to put the pin into one of the input modes.

While very rarely an issue, if you have used a library like OctoWS2811 which accesses the pin by DMA, it may have been reconfigured for slow (but DMA compatible) GPIO. By default the pins are all configured for fast GPIO, which can't be accessed by DMA. In this special situation, just calling pinMode() isn't enough.

For pins driven through a resistor, a brief time may be needed for the voltage to actually change because the pin and wiring has a small capacitance. Usually this is less than 1 or 2 microseconds, but Teensy is extremely fast. A common problem is using digitalRead() immediately after pinMode with INPUT_PULLUP. The pin can read 0 for a short time until the weak pullup resistor causes it to read as logic high.


Is the USBHost_t36.h library and the MIDI input functions example reliable ?

USB host MIDI is pretty reliable.

However, there is a known issue with certainly poorly made USB MIDI keyboards which transmit many MIDI messages in rapid bursts in separate USB packets without adaquate buffering. This situation can occur if many keys are rapidly pressed and released together, causing many Note On or Note Off messages to be transmitted at nearly the same moment. If the program on Teensy doesn't read the MIDI messages quickly enough, and if the transmitting MIDI keyboard doesn't properly buffer its outgoing USB packets, the outgoing MIDI data can be deleted and overwritten inside the USB keyboard before they are ever transmitted over the USB cable. The problem is particularly noticeable when any of the deleted MIDI messages is a Note Off event. Arturia Minilab mkii is the main USB MIDI device known to have this problem when used with Teensy USB host. I'm planning to increase the amount of packet buffers within USBHost_t36 MIDI in future versions, so we can capture more incoming MIDI data quickly even if the Arduino sketch code doesn't read and process it quickly. But just to keep perspective, this problem only occurs when 3 things happen: many MIDI messages nearly simultaneuosly, program on Teensy side reads slowly, transmitting device lacks buffering and must delete any unsent data if more MIDI messages are generated quickly. Even with Arturia Minilab mkii, the problem only occurrs with pressing many keys rapidly.


Any Idea of things I could try with this setup on my own ?

If you can whittle away a lot of the unneeded code and ideally come up with a way to reproduce the problem without MIDI gear or other special hardware, I and others could do much more to help.
 
I want to thank everyone especially Paul for helping me with this problem.
The problem has been solved.
It turns out I was trying to read the input pins before the gate signal arrive.
The Teensy 4.0 is running at 600Mhz and was completing the MIDI callback for My note on detection before the Jakes Custom Shop Gate outputs went high.
The Jakes Custom Shop modules are using a ATMEGA328P probably running at 20Mhz.
This is much more clear to me now what was happening.
My new rewritten code makes use of the Bounce.h library and is now working as intended.
I did not need Bounce.h because of switch bounce.
The gates do not bounce.
I needed it for the rising edge detection function.
I am sharing my now working code also cleaned up a bit.

C++:
```cpp

// * MIDIsustainPitchbendv8 *
// all extra unused code and extra notes in v7
// This probably needs to be on MIDI ch 1 only to match JCS module in poly mode.

#include <USBHost_t36.h>
#include <Bounce.h>
// maybe add PWM frequency ? now running at 500hz could be much higher

//File myFile;
USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
MIDIDevice midi1(myusb);

#define GateIn1 1
#define GateIn2 2
#define GateIn3 3
#define GateIn4 4
#define GateIn5 5
#define GateIn6 6

byte mc=1;// MIDI channel // 0 is omni mode
// mc probably needs to be on ch 1 to match JCS module
byte spp=0;// sustain pedal polarity 0 or 1// global
byte hv=0;// use to set pedal polarity
byte nhv=127;// to use other polarity swap values of hv and nhv.
byte mds=false;// modulation switch state not used
byte sustainp = false;// sustain or hold mode
byte gateout1 = false; //gate 1 output
byte gateout2 = false;
byte gateout3 = false;
byte gateout4 = false;
byte gateout5 = false;
byte gateout6 = false;
int bndp;// bender right or positive
int bndn;// bender left or negative
byte sph1;//send retrigger gate pulse on next main loop
byte sph2;
byte sph3;
byte sph4;
byte sph5;
byte sph6;
unsigned long p1;// retigger pulse duration and timing
unsigned long p2;
unsigned long p3;
unsigned long p4;
unsigned long p5;
unsigned long p6;
byte onelht = false; // low to high transition of gate
byte twolht = false;
byte threelht = false;
byte fourlht = false;
byte fivelht = false;
byte sixlht = false;

Bounce gater1 = Bounce(GateIn1, 1); //try 0 ms ? // 0 works but leave it at 1 ms for now
Bounce gater2 = Bounce(GateIn2, 1);
Bounce gater3 = Bounce(GateIn3, 1);
Bounce gater4 = Bounce(GateIn4, 1);
Bounce gater5 = Bounce(GateIn5, 1);
Bounce gater6 = Bounce(GateIn6, 1);
 
void setup() {
  Serial.begin(115200);
  // maybe add PWM frequency ? now running at 500hz could be much higher
  analogWriteResolution(12);// maybee add write frequency and frequencytimer2 library
  pinMode(0, INPUT_PULLUP); // Sustain pedal polarity switch
  //pinMode(13, INPUT_PULLUP); // maybe parellel sustain pedal input ?
  pinMode(GateIn1, INPUT);
  pinMode(GateIn2, INPUT);
  pinMode(GateIn3, INPUT);
  pinMode(GateIn4, INPUT);
  pinMode(GateIn5, INPUT);
  pinMode(GateIn6, INPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(22, OUTPUT);
  pinMode(23, OUTPUT);
  delay(300); 
  myusb.begin();
  //midi1.setHandleNoteOn(myNoteOn);
  //midi1.setHandleNoteOff(myNoteOff);
  //midi1.setHandleAfterTouchPoly(myAfterTouchPoly);
  midi1.setHandleControlChange(myControlChange);
  //midi1.setHandleProgramChange(myProgramChange);
  //midi1.setHandleAfterTouchChannel(myAfterTouchChannel);
  midi1.setHandlePitchChange(myPitchChange);
  // Only one of these System Exclusive handlers will actually be
  // used.  See the comments below for the difference between them.
  //midi1.setHandleSystemExclusive(mySystemExclusiveChunk);
  //midi1.setHandleSystemExclusive(mySystemExclusive);
  //midi1.setHandleTimeCodeQuarterFrame(myTimeCodeQuarterFrame);
  //midi1.setHandleSongPosition(mySongPosition);
  //midi1.setHandleSongSelect(mySongSelect);
  //midi1.setHandleTuneRequest(myTuneRequest);
  //midi1.setHandleClock(myClock);
  //midi1.setHandleStart(myStart);
  //midi1.setHandleContinue(myContinue);
  //midi1.setHandleStop(myStop);
  //midi1.setHandleActiveSensing(myActiveSensing);
  //midi1.setHandleSystemReset(mySystemReset);
  // This generic System Real Time handler is only used if the
  // more specific ones are not set.
  //midi1.setHandleRealTimeSystem(myRealTimeSystem);
 
  Serial.println("MIDI Sustain and Pitch Bend v8");
  Serial.println("Firmware File: MIDIsustainPitchbendv8");
  Serial.println("Teensy 4.0 board with MIDI host.");
  PedPol();// sustain pedal plarity
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
  digitalWrite(12, LOW);
}// setup

void loop() {
  // The handler functions are called when midi1 reads data.  They
  // will not be called automatically.  You must call midi1.read()
  // regularly from loop() for midi1 to actually read incoming
  // data and run the handler functions as messages arrive.
  myusb.Task();
  midi1.read();

  spp = digitalRead(0);// sustain pedal plarity switch

  gater1.update();
  gater2.update();
  gater3.update();
  gater4.update();
  gater5.update();
  gater6.update();

  if ( gater1.read() ){
    if ( sustainp ){ // this is working now
      if ( gater1.risingEdge() ) onelht= true;// low to high gate detection
      if (onelht) { // gate 1 retrigger set low and start 1ms timer
        gateout1 = false;
        digitalWrite(7, gateout1);
        p1 = micros() + 900;// 1ms
        sph1 = true; // flag to set gate 1 high again after 1ms
        onelht = false;// reset low to high transistion flag to low
        } // lht1 
      if ((p1 < micros())&& (sph1)){ // gate 1 retrigger, 1ms has past , set gate 1 high again
        gateout1 = true;   
        digitalWrite(7, gateout1);// maybe use real port address // it is faster
        sph1 = false;// reset flag low because Gate 1 has been set high again
        onelht= false;// reset flag low for next low to high transition of gate 1
        }// micros
    }// if sustinp
    else { // gate 1 on without hold or sustain
    gateout1 = true;
    digitalWrite(7, gateout1);
      } // else sustain
    } // if gate
  else {
    if ( sustainp == false ){// gate 1 off without hold
      gateout1 = false;
      digitalWrite(7, gateout1);     
    }// if sustainp
  }// else

  if ( gater2.read() ){
    if ( sustainp ){
      if ( gater2.risingEdge() ) twolht= true;
      if (twolht) {
        gateout2 = false;
        digitalWrite(8, gateout2);// maybe use real port address // it is faster
        p2 = micros() + 900;// 1ms
        sph2 = true;
        twolht = false;
        } // lht1 
      if ((p2 < micros())&& (sph2)){
        gateout2 = true;   
        digitalWrite(8, gateout2);// maybe use real port address // it is faster
        sph2 = false;
        twolht= false;   
        }// micros
    }// if sustinp
    else {
    gateout2 = true;
    digitalWrite(8, gateout2);
    } // else sustain
    }// if gate
  else {
    if ( sustainp == false ){
      gateout2 = false;
      digitalWrite(8, gateout2);     
    }// if sustainp
  }// else

  if ( gater3.read() ){
    if ( sustainp ){
      if ( gater3.risingEdge() ) threelht= true;
      if (threelht) {
        gateout3 = false;
        digitalWrite(9, gateout3);
        p3 = micros() + 900;// 1ms
        sph3 = true;
        threelht = false;
        } // lht1 
      if ((p3 < micros())&& (sph3)){
        gateout3 = true;   
        digitalWrite(9, gateout3);
        sph3 = false;
        threelht= false;
        }// micros
    }// if sustinp
    else {
    gateout3 = true;
    digitalWrite(9, gateout3);
    } // else sustain
    }// if gate
  else {
    if ( sustainp == false ){
      gateout3 = false;
      digitalWrite(9, gateout3);     
    }// if sustainp
  }// else

  if ( gater4.read() ){
    if ( sustainp ){
      if ( gater4.risingEdge() ) fourlht= true;
      if (fourlht) {
        gateout4 = false;
        digitalWrite(10, gateout4);
        p4 = micros() + 900;// 1ms
        sph4 = true;
        fourlht = false;
        } // lht1 
      if ((p4 < micros())&& (sph4)){
        gateout4 = true;   
        digitalWrite(10, gateout4);
        sph4 = false;
        fourlht= false;
        }// micros
    }// if sustinp
    else {
    gateout4 = true;
    digitalWrite(10, gateout4);
      } // else sustain
    }// if gate
  else {
    if ( sustainp == false ){
      gateout4 = false;
      digitalWrite(10, gateout4);     
    }// if sustainp
  }// else

  if ( gater5.read() ){
    if ( sustainp ){
      if ( gater5.risingEdge() ) fivelht= true;
      if (fivelht) {
        gateout5 = false;
        digitalWrite(11, gateout5);
        p5 = micros() + 900;// 1ms
        sph5 = true;
        fivelht = false;
        } // lht1 
      if ((p5 < micros())&& (sph5)){
        gateout5 = true;   
        digitalWrite(11, gateout5);
        sph5 = false;
        fivelht= false;
        }// micros
    }// if sustinp
    else {
    gateout5 = true;
    digitalWrite(11, gateout5);
     } // else sustain
    }// if gate
  else {
    if ( sustainp == false ){
      gateout5 = false;
      digitalWrite(11, gateout5);     
    }// if sustainp
  }// else

  if ( gater6.read() ){
    if ( sustainp ){
      if ( gater6.risingEdge() ) sixlht= true;
      if (sixlht) {
        gateout6 = false;
        digitalWrite(12, gateout6);
        p6 = micros() + 900;// 1ms
        sph6 = true;
        sixlht = false;
        } // lht1 
      if ((p6 < micros())&& (sph6)){
        gateout6 = true;   
        digitalWrite(12, gateout6);
        sph6 = false;
        sixlht= false;
        }// micros
    }// if sustinp
    else {
    gateout6 = true;
    digitalWrite(12, gateout6);
     } // else sustain
    }// if gate
  else {
    if ( sustainp == false ){
      gateout6 = false;
      digitalWrite(12, gateout6);     
    }// if sustainp
  }// else
}// Main loop

void myControlChange(byte channel, byte control, byte value) { //This works With the S-10 joystick modulation switch as control #1 value on #127 off #0
  // sustain pedal function, control 64, value off 0, on 127// has polarity option.
  if (( mc == channel ) || ( mc == 0 )) {
  if ( control == 64 ){
    PedPol(); // pedal works perfect with no changes needed.
   if ( value == hv ){// had to use reverse polarity pedal/0 = hold or hv/ 127= not hold or nhv.
    sustainp = true;
   }//value==hv
   if ( value == nhv ){
    sustainp = false;
   }//value==nhv
  }//control==64
 
  if ( control == 1 ){
    if ( value == 127 ){// could be dynamic on some keyboard controllers // check it // Triton LE it is dynamic
      mds=true;// modulation swich variable not used
     }//value=127     
    else{//else of value==127
      mds=false;// modulation swich variable not used
    }//else of value==127
  }//control
 }//mc
}//my

void myPitchChange(byte channel, int pitch) { // This works with the joystick on the Roland S-10
  if (( mc == channel ) || ( mc == 0 )) {// pitch has a range of +/-8192 then converted to +/- 100 and multiplied by bender range   
  if ( pitch > -1 ) {     
    bndp = pitch / 2;// bender right side or +
    bndn = 0;
    analogWrite(22,bndp);// maybe add PWM frequency ? now running at 500hz could be much higher
    analogWrite(23,bndn);// seems to work ok without PWM frequency// there are two stages of 10uf filtering and it is not too slow.
  }// if pitch
  else{
    bndn = ( abs( pitch ) / 2 ) - 1;// bender left side or -
    bndp = 0;
    analogWrite(23,bndn);
    analogWrite(22,bndp); 
  }// else         
 }//mc 
}//my

void PedPol(void){// sustain pedal plarity
  if ( spp == 0) {
    hv=0;
    nhv=127;
  }//spp==0
  if ( spp == 1) {
    hv=127;
    nhv=0;
  }//spp==1
}//PedPol

```
 
Back
Top