Help with incorporating USB Host routing with midi synthesizer project

livingsteel

New member
Hello! I am currently working on a version of a sample based eurorack module code from this source: https://github.com/otem/Eurorack/tree/master/tinyDrummer. I am using a Teensy 4.1 with a pcm5102a connected to pins 18 and 19.I am working in the Arduino IDE 1.8 on a Windows 11 system.
I have successfully modified the code to work with usb host in that I can directly connect a diy midi sequencer to the usb host port and have no issues. I want to be able to take the incoming usb midi information and route some of it (in particular, channel 3) through the tx2 pin of the teensy to a separate synth with 5 pin din midi. I tried to use some of the 16x16 midi interface example along with my previous modifications and have got it to compile but any usb messages sent through the host port no longer work in any way. I am quite new to coding and would really appreciate anyone's help! Thanks!
Code:
#include <Arduino.h>
#include <USBHost_t36.h>
#include <Audio.h>
#include <SPI.h>
#include <Wire.h>
#include <TeensyVariablePlayback.h>
#include <MIDI.h>
#include "flashloader.h"
#include <ResponsiveAnalogRead.h>
#include "effect_platervbstereo.h"

USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
MIDIDevice midi1(myusb);

// GUItool: begin automatically generated code
AudioSynthWaveformDc     dc1;            //xy=190.77771949768066,175.77776718139648
AudioSynthWaveformDc     dc2; //xy=191.66666221618652,262.3333110809326
AudioSynthWaveformDc     dc5; //xy=192.66666221618652,531.3333110809326
AudioSynthWaveformDc     dc6; //xy=193.55560493469238,617.8888549804688
AudioSynthWaveformDc     dc3; //xy=194.66666221618652,342.3333110809326
AudioSynthWaveformDc     dc4; //xy=195.55560493469238,428.88885498046875
AudioPlayArrayResmp          playMem1;       //xy=198.11105728149414,213.44445610046387
AudioSynthWaveformDc     dc7; //xy=196.55560493469238,697.8888549804688
AudioPlayArrayResmp          playMem2; //xy=199,300
AudioSynthWaveformDc     dc8; //xy=197.44454765319824,784.4443988800049
AudioPlayArrayResmp          playMem5; //xy=200,569
AudioPlayArrayResmp          playMem6;  //xy=200.88894271850586,655.5555438995361
AudioPlayArrayResmp          playMem3; //xy=202,380
AudioPlayArrayResmp          playMem4; //xy=202.88894271850586,466.55554389953613
AudioPlayArrayResmp          playMem7; //xy=203.88894271850586,735.5555438995361
AudioPlayArrayResmp          playMem8; //xy=204.77788543701172,822.1110877990723
AudioEffectMultiply      multiply1;      //xy=443.1110534667969,200.44444274902344
AudioEffectMultiply      multiply2; //xy=443.99999618530273,286.99998664855957
AudioEffectMultiply      multiply5; //xy=444.99999618530273,555.9999866485596
AudioEffectMultiply      multiply6; //xy=445.8889389038086,642.5555305480957
AudioEffectMultiply      multiply3; //xy=446.99999618530273,366.99998664855957
AudioEffectMultiply      multiply4; //xy=447.8889389038086,453.5555305480957
AudioEffectMultiply      multiply7; //xy=448.8889389038086,722.5555305480957
AudioEffectMultiply      multiply8; //xy=449.77788162231445,809.1110744476318
AudioMixer4              mixer2;         //xy=772.5555419921875,594.5555419921875
AudioMixer4              mixer1;         //xy=776,343
AudioSynthWaveformDc     filterDC;            //xy=945.9999961853027,547.9999942779541
AudioMixer4              mixer3;         //xy=950.9999961853027,471.9999942779541
AudioFilterLadder        ladder1;        //xy=1097.9999961853027,538.9999942779541
AudioEffectPlateReverb       verb1;       //xy=1198.9999961853027,681.9999942779541
AudioMixer4              verbMixer;         //xy=1333.9999961853027,557.9999942779541
AudioOutputI2S           i2s1;           //xy=1537.9999961853027,538.9999942779541
AudioConnection          patchCord1(dc1, 0, multiply1, 0);
AudioConnection          patchCord2(dc2, 0, multiply2, 0);
AudioConnection          patchCord3(dc5, 0, multiply5, 0);
AudioConnection          patchCord4(dc6, 0, multiply6, 0);
AudioConnection          patchCord5(dc3, 0, multiply3, 0);
AudioConnection          patchCord6(dc4, 0, multiply4, 0);
AudioConnection          patchCord7(playMem1, 0, multiply1, 1);
AudioConnection          patchCord8(dc7, 0, multiply7, 0);
AudioConnection          patchCord9(playMem2, 0, multiply2, 1);
AudioConnection          patchCord10(dc8, 0, multiply8, 0);
AudioConnection          patchCord11(playMem5, 0, multiply5, 1);
AudioConnection          patchCord12(playMem6, 0, multiply6, 1);
AudioConnection          patchCord13(playMem3, 0, multiply3, 1);
AudioConnection          patchCord14(playMem4, 0, multiply4, 1);
AudioConnection          patchCord15(playMem7, 0, multiply7, 1);
AudioConnection          patchCord16(playMem8, 0, multiply8, 1);
AudioConnection          patchCord17(multiply1, 0, mixer1, 0);
AudioConnection          patchCord18(multiply2, 0, mixer1, 1);
AudioConnection          patchCord19(multiply5, 0, mixer2, 0);
AudioConnection          patchCord20(multiply6, 0, mixer2, 1);
AudioConnection          patchCord21(multiply3, 0, mixer1, 2);
AudioConnection          patchCord22(multiply4, 0, mixer1, 3);
AudioConnection          patchCord23(multiply7, 0, mixer2, 2);
AudioConnection          patchCord24(multiply8, 0, mixer2, 3);
AudioConnection          patchCord25(mixer2, 0, mixer3, 1);
AudioConnection          patchCord26(mixer1, 0, mixer3, 0);
AudioConnection          patchCord27(filterDC, 0, ladder1, 1);
AudioConnection          patchCord28(mixer3, 0, ladder1, 0);
AudioConnection          patchCord29(ladder1, 0, verbMixer, 0);
AudioConnection          patchCord30(ladder1, 0, verb1, 0);
AudioConnection          patchCord31(ladder1, 0, verb1, 1);
AudioConnection          patchCord32(verb1, 0, verbMixer, 1);
AudioConnection          patchCord33(verb1, 1, verbMixer, 2);
AudioConnection          patchCord34(verbMixer, 0, i2s1, 0);
// GUItool: end automatically generated code

