Send 1 Sysex message depending on momentary switch State

Status
Not open for further replies.
....This is how it is now...

Trying to debug my code and yours together is not going to work... especially if you are not making the changes I'm suggesting.

Here's what I was suggesting last (that the reset needs to be only when a PC is received which should also limit the print to once per PC and therefore the lagged SW1 and SW2 values are not required).

Code:
// include the ResponsiveAnalogRead library for analog smoothing
#include <ResponsiveAnalogRead.h>
#include <Bounce.h>  // Bounce library makes button change detection easy
// ******CONSTANT VALUES******** - customize code behaviour here!


// SET THESE SIX VALUES FOR JOYSTICK!
const int pitchPin = 0; // PIN numbers ** MUST CHANGE!
const int modPin = 1;
const int modPin2 = 1;
const int pitchMaxRaw = 1019; // Max reading with full bend up... as raw 10-bit value
const int modMaxRaw = 1019; // Max reading full mod down


// SET THESE VALUES FOR RIBBON
//const int ribbonPin = touch_pressed; // Max reading on right side... as raw 10-bit value
const int ribbonMaxRaw = 474; // Max reading on right side... as raw 10-bit value
//


int Button1 = 0; //This is the default "Button Off" and 1 is "Button On"
int Button2 = 0; //This is the default "Button Off" and 1 is "Button On"
int OldButton1 = 0; //Variable to store button1 old value
int OldButton2 = 0; //Variable to store button2 old value


const int scanMax = 9;
//const byte channel = 1;
byte SW1;
byte SW1D2;
[COLOR="#FF0000"]//byte SW1lag;[/COLOR]
byte SW2;
byte SW2D2;
[COLOR="#FF0000"]//byte SW2lag;[/COLOR]
byte d2;


const int channel = 1; // MIDI channel
const int MIDIdelay = 5; // will update MIDI only if this many milliseconds have passed
//******VARIABLES***********
// data variables and a lagged copy to compare before updating MIDI value
int pitch;
int mod;
int mod2;
int pitchRaw;
int modRaw;
int modRaw2;
int pitchLag;
int modLag;
int modLag2;
int ribbon;
int ribbonRaw;
int ribbonLag;


elapsedMillis pitchUpdate;
elapsedMillis modUpdate;
elapsedMillis modUpdate2;
elapsedMillis ribbonUpdate;
elapsedMillis scanStart;
elapsedMillis reportLast;


// ititialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead readPitch = {pitchPin, true};
ResponsiveAnalogRead readMod = {modPin, true};
ResponsiveAnalogRead readMod2 = {modPin2, true};


#include <Adafruit_GFX.h>    // Core graphics library


#define LCD_ROTATION  1        //should work in all rotations
#define USE_READID    0        //Adafruit and ILI9488 can't read ID
//#include <MCUFRIEND_kbv.h>     // Hardware-specific library
//MCUFRIEND_kbv tft;
//#include <Adafruit_ILI9341.h>   // Hardware-specific library
//Adafruit_ILI9341 tft(10, 9, 8);
//#include <HX8347D_kbv.h>        // Hardware-specific library
//HX8347D_kbv tft;
#include <ILI9488.h>            // Hardware-specific library
ILI9488 tft(10, 9, 8);
//#include <ILI9488_kbv.h>            // Hardware-specific library
//ILI9488_kbv tft;


extern void Touch_initialise(int aspect, int wid, int ht);
extern bool Touch_getXY(void);
bool touch_pressed;
int pixel_x, pixel_y;
boolean SW1on = false;
boolean SW2on = false;
boolean ribbonCtrl = false;


// Color definitions
#define TFT_BLACK       0x0000      /*   0,   0,   0 */
#define TFT_NAVY        0x000F      /*   0,   0, 128 */
#define TFT_DARKGREEN   0x03E0      /*   0, 128,   0 */
#define TFT_DARKCYAN    0x03EF      /*   0, 128, 128 */
#define TFT_MAROON      0x7800      /* 128,   0,   0 */
#define TFT_PURPLE      0x780F      /* 128,   0, 128 */
#define TFT_OLIVE       0x7BE0      /* 128, 128,   0 */
#define TFT_LIGHTGREY   0xC618      /* 192, 192, 192 */
#define TFT_DARKGREY    0x7BEF      /* 128, 128, 128 */
#define TFT_BLUE        0x001F      /*   0,   0, 255 */
#define TFT_GREEN       0x07E0      /*   0, 255,   0 */
#define TFT_CYAN        0x07FF      /*   0, 255, 255 */
#define TFT_RED         0xF800      /* 255,   0,   0 */
#define TFT_RED2        0xF88D      /* 254,  18, 106 */
#define TFT_MAGENTA     0xF81F      /* 255,   0, 255 */
#define TFT_YELLOW      0xFFE0      /* 255, 255,   0 */
#define TFT_WHITE       0xFFFF      /* 255, 255, 255 */
#define TFT_ORANGE      0xFD20      /* 255, 165,   0 */
#define TFT_ORANGE2     0xFB20      /* 254, 102,   1 */
#define TFT_GREENYELLOW 0xAFE5      /* 173, 255,  47 */
#define TFT_PINK        0xF81F


