Skip to content

Commit 4249589

Browse files
authored
Merge pull request #98 from lathoub/v.3.0.0rc
V.3.0.0rc
2 parents ba3db18 + 4dd5446 commit 4249589

30 files changed

+1080
-563
lines changed

.travis.yml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,18 @@ cache:
1010
install:
1111
- pip install -U platformio
1212
- platformio update
13-
- platformio lib -g install 62@5.0.0 870 872
13+
- platformio lib -g install 62@5.0.0 870 872 236
1414

1515
script:
16-
- pio ci --board=uno --lib=. examples/EthernetShield_NoteOnOffEverySec/EthernetShield_NoteOnOffEverySec.ino;
16+
- pio ci --board=uno --lib=. examples/AVR_Callbacks/AVR_Callbacks.ino
17+
- pio ci --board=uno --lib=. examples/AVR_Directory/AVR_Directory.ino
18+
- pio ci --board=uno --lib=. examples/AVR_Initiator/AVR_Initiator.ino
19+
- pio ci --board=uno --lib=. examples/AVR_MinMemUsage/AVR_MinMemUsage.ino
20+
- pio ci --board=uno --lib=. examples/AVR_MultipleSessions/AVR_MultipleSessions.ino
21+
- pio ci --board=uno --lib=. examples/AVR_NonDefaultSession/AVR_NonDefaultSession.ino
22+
- pio ci --board=uno --lib=. examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino
23+
- pio ci --board=uno --lib=. examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino
24+
- pio ci --board=uno --lib=. examples/AVR_SysEx/AVR_SysEx.ino
25+
- pio ci --board=mkrzero --lib=. examples/SAMD_Bonjour/SAMD_Bonjour.ino
26+
- pio ci --board=huzzah --lib=. examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino
27+
- pio ci --board=featheresp32 --lib=. examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino

README.md

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@ Enables an Arduino with IP/UDP capabilities (Ethernet shield, ESP8266, ESP32, ..
55

66
## Features
77
* Build on top of the popular [FortySevenEffects MIDI library](https://github.com/FortySevenEffects/arduino_midi_library)
8-
* Tested with AppleMIDI on Mac OS (Catalina) and using [rtpMIDI](https://www.tobias-erichsen.de/software/rtpmidi.html) from Tobias Erichsen on Windows 10
8+
* Tested with AppleMIDI on Mac OS (Big Sur) and using [rtpMIDI](https://www.tobias-erichsen.de/software/rtpmidi.html) from Tobias Erichsen on Windows 10
99
* Send and receive all MIDI messages
1010
* Uses callbacks to receive MIDI commands (no need for polling)
1111
* Automatic instantiation of AppleMIDI object (see at the end of 'AppleMidi.h')
1212
* Compiles on Arduino, MacOS (XCode) and Windows (MSVS)
1313

14+
## New in 3.0.0
15+
* Bug Fixes (long session names get cropped)
16+
* Reduced memory footprint (see AVR_MinMemUsage example and note below)
17+
* Extended and revised callbacks to receive AppleMIDI protocol feedback (see AVR_Callbacks example)
18+
* Who may connect to me (Directory) (see AVR_Directory example)
19+
1420
## Installation
1521
From the Arduino IDE Library Manager, search for AppleMIDI
1622

@@ -57,21 +63,31 @@ More usages in the [examples](https://github.com/lathoub/Arduino-AppleMIDI-Libra
5763
* ESP32 (Adafruit HUZZAH32 – ESP32 Feather Board)
5864
* Teensy 3.2
5965
* Adafruit Feather M0 WiFi - ATSAMD21 + ATWINC1500
60-
66+
67+
## Network Shields
68+
* Arduino Ethernet shield (Wiznet W5100 and W5500)
69+
* Arduino Wifi R3 shield
70+
* MKR ETH shield
71+
* Teensy WIZ820io W5200
72+
6173
## Memory usage
74+
Out of the box, this library has been setup to use a minimum amount of memory. Extended callbacks are not enabled by default, and can be anabled by USE_EXT_CALLBACKS. See the callback examamples.
75+
6276
This library is not using any dynamic memory allocation methods - all buffers have a fixed size, set in the `AppleMIDI_Settings.h` file, avoiding potential memory leaks and memory fragmentation.
6377

6478
The minimum buffer size (`MaxBufferSize`) should be set to 64 bytes (also the default). Setting it to a higher value will make sending larger SysEx messages more efficiant (large SysEx messages are chopped in pieces, the larger the buffer, the less pieces needed), at the price of a bigger memory footprint.
6579

6680
`MaxNumberOfParticipants` is another way to cut memory - each particpants uses approx 300 bytes. Default number of participants is 1 (using 2 sockets).
6781
Beware: the number of sockets on the Arduino is limited. The W5100 support 4, the W5200 and W5500 based IP chips can use 8 sockets. (Each participant uses 2 sockets: port 5004 and 5004+1). (Base port can be set in `APPLEMIDI_CREATE_DEFAULT_INSTANCE`)
68-
69-
## Network Shields
70-
* Arduino Ethernet shield (Wiznet W5100 and W5500)
71-
* Arduino Wifi R3 shield
72-
* MKR ETH shield
73-
* Teensy WIZ820io W5200
74-
82+
83+
Reduce the memory footprint by a further 500 bytes by `#define NO_SESSION_NAME` before `#include <AppleMIDI.h>`. This will leave out all the code to manage the optional session name. By default the session name is kept.
84+
85+
Even further reduce the memory footprint by `#define ONE_PARTICIPANT` limiting the number of particpants to just 1.
86+
On an UNO the absolute minimum memory footprint is 21966 bytes (68%) and 945 global variables (46%). For a Leonardo that is 24906 bytes (86%) and 1111 bytes (43%) of global variables.
87+
88+
## Notes
89+
Session names can get really long on Macs (eg 'Macbook Pro of Johann Gambolputty .. von Hautkopft of Ulm') and will be trunctated to the `MaxSessionNameLen` (as set in the settings file).
90+
7591
## Arduino IDE (arduino.cc)
7692
* 1.8.13
7793

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#include <Ethernet.h>
2+
3+
#define USE_EXT_CALLBACKS
4+
#define SerialMon Serial
5+
#define APPLEMIDI_DEBUG SerialMon
6+
#include <AppleMIDI.h>
7+
8+
// Enter a MAC address for your controller below.
9+
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
10+
byte mac[] = {
11+
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
12+
};
13+
14+
unsigned long t1 = millis();
15+
int8_t isConnected = 0;
16+
17+
APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE();
18+
19+
void OnAppleMidiException(const APPLEMIDI_NAMESPACE::ssrc_t&, const APPLEMIDI_NAMESPACE::Exception&, const int32_t);
20+
21+
// -----------------------------------------------------------------------------
22+
//
23+
// -----------------------------------------------------------------------------
24+
void setup()
25+
{
26+
DBG_SETUP(115200);
27+
DBG("Das Booting");
28+
29+
if (Ethernet.begin(mac) == 0) {
30+
DBG(F("Failed DHCP, check network cable & reboot"));
31+
for (;;);
32+
}
33+
34+
DBG(F("OK, now make sure you an rtpMIDI session that is Enabled"));
35+
DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")");
36+
DBG(F("Select and then press the Connect button"));
37+
DBG(F("Then open a MIDI listener and monitor incoming notes"));
38+
39+
MIDI.begin();
40+
41+
// Normal callbacks - always available
42+
// Stay informed on connection status
43+
AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) {
44+
isConnected++;
45+
DBG(F("Connected to session"), ssrc, name);
46+
});
47+
AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) {
48+
isConnected--;
49+
DBG(F("Disconnected"), ssrc);
50+
});
51+
52+
// Extended callback, only available when defining USE_EXT_CALLBACKS
53+
AppleMIDI.setHandleSentRtp([](const APPLEMIDI_NAMESPACE::Rtp_t & rtp) {
54+
DBG(F("an rtpMessage has been sent with sequenceNr"), rtp.sequenceNr);
55+
});
56+
AppleMIDI.setHandleSentRtpMidi([](const APPLEMIDI_NAMESPACE::RtpMIDI_t& rtpMidi) {
57+
DBG(F("an rtpMidiMessage has been sent"), rtpMidi.flags);
58+
});
59+
AppleMIDI.setHandleReceivedRtp([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const APPLEMIDI_NAMESPACE::Rtp_t & rtp, const int32_t& latency) {
60+
DBG(F("setHandleReceivedRtp"), ssrc, rtp.sequenceNr , "with", latency, "ms latency");
61+
});
62+
AppleMIDI.setHandleStartReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t& ssrc) {
63+
DBG(F("setHandleStartReceivedMidi from SSRC"), ssrc);
64+
});
65+
AppleMIDI.setHandleReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t& ssrc, byte value) {
66+
DBG(F("setHandleReceivedMidi from SSRC"), ssrc, ", value:", value);
67+
});
68+
AppleMIDI.setHandleEndReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t& ssrc) {
69+
DBG(F("setHandleEndReceivedMidi from SSRC"), ssrc);
70+
});
71+
AppleMIDI.setHandleException(OnAppleMidiException);
72+
73+
MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) {
74+
DBG(F("NoteOn"), note);
75+
});
76+
MIDI.setHandleNoteOff([](byte channel, byte note, byte velocity) {
77+
DBG(F("NoteOff"), note);
78+
});
79+
80+
DBG(F("Sending MIDI messages every second"));
81+
}
82+
83+
// -----------------------------------------------------------------------------
84+
//
85+
// -----------------------------------------------------------------------------
86+
void loop()
87+
{
88+
// Listen to incoming notes
89+
MIDI.read();
90+
91+
// send a note every second
92+
// (dont cáll delay(1000) as it will stall the pipeline)
93+
if ((isConnected > 0) && (millis() - t1) > 1000)
94+
{
95+
t1 = millis();
96+
97+
byte note = random(1, 127);
98+
byte velocity = 55;
99+
byte channel = 1;
100+
101+
DBG(F("\nsendNoteOn"), note, velocity, channel);
102+
MIDI.sendNoteOn(note, velocity, channel);
103+
//MIDI.sendNoteOff(note, velocity, channel);
104+
105+
}
106+
}
107+
108+
// -----------------------------------------------------------------------------
109+
//
110+
// -----------------------------------------------------------------------------
111+
void OnAppleMidiException(const APPLEMIDI_NAMESPACE::ssrc_t& ssrc, const APPLEMIDI_NAMESPACE::Exception& e, const int32_t value ) {
112+
switch (e)
113+
{
114+
case APPLEMIDI_NAMESPACE::Exception::BufferFullException:
115+
DBG(F("*** BufferFullException"));
116+
break;
117+
case APPLEMIDI_NAMESPACE::Exception::ParseException:
118+
DBG(F("*** ParseException"));
119+
break;
120+
case APPLEMIDI_NAMESPACE::Exception::TooManyParticipantsException:
121+
DBG(F("*** TooManyParticipantsException"));
122+
break;
123+
case APPLEMIDI_NAMESPACE::Exception::UnexpectedInviteException:
124+
DBG(F("*** UnexpectedInviteException"));
125+
break;
126+
case APPLEMIDI_NAMESPACE::Exception::ParticipantNotFoundException:
127+
DBG(F("*** ParticipantNotFoundException"), value);
128+
break;
129+
case APPLEMIDI_NAMESPACE::Exception::ComputerNotInDirectory:
130+
DBG(F("*** ComputerNotInDirectory"), value);
131+
break;
132+
case APPLEMIDI_NAMESPACE::Exception::NotAcceptingAnyone:
133+
DBG(F("*** NotAcceptingAnyone"), value);
134+
break;
135+
case APPLEMIDI_NAMESPACE::Exception::ListenerTimeOutException:
136+
DBG(F("*** ListenerTimeOutException"));
137+
break;
138+
case APPLEMIDI_NAMESPACE::Exception::MaxAttemptsException:
139+
DBG(F("*** MaxAttemptsException"));
140+
break;
141+
case APPLEMIDI_NAMESPACE::Exception::NoResponseFromConnectionRequestException:
142+
DBG(F("***:yyy did't respond to the connection request. Check the address and port, and any firewall or router settings. (time)"));
143+
break;
144+
case APPLEMIDI_NAMESPACE::Exception::SendPacketsDropped:
145+
DBG(F("*** SendPacketsDropped"), value);
146+
break;
147+
case APPLEMIDI_NAMESPACE::Exception::ReceivedPacketsDropped:
148+
DBG(F("*** ReceivedPacketsDropped"), value);
149+
break;
150+
}
151+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#include <Ethernet.h>
2+
3+
#define USE_DIRECTORY
4+
#define SerialMon Serial
5+
#define APPLEMIDI_DEBUG SerialMon
6+
#include <AppleMIDI.h>
7+
8+
// Enter a MAC address for your controller below.
9+
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
10+
byte mac[] = {
11+
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
12+
};
13+
14+
unsigned long t1 = millis();
15+
int8_t isConnected = 0;
16+
17+
APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE();
18+
19+
// -----------------------------------------------------------------------------
20+
//
21+
// -----------------------------------------------------------------------------
22+
void setup()
23+
{
24+
DBG_SETUP(115200);
25+
DBG("Booting");
26+
27+
if (Ethernet.begin(mac) == 0) {
28+
DBG(F("Failed DHCP, check network cable & reboot"));
29+
for (;;);
30+
}
31+
32+
AppleMIDI.directory.push_back(IPAddress(192, 168, 1, 63));
33+
AppleMIDI.directory.push_back(IPAddress(192, 168, 1, 66));
34+
// AppleMIDI.whoCanConnectToMe = APPLEMIDI_NAMESPACE::None;
35+
AppleMIDI.whoCanConnectToMe = APPLEMIDI_NAMESPACE::OnlyComputersInMyDirectory;
36+
// AppleMIDI.whoCanConnectToMe = APPLEMIDI_NAMESPACE::Anyone;
37+
38+
DBG(F("OK, now make sure you an rtpMIDI session that is Enabled"));
39+
DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")");
40+
DBG(F("Select and then press the Connect button"));
41+
DBG(F("Then open a MIDI listener and monitor incoming notes"));
42+
43+
MIDI.begin();
44+
45+
// Stay informed on connection status
46+
AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) {
47+
isConnected++;
48+
DBG(F("Connected to session"), ssrc, name);
49+
});
50+
AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) {
51+
isConnected--;
52+
DBG(F("Disconnected"), ssrc);
53+
});
54+
55+
MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) {
56+
DBG(F("NoteOn"), note);
57+
});
58+
MIDI.setHandleNoteOff([](byte channel, byte note, byte velocity) {
59+
DBG(F("NoteOff"), note);
60+
});
61+
62+
DBG(F("Sending MIDI messages every second"));
63+
}
64+
65+
// -----------------------------------------------------------------------------
66+
//
67+
// -----------------------------------------------------------------------------
68+
void loop()
69+
{
70+
// Listen to incoming notes
71+
MIDI.read();
72+
73+
// send a note every second
74+
// (dont cáll delay(1000) as it will stall the pipeline)
75+
if ((isConnected > 0) && (millis() - t1) > 1000)
76+
{
77+
t1 = millis();
78+
79+
byte note = random(1, 127);
80+
byte velocity = 55;
81+
byte channel = 1;
82+
83+
MIDI.sendNoteOn(note, velocity, channel);
84+
// MIDI.sendNoteOff(note, velocity, channel);
85+
}
86+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#include <Ethernet3.h> // from https://github.com/sstaub/Ethernet3
2+
3+
#define SerialMon Serial
4+
#define APPLEMIDI_DEBUG SerialMon
5+
#include <AppleMIDI.h>
6+
7+
// Enter a MAC address for your controller below.
8+
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
9+
byte mac[] = {
10+
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
11+
};
12+
13+
unsigned long t1 = millis();
14+
int8_t isConnected = 0;
15+
16+
APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE();
17+
18+
// -----------------------------------------------------------------------------
19+
//
20+
// -----------------------------------------------------------------------------
21+
void setup()
22+
{
23+
DBG_SETUP(115200);
24+
DBG("Booting");
25+
26+
if (Ethernet.begin(mac) == 0) {
27+
DBG(F("Failed DHCP, check network cable & reboot"));
28+
for (;;);
29+
}
30+
31+
DBG(F("OK, now make sure you an rtpMIDI session that is Enabled"));
32+
DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")");
33+
DBG(F("Select and then press the Connect button"));
34+
DBG(F("Then open a MIDI listener and monitor incoming notes"));
35+
36+
MIDI.begin();
37+
38+
// Stay informed on connection status
39+
AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) {
40+
isConnected++;
41+
DBG(F("Connected to session"), ssrc, name);
42+
});
43+
AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) {
44+
isConnected--;
45+
DBG(F("Disconnected"), ssrc);
46+
});
47+
48+
MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) {
49+
DBG(F("NoteOn"), note);
50+
});
51+
MIDI.setHandleNoteOff([](byte channel, byte note, byte velocity) {
52+
DBG(F("NoteOff"), note);
53+
});
54+
55+
DBG(F("Sending MIDI messages every second"));
56+
}
57+
58+
// -----------------------------------------------------------------------------
59+
//
60+
// -----------------------------------------------------------------------------
61+
void loop()
62+
{
63+
// Listen to incoming notes
64+
MIDI.read();
65+
66+
// send a note every second
67+
// (dont cáll delay(1000) as it will stall the pipeline)
68+
if ((isConnected > 0) && (millis() - t1) > 1000)
69+
{
70+
t1 = millis();
71+
72+
byte note = random(1, 127);
73+
byte velocity = 55;
74+
byte channel = 1;
75+
76+
MIDI.sendNoteOn(note, velocity, channel);
77+
// MIDI.sendNoteOff(note, velocity, channel);
78+
}
79+
}

0 commit comments

Comments
 (0)