• 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

Another question, is there provision in this library to read MIDI PC/CC from the FM3?

For example, have the control library be able to respond to MIDI messages from the MIDI block in a scene/preset.
Hi snoozy,

Try this:

https://github.com/tysonlt/AxeFxControl/tree/control-change

  • added registerControlChangeCallback(byte control, byte value)
  • added registerMidiByteCallback(byte data)

WARNING: coded in github, haven't even compiled it :) I don't have my rig available atm so let me know if it's completely busted!
 
Hey, I just had a look at the code. AxeSystem_Callbacks.cpp:15 - signature has void void so it doesn't compile.
I removed the extra void, updated my code to call the new callback and it works perfectly. Thanks for getting this included!
 
Hey, I just had a look at the code. AxeSystem_Callbacks.cpp:15 - signature has void void so it doesn't compile.
I removed the extra void, updated my code to call the new callback and it works perfectly. Thanks for getting this included!
Ripper, not bad for blind coding 😂 glad it works, I’ll get it fixed
 
Ripper, not bad for blind coding 😂 glad it works, I’ll get it fixed
Hey there,

I can confirm that the code also compiled on the Teensy 4.1 without errors (I manually deleted the extra void as mentioned)

Request:
Could you find a solution to update src\interface\AxeSystem.h
Now the MAX_PRESETS = 512 because of 128 presets * 4 banks
MK2 has MAX_PRESETS = 1023 because of 128 presets * 8 banks

I manually edited the file by changing:
const static byte MAX_BANKS = 4;
to
const static byte MAX_BANKS = 8;

It would be awesome if the libriary would have this option default.

This will effect the following functions:
Axe.sendPresetDecrement();
Axe.sendPresetIncrement();
constexpr static PresetNumber MAX_PRESETS = (MAX_BANKS * BANK_SIZE) - 1;

!! The MK1 user will go from 0 to 1023 on Decrement or beyond the 512 on Increment because of this. This would need a solution?


If it is not an option a.t.m. than its no big problem.


Thank you in advance, Cheers
 
Hey there,

I implemented the callback and use it from a pushbutton to print ALL presetNames to a file on my SD. That way I can update the file manually.
It works, but with my code it kinda doesn't work.

When requesting all presetNames, the code stops at the activePreset say preset 50
The program will update all presetNames until 49, then it loads preset 50 again.
When activePreset is 1023 the program will update all presetNames until 1022 and loads 1023
Have made long hours on this one, but havnt found a solution.

Any help is appreciated ;)

Here is my code. I call printAllPresets(); from a pushbutton.

C++:
int presetNumberNames;

void PresetNameCallback(const PresetNumber presetNumber, const char *presetName, const byte length)
{
  //To keep the standard of the Fractal export file "preset names.txt" output, I need to edit the presetnumber and add 3 spaces
  //The equalisation of presetNumber == presetNumberNames  is because this is the only way the program prints all 1023 presetnames
  //All other solutions skipped the first 45 to 150 presets, but did print the rest of the 1023 presetNames
  if (presetNumber == presetNumberNames)
  {
    char formattedNumber[5];
    snprintf(formattedNumber, sizeof(formattedNumber), "%04d", presetNumber);

    debug("\n");
    debug(formattedNumber);
    debug("   ");
    debug(presetName);

    presetNumberNames++;
      
    if (presetNumberNames <= 1023) {
      Axe.requestPresetName(presetNumberNames);
    }
  }
}

void printAllPresets()
{
  Axe.registerStalePresetNameCallback(PresetNameCallback);
  //start at zero
  PresetNumber presetNumberNames = 0;
  Axe.requestPresetName(presetNumberNames);
}

Cheers
 
Hey there,

I implemented the callback and use it from a pushbutton to print ALL presetNames to a file on my SD. That way I can update the file manually.
It works, but with my code it kinda doesn't work.