/******************* UI details */


#define SW1FRAME_X 90
#define SW1FRAME_Y 110
#define SW1FRAME_W 130
#define SW1FRAME_H 70


#define SW1BUTTON_X SW1FRAME_X
#define SW1BUTTON_Y SW1FRAME_Y
#define SW1BUTTON_W SW1FRAME_W
#define SW1BUTTON_H SW1FRAME_H


#define SW2FRAME_X 310
#define SW2FRAME_Y 110
#define SW2FRAME_W 130
#define SW2FRAME_H 70


#define SW2BUTTON_X SW2FRAME_X
#define SW2BUTTON_Y SW2FRAME_Y
#define SW2BUTTON_W SW2FRAME_W
#define SW2BUTTON_H SW2FRAME_H


#define RIBBONFRAME_X 10
#define RIBBONFRAME_Y 240
#define RIBBONFRAME_W 470
#define RIBBONFRAME_H 70


#define RIBBON_X RIBBONFRAME_X
#define RIBBON_Y RIBBONFRAME_Y
#define RIBBON_W RIBBONFRAME_W
#define RIBBON_H RIBBONFRAME_H


void sw1Btn()
{ 
  tft.drawRect(SW1BUTTON_X, SW1BUTTON_Y, SW1BUTTON_W, SW1BUTTON_H, TFT_DARKGREY);
  tft.fillRect(SW1BUTTON_X, SW1BUTTON_Y, SW1BUTTON_W, SW1BUTTON_H, TFT_RED);
  tft.setCursor(160, 140);
  tft.setTextColor(TFT_WHITE);
  tft.setTextSize(2);
  tft.println("SW1");
  usbMIDI.sendControlChange(SW1, SW1D2, 1);
  SW1on = false;
}
void sw2Btn()
{ 
  tft.drawRect(SW2BUTTON_X, SW2BUTTON_Y, SW2BUTTON_W, SW2BUTTON_H, TFT_DARKGREY);
  tft.fillRect(SW2BUTTON_X, SW2BUTTON_Y, SW2BUTTON_W, SW2BUTTON_H, TFT_RED);
  tft.setCursor(340,140);
  tft.setTextColor(TFT_WHITE);
  tft.setTextSize(2);
  tft.println("SW2");
  usbMIDI.sendControlChange(SW2, SW2D2, 1);
  SW2on = false;
}
void rbCtrl()
{ 
  tft.drawRect(RIBBON_X, RIBBON_Y, RIBBON_W, RIBBON_H, TFT_LIGHTGREY);
  tft.fillRect(RIBBON_X, RIBBON_Y, RIBBON_W, RIBBON_H, TFT_LIGHTGREY);
  tft.setCursor(10,240);
    //remap to output data and send if changed and MIDIdelay has lapsed since last update for that parameter
    ribbon = map(pixel_x, 11, 474, 0, 127);
    //ribbon = max(ribbon, 0); // need this now that the bottom isn't zero
   // ribbon = min(ribbon, 127); // cap to avoid overflow
   // if (abs(ribbon - ribbonLag) > 0 && ribbonUpdate > MIDIdelay ) {
   //   ribbonLag = ribbon;
    usbMIDI.sendControlChange(16, ribbon, channel);
   //   ribbonUpdate = 0;
  //  }
  ribbonCtrl = false;
}


void setup(void)
{ 
    Serial.begin(9600);
    Serial.println(F("TFT LCD test"));


    tft.begin();


    int aspect = LCD_ROTATION;   //PORTRAIT
    tft.setRotation(aspect);
    Touch_initialise(aspect, tft.width(), tft.height());  //.kbv external function
    tft.fillScreen(TFT_BLACK);
    


    // create 'SW1 Switch'
    tft.drawRect(SW1BUTTON_X, SW1BUTTON_Y, SW1BUTTON_W, SW1BUTTON_H, TFT_DARKGREY);
    tft.fillRect(SW1BUTTON_X, SW1BUTTON_Y, SW1BUTTON_W, SW1BUTTON_H, TFT_RED);
    tft.setCursor(155, 140);
    tft.setTextColor(TFT_BLACK);
    tft.setTextSize(2);
    tft.print("SW1");


    // create 'SW2 Switch'
    tft.drawRect(SW2BUTTON_X, SW2BUTTON_Y, SW2BUTTON_W, SW2BUTTON_H, TFT_DARKGREY);
    tft.fillRect(SW2BUTTON_X, SW2BUTTON_Y, SW2BUTTON_W, SW2BUTTON_H, TFT_RED);
    tft.setCursor(340, 140);
    tft.setTextColor(TFT_BLACK);
    tft.setTextSize(2);
    tft.print("SW2");


    // create 'Ribbon Emulator field'
    tft.drawRect(RIBBON_X, RIBBON_Y, RIBBON_W, RIBBON_H, TFT_DARKGREY);
    tft.fillRect(RIBBON_X, RIBBON_Y, RIBBON_W, RIBBON_H, TFT_LIGHTGREY);
}
unsigned long t=0;


void loop(void)
{
 
{ 
  if (usbMIDI.read(channel)) { // limit reads to single channel
    if (usbMIDI.getType() == usbMIDI.ProgramChange){
      scanStart = 0;      
      SW1 = 0;
      SW2 = 0;
    }else if(usbMIDI.getType() == usbMIDI.ControlChange) {
      if (scanStart <= scanMax) {
        SW1 = SW2;
        SW1D2 = SW2D2;
        SW2 = usbMIDI.getData1();
        SW2D2 = usbMIDI.getData2();
      }
    }
  }
  if (scanStart >= scanMax) {
    if (SW1 == 0) { // if there was only 1 CC SW1 is blank and we will swap
      SW1 = SW2;
      SW2 = 0;
    }
[COLOR="#FF0000"]//   if ((SW1 != SW1lag) || (SW2 != SW2lag)) { // if there is a change...[/COLOR]
      Serial.println(SW1);
      Serial.println(SW2);
[COLOR="#FF0000"]//      SW1lag = SW1;
//      SW2lag = SW2;
//    }
//     scanStart = 0;[/COLOR]
  }
 
}


   if (millis() - t > 10000) {
      t += 10000;
      Serial.println("(inactivity)");
 }


   


    int x = -1, y = -1;   //regular pixel coordinates
    touch_pressed = Touch_getXY();  //external function
#if 0
    Serial.print("X="); Serial.print(pixel_x); 
    Serial.print(" Y="); Serial.print(pixel_y); 
    Serial.print(" Z="); Serial.print(touch_pressed); 
    Serial.println("");
#endif
    if (touch_pressed) {
        x = pixel_x;      //copy global variable
        y = pixel_y;
    } 
{
      if((x > SW1BUTTON_X) && (x < (SW1BUTTON_X + SW1BUTTON_W))) {
        if ((y > SW1BUTTON_Y) && (y <= (SW1BUTTON_Y + SW1BUTTON_H))) {
          Serial.println("SW1 btn hit"); 
          Serial.println(String("Message,") + ",channel " + channel + ",data = " + SW1 + " " + d2);
          delay(100); // UI debouncing
          sw1Btn();
        }
      }
    }


{
      if((x > SW2BUTTON_X) && (x < (SW2BUTTON_X + SW2BUTTON_W))) {
        if ((y > SW2BUTTON_Y) && (y <= (SW2BUTTON_Y + SW2BUTTON_H))) {
          Serial.println("SW2 btn hit"); 
          Serial.println(String("Message,") + ",channel " + channel + ",data = " + SW2 + " " + d2);
          delay(100); // UI debouncing
          sw2Btn();
        }
      }
    } 
{
      if((x > RIBBON_X) && (x < (RIBBON_X + RIBBON_W))) {
        if ((y > RIBBON_Y) && (y <= (RIBBON_Y + RIBBON_H))) {
          Serial.println("Ribbon pressed"); 
          Serial.println(pixel_x);
          Serial.println(ribbon);       
          delay(100); // UI debouncing
          rbCtrl();
        }
      }
    } 
    
  }