AudioPlayArrayResmp *sampPlayers[8] = {
  &playMem1,&playMem2,&playMem3,&playMem4,
  &playMem5,&playMem6,&playMem7,&playMem8,
};
AudioSynthWaveformDc *envs[8] = {
  &dc1,&dc2,&dc3,&dc4,
  &dc5,&dc6,&dc7,&dc8,
};

ResponsiveAnalogRead analogs[4] = {
  ResponsiveAnalogRead (A10, true),
  ResponsiveAnalogRead (A11, true),
  ResponsiveAnalogRead (A12, true),
  ResponsiveAnalogRead (A14, true),
};

ResponsiveAnalogRead setCV(A2, true);

int cvPins[3] = {A0,A1,A3};


newdigate::audiosample *samps[128];

MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI2);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial2, MIDI3);

int dirCount;
int fileCount;
String dirName;
// int dirItter[16] = {
//   0,8,16,24,32,40,48,56,
//   64,72,80,88,96,104,112,120,
// };

int setIndex;
int setIndexCV;
int setIndexCC;
int voiceIndex;
float globalSamplePitch = 1;
unsigned int globalDecayTime = 500;
float filterFreq;
float filterFreqCC;
float verbMixCC;
float pitchCV;
float decayCV;
float filterCV;

int folderTotal;

float voiceDecayTime[8];
float voiceSamplepitch[8];

elapsedMillis printTime;

newdigate::flashloader loader;

void setup(){
  // Serial.begin(9600);
  //  while (!Serial) {
  //   delay(10);
  // }

  while (!SD.begin(BUILTIN_SDCARD)) {
    Serial.println("No SD Card");
    delay(500);
  }

  AudioMemory(94);
  dc1.amplitude(1);

  for (size_t i = 0; i < 8; i++) {
    if (i<4) {
      mixer1.gain(i,0.5);
      mixer2.gain(i,0.5);
      analogs[i].setActivityThreshold(5);
      analogs[i].enableEdgeSnap();
    }
    sampPlayers[i]->enableInterpolation(true);
  }

  ladder1.resonance(0);
  ladder1.octaveControl(7);
  ladder1.inputDrive(1);
  filterDC.amplitude(1);
  verb1.size(1);     // max reverb length
  verb1.lowpass(1);  // sets the reverb master lowpass filter
  verb1.lodamp(0.1);   // amount of low end loss in the reverb tail
  verb1.hidamp(0.1);   // amount of treble loss in the reverb tail
  verb1.diffusion(1);  // 1.0 is the detault setting, lower it to create more "echoey" reverb


  verbMixer.gain(0,1);
  verbMixer.gain(1,0);
  verbMixer.gain(2,0);

  myusb.begin();
  MIDI2.begin(11);
  MIDI3.begin(2);
  usbMIDI.setHandleNoteOn(handleNoteOn);
  usbMIDI.setHandleControlChange(myControlChange);
  MIDI2.setHandleNoteOn(handleNoteOn);
  MIDI2.setHandleControlChange(myControlChange);
  midi1.setHandleNoteOn(handleNoteOn);
  midi1.setHandleControlChange(myControlChange);

  File root = SD.open("samples");
  getDirectories(root, 0);

  folderTotal = dirCount-1;

  setCV.enableEdgeSnap();
  setCV.setActivityThreshold(600/dirCount);

}
void loop(){
  myusb.Task();
  midi1.read();
  usbMIDI.read();
  MIDI2.read(11);
  for (size_t i = 0; i < 4; i++) {
    analogs[i].update();
    if(analogs[i].hasChanged()) {
      // Serial.println("Analog "+String(i)+": "+String(analogs[i].getValue()));
      if(i==0){
        setIndex = map(analogs[i].getValue(), 0,1023,0,folderTotal);
        // Serial.println("Set: "+String(setIndex));
      }else if(i==1){
        globalSamplePitch = map(float(analogs[i].getValue()),0,1023,-2,2);
        // Serial.println("pitch: "+String(globalSamplePitch));
      }else if(i==2){
        // volume = map(float(analogs[i].getValue()),0,1023,0,1);
        filterFreq = map(float(analogs[i].getValue()),0,1023,-1,1);

        // Serial.println("Volume: "+String(volume));
      }else if(i==3){
        globalDecayTime = float(analogs[i].getValue());
        // Serial.println("globalDecayTime: "+String(globalDecayTime));
      }
    }
  }

  for (size_t i = 0; i < 8; i++) {
    sampPlayers[i]->setPlaybackRate(globalSamplePitch+pitchCV+voiceSamplepitch[i]);
  }


  //cv
  for (size_t i = 0; i < 4; i++) {
    if (i==0) {
      pitchCV = map(float(analogRead(cvPins[i])),20,1000,2,-2);
    }else if(i==1){
      decayCV = map(float(analogRead(cvPins[i])),20,1000,512,-512);
    }else if(i==2){
      filterCV = map(float(analogRead(cvPins[i])),20,1000,1,-1);
    }
  }
  setCV.update();
  if (setCV.hasChanged()) {
    setIndexCV = map(setCV.getValue(),215,820,0,folderTotal);
    if (setIndexCV > -1 && setIndexCV <= folderTotal) {
      // Serial.println("SetCV: "+String(setIndexCV));
      setIndex = setIndexCV;
    }
  }
  for (size_t i = 0; i < 8; i++) {
    envs[i]->amplitude(0,globalDecayTime+decayCV+voiceDecayTime[i]);
  }
  filterDC.amplitude(filterFreq+filterCV+filterFreqCC);

  if (printTime > 100) {
    // Serial.println("set raw cv: "+String(analogRead(A2)));
    printTime = 0;
  }
}
 
