So as a part of a project im doing im using the control surface to act as simply a MIDI to usb adapter with a seperate I2C 16x2 LCD screen that im am trying to use to dispaly the note value and velocity of incoming notes from the serial midi on channel 1.
The isssue im having is i dont know what function I could extract those values from so that I can send those to the LCD.
this is roughly what i had tried to do based on a sketch that parts of the code came from but
#include <Arduino.h> // Include standard arduino library
#include <Control_Surface.h> // Include the Control Surface library
#include <MIDIUSB.h> // Include the USB MIDI library
#include <LiquidCrystal_I2C.h> // Include the LCD I2C Library
LiquidCrystal_I2C lcd(0x3F, 16, 2);
USBMIDI_Interface midiusb;
HardwareSerialMIDI_Interface midiser = {Serial1, MIDI_BAUD};
// Create a MIDI pipe factory to connect the MIDI interfaces to eachother and to the Control Surface
MIDI_PipeFactory<5> pipes;
// creates a list of midi notes to be displayd on the lcd
String lcdNotes[12] = {"C","C#/Db","D","D#/Eb","E","F","F#/Gb","G","G#/Ab","A","A#/Bb","B"};
int noteNo;
int velVal;
bool screenUpdate;
// Custom MIDI callback that prints incoming messages.
struct MyMIDI_Callbacks : MIDI_Callbacks {
// Callback for channel messages (notes, control change, pitch bend, etc.).
void onChannelMessage(Parsing_MIDI_Interface &midi) override {
ChannelMessage cm = midi.getChannelMessage();
if (cm.header == 0x90) {
noteNo = cm.data1;
velVal = cm.data2;
screenUpdate = true;
}
else if (cm.header == 0x80) {
noteNo = 0;
velVal = 0;
screenUpdate = false;
}
// forward channel mesages without changes
midiusb.send(cm);
}
// Callback for system exclusive messages
void onSysExMessage(Parsing_MIDI_Interface &midi) override {
SysExMessage se = midi.getSysExMessage();
// forward system exclusive messages without changes
midiusb.send(se);
}
// Callback for real-time messages
void onRealTimeMessage(Parsing_MIDI_Interface &midi) override {
RealTimeMessage rt = midi.getRealTimeMessage();
// forward real-time messages without changes
midiusb.send(rt);
}
} callbacks;
// setup code
void setup() {
Serial.begin(115200);
// forward MIDI USB to MIDI serial
midiusb >> pipes >> midiser;
// forward MIDI serial to MIDI USB
midiser >> pipes >> midiusb;
// send control suface messages only to MIDI USB
Control_Surface >> pipes >> midiusb;
// connect both MIDI USB and serial to control surface
midiser >> pipes >> Control_Surface;
midiusb >> pipes >> Control_Surface;
// initialize Control Surface _after_ connecting the interfaces
Control_Surface.begin();
// set up lcd
lcd.begin();
lcd.backlight();
lcd.setCursor(0,0);
lcd.print("Note: ");
lcd.setCursor(0,1);
lcd.print("velocity: ");
}
void screenClear() {
lcd.setCursor(6,0);
lcd.print(" ");
lcd.setCursor(10,1);
lcd.print(" ");
}
void screenNewVals() {
lcd.setCursor(6,0);
lcd.print(noteNo);
lcd.setCursor(10,1);
lcd.print(velVal);
}
// main processing loop
void loop() {
if (screenUpdate == true) {
screenNewVals();
}
else if (screenUpdate == false) {
screenClear();
}
Control_Surface.loop();
}
however the only time that data gets written to the display is on the startup section and values do update so if anyone has any sugestions on what im doing wrong I would be glad to hear them.
A bool is either true or false so no need for the second if().
The logic seems a bit off. You should only update the screen when a new note arrives, not every time through loop() since you never reset screenUpdate. The decision to print the note value or clear should be based on noteNo == 0 or not. It seems like this might be better
#include <Arduino.h> // Include standard arduino library
#include <Control_Surface.h> // Include the Control Surface library
#include <MIDIUSB.h> // Include the USB MIDI library
#include <LiquidCrystal_I2C.h> // Include the LCD I2C Library
LiquidCrystal_I2C lcd(0x3F, 16, 2);
USBMIDI_Interface midiusb;
HardwareSerialMIDI_Interface midiser = {Serial1, MIDI_BAUD};
// Create a MIDI pipe factory to connect the MIDI interfaces to eachother and to the Control Surface
MIDI_PipeFactory<5> pipes;
// creates a list of midi notes to be displayd on the lcd
String lcdNotes[12] = {"C", "C#/Db", "D", "D#/Eb", "E", "F", "F#/Gb", "G", "G#/Ab", "A", "A#/Bb", "B"};
int noteNo;
int velVal;
bool screenUpdate;
// Custom MIDI callback that prints incoming messages.
struct MyMIDI_Callbacks : MIDI_Callbacks {
// Callback for channel messages (notes, control change, pitch bend, etc.).
void onChannelMessage(Parsing_MIDI_Interface &midi) override {
ChannelMessage cm = midi.getChannelMessage();
if (cm.header == 0x90) {
noteNo = cm.data1;
velVal = cm.data2;
screenUpdate = true;
}
else if (cm.header == 0x80) {
noteNo = 0;
velVal = 0;
screenUpdate = true;
}
// forward channel mesages without changes
midiusb.send(cm);
}
// Callback for system exclusive messages
void onSysExMessage(Parsing_MIDI_Interface &midi) override {
SysExMessage se = midi.getSysExMessage();
// forward system exclusive messages without changes
midiusb.send(se);
}
// Callback for real-time messages
void onRealTimeMessage(Parsing_MIDI_Interface &midi) override {
RealTimeMessage rt = midi.getRealTimeMessage();
// forward real-time messages without changes
midiusb.send(rt);
}
} callbacks;
// setup code
void setup() {
Serial.begin(115200);
// forward MIDI USB to MIDI serial
midiusb >> pipes >> midiser;
// forward MIDI serial to MIDI USB
midiser >> pipes >> midiusb;
// send control suface messages only to MIDI USB
Control_Surface >> pipes >> midiusb;
// connect both MIDI USB and serial to control surface
midiser >> pipes >> Control_Surface;
midiusb >> pipes >> Control_Surface;
// initialize Control Surface _after_ connecting the interfaces
Control_Surface.begin();
// set up lcd
lcd.begin();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Note: ");
lcd.setCursor(0, 1);
lcd.print("velocity: ");
}
void screenNewVals() {
if ( noteNo ) {
lcd.setCursor(6, 0);
lcd.print(noteNo);
lcd.setCursor(10, 1);
lcd.print(velVal);
}
else {
lcd.setCursor(6, 0);
lcd.print(" ");
lcd.setCursor(10, 1);
lcd.print(" ");
}
}
// main processing loop
void loop() {
if (screenUpdate == true) {
screenNewVals();
screenUpdate = false;
}
Control_Surface.loop();
}
the update screen function whilst not writtten well isnt the issue that im having but i apreciate your help there.
the issue is that i cant find what function i need to call to get the data to send to the function
this callback function here that i am trying to use to set global variables based on sections within it doesnt seem to send them to global but to local which i then cant read.
im sure that there is a function within the control surfae library that i can use to give me the values that im looking for in a way that i can read them but i dont know what it is
You create a variable named callbacks, but it is never used, you never set it as the callbacks for any of the MIDI interfaces in your code.
Please see Control Surface: MIDI Tutorial (note that this is the documentation for the master branch, so you might have to upgrade if you have an old version, which appears to be the case given that you're using the old MIDI_Callbacks API).
Either use the MIDI pipes to forward MIDI from one interface to another, or use the callbacks, but not both.
yeah the old callbacks api is from the code that i orignaly coppied and tried to modify which had used the callbacks to stop the all notes off command and i had tried to hyjack that.
I'll look at the new api and see if i can get it working from there.
Like I said, the documentation is for the master branch, not for 1.2.0.
I think you should be able to install it using
pio lib install https://github.com/tttapa/Control-Surface.git#master
If you really want to, you could use the 1.2.0 version, but then you have to consult the correct documentation: Control Surface: MIDI-Input.ino
(There is no "MIDI tutorial" for version 1.2.0.)