tysonlt
Power User
Greetings!
I have been working on a DIY MIDI controller with an Arduino Nano. I have a problem where I can send sysex commands to get preset name, scene name, firmware version... but not sequentially. It seems that whatever sysex I send first is the only one that arrives.
For example, I can request the preset name 3 times, and I will get three responses... but if I request preset name, then scene name (eg responding to program change) then I only get the preset name.
Get ready for some code:
PLEEEASE tell me there's something stupid and obvious that I have missed! Thanks!
I have been working on a DIY MIDI controller with an Arduino Nano. I have a problem where I can send sysex commands to get preset name, scene name, firmware version... but not sequentially. It seems that whatever sysex I send first is the only one that arrives.
For example, I can request the preset name 3 times, and I will get three responses... but if I request preset name, then scene name (eg responding to program change) then I only get the preset name.
Get ready for some code:
Code:
#include <TFT.h>
#include <MIDI.h>
#define XDEBUG
#define CHAR_W 6
#define BANK_CHANGE_CC 0
#define BANK_SIZE 128
#define MAX_PRESET_NAME 32
#define MAX_SCENE_NAME MAX_PRESET_NAME
#define AXE_MANUFACTURER_B1 0x00
#define AXE_MANUFACTURER_B2 0x01
#define AXE_MANUFACTURER_B3 0x74
#define SYSEX_HEADER 0x00, 0x01, 0x74, 0x10
#define SYSEX_REQUEST_FIRMWARE 0x08
#define SYSEX_REQUEST_PRESET_INFO 0x0D
#define SYSEX_PRESET_CHANGED 0x14
#define SYSEX_REQUEST_SCENE_INFO 0x0E
#define SYSEX_REQUEST_SCENE_NUMBER 0x0C
#define SYSEX_SCENE_STATUS 0x29
#define SYSEX_TAP_TEMPO 0x10
#define SYSEX_FRONT_PANEL_CHANGE 0x21
TFT screen = TFT(10, 9, -1);
struct {
byte bank;
byte patch;
byte scene;
int preset;
bool firmwareRequested;
bool dirty;
char sceneName[35], presetName[35];
byte firmwareMajor;
byte firmwareMinor;
byte usbMajor;
byte usbMinor;
} state;
char buf[100];
MIDI_CREATE_DEFAULT_INSTANCE();
/**
*
*/
void setup() {
screen.initR(INITR_BLACKTAB);
screen.setRotation(1);
screen.setTextColor(0xFFE0, 0x0000);
screen.setTextSize(1);
screen.fillScreen(0x0000);
MIDI.begin();
MIDI.turnThruOff();
//requestFirmwareVersion(); <-- enabling 'blocks' further sysex!!!
}
/**
*
*/
void loop() {
if (MIDI.read(MIDI_CHANNEL_OMNI)) {
if (MIDI.getType() == midi::ProgramChange) {
//this works fine...
requestPresetName();
/* this works too...
requestPresetName();
requestPresetName();
requestPresetName();
*/
/* as above, this works on its own...
requestSceneName();
*/
/* but sending different types, I only get the first type back
requestPresetName();
requestSceneName();
*/
} else if (MIDI.getType() == midi::SystemExclusive) {
byte * sysex = (byte *) MIDI.getSysExArray();
int length = MIDI.getData1();
if (isAxeSysEx(sysex, length)) {
switch (sysex[5]) {
case SYSEX_REQUEST_FIRMWARE: {
snprintf(buf, 5, "%d.%02d", sysex[6], sysex[7]);
text(buf, 0, 0);
break;
}
case SYSEX_REQUEST_PRESET_INFO: {
state.preset = (sysex[7] * 128) + sysex[6];
for (byte i=0; i<32; i++) {
state.presetName[i] = sysex[i+8];
}
snprintf(buf, sizeof(buf), "%d: %s", state.preset, state.presetName);
text(buf, 0, 10);
break;
}
case SYSEX_REQUEST_SCENE_INFO: {
state.scene = sysex[6];
for (byte i=0; i<32; i++) {
state.sceneName[i] = sysex[i+7];
}
snprintf(buf, sizeof(buf), "(%d) %s", state.scene, state.sceneName);
text(buf, 0, 20);
break;
}
case SYSEX_REQUEST_SCENE_NUMBER: {
text("SYSEX_REQUEST_SCENE_NUMBER", 0, 30);
break;
}
default: {
toHex(sysex, length, buf);
text(buf, 0, 100);
}
}
}
}
}
}
/**
*
*/
boolean isAxeSysEx(const byte *sysex, const int len) {
return
len > 4 &&
sysex[1] == AXE_MANUFACTURER_B1 &&
sysex[2] == AXE_MANUFACTURER_B2 &&
sysex[3] == AXE_MANUFACTURER_B3;
}
/**
*
*/
void requestFirmwareVersion() {
static const byte msg[] = {
SYSEX_HEADER,
SYSEX_REQUEST_FIRMWARE,
};
sendSysEx(6, (byte*) msg); //<-- 6 bytes = 4 header, 1 command, 1 spare for checksum
}
/**
*
*/
void requestPresetName() {
static const byte msg[] = {
SYSEX_HEADER,
SYSEX_REQUEST_PRESET_INFO,
0x7F, 0x7F,
};
sendSysEx(8, (byte*) msg);
}
/**
*
*/
void requestSceneNumber() {
static const byte msg[] = {
SYSEX_HEADER,
SYSEX_REQUEST_SCENE_NUMBER,
0x7F,
};
sendSysEx(7, (byte*) msg);
}
/**
*
*/
void requestSceneName() {
static const byte msg[] = {
SYSEX_HEADER,
SYSEX_REQUEST_SCENE_INFO,
0x7F,
};
sendSysEx(7, (byte*) msg);
}
/**
*
*/
void sendSysEx(byte length, byte *sysex) {
byte sum = 0xF0;
for (int i=0; i<length-1; ++i) {
sum ^= sysex[i];
}
sysex[length-1] = (sum & 0x7F);
MIDI.sendSysEx(length, sysex);
Serial.flush();
}
/**
*
*/
void text(const char *text, byte x, byte y) {
screen.setCursor(x, y);
screen.print(text);
}
/**
* Turn a byte buffer into a hex string.
*/
void toHex(const byte array[], int len, char buffer[]) {
int c = 0;
for (int i = 0; i < len; i++) {
byte nib1 = (array[i] >> 4) & 0x0F;
byte nib2 = (array[i] >> 0) & 0x0F;
buffer[c*3+0] = nib1 < 0xA ? '0' + nib1 : 'A' + nib1 - 0xA;
buffer[c*3+1] = nib2 < 0xA ? '0' + nib2 : 'A' + nib2 - 0xA;
buffer[c*3+2] = ' ';
c++;
}
buffer[len*3] = '\0';
}
PLEEEASE tell me there's something stupid and obvious that I have missed! Thanks!