void handleNoteOn(uint8_t channel, uint8_t pitch, uint8_t velocity){
  if (pitch < 52 && pitch > 43){
    voiceIndex =  pitch-44;

    if(voiceIndex < 4){
      mixer1.gain(voiceIndex, float(velocity)/127);
    }else{
      mixer2.gain(voiceIndex-4, float(velocity)/127);
    }
    envs[voiceIndex]->amplitude(1);

    int sampleSelect = setIndex*8;

    if (samps[voiceIndex+sampleSelect]) {
      // Serial.println("voice: "+String(voiceIndex)+" | sample: "+String(voiceIndex+sampleSelect));
      sampPlayers[voiceIndex]->playWav(samps[voiceIndex+sampleSelect]->sampledata, samps[voiceIndex+sampleSelect]->samplesize);
    }
  }
}  
void myControlChange(byte channel, byte control, byte value){
  if (control > 0 && control < 9 ) {
    voiceSamplepitch[control-1] = map(float(value),0,127,-2,2);
  }
  if (control > 8 && control < 17 ) {
    voiceDecayTime[control-9] = map(value,0,127,-512,512);
  }

  if (control==17) {
    filterFreqCC = float(value)/63 - 1;
  }

  if (control==18){
    verbMixCC = float(value)/127;
    verbMixer.gain(0,1-verbMixCC);
    verbMixer.gain(1,verbMixCC);
    verbMixer.gain(2,verbMixCC);
  }
  if (control==19) {
    float verbSize = float(value)/127;
    verb1.size(verbSize);
  }
  if (control==20) {
    setIndexCC = map(int(value),0,127,0,folderTotal);
    if (setIndexCC > -1 && setIndexCC <= folderTotal) {
      setIndex = setIndexCC;
      // Serial.println("set index cc: "+String(setIndexCC));
    }
  }
  if (control==50) {
    if (value > 60) {
      filterFreqCC = 0;
      verbMixer.gain(0,1);
      verbMixer.gain(1,0);
      verbMixer.gain(2,0);
      verb1.size(1);
      for (size_t i = 0; i < 8; i++) {
        voiceSamplepitch[i] = 0;
        voiceDecayTime[i] = 0;
      }
    }
  }
 
  if (usbMIDI.read(3)) {
    byte type = usbMIDI.getType();
    byte channel = usbMIDI.getChannel();
    byte data1 = usbMIDI.getData1();
    byte data2 = usbMIDI.getData2();
    byte cable = usbMIDI.getCable();

        // forward this message to 1 of the 3 Serial MIDI OUT ports
    if (type != usbMIDI.SystemExclusive) {
      // Normal messages, first we must convert usbMIDI's type (an ordinary
      // byte) to the MIDI library's special MidiType.
      midi::MidiType mtype = (midi::MidiType)type;

      // Then simply give the data to the MIDI library send()
      switch (cable) {
        MIDI3.send(mtype, data1, data2, channel); break;
        //case  1: MIDI3.send(mtype, data1, data2, channel); break;
        //case  2: MIDI3.send(mtype, data1, data2, channel); break;
        //case  3: MIDI3.send(mtype, data1, data2, channel); break;
        //case  4: MID3.send(mtype, data1, data2, channel); break;
        //case  5: MIDI3.send(mtype, data1, data2, channel); break;  
      }
    }
  }
}
 
Here's one approach, which is how I accomplish something very similar in the latest version of my TeensyMIDIPolySynth to what I believe you are looking for:

Following the MIDI Library / Callbacks example program, I defined & implemented all of the callback handlers as follows:

Code:
void handleActiveSensing(void);
void handleAfterTouchChannel(byte channel, byte pressure);
void handleAfterTouchPoly(midi::DataByte note, midi::DataByte pressure, midi::Channel channel);
void handleClock(void);
void handleContinue(void);
void handleControlChange(byte channel, byte number, byte value);
void handleNoteOff(byte channel, byte pitch, byte velocity);
void handleNoteOn(byte channel, byte pitch, byte velocity);
void handlePitchBend(byte channel, int bend);
void handleProgramChange(byte channel, byte number);
void handleSongPosition(unsigned beats);
void handleSongSelect(byte songnumber);
void handleStart(void);
void handleStop(void);
void handleSystemExclusive(byte * array, unsigned size);
void handleSystemReset(void);
void handleTimeCodeQuarterFrame(byte data);
void handleTuneRequest(void);

void MIDIhandleActiveSensing(void);
void MIDIhandleAfterTouchChannel(byte channel, byte pressure);
void MIDIhandleAfterTouchPoly(midi::DataByte note, midi::DataByte pressure, midi::Channel channel);
void MIDIhandleClock(void);
void MIDIhandleContinue(void);
void MIDIhandleControlChange(byte channel, byte number, byte value);
void MIDIhandleNoteOff(byte channel, byte pitch, byte velocity);
void MIDIhandleNoteOn(byte channel, byte pitch, byte velocity);
void MIDIhandlePitchBend(byte channel, int bend);
void MIDIhandleProgramChange(byte channel, byte number);
void MIDIhandleSongPosition(unsigned beats);
void MIDIhandleSongSelect(byte songnumber);
void MIDIhandleStart(void);
void MIDIhandleStop(void);
void MIDIhandleSystemExclusive(byte * array, unsigned size);
void MIDIhandleSystemReset(void);
void MIDIhandleTimeCodeQuarterFrame(byte data);
void MIDIhandleTuneRequest(void);

