Send 1 Sysex message depending on momentary switch State

Status
Not open for further replies.
No CC sent:

Code:
PC_SW1=0
PC_SW2=-1


Only one CC
Code:
C_SW1=0
PC_SW2=-1
CC_SW1=-1
CC_SW2=80
TO_SW1=80
TO_SW2=0

All directly from the synth
 
Sending one CC with MSB/LSB from Midi-ox, it works:

Code:
PC_SW1=0
PC_SW2=-1
CC_SW1=-1
CC_SW2=80
CC_SW1=80
CC_SW2=81

If i unmanrk MSB/LSB nothing is sent, as happens with the midi controller.
 
Sending one CC with MSB/LSB from Midi-ox, it works:

Code:
PC_SW1=0
PC_SW2=-1
CC_SW1=-1
CC_SW2=80
CC_SW1=80
CC_SW2=81

If i unmanrk MSB/LSB nothing is sent, as happens with the midi controller.

I meant: nothing is received by teensy!
 
Printing nothing implies no PC was received on channel 1.

Other than that the variables look like they work as expected.
 
Printing nothing implies no PC was received on channel 1.

Other than that the variables look like they work as expected.

I will be far from home today but when i arrive i will try to send the PC simultanniously from the controller to both the M3 and Teensy.
 
Oddson: It WOOOOOOOOOORKS!
A BIG THANK YOU for your invaluable help and apologies for that physical vs tft buttons., although not intentional.

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) 
int SW1D2 = 0;                                                                      // default SW1 CC number (D2)                  
int SW2D2 = 0;                                                                      // default SW2 CC number (D2) 




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, SW1D2, channel);
  }
  if (button2.fallingEdge()) {
    usbMIDI.sendControlChange(SW2, SW2D2, channel);
  }




  if (usbMIDI.read(channel)) { // limit reads to single channel
    if (usbMIDI.getType() == usbMIDI.ProgramChange){
      scanStart = 0;      
      SW1 = 0;
      SW1D2 = 0;
      SW2 = -1;
      SW2D2 = -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;
        SW1D2 = SW2D2;
        SW2 = usbMIDI.getData1();
        SW2D2 = usbMIDI.getData2();
        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;
      SW1D2 = SW2D2;
      SW2 = 0;
      SW2D2 = 0;
        Serial.print("TO_SW1=");
        Serial.println(SW1);
        Serial.print("TO_SW2=");
        Serial.println(SW2);
    }
  }
}
 
...apologies for that physical vs tft buttons...

My fault, I wasn't reading your replies carefully.

It is definitely better to make minimal Teensy hardware/sketch rigs when trying something new instead of trying to bolt them on directly to some multifunctional sketch with displays, encoders etc.

In future you could consider adopting sysex-triggering instead of program-change triggering if it turns out you are getting errant settings. In the current set up it's possible some unexpected combination of chatter between the controller and the M3 might set SW1/SW2 incorrectly.

Also, if you were looking for the M3's Sysex message you would not need the long time limit for the threshold as the M3 sends sysex and CCs in the same burst (looking at hex timecode from the Ox output above).

The if/else structure could easily be adapted to use the sysex in place of the program-change message and parsing the data array is really not very difficult.

Cheers

Leif
 
Yes oddson, that sysex approach is something I will consider if i start to notice some wrong results during the use of the controller.
I think I'll be able to do it if thats the case.
Anyway, thanks for the tips!

Cheers
 
It is working flawless: Not even one fault in the CC# and data2 assignments.
I already made the conditional data2 buttons state and reversing it's value. I even did the colors changing according to on or off state. All in the TFT UI!

:cool:

Now: Put this sh#t in the enclosure. :p
 
You should post a photo if you get it looking nice.

Glad to hear it worked out for you (finally!)
 
If i can make it look like it deserves being here, i will post some photos!

It took longer than it was supposed to because i had some stuff going in my life that really didn't make me be fine to work on it.
Lets see how it goes now.
 
Hi.
I'm in the process of calibrating my joystick with this code:

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!
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


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;
elapsedMillis pitchUpdate;
elapsedMillis modUpdate;
elapsedMillis modUpdate2;


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


void setup() {
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
 
}


void loop() 


{
 delay(100);


  getAnalogData();
  while (usbMIDI.read()) {
  }
}






