Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 16 of 16

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

  1. #1
    Member Van's Avatar
    Join Date
    Mar 2018
    Location
    Dresden, Germany
    Posts
    35

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

    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

  2. #2
    Member Van's Avatar
    Join Date
    Mar 2018
    Location
    Dresden, Germany
    Posts
    35
    no one on this?

  3. #3
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,544
    Most probably, nobody understands why you would do that include in an external file instead of the main sketch .ino file.

  4. #4
    Member Van's Avatar
    Join Date
    Mar 2018
    Location
    Dresden, Germany
    Posts
    35
    Quote Originally Posted by Theremingenieur View Post
    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?

  5. #5
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,821
    Quote Originally Posted by Van View Post
    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.

  6. #6
    Member Van's Avatar
    Join Date
    Mar 2018
    Location
    Dresden, Germany
    Posts
    35
    Quote Originally Posted by PaulStoffregen View Post
    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!

  7. #7
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,544
    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.

  8. #8
    Member Van's Avatar
    Join Date
    Mar 2018
    Location
    Dresden, Germany
    Posts
    35
    Quote Originally Posted by Theremingenieur View Post
    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!

  9. #9
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,821
    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

  10. #10
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,544
    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(":)");
    }

  11. #11
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,544
    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.

  12. #12
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,734
    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

  13. #13
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,544
    That makes 3 almost identical answers which point out different aspects of the same problem. If that isn't helpful...

  14. #14
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,821
    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.

  15. #15
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,821
    Quote Originally Posted by Theremingenieur View Post
    That makes 3 almost identical answers which point out different aspects of the same problem. If that isn't helpful...
    Yup, we're pretty good here when people actually follow the Forum Rule!

  16. #16
    Member Van's Avatar
    Join Date
    Mar 2018
    Location
    Dresden, Germany
    Posts
    35
    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!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •