<MIDI.h> in external .hpp/.cpp file and callbacks question

Status
Not open for further replies.

Van

Well-known member
Hi,
I'm trying to include the <MIDI.h> in an external .hpp/.cpp file and setting up the callback how we normally would do in the main.ino file,
but I'm getting this error:

Code:
invalid use of non-static member function

My function can't be static so ist there a way, like in the main.cpp(ino) file, to include the MIDI lib and use the callbacks?

many thanks in advance!
van
 
Most probably, nobody understands why you would do that include in an external file instead of the main sketch .ino file.
 
Most probably, nobody understands why you would do that include in an external file instead of the main sketch .ino file.

thank you for your answer!

well I would like to refactor my code. Don't wanna have 500 lines of code in my main.ino file just for the midi stuff where i have to initialize another classes and do other stuff there.

is this so a bad idea?
 
no one on this?

What do you expect when you don't follow the "Forum Rule", nor even show a complete copy of the error message?

That's not how we work here. You need to post a complete (and hopefully minimum) program that we can copy and paste into Arduino (or copy twice into 2 tabs within Arduino in this case) so we can recreate the compiler error. If you look over the many threads on this forum, we're very good at solving problems when you follow this simple rule, and not so much when you give incomplete info.
 
What do you expect when you don't follow the "Forum Rule", nor even show a complete copy of the error message?

That's not how we work here. You need to post a complete (and hopefully minimum) program that we can copy and paste into Arduino (or copy twice into 2 tabs within Arduino in this case) so we can recreate the compiler error. If you look over the many threads on this forum, we're very good at solving problems when you follow this simple rule, and not so much when you give incomplete info.

ok. got it!
sorry i'm beginner and pretty shure this is basic c++ stuff butt I still need help with that..

so here is the main.ino file:

Code:
#include "MidiController.h"

MidiController midiController;

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}

Here ist the MidiController.h

Code:
#ifndef MidiController_h
#define MidiController_h
#include "Arduino.h"

class MidiController
{
  public:
  MidiController();
  void MidiCallback();
  void next();
};
#endif

and here the cpp:

Code:
#include "MidiController.h"

//include midi here because in .h file it throws the error:
/*
 * 
 * var/folders/5j/8x9_vr3d0bzc2lfwylqv167h0000gn/T/arduino_build_375935/sketch/externalMIDI.ino.cpp.o:(.bss.MIDI+0x0): multiple definition of `MIDI'
/var/folders/5j/8x9_vr3d0bzc2lfwylqv167h0000gn/T/arduino_build_375935/sketch/MidiController.cpp.o:(.bss.MIDI+0x0): first defined here
/Applications/Arduino.app/Contents/Java/hardware/tools/arm/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/bin/ld: Disabling relaxation: it will not work with multiple definitions
collect2: error: ld returned 1 exit status
Fehler beim Kompilieren für das Board Teensy 3.2 / 3.1.
 */
#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();

MidiController::MidiController()
{
  MIDI.setHandleClock(MidiCallback);
}
void MidiController::MidiCallback()
{
  next();
}
void MidiController::next()
{
  Serial.println(":)");
}

the error:

Code:
var/folders/5j/8x9_vr3d0bzc2lfwylqv167h0000gn/T/arduino_build_375935/sketch/MidiController.cpp: In constructor 'MidiController::MidiController()':
MidiController.cpp:17: error: invalid use of non-static member function
   MIDI.setHandleClock(MidiCallback);
                                   ^
invalid use of non-static member function

greets!
 
The problem does not only seem to be the include chaos, but also that you try to encapsulate the native Midi class in another class without friending it... <Midi.h> should be included in your header file as should the default instantiation. That "problem" has to fixed first. Your cpp file should then only include your MidiController.h file.
 
The problem does not only seem to be the include chaos, but also that you try to encapsulate the native Midi class in another class without friending it... <Midi.h> should be included in your header file as should the default instantiation. That "problem" has to fixed first. Your cpp file should then only include your MidiController.h file.

well it sounds logical but I have no clue how to do this..
would you please provide me an small example?
many thanks!
 
Ok, first the "easy" answer. You can get your code to compile by adding "static" in 2 places in MidiController.h.