void USBhandleActiveSensing(void);
void USBhandleAfterTouchChannel(byte channel, byte pressure);
void USBhandleAfterTouchPoly(midi::DataByte note, midi::DataByte pressure, midi::Channel channel);
void USBhandleClock(void);
void USBhandleContinue(void);
void USBhandleControlChange(byte channel, byte number, byte value);
void USBhandleNoteOff(byte channel, byte pitch, byte velocity);
void USBhandleNoteOn(byte channel, byte pitch, byte velocity);
void USBhandlePitchBend(byte channel, int bend);
void USBhandleProgramChange(byte channel, byte number);
void USBhandleSongPosition(uint16_t beats);
void USBhandleSongSelect(byte songnumber);
void USBhandleStart(void);
void USBhandleStop(void);
void USBhandleSystemExclusive(byte * array, unsigned size);
void USBhandleSystemReset(void);
void USBhandleTimeCodeQuarterFrame(byte data);
void USBhandleTuneRequest(void);

void usbhostMIDIhandleActiveSensing(void);
void usbhostMIDIhandleAfterTouchChannel(byte channel, byte pressure);
void usbhostMIDIhandleAfterTouchPoly(midi::DataByte note, midi::DataByte pressure, midi::Channel channel);
void usbhostMIDIhandleClock(void);
void usbhostMIDIhandleContinue(void);
void usbhostMIDIhandleControlChange(byte channel, byte number, byte value);
void usbhostMIDIhandleNoteOff(byte channel, byte pitch, byte velocity);
void usbhostMIDIhandleNoteOn(byte channel, byte pitch, byte velocity);
void usbhostMIDIhandlePitchBend(byte channel, int bend);
void usbhostMIDIhandleProgramChange(byte channel, byte number);
void usbhostMIDIhandleSongPosition(unsigned beats);
void usbhostMIDIhandleSongSelect(byte songnumber);
void usbhostMIDIhandleStart(void);
void usbhostMIDIhandleStop(void);
void usbhostMIDIhandleSystemExclusive(byte * array, unsigned size);
void usbhostMIDIhandleSystemReset(void);
void usbhostMIDIhandleTimeCodeQuarterFrame(byte data);
void usbhostMIDIhandleTuneRequest(void);

I added specific variables to keep track of / control forwarding MIDI commands between the various MIDI interfaces as follows (the BUTTON_TYPE is an integrated structure/type that I defined to allow me to paint a button on the screen & to implement the associated process handling when the button is pressed to activate/deactivate its associated boolean):

Code:
BUTTON_TYPE midiMIDIthruButton;
BUTTON_TYPE midiFWDtoMIDIButton;
BUTTON_TYPE midiFWDtoUSBButton;
BUTTON_TYPE midiFWDtoHOSTButton;


I have similar variables to allow me to control whether messages tagged with individual MIDI channels are forwarded (or not) as follows:

Code:
BUTTON_TYPE midiFwdChanButton
BUTTON_TYPE midiFwdCh01Button
BUTTON_TYPE midiFwdCh02Button
BUTTON_TYPE midiFwdCh03Button
BUTTON_TYPE midiFwdCh04Button
BUTTON_TYPE midiFwdCh05Button
BUTTON_TYPE midiFwdCh06Button
BUTTON_TYPE midiFwdCh07Button
BUTTON_TYPE midiFwdCh08Button
BUTTON_TYPE midiFwdCh09Button
BUTTON_TYPE midiFwdCh10Button
BUTTON_TYPE midiFwdCh11Button
BUTTON_TYPE midiFwdCh12Button
BUTTON_TYPE midiFwdCh13Button
BUTTON_TYPE midiFwdCh14Button
BUTTON_TYPE midiFwdCh15Button
BUTTON_TYPE midiFwdCh16Button


Using these control variables, I implemented code in the callback handlers to specifically route MIDI commands between the MIDI interfaces as follows ( in this case, using the Control Change handler processing as a specific example):

Code:
      if (midiFWDtoMIDIButton.activated)
      {
         // echo the Control Change message to MIDI out
         MIDI.sendControlChange(number, value, channel);
      }

      if (midiFWDtoHOSTButton.activated)
      {
         // echo the Control Change message to usbhostMIDI out
         usbhostMIDI.sendControlChange(number, value, channel);
      }

As another example, here's the same kind of processing for a MIDI NoteOff message (received on any of the interfaces):

Code:
                        if ((midiFwdCh01Button.activated) && (midiFWDtoUSBButton.activated))
                        {
                           // echo the note off message to usbMIDI out
                           usbMIDI.sendNoteOff(keyboard_pitch, 0, 1);
                        }

                        if ((midiFwdCh01Button.activated) && (midiFWDtoHOSTButton.activated))
                        {
                           // echo the note off message to usbhostMIDI out
                           usbhostMIDI.sendNoteOff(keyboard_pitch, 0, 1);
                        }

                        if ((midiFwdCh01Button.activated) && (midiFWDtoMIDIButton.activated))
                        {
                           // echo the note off message to MIDI out
                           MIDI.sendNoteOff(keyboard_pitch, 0, 1);
                        }

And finally, another example showing the channel specific processing for processing a Note On message (received on any of the interfaces):

Code:
                     if ((midiFwdCh01Button.activated) && (midiFWDtoMIDIButton.activated))
                     {
                        // echo the note on message to MIDI out
                        MIDI.sendNoteOn(keyboard_pitch, 128, 1);
                     }

Hope this helps !!

Mark J Culross
KD5RXT

P.S. One thing to note: the list of parameters is not necessarily in the same order for similar callbacks, but on the different kinds of interfaces, so that may be one contributor that will required extra attention when you implement your MIDI message forwarding.
 
Thanks so much for your response! I took a look at your code for the teensymidipolysynth and, although it is way over my head, it is really helpful for my future reference. Forgive my ignorance, but although I found the callback handlers and their usage in your polysynth code, I could not find any reference to the button specific implementation. Would I be using physical buttons that correspond to the defined buttons you included above to trigger the midi message forwarding? Also, in the code I am using to base my sample player on, the handleNoteOn function looks like this
Code:
void handleNoteOn(uint8_t channel, uint8_t pitch, uint8_t velocity){
  if (pitch < 52 && pitch > 43){
    voiceIndex =  pitch-44;

    if(voiceIndex < 4){
      mixer1.gain(voiceIndex, float(velocity)/127);
    }else{
      mixer2.gain(voiceIndex-4, float(velocity)/127);
    }
    envs[voiceIndex]->amplitude(1);

    int sampleSelect = setIndex*8;

    if (samps[voiceIndex+sampleSelect]) {
      // Serial.println("voice: "+String(voiceIndex)+" | sample: "+String(voiceIndex+sampleSelect));
      sampPlayers[voiceIndex]->playWav(samps[voiceIndex+sampleSelect]->sampledata, samps[voiceIndex+sampleSelect]->samplesize);
    }
  }
}

