[SOLVED] Arduino sysex problem

You can try to use a delay using a timer with the millis() function instead of using the delay. The delay just holds the entire program for the entered time.
I tried using the Timer library to defer the sysex call, but it had the same results. I might try again.
 
Perhaps one of the most recent adjustments to the midi in the Axe III created an issue?? Sounds like you’ve covered the bases.

Oh, what if you have multiple requests that are all the same, but not asking for the preset name? Could it be that is the only value it will presently allow more than one at a time?? (Sorry if I missed that you already did this)

Lee
 
So I got my cheapy Teensy++ 2.0 from China today.

Having a separate serial port makes debugging MUCH easier... what a luxury!

Here is what is happening:

Code:
PROGRAM CHANGE: 24
OUTPUT QUEUE: 2
-- SEND SYSEX: 0x66 0x01 0x74 0x10 0x0D 0x7F 0x7F 0x18 
OUTPUT QUEUE: 1
-- SEND SYSEX: 0x00 0x01 0x74 0x10 0x0C 0x7F 0x66 
-- RECV SYSEX: 0x00 0x01 0x74 0x10 0x0C 0x00 0x19 
AXE FX III 2.04 (USB 1.06)
PRESET [0]: 
SCENE [0]: 
------------------------------

So that answers it... the MIDI.read() call is not blocking while waiting for the response to the first sysex call. Somehow I need to get it to block, or roll my own blocking serial read (yuk)
 
At least for debugging, I would consider building this sort of thing using an async state machine pattern. You know at certain times you are expecting to query for multiple things. So you issue each request one at a time and wait for a response and then reenter the state machine and resume where you left off. The good thing about this is you can change it to do as many concurrent commands as you want later on by simply looping over the state machine up to your pending request limit (of course, no limit is maxint).

With MIDI, you’re usually better off not being super aggressive about doing too much at once. That’s been true since the dawn of MIDI.
 
SOLVED!!!!!!!!!!!

Love heart and joy emojis!!!

The key was to do this:

Code:
void loop() {

  <SNIP>

  if (checkSysexOutQueue()) {
    //a sysex was just sent, so block for reply
    while (!MIDI.read());
  } else {
    //just do a normal non-blocking read
    MIDI.read();
  }

  <SNIP>

}

boolean checkSysexOutQueue() {
 
  if (!sysexOut.isEmpty()) {
 
    SysexCommand command = sysexOut.pop();
    if (command.length > 0) {
      MIDI.sendSysEx(command.length, command.data);
      Serial1.flush();
    }
 
  }
  return sysexOut.isEmpty();
 
}

the sysex out-queue looks like this:

Code:
typedef struct SysexCommand {
  byte length;
  byte *data;
} SysexCommand;

QueueList<SysexCommand> sysexOut;

Instead of directly sending sysex byte packets, I add them to the queue (eg when program change is detected). If there's stuff in the queue, it pops ONE command off and sends it and then blocks for a reply. (That means that when the very last command is popped, the queue will be empty and it will do a normal non-blocking MIDI.read() call, but that's ok, that seems to work anyway.)

Oh my. That is VERY satisfying.
 
Well done tysonlt!
Is the snipped code identical to the earlier post? I ask as I’d love to play with it...after all...can,t just have all this Arduino crap lying around doing nothing eh?
Thanks
Pauly

In fact, you don't even need to queue. It helped me for debugging, but the only thing that is required is to wait for the MIDI.read() method to return true in the main loop:

Code:
while (!MIDI.read());

I am now back to just sending sysex messages directly.
 
Well done tysonlt!
Is the snipped code identical to the earlier post? I ask as I’d love to play with it...after all...can,t just have all this Arduino crap lying around doing nothing eh?
Thanks
Pauly
Hi pauly, it's essentially the same, except I moved to using MIDI callbacks:

Code:
void setup() {
  pinMode(TAP_TEMPO_LED_PIN, OUTPUT);
 
  Serial.begin(9600); 
  Serial.println("------------------------------------");
  Serial.println("AXE FX III MIDI TEST - Teensy ++ 2.0");
  Serial.println("------------------------------------");
  Serial.println();
  screen.init();
 
  MIDI.begin();
  MIDI.turnThruOff();
  MIDI.setHandleProgramChange(onProgramChange);
  MIDI.setHandleSystemExclusive(onSystemExclusive);
  state.channel = 1; //TODO: read from Axe?
  timer.every(DEFAULT_REFRESH_INTERVAL, refresh);
}

and the loop looks like this:

Code:
void loop() {
  //update the timer
  timer.update();
   
  //make sure we have the firmware version and current patch after power-on
  if (!state.firmwareRequested) {
    requestFirmwareVersion();
    refresh();
    state.firmwareRequested = true;
  }
  //block for MIDI read
  while (!MIDI.read()) {
    //update the timer again or it gets stuck
    timer.update();
  }
  //debugs
  #ifdef DEBUG
  printAll();
  #endif
  //update screen
  screen.update();
 
}
[/code/
 
Wow that display looks exceptional! Well done :)
Where are you going to put the code?
Thanks
Pauly
 
Last edited:
tysonlt: what kind of enclosure do you plan to use?



I have made a wooden one, but I might end up with something like this:

1pcs-110x230x200mm-steel-metal-enclosure-for-electronics-control-box-electronics-project-box-electronical-junction-box.jpg_640x640.jpg
 
Cool! I have put it on github like a proper person. The bitbucket version was just a prototype, this version is more like how I want the actual code to look:

https://github.com/tysonlt/AxeFx3Control/

Hopefully it can be a generic template for anyone who wants a MIDI firmware. I'm a Java programmer so I hope none of the C++ is too obnoxious! :)
 
Back
Top Bottom