I will be returning to my code if this does not work for you as I cannot test your code without the hardware.
 
Hi oddson. I did make the changes you suggested, i just reverted them after making the tests.
Please, don't take me wrong. If you tell me to do them again i will.

I appreciate immensely the effort your doing to help me!
 
I don't have access to the stuff now, but tomorrow morning i will do your suggestions and let you now how it went.

My time is Lisbon, it is 22:40 now.
 
hey... didn't mean to sound snarky about it but it will be a lot easier if we are using the same code until that code does what it needs to.

I'm going to strip out the prints and debug with MIDI so I don't need to mess with USB serial and MIDI together on the same Windows box.

I'm away from my main Teensy machine so will have limited access to a Teensy+compiler this weekend but I think it's really close and just needs a bit more (sober) attention than I could manage yesterday.
 
This uses no Serial.print.
Instead the BOUNCE objects for the functional switches are present (at pins 0 and 1 - change the constant definition if you are using other pins) and when pressed they will send a CC MIDI message with D1=value sent by M3 and D2 = 0 (for now).

This is what I take to be the goal and it also eliminates the difficulty of reporting the CC update results only once.

Code:
#include <Bounce.h>  // Bounce library makes button change detection easy
const int scanMax = 100;                                                               // set the time limit for CC to follow PC
const byte channel = 1;                                                                // set channel to filter/send midi
const int SW1pin = 0;                                                                  // set SW1 pin
const int SW2pin = 1;                                                                  // set SW2 pin

int SW1 = 80;                                                                          // default SW1 CC number (D1)                  
int SW2 = 81;                                                                          // default SW2 CC number (D1) 

elapsedMillis scanStart;
Bounce button1 = Bounce(0, 25);  // 5 = 5 ms debounce time
Bounce button2 = Bounce(1, 25);  // which is appropriate for good quality mechanical pushbuttons but I'm using a bare wire!
void setup() {
  pinMode(SW1pin, INPUT_PULLUP); 
  pinMode(SW2pin, INPUT_PULLUP);
}

void loop(void)
{ 
  button1.update();
  button2.update();


  // send CC messages when SW1 or SW2 are pulled LOW
  if (button1.fallingEdge()) { 
    usbMIDI.sendControlChange(SW1, 0, channel);
  }
  if (button2.fallingEdge()) {
    usbMIDI.sendControlChange(SW2, 0, channel);
  }


  if (usbMIDI.read(channel)) { // limit reads to single channel
    if (usbMIDI.getType() == usbMIDI.ProgramChange){
      scanStart = 0;      
      SW1 = 0;
      SW2 = -1;
    }else if(usbMIDI.getType() == usbMIDI.ControlChange) {
      if (scanStart <= scanMax) {
      Serial.println(" cc");
        SW1 = SW2;
        SW2 = usbMIDI.getData1();
      }
    }
  }
  if (scanStart >= scanMax) {
    if (SW1 < 0) { // if there was only 1 CC SW1 is negative and we will swap and set SW2 = 0
      SW1 = SW2;
      SW2 = 0;
    }
  }
}

If you don't have a usable MIDI utility to confirm the output just add Serial.prints after the usbMIDI.sendControlChange() statements.
 
This uses no Serial.print.
Instead the BOUNCE objects for the functional switches are present (at pins 0 and 1 - change the constant definition if you are using other pins) and when pressed they will send a CC MIDI message with D1=value sent by M3 and D2 = 0 (for now).

This is what I take to be the goal and it also eliminates the difficulty of reporting the CC update results only once.

Code:
#include <Bounce.h>  // Bounce library makes button change detection easy
const int scanMax = 100;                                                               // set the time limit for CC to follow PC
const byte channel = 1;                                                                // set channel to filter/send midi
const int SW1pin = 0;                                                                  // set SW1 pin
const int SW2pin = 1;                                                                  // set SW2 pin

int SW1 = 80;                                                                          // default SW1 CC number (D1)                  
int SW2 = 81;                                                                          // default SW2 CC number (D1) 

elapsedMillis scanStart;
Bounce button1 = Bounce(0, 25);  // 5 = 5 ms debounce time
Bounce button2 = Bounce(1, 25);  // which is appropriate for good quality mechanical pushbuttons but I'm using a bare wire!
void setup() {
  pinMode(SW1pin, INPUT_PULLUP); 
  pinMode(SW2pin, INPUT_PULLUP);
}