The only difference between your handling and the handling in my base code is "uint8_t", rather than "byte". Would changing the handle from "uint8_t" to "byte" so as to match your code have any drastic effects? I'm sorry if my question sounds a little silly, I am really quite new to all this. Thanks!
 
Thanks so much for your response! I took a look at your code for the teensymidipolysynth and, although it is way over my head, it is really helpful for my future reference. Forgive my ignorance, but although I found the callback handlers and their usage in your polysynth code, I could not find any reference to the button specific implementation. Would I be using physical buttons that correspond to the defined buttons you included above to trigger the midi message forwarding? Also, in the code I am using to base my sample player on, the handleNoteOn function looks like this
Code:
void handleNoteOn(uint8_t channel, uint8_t pitch, uint8_t velocity)
The only difference between your handling and the handling in my base code is "uint8_t", rather than "byte". Would changing the handle from "uint8_t" to "byte" so as to match your code have any drastic effects?

I wouldn't think that byte vs. uint8_t would make much of a difference, if any.

Sorry, I didn't really give enough info on the buttons that I referenced which would have avoided any possible confusion. The published version of my TeensyMIDIPolySynth that you most likely found was a "hardware-based" operator interface (e.g. physical potentiometers, physical buttons, & physical LEDs). Because I literally ran out of front panel space on the plastic storage box that I used for that implementation, I was unable to add any more capabilities and/or expand what I had. As a result, I had to abandon the "hardware-based" implementation & traded it for a "virtual" implementation. The sliders, buttons, & LEDs are all now drawn on a 800x480 RA8875 based TFT touchscreen display. Depending upon which synthesizer section is currently selected/active, I draw the appropriate buttons & sliders on the screen, & as those "virtual" controls are adjusted, the corresponding settings are assigned & sent to the audio library objects. I haven't published that code as it is still very much a work-in-progress (& a very sloppy one at that !!).

For instance, in the MIDI control screen, as the "midiFWDtoMIDIButton" area is touched on the screen, the boolean variable is toggled to represent enabling/disabling that selection. Similarly, in the VFO-A screen, as the amplitude slider for the sine oscillator is adjusted on the display, the amplitude() function for that audio library object is called with the value (ranging between -1 & +1) represented by the current location of the slider's control.

It may not really be of any direct use for you, unless you also have a touchscreen implementation of buttons & sliders, but here's the definition of the buttons & sliders that I have implemented (along with a few button & slider declarations):

Code:
struct BUTTON_TYPE
{
   unsigned int   xCenterLoc;
   unsigned int   yCenterLoc;
   unsigned int   xSize;
   unsigned int   ySize;
   const String*  textPtr;
   uint16_t       textColor;
   uint16_t       buttonColor;
   uint16_t       borderColor;
   bool           activated;
};

// create button objects, passing in the display object

// MIDI CHANNEL BUTTONS
const String midiMIDIthruButtonText       = "MIDI THRU";
BUTTON_TYPE midiMIDIthruButton            = { 80, 215, 120, 40,    &midiMIDIthruButtonText, RA8875_BLACK, RA8875_GREEN, RA8875_RED,  true };
[CODE]
const String midiFWDtoMIDIButtonText = "FWD-to-MIDI";
BUTTON_TYPE midiFWDtoMIDIButton = { 80, 275, 120, 40, &midiFWDtoMIDIButtonText, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true };

const String midiFWDtoUSBButtonText = "FWD-to-USB";
BUTTON_TYPE midiFWDtoUSBButton = { 80, 335, 120, 40, &midiFWDtoUSBButtonText, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true };

const String midiFWDtoHOSTButtonText = "FWD-to-hostUSB";
BUTTON_TYPE midiFWDtoHOSTButton = { 80, 395, 120, 40, &midiFWDtoHOSTButtonText, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true };



struct SLIDER_TYPE
{
unsigned int xCenterLoc;
unsigned int yCenterLoc;
unsigned int xSize;
unsigned int ySize;
float value;
unsigned int minorTickSections; // normally = 10
unsigned int majorTickSections; // normally = 2
unsigned int placesBeforeTheDecimal;
unsigned int placesAfterTheDecimal;
bool showPlusMinusSign;
float minValue; // for HORIZONTAL = all the way to the left, for VERTICAL, all the way up
float maxValue; // for HORIZONTAL = all the way to the right, for VERTICAL, all the way down
unsigned int xValueCenterLoc;
unsigned int yValueCenterLoc;
uint16_t valueColor;
uint16_t backgroundColor;
uint16_t borderColor;
uint16_t scaleColor;
uint16_t handleColor;
uint16_t handleBorderColor;
uint16_t backgroundColorDisabled;
uint16_t borderColorDisabled;
uint16_t scaleColorDisabled;
uint16_t handleColorDisabled;
uint16_t handleBorderColorDisabled;
bool activated;
SLIDER_MODE orientation;
};

SLIDER_TYPE keyboardPitchBendSlider = { 200, 180, 255, 30, 0.00, 16, 4, 4, 0, true, -8192.0, 8191.0, 35, 195, RA8875_WHITE, RA8875_SHADOWGREY, RA8875_GREEN, RA8875_BLACK, RA8875_GREEN, RA8875_BLACK, RA8875_BLACK, RA8875_SHADOWGREY, RA8875_SHADOWGREY, RA8875_SHADOWGREY, RA8875_BLACK, true, SLIDER_MODE_HORIZONTAL };
SLIDER_TYPE keyboardModWheelSlider = { 600, 180, 255, 30, 0.00, 16, 4, 3, 0, false, 0.0, 127.0, 765, 195, RA8875_WHITE, RA8875_SHADOWGREY, RA8875_GREEN, RA8875_BLACK, RA8875_GREEN, RA8875_BLACK, RA8875_BLACK, RA8875_SHADOWGREY, RA8875_SHADOWGREY, RA8875_SHADOWGREY, RA8875_BLACK, true, SLIDER_MODE_HORIZONTAL };
[/CODE]

And here's how these virtual objects are drawn:

Code:
// draw a button
void drawButton(BUTTON_TYPE thisButton)
{
   if (thisButton.activated)
   {
      tft.fillRect(thisButton.xCenterLoc - (thisButton.xSize / 2) + 1, thisButton.yCenterLoc - (thisButton.ySize / 2) + 1, thisButton.xSize - 2, thisButton.ySize - 2, thisButton.buttonColor);
      tft.drawRect(thisButton.xCenterLoc - (thisButton.xSize / 2), thisButton.yCenterLoc - (thisButton.ySize / 2), thisButton.xSize, thisButton.ySize, thisButton.borderColor);

      centerDrawText(*(thisButton.textPtr), thisButton.xCenterLoc, thisButton.yCenterLoc, thisButton.textColor, thisButton.buttonColor);
   } else {
      tft.fillRect(thisButton.xCenterLoc - (thisButton.xSize / 2) + 1, thisButton.yCenterLoc - (thisButton.ySize / 2) + 1, thisButton.xSize - 2, thisButton.ySize - 2, thisButton.borderColor);
      tft.drawRect(thisButton.xCenterLoc - (thisButton.xSize / 2), thisButton.yCenterLoc - (thisButton.ySize / 2), thisButton.xSize, thisButton.ySize, thisButton.buttonColor);

      centerDrawText(*(thisButton.textPtr), thisButton.xCenterLoc, thisButton.yCenterLoc, thisButton.textColor, thisButton.borderColor);
   }
}  // drawButton()