Code:
#ifndef MidiController_h
#define MidiController_h
#include "Arduino.h"

class MidiController
{
  public:
  MidiController();
  static void MidiCallback();
  static void next();
};
#endif
 
I was about to post the same...
The .ino :
Code:
#include "MidiController.h"


MidiController midicontroller;


void setup() {
  // put your setup code here, to run once:


}


void loop() {
  // put your main code here, to run repeatedly:


}

The .h :
Code:
#ifndef MidiController_h
#define MidiController_h
#include "Arduino.h"
#include <MIDI.h>


class MidiController 
{
  public:
  MidiController();
  static void MidiCallback();
  static void next();
};
#endif

The .cpp :
Code:
#include "MidiController.h"


MIDI_CREATE_DEFAULT_INSTANCE();


MidiController::MidiController() {
  
  MIDI.begin(MIDI_CHANNEL_OMNI);
  MIDI.setHandleClock (MidiCallback);
}


void MidiController::MidiCallback()
{
  next();
}
void MidiController::next()
{
  Serial.println(":)");
}
 
Background information: Handling over function pointers, i.e. as callback functions, has a little constraint. Non-static member functions don't allow the compiler to know from which instance of the object the member function should be taken. That's why such functions have to be declared as static, so that these are unique, even if multiple object instances exist.
 
I could be wrong, but I believe that the main error is you are trying to calling a non static method...

That is: MIDI.setHandleClock(MidiCallback);

The method MidiCallback is not static, so the system wants to call this method with a "this" pointer to the instance of your Midi Controller class. The problem is that the setHandleClock wants a simple function void Myfunction(void)... So it errors.

You can solve this assuming that you are not expecting to have multiple of these objects by doing something like:

Code:
#ifndef MidiController_h
#define MidiController_h
#include "Arduino.h"

class MidiController
{
  public:
  MidiController();
  static void MidiCallback();
  void next();
};
#endif

This would be fine as long as you are not expecting to have multiple of these objects and you are not interested in a pointer to the actual object being passed to the method... Otherwise you may need/want to setup some other way to get the this pointer...

There are multiple ways to do that, including I believe some magic c++ wrapping stuff.

But I have seen/used things like: Have an array of this pointers as a static array as part of the class, then have a number of static callback functions, which then callback to the main class code, and some form of register function, that you say register this object with the array. The register, looks for an empty spot, saves the this pointer, with that spot, likewise registers the appropriate static callback for that index, with the Midi code. If that callback is called, you then do something like: my_this_pointers[object_instance_index]->doCallbackCode()...

Hope that makes a little sense

Kurt
 
Now the harder answer... using static like this probably defeats the purpose of creating this C++ class. But even without those functions static, maybe the purpose was already defeated by using the static "MIDI" instance in the constructor?

And aside from whether this C++ class is effectively a singleton (limited to only 1 instance), you might also consider whether calling another C++ class function from a static constructor risks the C++ static initialization order fiasco. Usually on the Arduino platform C++ constructors are limited to initializing variables within their own class and a begin() function is used for actually initializing hardware. Unless you are a C++ expert, I highly recommend you follow that programming convention. In fact, static initialization order problems are tough for everyone, even experts...

The really bad news here is the MIDI library isn't really designed to be used this way. Its callbacks don't provide an instance parameter, which is really what you would need to do this well. Also complicating matter is MIDI.h use of templates for the C++ class. These are really going to make this sort of C++ class tough to use for more than 1 instance. It might seem the best and proper way, but just to be realistic, if you're doing this to save typing and editing 1 set of code rather than a few copies, all these complexities will probably add up to a lot more trouble than just having a few "duplicate" but slightly different copies of your code.
 
thank you guys!! really kind of you!
so now I understand the problematic!
I'll stick to main.ino because static is not an option.
but many thanks!

btw. @KurtE this doesn't compile because next() is not a static method..

Code:
#ifndef MidiController_h
#define MidiController_h
#include "Arduino.h"

class MidiController
{
  public:
  MidiController();
  static void MidiCallback();
  void next();
};
#endif


cheers!
 
Status
Not open for further replies.
Back
Top