When requesting all presetNames, the code stops at the activePreset say preset 50
The program will update all presetNames until 49, then it loads preset 50 again.
When activePreset is 1023 the program will update all presetNames until 1022 and loads 1023
Have made long hours on this one, but havnt found a solution.

Any help is appreciated ;)

Here is my code. I call printAllPresets(); from a pushbutton.

C++:
int presetNumberNames;

void PresetNameCallback(const PresetNumber presetNumber, const char *presetName, const byte length)
{
  //To keep the standard of the Fractal export file "preset names.txt" output, I need to edit the presetnumber and add 3 spaces
  //The equalisation of presetNumber == presetNumberNames  is because this is the only way the program prints all 1023 presetnames
  //All other solutions skipped the first 45 to 150 presets, but did print the rest of the 1023 presetNames
  if (presetNumber == presetNumberNames)
  {
    char formattedNumber[5];
    snprintf(formattedNumber, sizeof(formattedNumber), "%04d", presetNumber);

    debug("\n");
    debug(formattedNumber);
    debug("   ");
    debug(presetName);

    presetNumberNames++;
     
    if (presetNumberNames <= 1023) {
      Axe.requestPresetName(presetNumberNames);
    }
  }
}

void printAllPresets()
{
  Axe.registerStalePresetNameCallback(PresetNameCallback);
  //start at zero
  PresetNumber presetNumberNames = 0;
  Axe.requestPresetName(presetNumberNames);
}

Cheers
I would try just fetching all presets in a loop. The callbacks are asynchronous so you will start receiving while you are still requesting them.

Then in your callback, you might not need that number check.
 
Hey there,

I can confirm that the code also compiled on the Teensy 4.1 without errors (I manually deleted the extra void as mentioned)

Request:
Could you find a solution to update src\interface\AxeSystem.h
Now the MAX_PRESETS = 512 because of 128 presets * 4 banks
MK2 has MAX_PRESETS = 1023 because of 128 presets * 8 banks

I manually edited the file by changing:
const static byte MAX_BANKS = 4;
to
const static byte MAX_BANKS = 8;

It would be awesome if the libriary would have this option default.

This will effect the following functions:
Axe.sendPresetDecrement();
Axe.sendPresetIncrement();
constexpr static PresetNumber MAX_PRESETS = (MAX_BANKS * BANK_SIZE) - 1;

!! The MK1 user will go from 0 to 1023 on Decrement or beyond the 512 on Increment because of this. This would need a solution?


If it is not an option a.t.m. than its no big problem.


Thank you in advance, Cheers
Hi Axelman!

Try this: https://github.com/tysonlt/AxeFxControl/tree/max-banks

Same caveat. I must get another teensy so that I can test this stuff....

There is a new function, Axe.setMaxBanks(4 or 8), and Axe.maxPresets(). You can still use the old constants, defaulted to MkI values for backwards compatibility.
 
I would try just fetching all presets in a loop. The callbacks are asynchronous so you will start receiving while you are still requesting them.

Then in your callback, you might not need that number check.
That is my next goal: The issue is solved by selecting preset 1023 first and then start the printAllPresets(); function.
It works great, It writes to the SD card with the same convention as the export file from Axe-edit.
Its nice that the code updates on screen 8 about the update on de SD-card.

20230920_133610.gif