// draw a slider
void drawSlider(SLIDER_TYPE thisSlider)
{
   int characterCount = 0;
   String outString = "";

   if (thisSlider.value < thisSlider.minValue)
   {
      thisSlider.value = thisSlider.minValue;
   }

   if (thisSlider.value > thisSlider.maxValue)
   {
      thisSlider.value = thisSlider.maxValue;
   }

   if (thisSlider.orientation == SLIDER_MODE_HORIZONTAL)
   {
      if (thisSlider.activated)
      {
         // clear the entire slider
         tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, thisSlider.xSize + 15, thisSlider.ySize + 6, thisSlider.backgroundColor);

         // draw the slider outline
         tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, thisSlider.xSize + 15, thisSlider.ySize + 6, thisSlider.borderColor);

         // draw the slider handle
         tft.fillRect((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)) - 6, thisSlider.yCenterLoc - (2 + thisSlider.ySize * 4 / 10), 13, (thisSlider.ySize * 8 / 10) + 4, RA8875_BLACK);
         tft.fillRect((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)) - 4, thisSlider.yCenterLoc - thisSlider.ySize * 4 / 10, 9, thisSlider.ySize * 8 / 10, thisSlider.handleColor);

         // draw the slider guide line
         tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.scaleColor);          // guide line

         tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc - 7, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc + 7, thisSlider.scaleColor);  // left end
         tft.drawLine(thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc - 7, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc + 7, thisSlider.scaleColor);  // right end

         // draw the slider minor tick lines
         for (unsigned int i = 1; i < thisSlider.minorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.minorTickSections), thisSlider.yCenterLoc - 2, thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.minorTickSections), thisSlider.yCenterLoc + 2, thisSlider.scaleColor);      // minor tick lines
         }

         // draw the slider major tick lines
         for (unsigned int i = 1; i < thisSlider.majorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.majorTickSections), thisSlider.yCenterLoc - 4, thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.majorTickSections), thisSlider.yCenterLoc + 4, thisSlider.scaleColor);      // major tick lines
         }
      } else {
         // clear the entire slider
         tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, thisSlider.xSize + 15, thisSlider.ySize + 6, thisSlider.backgroundColorDisabled);

         // draw the slider outline
         tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, thisSlider.xSize + 15, thisSlider.ySize + 6, thisSlider.borderColorDisabled);

         // draw the slider handle
         tft.fillRect((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)) - 6, thisSlider.yCenterLoc - (2 + thisSlider.ySize * 4 / 10), 13, (thisSlider.ySize * 8 / 10) + 4, RA8875_BLACK);
         tft.fillRect((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)) - 4, thisSlider.yCenterLoc - thisSlider.ySize * 4 / 10, 9, thisSlider.ySize * 8 / 10, thisSlider.handleColorDisabled);

         // draw the slider guide line
         tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.scaleColorDisabled);          // guide line

         tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc - 7, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc + 7, thisSlider.scaleColorDisabled);  // left end
         tft.drawLine(thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc - 7, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc + 7, thisSlider.scaleColorDisabled);  // right end

         // draw the slider minor tick lines
         for (unsigned int i = 1; i < thisSlider.minorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.minorTickSections), thisSlider.yCenterLoc - 2, thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.minorTickSections), thisSlider.yCenterLoc + 2, thisSlider.scaleColorDisabled);      // minor tick lines
         }

         // draw the slider major tick lines
         for (unsigned int i = 1; i < thisSlider.majorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.majorTickSections), thisSlider.yCenterLoc - 4, thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.majorTickSections), thisSlider.yCenterLoc + 4, thisSlider.scaleColorDisabled);      // major tick lines
         }
      }
   } else {
      if (thisSlider.activated)
      {
         // clear the entire slider
         tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.backgroundColor);

         // draw the slider outline
         tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.borderColor);

         // draw the slider handle
         tft.fillRect(thisSlider.xCenterLoc - (2 + thisSlider.xSize * 4 / 10), (int)map(thisSlider.value, thisSlider.maxValue, thisSlider.minValue, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.yCenterLoc + (thisSlider.ySize / 2)) - 6, (thisSlider.xSize * 8 / 10) + 4, 13, RA8875_BLACK);
         tft.fillRect(thisSlider.xCenterLoc - thisSlider.xSize * 4 / 10, (int)map(thisSlider.value, thisSlider.maxValue, thisSlider.minValue, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.yCenterLoc + (thisSlider.ySize / 2)) - 4, thisSlider.xSize * 8 / 10, 9, thisSlider.handleColor);

         // draw the slider guide line
         tft.drawLine(thisSlider.xCenterLoc, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColor);          // guide line

         tft.drawLine(thisSlider.xCenterLoc - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc + 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.scaleColor);  // top end
         tft.drawLine(thisSlider.xCenterLoc - 7, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.xCenterLoc + 7, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColor);  // bottom end

         // draw the slider minor tick lines
         for (unsigned int i = 1; i < thisSlider.minorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - 2, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.minorTickSections), thisSlider.xCenterLoc + 2, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.minorTickSections), thisSlider.scaleColor);      // minor tick lines
         }

         // draw the slider major tick lines
         for (unsigned int i = 1; i < thisSlider.majorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - 4, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.majorTickSections), thisSlider.xCenterLoc + 4, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.majorTickSections), thisSlider.scaleColor);      // major tick lines
         }
      } else {
         // clear the entire slider
         tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.backgroundColorDisabled);

         // draw the slider outline
         tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.borderColorDisabled);

         // draw the slider handle
         tft.drawRect(thisSlider.xCenterLoc - (2 + thisSlider.xSize * 4 / 10), (int)map(thisSlider.value, thisSlider.maxValue, thisSlider.minValue, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.yCenterLoc + (thisSlider.ySize / 2)) - 4, (thisSlider.xSize * 8 / 10) + 4, 9, thisSlider.borderColorDisabled);

         // draw the slider guide line
         tft.drawLine(thisSlider.xCenterLoc, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColorDisabled);          // guide line

         tft.drawLine(thisSlider.xCenterLoc - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc + 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.scaleColorDisabled);  // top end
         tft.drawLine(thisSlider.xCenterLoc - 7, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.xCenterLoc + 7, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColorDisabled);  // bottom end

         // draw the slider minor tick lines
         for (unsigned int i = 1; i < thisSlider.minorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - 2, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.minorTickSections), thisSlider.xCenterLoc + 2, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.minorTickSections), thisSlider.scaleColorDisabled);      // minor tick lines
         }

         // draw the slider major tick lines
         for (unsigned int i = 1; i < thisSlider.majorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - 4, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.majorTickSections), thisSlider.xCenterLoc + 4, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.majorTickSections), thisSlider.scaleColorDisabled);      // major tick lines
         }
      }
   }

   characterCount = thisSlider.placesBeforeTheDecimal + thisSlider.placesAfterTheDecimal;
   if (thisSlider.placesAfterTheDecimal != 0)
   {
      // add one character for the decimal point
      characterCount++;
   }
   if (thisSlider.showPlusMinusSign)
   {
      // add one for the +/- sign
      characterCount++;

      if (thisSlider.value >= 0.0)
      {
         outString = outString + "+";
      } else {
         outString = outString + "-";
      }
   }

   switch (thisSlider.placesBeforeTheDecimal)
   {
      case 5:
      {
         if (abs(thisSlider.value) >= 10000.0)
         {
            outString = outString + (char)(((int)(abs(thisSlider.value)) / 10000) + 0x30);
         }
      }
      // no break, so fall-thru

      case 4:
      {
         if (abs(thisSlider.value) >= 1000)
         {
            outString = outString + (char)((((int)(abs(thisSlider.value)) % 10000) / 1000) + 0x30);
         }
      }
      // no break, so fall-thru

      case 3:
      {
         if (abs(thisSlider.value) >= 100)
         {
            outString = outString + (char)((((int)(abs(thisSlider.value)) % 1000) / 100) + 0x30);
         }
      }
      // no break, so fall-thru

      case 2:
      {
         if (abs(thisSlider.value) >= 10)
         {
            outString = outString + (char)((((int)(abs(thisSlider.value)) % 100) / 10) + 0x30);
         }
      }
         // no break, so fall-thru
   }

   outString = outString + (char)(((int)(abs(thisSlider.value)) % 10) + 0x30);

   if (thisSlider.placesAfterTheDecimal != 0)
   {
      outString = outString + ".";
   }

   switch (thisSlider.placesAfterTheDecimal)
   {
      case 1:
      {
         outString = outString + (char)(((int)((abs(thisSlider.value) * 10.0f)) % 10) + 0x30);
      }
      break;

      case 2:
      {
         outString = outString + (char)(((int)((abs(thisSlider.value) * 10.0f)) % 10) + 0x30);
         outString = outString + (char)(((int)((abs(thisSlider.value) * 100.0f)) % 10) + 0x30);
      }
      break;
   }

   tft.fillRect(thisSlider.xValueCenterLoc - ((thisSlider.placesBeforeTheDecimal + thisSlider.placesAfterTheDecimal + 2) * 4), thisSlider.yValueCenterLoc - 4, (thisSlider.placesBeforeTheDecimal + thisSlider.placesAfterTheDecimal + 2) * 8, 10, RA8875_BLACK);

   centerDrawText(outString, thisSlider.xValueCenterLoc + 1, thisSlider.yValueCenterLoc, thisSlider.valueColor, RA8875_BLACK);
}  // drawSlider()

Here's the code that draws text centered around a given point, which is somewhat important to drawing these virtual objects on the screen:

Code:
// draw text, centered around xLoc & yLoc
void centerDrawText(const String text, unsigned int xCenterLoc, unsigned int yCenterLoc, uint16_t textColor, uint16_t textBackground)
{
   unsigned int xOffset = (text.length() * 8) / 2;
   unsigned int yOffset = 8;

   tft.setTextColor(textColor, textBackground);
   tft.setTextSize(1);

   tft.setCursor(xCenterLoc - xOffset, yCenterLoc - yOffset);
   tft.print(text);
}  // centerDrawText

And here's the code that decides whether or not a button has been pressed, & when a slider has been moved (BtnX & BtnY are globals that keep track of where the screen was last touched when the loss of touch is detected):

