• We would like to remind our members that this is a privately owned, run and supported forum. You are here at the invitation and discretion of the owners. As such, rules and standards of conduct will be applied that help keep this forum functioning as the owners desire. These include, but are not limited to, removing content and even access to the forum.

    Please give yourself a refresher on the forum rules you agreed to follow when you signed up.

Arduino Axe-Fx control library

AlbertA

Fractal Fanatic
Solved! After having spent countless hours trying all king of possibilities... The pointer!

This works: lcd.print(*note); no matter how many lines I print to the I2C LCD. Without the asterisk, the data was corrupted randomly when I printed more than two lines.

You are masking the issue :)

*note is of type char, which is just a single character (which works in this particular case) . I suspect the original string is probably not null terminated?

Edit: Umm table of strings looks fine, "note" probably needs validation then:
https://github.com/tysonlt/AxeFxCon...interface/private/AxeSystem_Handlers.cpp#L138

And to resurrect tabs vs spaces... Another point for spaces :)
https://raw.githubusercontent.com/t...e90/src/interface/private/AxeSystem_Private.h
 
Last edited:

tysonlt

Inspired
AlbertA to the rescue again! I did think it was strange that pointing to the char array would work, I wonder if it only works for notes that have a single character. The notes with flats and sharps would probably just appear as single notes in this case, appearing correct when they aren't.
 

AlbertA

Fractal Fanatic
AlbertA to the rescue again! I did think it was strange that pointing to the char array would work, I wonder if it only works for notes that have a single character. The notes with flats and sharps would probably just appear as single notes in this case, appearing correct when they aren't.

Right. note is probably >=12, outside the range of the table (bad sysex data?, a glitch in the matrix?) in which case an invalid const char* is being sent to the callback.
 

Piing

Fractal Fanatic
You are right @AlbertA: that was not right. With the asterisk the LCD was not displaying the flat and sharp symbols, only the first character.

However, the new branch is working! No corrupted data :) Thank you @tysonlt !
Your library is getting bulletproof

I am using the standard circuit with a 4N28 opto
 
Last edited:

tysonlt

Inspired
Good to hear... I’m still wondering why it happened at all, but I guess with validation it won’t be a problem
 

axifist

Experienced
On my project I too had strange artefacts I could solve by validation. E.g. when I pressed the tuner button (Axe not connected) and then changed presets, there appeared an arrow on the screen! That was SO strange! Validating everything concerning the tuner solved it. I still don't know where that arrow came from, but since it's gone now I don't care too much, although it would be nice to know.
 

tysonlt

Inspired
Hmm ok so that was with the MIDI disconnected? Funny characters usually indicate that it is reading beyond the end of a buffer and interpreting other bytes memory as ascii, hence the unusual ascii codes. I do remember seeing that during the early phases of developing the library actually. I'll have to try more debugging with the axe disconnected. I have noticed that the pedal project I was using the library for did not like being connected to the axe when the tuner is already engaged.
 

tysonlt

Inspired
On my project I too had strange artefacts I could solve by validation. E.g. when I pressed the tuner button (Axe not connected) and then changed presets, there appeared an arrow on the screen! That was SO strange! Validating everything concerning the tuner solved it. I still don't know where that arrow came from, but since it's gone now I don't care too much, although it would be nice to know.

Could you please go into more detail about the particular validation you had to use? One thing I know is that the tuner MIDI messages come through thick and fast, so it may just be a case of throttling them a bit, although I would really prefer not to do that. Better to figure out the problem properly.

Are you able to reliably reproduce the arrow thing? A set of steps would help me narrow down the issue. Also if you are willing to share the code you are using, it will help me see how you are calling the library.
 

AlbertA

Fractal Fanatic
@tysonit, I also see there's no checksum validation for received messages - it's a good idea to check it and ignore the message if the computed checksum doesn't match what you received.
 

axifist

Experienced
I've written it for the Ultra, which doesn't have checksums. What I did was to define the length and the first and sixth piece of the tuner data:
Code:
if ((sysExSize == 10) && (array[0] == 0xF0) && (array[5] == 0x0D)) {
  //action
}
The length part solved my bug.

For the II and III I'd definitely use checksums! That's what they are there for!

edit: Sorry, missed that part
Also if you are willing to share the code you are using, it will help me see how you are calling the library.
I'm not using your library, sorry, should have cleared that up, especially since this thread IS for your library! Had to write the thing all by myself. I'm planning on releasing the thing soon, have been waiting too long... @Piing used my tuner code as a starting point, so at least that part is out there ;)
 