C++:
void PresetNameCallback(const PresetNumber presetNumber, const char *presetName, const byte length)
{
  //To keep the standard of the Fractal export file "preset names.txt" output, I need to edit the presetnumber and add 3 spaces
  //The equalisation of presetNumber == presetNumberNames  is because this is the only way the program prints all 1023 presetnames
  //All other solutions skipped the first 45 to 150 presets, but did print the rest of the 1023 presetNames
  if (presetNumber == presetNumberNames)
  {
    presetNameFile = sd.open("preset names.txt", O_WRITE | O_APPEND);
    char formattedNumber[5];
    snprintf(formattedNumber, sizeof(formattedNumber), "%04d", presetNumber);

    debug("\n"); debug(formattedNumber); debug("   "); debug(presetName);

    digitalWriteFast(CS8, LOW);
    presetNumberStyle();
    tft.println(presetNumber);
    digitalWriteFast(CS8, HIGH);

    presetNumberNames++;
       
    if (presetNumberNames <= 1023)
    {
      Axe.requestPresetName(presetNumberNames);
      if (presetNameFile)
      {
       
        String formattedNumber = String(presetNumber);
        while (formattedNumber.length() < 4) {
          formattedNumber = "0" + formattedNumber;
        }
       
        String outputLine = formattedNumber + "   " + presetName + "\n";
        presetNameFile.print(outputLine);  //
        delay(10);
      }
    }
    presetNameFile.close();
  }
}


void printAllPresets()
{
  PresetNumber presetNumberNames = 0;
    if (presetNameFile.open("preset names.txt", O_WRITE))
    {
    presetNameFile.truncate(0);
    presetNameFile.close();
    delay(10);
    Serial.println(" SD card file -> Preset Names.txt is now empty.");
    }
    clearSceneScreens();
    digitalWriteFast (CS8, LOW);
    tft.setTextColor(screen13Style_txt3_color,screen13Style_fillscreen);
    tft.setTextSize(3); tft.setCursor(12, 5);
    tft.println("Updating");
    tft.setTextSize(2); tft.setCursor(40, 35);
    tft.println("SD-CARD");
    digitalWriteFast (CS8, HIGH);
  Axe.requestPresetName(presetNumberNames);
}
 
Hey there,

I implemented the callback and use it from a pushbutton to print ALL presetNames to a file on my SD. That way I can update the file manually.
It works, but with my code it kinda doesn't work.

When requesting all presetNames, the code stops at the activePreset say preset 50
The program will update all presetNames until 49, then it loads preset 50 again.
When activePreset is 1023 the program will update all presetNames until 1022 and loads 1023
Have made long hours on this one, but havnt found a solution.

Any help is appreciated ;)

Here is my code. I call printAllPresets(); from a pushbutton.

C++:
int presetNumberNames;

void PresetNameCallback(const PresetNumber presetNumber, const char *presetName, const byte length)
{
  //To keep the standard of the Fractal export file "preset names.txt" output, I need to edit the presetnumber and add 3 spaces
  //The equalisation of presetNumber == presetNumberNames  is because this is the only way the program prints all 1023 presetnames
  //All other solutions skipped the first 45 to 150 presets, but did print the rest of the 1023 presetNames
  if (presetNumber == presetNumberNames)
  {
    char formattedNumber[5];
    snprintf(formattedNumber, sizeof(formattedNumber), "%04d", presetNumber);

    debug("\n");
    debug(formattedNumber);
    debug("   ");
    debug(presetName);

    presetNumberNames++;
     
    if (presetNumberNames <= 1023) {
      Axe.requestPresetName(presetNumberNames);
    }
  }
}

void printAllPresets()
{
  Axe.registerStalePresetNameCallback(PresetNameCallback);
  //start at zero
  PresetNumber presetNumberNames = 0;
  Axe.requestPresetName(presetNumberNames);
}

Cheers
Thinking about it more, that makes sense. It will not call the stale preset callback because the incoming preset matches the current preset number. The stale callback will only fire if a preset name comes in that is NOT the current preset.

So in your code, since you are fetching them sequentially, as soon as you fetch whatever the current preset is, it will not call the stale callback, and your callback will not increment the number to fetch again.

If you call the fetch outside of your callback it should fetch them all:

Code:
void printAllPresets()
{

  Axe.registerStalePresetNameCallback(PresetNameCallback);
  //^^^^^^ THIS should go in setup() - no need to call it multiple times (although it won't hurt)

  int maxPresets = 1024; //or Axe.maxPresets() if you use the branch above

  for (int i = 0; i < Axe.maxPresets(); i++) {
    Axe.requestPresetName(i);
  }
}