Code:
// check if a button was pressed
bool checkButton(BUTTON_TYPE thisButton)
{
   bool retVal = false;

   // if touched most recently in thisButton
   if ((BtnX >= (uint16_t)(thisButton.xCenterLoc - (thisButton.xSize / 2))) &&
         (BtnX <= (uint16_t)(thisButton.xCenterLoc + (thisButton.xSize / 2))) &&
         (BtnY >= (uint16_t)(thisButton.yCenterLoc - (thisButton.ySize / 2))) &&
         (BtnY <= (uint16_t)(thisButton.yCenterLoc + (thisButton.ySize / 2))))
   {
      retVal = true;
   }

   return (retVal);
}  // checkButton()


// check if a slider has changed
bool checkSlider(SLIDER_TYPE* thisSlider)
{
   bool retVal = false;
   float newValue = 0.0;

   // if thisSlider is active & touched most recently in thisSlider
   if ((thisSlider->activated) &&
         (BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2) + 15))) &&
         (BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2) + 15))) &&
         (BtnY >= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2) + 15))) &&
         (BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2) + 15))))
   {
      if (BtnX < (uint16_t)(thisSlider->xCenterLoc - (thisSlider->xSize / 2)))
      {
         BtnX = (uint16_t)(thisSlider->xCenterLoc - (thisSlider->xSize / 2));
      }

      if (BtnX > (uint16_t)(thisSlider->xCenterLoc + (thisSlider->xSize / 2)))
      {
         BtnX = (uint16_t)(thisSlider->xCenterLoc + (thisSlider->xSize / 2));
      }

      if (BtnY < (uint16_t)(thisSlider->yCenterLoc - (thisSlider->ySize / 2)))
      {
         BtnY = (uint16_t)(thisSlider->yCenterLoc - (thisSlider->ySize / 2));
      }

      if (BtnY > (uint16_t)(thisSlider->yCenterLoc + (thisSlider->ySize / 2)))
      {
         BtnY = (uint16_t)(thisSlider->yCenterLoc + (thisSlider->ySize / 2));
      }

      if (thisSlider->orientation == SLIDER_MODE_HORIZONTAL)
      {
         newValue = (float)map((float)BtnX, (float)(thisSlider->xCenterLoc - (thisSlider->xSize / 2)), (float)(thisSlider->xCenterLoc + (thisSlider->xSize / 2)), thisSlider->minValue, thisSlider->maxValue);
      } else {
         newValue = (float)map((float)BtnY, (float)(thisSlider->yCenterLoc - (thisSlider->ySize / 2)), (float)(thisSlider->yCenterLoc + (thisSlider->ySize / 2)), thisSlider->maxValue, thisSlider->minValue);
      }

      if (newValue != thisSlider->value)
      {
         thisSlider->value = newValue;

         drawSlider(*thisSlider);

         retVal = true;
      }
   }

   return (retVal);
}  // checkSlider()

And finally, here's the processing that manages touch & loss of touch detection:

Code:
// process any touchscreen activity
bool processTouchscreen(void)
{
   uint16_t coordinates[RA8875_MAX_TOUCH_LIMIT][2];   // array to hold the touch coordinates

   bool currently_touched = tft.touched();

   if (!currently_touched && previously_touched)
   {
      touch_triggered = true;

      tft.writeTo(L2);   // temporarily write on layer 2
      tft.clearScreen();
      tft.writeTo(L1);   // write on layer 1
   }

   if (currently_touched)
   {
#ifdef USE_RA8875_TOUCH
      tft.touchReadAdc(&coordinates[0][0], &coordinates[0][1]);   // using 10bit adc data here
      BtnX = map(coordinates[0][0], TOUCSRCAL_XHIGH, TOUCSRCAL_XLOW, 0, tft.width());
      BtnY = map(coordinates[0][1], TOUCSRCAL_YHIGH, TOUCSRCAL_YLOW, 0, tft.height());
#else
      // fill the FT5206 registers to get access to the data inside the library...
      tft.updateTS();

      tft.getTScoordinates(coordinates);

      // range-check the values before using them (NOTE: 0,0 is treated as invalid)
      if ((coordinates[0][0] > 0) && (coordinates[0][0] <= tft.width()) && (coordinates[0][1] > 0) && (coordinates[0][1] <= tft.height()))
      {
         BtnX = coordinates[0][0];
         BtnY = coordinates[0][1];
      }
#endif

      previously_touched = true;

#ifndef USE_RA8875_TOUCH
      tft.enableCapISR();   // rearm ISR if needed (touched(true))
#endif

      tft.writeTo(L2);   // temporarily write on layer 2
      tft.clearScreen();
      tft.fillCircle(BtnX, BtnY, 10, RA8875_BLUE);
      tft.drawCircle(BtnX, BtnY, 7, RA8875_BLACK);
      tft.drawCircle(BtnX, BtnY, 3, RA8875_BLACK);
      tft.drawLine(BtnX, BtnY - 10, BtnX, BtnY + 10, RA8875_BLACK);
      tft.drawLine(BtnX - 10, BtnY, BtnX + 10, BtnY, RA8875_BLACK);
      tft.writeTo(L1);   // write on layer 1

#ifdef DEBUG_TOUCHSCREEN
      Serial.print("X : ");
      Serial.print(BtnX);
      Serial.print("     Y : ");
      Serial.println(BtnY);
#endif
   } else {
      previously_touched = false;
   }

   return (currently_touched);  // whether the touchscreen is being touched or not
}  // processTouchscreen()

To answer your (paraphrasing) "do the buttons trigger the message forwarding ??" question, the short answer is no. The booleans that correspond to the button's state are alternately toggled on/off with each press of the button. These button state booleans are then used to decide whether forwarding is on or off. If a particular boolean is set to indicate that forwarding is enabled, then the actual forwarding of the MIDI messages is done whenever a MIDI message is received (as part of the callback handler).

I hope I haven't just muddied the waters further !! Please feel free to ask any further questions that you may have.

Mark J Culross
KD5RXT
 
Back
Top