//************ANALOG SECTION**************
void getAnalogData() {
  readPitch.update();
  if (readPitch.hasChanged()) {
    pitchRaw = readPitch.getValue();
    Serial.println(pitchRaw);
    // remap to output data and send if changed and MIDIdelay has lapsed since last update for that parameter
    pitch = map(pitchRaw, 3, 1019, 0, 127);
    pitch = max(pitch, 0); // need this now that the bottom isn't zero
    pitch = min(pitch, 127); // cap to avoid overflow
    if (abs(pitch - pitchLag) > 0 && pitchUpdate > MIDIdelay ) {
      pitchLag = pitch;
      usbMIDI.sendPitchBend(pitch, channel);
      Serial.print("Joystick Pitchbend=");
      Serial.println(pitch);
      pitchUpdate = 0;
    }
  }




  readMod.update();
  if (readMod.hasChanged()) {
    modRaw = readMod.getValue();
    // remap to output data and send if changed and MIDIdelay has lapsed since last update for that parameter
    mod = map(modRaw, 510, 1019, 64, 127); // N.B. - map does not limit values
    mod = max(mod, 64); // minimum could overflow is modRaw is greater than calabrated -This way Y Center-Down will only send from 64 to 127 values
    //mod = min(mod,64);
    if (mod != modLag && modUpdate > MIDIdelay ) { // resolution reduction should be enough wi
      modLag = mod;
      usbMIDI.sendControlChange(1, mod, channel); // CC = 1 is mod wheel in standard MIDI
      modUpdate = 0;
    }
  }
  readMod2.update();
  if (readMod2.hasChanged()) {
    modRaw2 = readMod2.getValue();
    // remap to output data and send if changed and MIDIdelay has lapsed since last update for that parameter
    mod2 = map(modRaw2, 3, 507, 0, 63); // N.B. - map does not limit values
    mod2 = max(mod2, 0); // minimum could overflow if modRaw2 is greater than calibrated
    mod2 = min(mod2, 63); // This way Y Center-Up will only send from 0 till 63 values
    //mod = min(mod2,63);
    if (mod2 != modLag2 && modUpdate2 > MIDIdelay ) { // resolution reduction should be enough wi
      modLag2 = mod2;
      usbMIDI.sendControlChange(2, mod2, channel); // CC = 2 is Breath Control in standard MIDI -In this case it is 
      modUpdate2 = 0;
    }
  {
  }
  }
  }

My problem is the middle Pitchbend point.
I haven't gone to the mod part, but as they have separate parts for down and up i think that the problem will not hapen in the modulation part of the joystick once that i can work the values separately. (once the pitchbend part is figured of course)

508-511 raw values is where the serial print shows the 64 value.
Pitchbend up raw value is 1021-1023.
Pitchbend down value goes to 1-2 in raw and the Pitchbend CC value 1 appears at 11-12 raw.
I thought i had this thing calibrated before in July, but now that i was checking everything to assemble in the enclosure it came with this surprise over me.
Can some update on a library change this?
 
Last edited:
Forgot the most important one, lol:
The centered, untouched, Joystick is at 585 and the CC value is at 73.

Hum... have to measure it electricaly. This is not how it should be.
 
I believe the code is the problem.. what's the source of the mapping values?

Why does everything start halfway up the scale?

I see fragments of my code but I'm hoping I didn't write the dodgy parts.
 
Hi oddson.
The parts with half way values are the ones for the modwheel. Pitchbend doesn't have that.
But yes, it would be nice if the problem was only in the code.
 
Just measured the Ohm with a multimeter;

The side i'm using for the Pitchbend: 12,20 Ohm
The side i'm using for the ModWheel: 10,30 Ohm
 
Last edited:
The resistance only determines current. The voltage at the wiper is a ratio of the upper leg over the total so the total is scaled out.

What matters is the midpoint on a joystick.

It's possible the mechanical system is not resting at the same physical point and this caused the change, or you neglected to centre the midpoint as the main goal of the setting the values in the remap comand.

pitch = map(pitchRaw, 3, 1019, 0, 127);

These values appear to have been chosen just to help make sure the top and bottom are available on a joystick that moves the wiper very close to the edges and that centres very close to midpoint.

Your reading of 585 implies the voltage is well above 50% of supply (57%).