But you will still have the problem of it not calling your stale callback for the current preset. I'll have to think about that!
 
That is my next goal: The issue is solved by selecting preset 1023 first and then start the printAllPresets(); function.
It works great, It writes to the SD card with the same convention as the export file from Axe-edit.
Its nice that the code updates on screen 8 about the update on de SD-card.

View attachment 126948


C++:
void PresetNameCallback(const PresetNumber presetNumber, const char *presetName, const byte length)
{
  //To keep the standard of the Fractal export file "preset names.txt" output, I need to edit the presetnumber and add 3 spaces
  //The equalisation of presetNumber == presetNumberNames  is because this is the only way the program prints all 1023 presetnames
  //All other solutions skipped the first 45 to 150 presets, but did print the rest of the 1023 presetNames
  if (presetNumber == presetNumberNames)
  {
    presetNameFile = sd.open("preset names.txt", O_WRITE | O_APPEND);
    char formattedNumber[5];
    snprintf(formattedNumber, sizeof(formattedNumber), "%04d", presetNumber);

    debug("\n"); debug(formattedNumber); debug("   "); debug(presetName);

    digitalWriteFast(CS8, LOW);
    presetNumberStyle();
    tft.println(presetNumber);
    digitalWriteFast(CS8, HIGH);

    presetNumberNames++;
     
    if (presetNumberNames <= 1023)
    {
      Axe.requestPresetName(presetNumberNames);
      if (presetNameFile)
      {
     
        String formattedNumber = String(presetNumber);
        while (formattedNumber.length() < 4) {
          formattedNumber = "0" + formattedNumber;
        }
     
        String outputLine = formattedNumber + "   " + presetName + "\n";
        presetNameFile.print(outputLine);  //
        delay(10);
      }
    }
    presetNameFile.close();
  }
}


void printAllPresets()
{
  PresetNumber presetNumberNames = 0;
    if (presetNameFile.open("preset names.txt", O_WRITE))
    {
    presetNameFile.truncate(0);
    presetNameFile.close();
    delay(10);
    Serial.println(" SD card file -> Preset Names.txt is now empty.");
    }
    clearSceneScreens();
    digitalWriteFast (CS8, LOW);
    tft.setTextColor(screen13Style_txt3_color,screen13Style_fillscreen);
    tft.setTextSize(3); tft.setCursor(12, 5);
    tft.println("Updating");
    tft.setTextSize(2); tft.setCursor(40, 35);
    tft.println("SD-CARD");
    digitalWriteFast (CS8, HIGH);
  Axe.requestPresetName(presetNumberNames);
}
That looks super cool. Perhaps there needs to be a more explicit design for this case.

I'm thinking that perhaps it should pass a flag to the callback indicating whether or not this is the current preset. That way you can ignore it if you like.

Another option that will definitely work is to simply deregister your normal preset name callback while you are fetching all presets, and set it to your stale callback. Something like:


Code:
int dumpingPresetNumber = 0;

void printAllPresets() {

  //use the same callback whether it is the current preset or not
  Axe.registerStalePresetNameCallback(presetDumpCallback);
  Axe.registerPresetNameCallback(presetDumpCallback);

  //fetch the first preset
  dumpingPresetNumber = 0;
  Axe.requestPresetName(dumpingPresetNumber);

}

//once the button is pressed this will be called instead of your normal callback
void presetDumpCallback(const PresetNumber presetNumber, const char *presetName, const byte length) {

  //...do your thing

 dumpingPresetNumber++;
     
 if (dumpingPresetNumber <= 1023) {
      Axe.requestPresetName(dumpingPresetNumber);
  } else {
      //we are finished the dump, so set the callback to the one for normal operation
      stopPresetDump();
  }
 
}

void myNormalPresetNameCallback(const PresetNumber presetNumber, const char *presetName, const byte length) {
  //for normal operation, update your screens etc
}