void loop(void)
{ 
  button1.update();
  button2.update();


  // send CC messages when SW1 or SW2 are pulled LOW
  if (button1.fallingEdge()) { 
    usbMIDI.sendControlChange(SW1, 0, channel);
  }
  if (button2.fallingEdge()) {
    usbMIDI.sendControlChange(SW2, 0, channel);
  }


  if (usbMIDI.read(channel)) { // limit reads to single channel
    if (usbMIDI.getType() == usbMIDI.ProgramChange){
      scanStart = 0;      
      SW1 = 0;
      SW2 = -1;
    }else if(usbMIDI.getType() == usbMIDI.ControlChange) {
      if (scanStart <= scanMax) {
      Serial.println(" cc");
        SW1 = SW2;
        SW2 = usbMIDI.getData1();
      }
    }
  }
  if (scanStart >= scanMax) {
    if (SW1 < 0) { // if there was only 1 CC SW1 is negative and we will swap and set SW2 = 0
      SW1 = SW2;
      SW2 = 0;
    }
  }
}

If you don't have a usable MIDI utility to confirm the output just add Serial.prints after the usbMIDI.sendControlChange() statements.


That's not exactly what i need.
The value i need to send is the D1 value, yes, together with the oposite D2 value after a oldd2 vs newd2 value comparison of some sort.
Because the D2 sent from the M3 is the actual value it has in the preset at that moment and that is something that will not change anything if sent back with the same value.
That is, for example:
The M3 tells the teensy that it uses a SW1 with CC# 80 in OFF state at present. If the teensy tells it to "change" it to OFF it will do exactly that, that is... change nothing.
The teensy needs to get that D2 value (OFF in this example), hold it somewhere, and tell SW1 to send CC# 80 with the ON value when pressed. (If pressed again will change to OFF).

Anyway, need to adapt your sketch to work with the Touchscreen. Will take a while to figure what to do, but i'll let you know something when i'm ready.
 
Can you just check it reads CC values correctly.

Adding D2 should be no problem once I undrstand what you mean...

Are you saying you need to read the current D2 and toggle the state on next fallingEdge (switch contact)?
 
Wait... are SW1 and SW2 physical switches or part of the UI?

I could have sworn this started with switches
 
Can you just check it reads CC values correctly.

Yes, I will do that.

Adding D2 should be no problem once I undrstand what you mean...

Are you saying you need to read the current D2 and toggle the state on next fallingEdge (switch contact)?

Yes, because I will need to use the buttons more than once without a Program Change. When we press the buttons it's "new" D2 value will keep there until the next press, when it will change again.

Example:
First press send Value 127, next press will send value 0 (or vice versa, that also happens in some presets).

If it works how i think this is something easy to achieve, once that I already have that buttonstate working in a sketch with physical buttons, (the inicial OP sketch).
 
Wait... are SW1 and SW2 physical switches or part of the UI?

I could have sworn this started with switches

The SW switches are in the Touchscreen not physical.
I thought that was obvious in the dialog and in the sketch, sorry.
 
It was obvious when I bothered to look at those sections. I thought they were unrelated and you had not added the physical switches.

Now I understand why you've been so keen to integrate every iteration into your UI code.

.... just skip the bounce object stuff and assume the global varables will be correct if you call them in the outermost part of the main loop (or you call your UI routines from there).

Toggles are easy... especially if you just want 0 or 127 you can just store a boolean with the current state and use the negation operator ('SW1state = !SW1state'). Once you have a toggled boolean there are loads of ways to manage D2 so it is toggled.

I guess from here I can't really help coding directly if you insist on debugging with the display UI code in place.
 
It was obvious when I bothered to look at those sections. I thought they were unrelated and you had not added the physical switches.

Now I understand why you've been so keen to integrate every iteration into your UI code.

.... just skip the bounce object stuff and assume the global varables will be correct if you call them in the outermost part of the main loop (or you call your UI routines from there).

Toggles are easy... especially if you just want 0 or 127 you can just store a boolean with the current state and use the negation operator ('SW1state = !SW1state'). Once you have a toggled boolean there are loads of ways to manage D2 so it is toggled.

I guess from here I can't really help coding directly if you insist on debugging with the display UI code in place.


With what I learned till now, I have no problem on working with your sketches and adapt them later in the touchscreen. I already did that with the rest of the stuff, so, lets go with you stuff. Forget the ui, please.
 
