how to use MIDI.h in a class
SandroGrassia opened this issue · 7 comments
Hi, I'm trying to use MIDI.h inside a class, and use MIDI' s functions in separated methods of this class; for example:
class Test.h:
#ifndef Test_h_
#define Test_h_
#include "Arduino.h"
#include <MIDI.h>
class Test
{
public:
void start_midi(void)
{
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
MIDI.begin(MIDI_CHANNEL_OMNI);
}
void nostop_reading_midi(void)
{
do
{
if (MIDI.read())
{
switch (MIDI.getType())
{
case midi::NoteOn:
{
Serial.println();
Serial.print("NoteOn received");
}
break;
case midi::NoteOff:
{
Serial.println();
Serial.print("NoteOff received");
}
break;
default:
break;
}
}
}
while (1);
}
};
#endif
Of course this code generates errors, because MIDI was not declared in nostop_reading_midi(void)... Can you please me give me any help? Thank you!
PS: I apologize ... cannot find the way to get the right visualization of indentation!!
Indeed, calling MIDI_CREATE_INSTANCE
here will not help, since the MIDI interface will be destroyed after start_midi
returns, so it needs to be stored somewhere. Also, since version 5, the interface also needs a Transport object, to translate raw MIDI data into packets or serial streams. This is usually what the macro takes care of, but we'll see how it works internally and how to adapt it to your case.
There are two places you could store these objects. Either in global scope, or encapsulated in the class as members. It depends how your class object will be created and used, but by the looks of it this class has a run method that never returns, effectively encapsulating the setup / loop functions of Arduino into the class object, so either way will have the same effect.
In global scope, we'll have to use extern
, so that inclusions of Test.h in several compilation units (.cpp/.ino files) don't generate multiple objects (however this is unlikely in the case of Arduino):
// Test.h
#pragma once
#include <MIDI.h>
// Define your transport
extern MIDI_NAMESPACE::SerialMIDI<HardwareSerial> serialMIDI;
// Define the MIDI interface
extern MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<HardwareSerial>>;
class Test
{
public:
void start_midi()
{
MIDI.begin();
}
void nostop_reading_midi()
{
// Add the rest of the code around here
MIDI.read();
}
};
// main-sketch.ino --
#include <Test.h>
// Here we actually create the MIDI interface, that we previously declared, and bind it to Serial1.
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
To encapsulate the interface as a class member:
// Test.h
#pragma once
#include <MIDI.h>
class Test
{
private:
// Let's define some shorthand types:
using MidiTransport = MIDI_NAMESPACE::SerialMIDI<HardwareSerial>;
using MidiInterface = MIDI_NAMESPACE::MidiInterface<MidiTransport>;
MidiTransport midiTransport;
MidiInterface midiInterface;
public:
// In the constructor, which creates the member objects,
// we bind the Serial1 port to the transport, and the
// transport to the MIDI interface:
Test()
: midiTransport(Serial1)
, midiInterface((MidiTransport&)midiTransport)
{
}
void start_midi()
{
midiInterface.begin();
}
void nostop_reading_midi()
{
// Add the rest of the code around here
midiInterface.read();
}
};
// main-sketch.ino --
#include <Test.h>
// No need to create the MIDI objects here,
// they will be created as part of the `test` object:
Test test;
void setup()
{
test.start_midi();
}
void loop()
{
test.nostop_reading_midi();
}
Hi Francois, thank you for your fast reply; I tried both options you wrote, but none of them is correcly compiled using Teensy3.6 (sorry that I neglected to mention that I'm using this board). Worthless to say, that probably I introduced some mistakes or I misunderstood something while developing my code.... But I also would say that I tried other board-options and found that the way that you call "To encapsulate the interface as a class member" is correctly compiled using "Arduino Mega or 2560": may this fact can be important? Don't know if the reports of my trials are useful, if it's not enough I can surely post my code. Thank you!
Hi Francois, in the last days I've tried some code without success... As I wrote, I'm using a Teensy 3.6; this is my code:
#ifndef Test_h_
#define Test_h_
#pragma once
#include <MIDI.h>
// Define your transport
extern MIDI_NAMESPACE::SerialMIDI<HardwareSerial> serialMIDI;
// Define the MIDI interface
extern MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<HardwareSerial>>;
class Test
{
public:
void start_midi(void)
{
MIDI.begin();
}
void read_midi(void)
{
MIDI.read();
}
};
#endif
And this is the Arduino-main code:
#include <Test.h>
#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
Test test;
void setup()
{
test.start_midi();
}
void loop()
{
test.read_midi();
}
Trying to compile, Arduino shows many errors, example:
_C:\Users\dell\Google Drive\ARDUINO SKETCHES\libraries\TEST_classes/Test.h:10:24: warning: declaration does not declare anything [-fpermissive]
C:\Users\dell\Google Drive\ARDUINO SKETCHES\libraries\TEST_classes/Test.h: In member function 'void TestA::start_midi()':
C:\Users\dell\Google Drive\ARDUINO SKETCHES\libraries\TEST_classes/Test.h:17:9: error: 'MIDI' was not declared in this scope
MIDI.begin();
C:\Users\dell\Google Drive\ARDUINO SKETCHES\libraries\TEST_classes/Test.h: In member function 'void Test2A::read_midi()':
C:\Users\dell\Google Drive\ARDUINO SKETCHES\libraries\TEST_classes/Test.h:22:9: error: 'MIDI' was not declared in this scope
MIDI.read();_
As long as I can see I used the code you proposed... Could you please tell me where is my fault?
Yes I see, on line 10 of Test.h
, the variable name is missing (my bad), it should be:
extern MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<HardwareSerial>> MIDI;
WOW!! Now the code is compiled without errors! Thank you so much for your superfast answer!!
There was also a mistake I did, in main code:
errata: MIDI_CREATE_DEFAULT_INSTANCE();
corrige: MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
I apologize for hijacking this thread, i'm trying to do the same thing for USB-MIDI.h however i'm getting a bunch of errors, does something need to change for this?
I actually ended up figuring this out. for anyone used the USB-MIDI library you can do, so far no issues.
#include <USB-MIDI.h>
extern USBMIDI_NAMESPACE::usbMidiTransport usbMIDI;
extern MIDI_NAMESPACE::MidiInterface<USBMIDI_NAMESPACE::usbMidiTransport> MIDI;