// This is just in case you want to cancel it or something goes wrong and it gets stuck
void stopPresetDump() {
      Axe.registerStalePresetNameCallback(NULL);
      Axe.registerPresetNameCallback(myNormalPresetNameCallback);
      dumpingPresetNumber = 0;
}
 
I am loving the look of that controller so far! I have controller envy!!! I really love the tempo lights, very clever.

Glad to see the library is useful for someone!
 
Somewhere in this thread, is there detailed info on that enclosure, compatible displays, etc, the physical aspect of putting something like that together?

I'm a software guy, not Arduino, yet, but I'm sure I can get my head around that part, but I'd really appreciate info about actually building it into a footboard like that. Better yet maybe, do any of you have those for sale in small quantities, like 1?
 
Somewhere in this thread, is there detailed info on that enclosure, compatible displays, etc, the physical aspect of putting something like that together?

I'm a software guy, not Arduino, yet, but I'm sure I can get my head around that part, but I'd really appreciate info about actually building it into a footboard like that. Better yet maybe, do any of you have those for sale in small quantities, like 1?
Hey there,
Im here to help you out no problem. I dont know deep software coding and still managed to make it work.

The enclosure is easy, putting it together is super fun and making it work is a sleep killer and in the end... its never finished 🤣.

This DIY stuff really gets me going. Ive made a thread about the Teensy build with hardware and how-to's.
Teensy controller info

If you need any help, DM me anytime
The software will be free for anyone who wants to try it.

Cheers 🍻
 
Last edited:
That looks super cool. Perhaps there needs to be a more explicit design for this case.

I'm thinking that perhaps it should pass a flag to the callback indicating whether or not this is the current preset. That way you can ignore it if you like.

Another option that will definitely work is to simply deregister your normal preset name callback while you are fetching all presets, and set it to your stale callback. Something like:


Code:
int dumpingPresetNumber = 0;

void printAllPresets() {

  //use the same callback whether it is the current preset or not
  Axe.registerStalePresetNameCallback(presetDumpCallback);
  Axe.registerPresetNameCallback(presetDumpCallback);

  //fetch the first preset
  dumpingPresetNumber = 0;
  Axe.requestPresetName(dumpingPresetNumber);

}

//once the button is pressed this will be called instead of your normal callback
void presetDumpCallback(const PresetNumber presetNumber, const char *presetName, const byte length) {

  //...do your thing

 dumpingPresetNumber++;
    
 if (dumpingPresetNumber <= 1023) {
      Axe.requestPresetName(dumpingPresetNumber);
  } else {
      //we are finished the dump, so set the callback to the one for normal operation
      stopPresetDump();
  }
 
}

void myNormalPresetNameCallback(const PresetNumber presetNumber, const char *presetName, const byte length) {
  //for normal operation, update your screens etc
}

// This is just in case you want to cancel it or something goes wrong and it gets stuck
void stopPresetDump() {
      Axe.registerStalePresetNameCallback(NULL);
      Axe.registerPresetNameCallback(myNormalPresetNameCallback);
      dumpingPresetNumber = 0;
}
That i got to try for shure. It would make it somuch easier than first selecting preset 1023

Today I have no time, but will do it tomorrow

Thank you for this

Cheers 🍻
 
Hey there,
Im here to help you out no problem. I dont know deep software coding and still managed to make it work.

The enclosure is easy, putting it together is super fun and making it work is a sleep killer and in the end... its never finished 🤣.

This DIY stuff really gets me going. Ive made a thread about the Teensy build with hardware and how-to's.
Teensy controller info

If you need any help, DM me anytime
The software will be free for anyone who wants to try it.

Cheers 🍻
Awesome, thank you.

Cutting the rectangular holes for the displays cleanly looks tough, but it seems there's no magic bullet, you just drilled a starter hole for each one, then jigsawed each of them out.

Right?
 
Back
Top Bottom