Piing

Fractal Fanatic
How do you refresh the display data (preset/scene names and numbers) on the display after disengaging the tuner?

The only way I can do that is to press a scene or a preset inc/dec switch. And sometimes I have to press it 2 times.

I have tried sending a PresetChange (with the latest Preset Number used) after disengaging the tuner, but it doesn't work. The tuning data stays on the screen until I press a switch

Code:
void onTunerStatus(bool engaged) {
  // Send Preset Change on disengaging Tuner to refresh display data ** not working
  if (Axe.isTunerEngaged()==false)
  {
    Axe.sendPresetChange(PresetNumb);
    Axe.update();
    Axe.sendPresetChange(PresetNumb);
    Axe.update();
  }
}
 

axifist

Experienced
What I do:
Code:
void tunerOff() {
  if (millis() - tunerLastTime >= 100 && tunerStatus == true) { //Required so the tuner screen disappears, as soon as no more SysEx tuner data is being received. I chose 100ms, because at 20ms it started to go crazy, because the time between tuner data seems to be around 20ms. 50ms would have been safe, but to be absolutely safe I chose 100ms.
    tunerStatus = false;

    for (currentSwitch = 0; currentSwitch < numberOfSwitches; currentSwitch++) { //I have no static switch layout, so it has to search for the tuner switch.
      if (songSwitches[currentScene][currentSwitch][currentSwitchLayer] == Tune) {
        digitalWrite(leds[currentSwitch], LOW);
        ledState[currentSwitch] = LOW;
      }
    }
    mainScreen(); //So, if the last tuner data was more than 100ms ago, I switch back to the mainScreen(), which is defined in display_functions.h
  }
}
In your case that mainScreen() function should fetch all required data (Or load it from memory? You could store the current states.) and fill the display with it.
The tunerOff() function is called in the loop(), so it's being checked as often as possible.
tunerLastTime is being set to millis() in the callback function, which handles the tuner.

That way the tuner status changes on the controller no matter if it's being changed on the Axe or the controller. Neat! :)
 

Piing

Fractal Fanatic
What I do:
Code:
void tunerOff() {
  if (millis() - tunerLastTime >= 100 && tunerStatus == true) { //Required so the tuner screen disappears, as soon as no more SysEx tuner data is being received. I chose 100ms, because at 20ms it started to go crazy, because the time between tuner data seems to be around 20ms. 50ms would have been safe, but to be absolutely safe I chose 100ms.
    tunerStatus = false;

    for (currentSwitch = 0; currentSwitch < numberOfSwitches; currentSwitch++) { //I have no static switch layout, so it has to search for the tuner switch.
      if (songSwitches[currentScene][currentSwitch][currentSwitchLayer] == Tune) {
        digitalWrite(leds[currentSwitch], LOW);
        ledState[currentSwitch] = LOW;
      }
    }
    mainScreen(); //So, if the last tuner data was more than 100ms ago, I switch back to the mainScreen(), which is defined in display_functions.h
  }
}
In your case that mainScreen() function should fetch all required data (Or load it from memory? You could store the current states.) and fill the display with it.
The tunerOff() function is called in the loop(), so it's being checked as often as possible.
tunerLastTime is being set to millis() in the callback function, which handles the tuner.

That way the tuner status changes on the controller no matter if it's being changed on the Axe or the controller. Neat! :)

Got it! Just stored the names and created a recall screen.
Thank you
 

Piing

Fractal Fanatic
@tysonlt I've built a minimalist setup with one Arduino Mega, a 1.8" ST7735 and a CD74HC4067 for playing and learning with your AxeHandle program :)

I don't even need buttons; I just touch the multiplexer terminals with a bare wire connected to ground, and something is working!

The mess of resistors are voltage dividers to convert the arduino 5V logic signals to 3.3V for my "KMR-1.8" cheap version of the ST7735 display. It took me a couple of days to figure out that requirement. It works fine with the ST7735_t3.h library, though.



I am stuck into the SETUP routine. I can assign functions to the buttons, but I cannot go out of that loop.

"Hold MODE to save" saves the button function and goes back to the buttons setup (I assume that MODE is button 5)
"Hold TAP to cancel" goes back to the buttons setup (I assume that TAP is button 10)

Could you confirm if that is a working release? jut to be sure, before I spend more time reverse-engineering for debugging.
 
Last edited:
Top Bottom