This can be tricky if 585 is not close to the midpoint of the measured top and bottom (stick with raw readings until you've calibrated).

But if it is you can just change the map parameters.

Where does this code come from?
 
With this map it centers, but it's an ugly number :confused: :
Code:
pitch = map(pitchRaw, 158, 1021, 0, 127);

It it has to be this way, be it!
 
I could calibrate it by playing with the screw in the potentiometer, but still, is not perfect, but it will have to do.

Code:
pitch = map(pitchRaw, 12, 1021, 0, 127);
 
This is more a WTF moment than a teensy issue, althought it is still an issue!

The pitchbend sends values but it is sending them in the wrong place according to Midiox. The CC values (data2) are detected as the Data1!!!!!
Watch this:

Code:
TIMESTAMP IN PORT STATUS DATA1 DATA2 CHAN NOTE EVENT  
000392F7  23  --     E0    34    40    1  ---  Pitch Bend  
00039302  23  --     E0    35    40    1  ---  Pitch Bend  
0003930D  23  --     E0    36    40    1  ---  Pitch Bend  
00039315  23  --     E0    37    40    1  ---  Pitch Bend  
0003931F  23  --     E0    38    40    1  ---  Pitch Bend  
00039329  23  --     E0    39    40    1  ---  Pitch Bend  
00039332  23  --     E0    3A    40    1  ---  Pitch Bend  
0003933E  23  --     E0    3B    40    1  ---  Pitch Bend  
0003934A  23  --     E0    3C    40    1  ---  Pitch Bend  
0003935A  23  --     E0    3D    40    1  ---  Pitch Bend  
00039368  23  --     E0    3E    40    1  ---  Pitch Bend  
00039375  23  --     E0    3F    40    1  ---  Pitch Bend  
00039386  23  --     E0    40    40    1  ---  Pitch Bend  
0003C6AF  23  --     E0    41    40    1  ---  Pitch Bend


The Mod wheel parts work fine:

Code:
TIMESTAMP IN PORT STATUS DATA1 DATA2 CHAN NOTE EVENT  
000988BC  23  --     B0    02    3E    1  ---  CC: Breath      
000988CC  23  --     B0    02    3D    1  ---  CC: Breath      
000988D6  23  --     B0    02    3C    1  ---  CC: Breath      
000988DE  23  --     B0    02    3B    1  ---  CC: Breath      
000988E6  23  --     B0    02    3A    1  ---  CC: Breath      
000988EC  23  --     B0    02    39    1  ---  CC: Breath      
TIMESTAMP IN PORT STATUS DATA1 DATA2 CHAN NOTE EVENT  
000A3A96  23  --     B0    01    41    1  ---  CC: Modulation 
000A3AB8  23  --     B0    01    42    1  ---  CC: Modulation 
000A3AC6  23  --     B0    01    43    1  ---  CC: Modulation 
000A3ACC  23  --     B0    01    44    1  ---  CC: Modulation 
000A3AD3  23  --     B0    01    45    1  ---  CC: Modulation 
000A3AD8  23  --     B0    01    46    1  ---  CC: Modulation 
000A3ADE  23  --     B0    01    47    1  ---  CC: Modulation 
000A3AE5  23  --     B0    01    48    1  ---  CC: Modulation 
000A3AEA  23  --     B0    01    49    1  ---  CC: Modulation 
000A3AF0  23  --     B0    01    4A    1  ---  CC: Modulation 
000A3AF6  23  --     B0    01    4B    1  ---  CC: Modulation 
000A3AFC  23  --     B0    01    4D    1  ---  CC: Modulation 
000A3B02  23  --     B0    01    4E    1  ---  CC: Modulation
 
Changed this:

Code:
const int pitchMaxRaw = 1019; // Max reading with full bend up... as raw 10-bit value

Code:
    pitch = map(pitchRaw, 12, 1021, 0, [B]16383[/B]);
    pitch = max(pitch, 0); // need this now that the bottom isn't zero
    pitch = min(pitch, [B]16383[/B]); // cap to avoid overflow
... and it now sends the full pitchbend values from 0 to the middle. From the middle position and up it doesn't send anything else different from 7F (127). I get it, it reaches the upper value at the middle, but what is wrong in my code?
 
Status
Not open for further replies.
Back
Top