With your sketch, nothing more changed, not even the pins:

Code:
0002CC24   8  --     C0    2C    --    1  ---  PC: Tremolo String
0002CC55   1  --     B0    50    00    1  ---  Control Change    
0002CC55   1  --     B0    41    00    1  ---  CC: Portamento    
0002CE04   8  --     C0    2D    --    1  ---  PC: Pizz Strings  
0002CE2E   1  --     B0    50    00    1  ---  Control Change    
0002D329   8  --     C0    2C    --    1  ---  PC: Tremolo String
0002D35B   1  --     B0    50    00    1  ---  Control Change    
0002D35B   1  --     B0    41    00    1  ---  CC: Portamento    
0002DB53  18  --     B0    50    00    1  ---  Control Change    
0002E789  18  --     B0    51    00    1  ---  Control Change

As you can see (port 18 is Teensy's), it is not assigning that CC# 41 from the M3
 
Did some more digging in the Midi-Ox reports:

Code:
00085DF5   1  --     B0    00    00    1  ---  CC: Bank MSB      
00085DF5   1  --     B0    20    00    1  ---  CC: Bank LSB      
00085DF5   1  --     C0    46    --    1  ---  PC: Bassoon       
00085E1D   1  --     B0    50    00    1  ---  Control Change    
00086EA5  22  --     B0    50    00    1  ---  Control Change    
000875A3  22  --     B0    00    00    1  ---  CC: Bank MSB      
00088460   8  --     C0    43    --    1  ---  PC: Baritone Sax  
0008848A   1  --     B0    50    00    1  ---  Control Change    
0008848A   1  --     B0    51    00    1  ---  Control Change    
000897C0  22  --     B0    50    00    1  ---  Control Change    
000898EB  22  --     B0    50    00    1  ---  Control Change    
00089D1A  22  --     B0    00    00    1  ---  CC: Bank MSB

Midi OX port 1 is the Korg M3;
Midi OX port 22 is the Teensy (It changed from port 18 after a reboot i made just for testing);
Midi OX port 8 is the Studiologic Acuna 88 Midi controller;
If the PC is made on the M3 itself the SWs are correctly assigned in the Teensy. If i send the PC from the midi controller to the M3 they don't get assigned and they keep with the last assignment.

I would dare to say that the code is getting somehow "confused" by the missing MSB/LSB messages. I tried with changed the const int scanMax = 250; but it didn't matter on the result.

Looks something in the if clauses.
 
The PC is from another controller?

Yet another design detail I've missed.

Try a much longer treshold as the M3 needs time to reply
 
The PC is from another controller?

Yet another design detail I've missed.

Try a much longer treshold as the M3 needs time to reply

Just tried with const int scanMax = 1000 and 10000 and it is still the same.

The PC can be or not from another controller but 90% of the times it is sent from another controller, so the answer is yes.
The MSB/LSB messages are sent BEFORE the PC message!


 
Make sure the variable definitions are integer:

int SW1;
int SW2;


not byte. Change was needed for negative flag system.

...this is why I can't support your code... there will always be issues where I'm not sure what's going on.
 
Make sure the variable definitions are integer:

int SW1;
int SW2;


not byte. Change was needed for negative flag system.

...this is why I can't support your code... there will always be issues where I'm not sure what's going on.

This is my complete code at the moment. Absolutely no change from yours, no tft, no ribbon, no joystick, nada:

Code:
#include <Bounce.h>  // Bounce library makes button change detection easy
const int scanMax = 100;                                                               // set the time limit for CC to follow PC
const byte channel = 1;                                                                // set channel to filter/send midi
const int SW1pin = 0;                                                                  // set SW1 pin
const int SW2pin = 1;                                                                  // set SW2 pin

int SW1 = 80;                                                                          // default SW1 CC number (D1)                  
int SW2 = 81;                                                                          // default SW2 CC number (D1) 

elapsedMillis scanStart;
Bounce button1 = Bounce(0, 25);  // 5 = 5 ms debounce time
Bounce button2 = Bounce(1, 25);  // which is appropriate for good quality mechanical pushbuttons but I'm using a bare wire!
void setup() {
  pinMode(SW1pin, INPUT_PULLUP); 
  pinMode(SW2pin, INPUT_PULLUP);
}

void loop(void)
{ 
  button1.update();
  button2.update();


  // send CC messages when SW1 or SW2 are pulled LOW
  if (button1.fallingEdge()) { 
    usbMIDI.sendControlChange(SW1, 0, channel);
  }
  if (button2.fallingEdge()) {
    usbMIDI.sendControlChange(SW2, 0, channel);
  }


  if (usbMIDI.read(channel)) { // limit reads to single channel
    if (usbMIDI.getType() == usbMIDI.ProgramChange){
      scanStart = 0;      
      SW1 = 0;
      SW2 = -1;
    }else if(usbMIDI.getType() == usbMIDI.ControlChange) {
      if (scanStart <= scanMax) {
      Serial.println("cc");
        SW1 = SW2;
        SW2 = usbMIDI.getData1();
      }
    }
  }
  if (scanStart >= scanMax) {
    if (SW1 < 0) { // if there was only 1 CC SW1 is negative and we will swap and set SW2 = 0
      SW1 = SW2;
      SW2 = 0;
    }
  }
}
 
Ok... so your using physical switches now?

Then I'll have another go seeing if I can replicate the problem and if not I'll try some serial prints to see what's going wrong
 
If you don't send any with one cc does it keep working?


Code:
000BD2A7   1  --     B0    00    00    1  ---  CC: Bank MSB     
000BD2A7   1  --     B0    20    00    1  ---  CC: Bank LSB     
000BD2A7   1  --     C0    30    --    1  ---  PC: String Ens 1 
000BE8D2  22  --     B0    00    00    1  ---  CC: Bank MSB     
000BF0D5  22  --     B0    7F    00    1  ---  CC: Poly On

This one has no CC's assigned, so the M3 (Port 1) doesn't send them.
As you can see, Teensy (Port 22) sends CC#00 and CC#7F in this case.
 
I'm not able to replicate the problem sending MIDI sequences to Teensy... so here's code with serial.print that should sort out what is happening with the key variables as the MIDI messages process.

The output shows the PC message setting them to their flag values then the CC messages.

If only 1 CC is received the Time Out (TO_) code fires flagged by negative value.

Code:
#include <Bounce.h>  // Bounce library makes button change detection easy
const int scanMax = 100;                                                               // set the time limit for CC to follow PC
const byte channel = 1;                                                                // set channel to filter/send midi
const int SW1pin = 0;                                                                  // set SW1 pin
const int SW2pin = 1;                                                                  // set SW2 pin

int SW1 = 80;                                                                          // default SW1 CC number (D1)                  
int SW2 = 81;                                                                          // default SW2 CC number (D1) 

elapsedMillis scanStart;
Bounce button1 = Bounce(0, 25);  // 5 = 5 ms debounce time
Bounce button2 = Bounce(1, 25);  // which is appropriate for good quality mechanical pushbuttons but I'm using a bare wire!
void setup() {
  Serial.begin(9600);
  pinMode(SW1pin, INPUT_PULLUP); 
  pinMode(SW2pin, INPUT_PULLUP);
}

void loop(void)
{ 
  button1.update();
  button2.update();


  // send CC messages when SW1 or SW2 are pulled LOW
  if (button1.fallingEdge()) { 
    usbMIDI.sendControlChange(SW1, 1, channel);
  }
  if (button2.fallingEdge()) {
    usbMIDI.sendControlChange(SW2, 2, channel);
  }


  if (usbMIDI.read(channel)) { // limit reads to single channel
    if (usbMIDI.getType() == usbMIDI.ProgramChange){
      scanStart = 0;      
      SW1 = 0;
      SW2 = -1;
        Serial.print("PC_SW1=");
        Serial.println(SW1);
        Serial.print("PC_SW2=");
        Serial.println(SW2);
    }else if(usbMIDI.getType() == usbMIDI.ControlChange) {
      if (scanStart <= scanMax) {
        SW1 = SW2;
        SW2 = usbMIDI.getData1();
        Serial.print("CC_SW1=");
        Serial.println(SW1);
        Serial.print("CC_SW2=");
        Serial.println(SW2);
      }
    }
  }
  if (scanStart >= scanMax) {
    if (SW1 < 0) { // if there was only 1 CC SW1 is negative and we will swap and set SW2 = 0
      SW1 = SW2;
      SW2 = 0;
        Serial.print("TO_SW1=");
        Serial.println(SW1);
        Serial.print("TO_SW2=");
        Serial.println(SW2);
    }
  }
}
 
Status
Not open for further replies.
Back
Top