From e12eb30c1358c291c8bee0b6702dbc4a6191ff37 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Mon, 21 Dec 2020 21:55:54 +0100 Subject: [PATCH 01/60] debug text update (very minor update) --- examples/ESP32_Callbacks/ESP32_Callbacks.ino | 2 +- .../ESP8266_NoteOnOffEverySec.ino | 2 +- .../EthernetShield_MultipleSessions.ino | 2 +- .../EthernetShield_NonDefaultSession.ino | 2 +- .../EthernetShield_NoteOnOffEverySec.ino | 2 +- .../EthernetShield_ReceivedRawMidiData.ino | 2 +- .../EthernetShield_SysEx.ino | 2 +- keywords.txt | 47 +------------------ 8 files changed, 8 insertions(+), 53 deletions(-) diff --git a/examples/ESP32_Callbacks/ESP32_Callbacks.ino b/examples/ESP32_Callbacks/ESP32_Callbacks.ino index a431508..5568e5c 100644 --- a/examples/ESP32_Callbacks/ESP32_Callbacks.ino +++ b/examples/ESP32_Callbacks/ESP32_Callbacks.ino @@ -23,7 +23,7 @@ void setup() { DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); DBG(F("Add device named Arduino with Host"), WiFi.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); - DBG(F("Then press the Connect button")); + DBG(F("Select and then press the Connect button")); DBG(F("Then open a MIDI listener and monitor incoming notes")); AppleMIDI.setHandleConnected(OnAppleMidiConnected); diff --git a/examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino b/examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino index 4552a6d..c45e9fb 100644 --- a/examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino +++ b/examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino @@ -32,7 +32,7 @@ void setup() DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); DBG(F("Add device named Arduino with Host"), WiFi.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); - DBG(F("Then press the Connect button")); + DBG(F("Select and then press the Connect button")); DBG(F("Then open a MIDI listener and monitor incoming notes")); DBG(F("Listen to incoming MIDI commands")); diff --git a/examples/EthernetShield_MultipleSessions/EthernetShield_MultipleSessions.ino b/examples/EthernetShield_MultipleSessions/EthernetShield_MultipleSessions.ino index 293d659..95cbb8b 100644 --- a/examples/EthernetShield_MultipleSessions/EthernetShield_MultipleSessions.ino +++ b/examples/EthernetShield_MultipleSessions/EthernetShield_MultipleSessions.ino @@ -32,7 +32,7 @@ void setup() DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI1.getPort(), "(Name", AppleMIDI1.getName(), ")"); DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI2.getPort(), "(Name", AppleMIDI2.getName(), ")"); - DBG(F("Then press the Connect button")); + DBG(F("Select and then press the Connect button")); DBG(F("Then open a MIDI listener and monitor incoming notes")); // Listen for MIDI messages on channel 1 diff --git a/examples/EthernetShield_NonDefaultSession/EthernetShield_NonDefaultSession.ino b/examples/EthernetShield_NonDefaultSession/EthernetShield_NonDefaultSession.ino index e97c356..797cb07 100644 --- a/examples/EthernetShield_NonDefaultSession/EthernetShield_NonDefaultSession.ino +++ b/examples/EthernetShield_NonDefaultSession/EthernetShield_NonDefaultSession.ino @@ -31,7 +31,7 @@ void setup() DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); - DBG(F("Then press the Connect button")); + DBG(F("Select and then press the Connect button")); DBG(F("Then open a MIDI listener and monitor incoming notes")); MIDI.begin(); diff --git a/examples/EthernetShield_NoteOnOffEverySec/EthernetShield_NoteOnOffEverySec.ino b/examples/EthernetShield_NoteOnOffEverySec/EthernetShield_NoteOnOffEverySec.ino index 066fbbc..23d5f58 100644 --- a/examples/EthernetShield_NoteOnOffEverySec/EthernetShield_NoteOnOffEverySec.ino +++ b/examples/EthernetShield_NoteOnOffEverySec/EthernetShield_NoteOnOffEverySec.ino @@ -30,7 +30,7 @@ void setup() DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); - DBG(F("Then press the Connect button")); + DBG(F("Select and then press the Connect button")); DBG(F("Then open a MIDI listener and monitor incoming notes")); MIDI.begin(); diff --git a/examples/EthernetShield_ReceivedRawMidiData/EthernetShield_ReceivedRawMidiData.ino b/examples/EthernetShield_ReceivedRawMidiData/EthernetShield_ReceivedRawMidiData.ino index da139f0..ba61901 100644 --- a/examples/EthernetShield_ReceivedRawMidiData/EthernetShield_ReceivedRawMidiData.ino +++ b/examples/EthernetShield_ReceivedRawMidiData/EthernetShield_ReceivedRawMidiData.ino @@ -30,7 +30,7 @@ void setup() DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); - DBG(F("Then press the Connect button")); + DBG(F("Select and then press the Connect button")); DBG(F("Then open a MIDI listener and monitor incoming notes")); MIDI.begin(); diff --git a/examples/EthernetShield_SysEx/EthernetShield_SysEx.ino b/examples/EthernetShield_SysEx/EthernetShield_SysEx.ino index 2296d8c..eb023aa 100644 --- a/examples/EthernetShield_SysEx/EthernetShield_SysEx.ino +++ b/examples/EthernetShield_SysEx/EthernetShield_SysEx.ino @@ -45,7 +45,7 @@ void setup() DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); - DBG(F("Then press the Connect button")); + DBG(F("Select and then press the Connect button")); DBG(F("Then open a MIDI listener and monitor incoming notes")); AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { diff --git a/keywords.txt b/keywords.txt index 5f762b5..f8577b8 100644 --- a/keywords.txt +++ b/keywords.txt @@ -14,61 +14,16 @@ AppleMidi KEYWORD1 setHandleConnected KEYWORD2 setHandleDisconnected KEYWORD2 setHandleError KEYWORD2 +setHandleException KEYWORD2 setHandleStartReceivedMidi KEYWORD2 setHandleReceivedMidi KEYWORD2 setHandleEndReceivedMidi KEYWORD2 setHandleReceivedRtp KEYWORD2 -setHandleNoteOff KEYWORD2 -setHandleNoteOn KEYWORD2 -setHandleAfterTouchPoly KEYWORD2 -setHandleControlChange KEYWORD2 -setHandleProgramChange KEYWORD2 -setHandleAfterTouchChannel KEYWORD2 -setHandlePitchBend KEYWORD2 -setHandleSystemExclusive KEYWORD2 -setHandleTimeCodeQuarterFrame KEYWORD2 -setHandleSongPosition KEYWORD2 -setHandleSongSelect KEYWORD2 -setHandleTuneRequest KEYWORD2 -setHandleClock KEYWORD2 -setHandleStart KEYWORD2 -setHandleContinue KEYWORD2 -setHandleStop KEYWORD2 -setHandleActiveSensing KEYWORD2 -setHandleSystemReset KEYWORD2 - -begin KEYWORD2 -run KEYWORD2 -sendNoteOn KEYWORD2 -sendNoteOff KEYWORD2 -sendAfterTouchPoly KEYWORD2 -sendControlChange KEYWORD2 -sendProgramChange KEYWORD2 -sendAfterTouchChannel KEYWORD2 -sendPitchBend KEYWORD2 -sendSystemEx KEYWORD2 -sendTimeCodeQuarterFrame KEYWORD2 -sendSongPosition KEYWORD2 -sendSongSelect KEYWORD2 -sendTuneRequest KEYWORD2 -sendClock KEYWORD2 -sendStart KEYWORD2 -sendContinue KEYWORD2 -sendStop KEYWORD2 -sendActiveSensing KEYWORD2 -sendSystemReset KEYWORD2 -sendTimeCodeQuarterFrame KEYWORD2 -sendSysEx KEYWORD2 -sendAfterTouch KEYWORD2 -sendPolyPressure KEYWORD2 -sendTick KEYWORD2 - ####################################### # Instances (KEYWORD3) ####################################### AppleMIDI KEYWORD3 -MIDI KEYWORD3 ####################################### # Constants (LITERAL1) From 28a84a75c6cbb711a6fcfafd52a11d34f568b015 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Mon, 21 Dec 2020 21:56:59 +0100 Subject: [PATCH 02/60] debug update --- test/NoteOn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/NoteOn.cpp b/test/NoteOn.cpp index b0cb7cc..b36d3b0 100644 --- a/test/NoteOn.cpp +++ b/test/NoteOn.cpp @@ -100,7 +100,7 @@ void begin() { DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); - DBG(F("Then press the Connect button")); + DBG(F("Select and then press the Connect button")); DBG(F("Then open a MIDI listener and monitor incoming notes")); MIDI.begin(); From 9d47f3192ac35aac51cc96c96db715e182d018a0 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Mon, 21 Dec 2020 21:57:31 +0100 Subject: [PATCH 03/60] deprecate Error callback, replace with Exception callback --- .../wESP32_NoteOnOffEverySec.ino | 18 +++-- src/AppleMIDI.h | 9 ++- src/AppleMIDI.hpp | 73 +++++++++++++------ src/AppleMIDI_Defs.h | 5 +- src/AppleMIDI_Participant.h | 6 +- 5 files changed, 76 insertions(+), 35 deletions(-) diff --git a/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino b/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino index 195e12d..11d793a 100644 --- a/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino +++ b/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino @@ -19,11 +19,13 @@ void setup() ETH_startup(); - MDNS.begin(AppleMIDI.getName()); + if (!MDNS.begin(AppleMIDI.getName())) + DBG(F("Error setting up MDNS responder")); DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); - DBG(F("Add device named Arduino with Host"), ETH.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); - DBG(F("Then press the Connect button")); + DBG(F("Add device named Arduino with Host"), ETH.localIP(), "Port", AppleMIDI.getPort()); + DBG(F("The device should also be visible in the directory as"), AppleMIDI.getName()); + DBG(F("Select and then press the Connect button")); DBG(F("Then open a MIDI listener and monitor incoming notes")); MIDI.begin(); @@ -36,7 +38,13 @@ void setup() isConnected = false; DBG(F("Disconnected")); }); - + AppleMIDI.setHandleError([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, int32_t e) { + DBG(F("______________Error"), e); + }); + AppleMIDI.setHandleException([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const APPLEMIDI_NAMESPACE::Exception & e, const int32_t value) { + DBG(F("______________Exception"), e, value); + }); + MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { DBG(F("NoteOn"), note); }); @@ -66,6 +74,6 @@ void loop() byte channel = 1; MIDI.sendNoteOn(note, velocity, channel); - MIDI.sendNoteOff(note, velocity, channel); + // MIDI.sendNoteOff(note, velocity, channel); } } diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index 86832a7..6876d50 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -55,7 +55,8 @@ class AppleMIDISession void setHandleConnected(void (*fptr)(const ssrc_t&, const char*)) { _connectedCallback = fptr; } void setHandleDisconnected(void (*fptr)(const ssrc_t&)) { _disconnectedCallback = fptr; } - void setHandleError(void (*fptr)(const ssrc_t&, int32_t)) { _exceptionCallback = fptr; } + void setHandleError(void (*fptr)(const ssrc_t&, int32_t)) __attribute__ ((deprecated)) { _errorCallback = fptr; } // deprecated + void setHandleException(void (*fptr)(const ssrc_t&, const Exception&, const int32_t value)) { _exceptionCallback = fptr; } void setHandleReceivedRtp(void (*fptr)(const ssrc_t&, const Rtp_t&, const int32_t&)) { _receivedRtpCallback = fptr; } void setHandleStartReceivedMidi(void (*fptr)(const ssrc_t&)) { _startReceivedMidiByteCallback = fptr; } void setHandleReceivedMidi(void (*fptr)(const ssrc_t&, byte)) { _receivedMidiByteCallback = fptr; } @@ -150,8 +151,8 @@ class AppleMIDISession } else { - if (NULL != _exceptionCallback) - _exceptionCallback(ssrc, BufferFullException); + if (NULL != _errorCallback) + _errorCallback(ssrc, BufferFullException); } } @@ -224,6 +225,7 @@ class AppleMIDISession endReceivedMidiByteCallback _endReceivedMidiByteCallback = nullptr; receivedRtpCallback _receivedRtpCallback = nullptr; disconnectedCallback _disconnectedCallback = nullptr; + errorCallback _errorCallback = nullptr; exceptionCallback _exceptionCallback = nullptr; // buffer for incoming and outgoing MIDI messages @@ -237,7 +239,6 @@ class AppleMIDISession uint16_t port = DEFAULT_CONTROL_PORT; Deque, Settings::MaxNumberOfParticipants> participants; int32_t latencyAdjustment = 0; - uint16_t sequenceNr = random(1, UINT16_MAX); private: void readControlPackets(); diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index e9a041e..0a07a53 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -30,8 +30,8 @@ void AppleMIDISession::parseControlPackets() auto retVal = _appleMIDIParser.parse(controlBuffer, amPortType::Control); if (retVal == parserReturn::UnexpectedData) { - if (NULL != _exceptionCallback) - _exceptionCallback(ssrc, ParseException); + if (NULL != _errorCallback) + _errorCallback(ssrc, ParseException); controlBuffer.pop_front(); } @@ -81,8 +81,8 @@ void AppleMIDISession::parseDataPackets() || retVal2 == parserReturn::NotSureGiveMeMoreData) break; // one or the other buffer does not have enough data - if (NULL != _exceptionCallback) - _exceptionCallback(ssrc, UnexpectedParseException); + if (NULL != _errorCallback) + _errorCallback(ssrc, UnexpectedParseException); dataBuffer.pop_front(); } @@ -114,8 +114,8 @@ void AppleMIDISession::ReceivedControlInvitation(A { writeInvitation(controlPort, controlPort.remoteIP(), controlPort.remotePort(), invitation, amInvitationRejected); - if (NULL != _exceptionCallback) - _exceptionCallback(ssrc, TooManyParticipantsException); + if (NULL != _errorCallback) + _errorCallback(ssrc, TooManyParticipantsException); return; } @@ -143,8 +143,8 @@ void AppleMIDISession::ReceivedDataInvitation(Appl { writeInvitation(dataPort, dataPort.remoteIP(), dataPort.remotePort(), invitation, amInvitationRejected); - if (NULL != _exceptionCallback) - _exceptionCallback(ssrc, ParticipantNotFoundException); + if (NULL != _errorCallback) + _errorCallback(ssrc, ParticipantNotFoundException); return; } @@ -344,8 +344,23 @@ void AppleMIDISession::ReceivedSynchronization(App template void AppleMIDISession::ReceivedReceiverFeedback(AppleMIDI_ReceiverFeedback_t &receiverFeedback) { - // We do not keep any recovery journals, no command history, nothing! - // If we did, then we can flush the previous sent buffer until receiverFeedback.sequenceNr + // We do not keep any recovery journals, no command history, nothing! + // Here is where you would correct if packets are dropped (send them again) + + auto participant = getParticipantBySSRC(receiverFeedback.ssrc); + if (NULL != participant) { + if (participant->sendSequenceNr != receiverFeedback.sequenceNr) + { + Serial.print("ERRORRORORORORORORRROROROROROROR"); + + if (NULL != _exceptionCallback) + _exceptionCallback(ssrc, SendPacketsDropped, participant->sendSequenceNr - receiverFeedback.sequenceNr); + + Serial.print(participant->sendSequenceNr); + Serial.print(" "); + Serial.println(receiverFeedback.sequenceNr); + } + } } template @@ -504,10 +519,10 @@ void AppleMIDISession::writeRtpMidiBuffer(Particip // rtp.timestamp = (Settings::TimestampRtpPackets) ? htonl(rtpMidiClock.Now()) : 0; - // - sequenceNr++; // (modulo 2^16) modulo is automatically done for us () + // increament the sequenceNr + participant->sendSequenceNr++; - rtp.sequenceNr = sequenceNr; + rtp.sequenceNr = participant->sendSequenceNr; rtp.sequenceNr = htons(rtp.sequenceNr); dataPort.write((uint8_t *)&rtp, sizeof(rtp)); @@ -586,8 +601,8 @@ void AppleMIDISession::manageSynchronizationListen // otherwise the responder may assume that the initiator has died and terminate the session. if (now - participant->lastSyncExchangeTime > Settings::CK_MaxTimeOut) { - if (NULL != _exceptionCallback) - _exceptionCallback(ssrc, ListenerTimeOutException); + if (NULL != _errorCallback) + _errorCallback(ssrc, ListenerTimeOutException); sendEndSession(participant); @@ -652,8 +667,8 @@ void AppleMIDISession::manageSynchronizationInitia { if (participant->synchronizationCount > DefaultSettings::MaxSynchronizationCK0Attempts) { - if (NULL != _exceptionCallback) - _exceptionCallback(ssrc, MaxAttemptsException); + if (NULL != _errorCallback) + _errorCallback(ssrc, MaxAttemptsException); // After too many attempts, stop. sendEndSession(participant); @@ -711,8 +726,8 @@ void AppleMIDISession::manageSessionInvites() { if (participant->connectionAttempts >= DefaultSettings::MaxSessionInvitesAttempts) { - if (NULL != _exceptionCallback) - _exceptionCallback(ssrc, NoResponseFromConnectionRequestException); + if (NULL != _errorCallback) + _errorCallback(ssrc, NoResponseFromConnectionRequestException); // After too many attempts, stop. sendEndSession(participant); @@ -770,7 +785,7 @@ void AppleMIDISession::manageReceiverFeedback() { AppleMIDI_ReceiverFeedback_t rf; rf.ssrc = ssrc; - rf.sequenceNr = participant->sequenceNr; + rf.sequenceNr = participant->receiveSequenceNr; writeReceiverFeedback(participant->remoteIP, participant->remotePort, rf); // reset the clock. It is started when we receive MIDI @@ -795,8 +810,8 @@ bool AppleMIDISession::sendInvite(IPAddress ip, ui participant.remotePort = port; participant.lastInviteSentTime = now - 1000; // forces invite to be send immediately participant.lastSyncExchangeTime = now; - participant.initiatorToken = random(1, INT32_MAX) * 2; // 0xb7062030; - participant.sequenceNr = random(1, UINT16_MAX); // // http://www.rfc-editor.org/rfc/rfc6295.txt , 2.1. RTP Header + participant.initiatorToken = random(1, INT32_MAX) * 2; + participant.sequenceNr; participants.push_back(participant); @@ -846,7 +861,19 @@ void AppleMIDISession::ReceivedRtp(const Rtp_t& rt #else auto latency = 0; #endif - participant->sequenceNr = rtp.sequenceNr; + + if (participant->receiveSequenceNr + 1 != rtp.sequenceNr) { + + if (NULL != _exceptionCallback) + _exceptionCallback(ssrc, ReceivedPacketsDropped, participant->receiveSequenceNr + 1 - rtp.sequenceNr); + + Serial.print("___ERROR____"); + Serial.print(participant->receiveSequenceNr); + Serial.print(" "); + Serial.println(rtp.sequenceNr); + } + + participant->receiveSequenceNr = rtp.sequenceNr; if (NULL != _receivedRtpCallback) _receivedRtpCallback(0, rtp, latency); diff --git a/src/AppleMIDI_Defs.h b/src/AppleMIDI_Defs.h index 66b143a..7ae69f2 100644 --- a/src/AppleMIDI_Defs.h +++ b/src/AppleMIDI_Defs.h @@ -98,6 +98,8 @@ enum Exception : uint8_t ListenerTimeOutException, MaxAttemptsException, NoResponseFromConnectionRequestException, + SendPacketsDropped, + ReceivedPacketsDropped, }; using connectedCallback = void (*)(const ssrc_t&, const char *); @@ -106,7 +108,8 @@ using receivedMidiByteCallback = void (*)(const ssrc_t&, byte); using endReceivedMidiByteCallback = void (*)(const ssrc_t&); using receivedRtpCallback = void (*)(const ssrc_t&, const Rtp_t&, const int32_t&); using disconnectedCallback = void (*)(const ssrc_t&); -using exceptionCallback = void (*)(const ssrc_t&, int32_t); +using errorCallback = void (*)(const ssrc_t&, int32_t); +using exceptionCallback = void (*)(const ssrc_t&, const Exception&, const int32_t value); /* Signature "Magic Value" for Apple network MIDI session establishment */ const byte amSignature[] = {0xff, 0xff}; diff --git a/src/AppleMIDI_Participant.h b/src/AppleMIDI_Participant.h index f1099cf..878dd8d 100644 --- a/src/AppleMIDI_Participant.h +++ b/src/AppleMIDI_Participant.h @@ -13,10 +13,12 @@ struct Participant ssrc_t ssrc; IPAddress remoteIP; uint16_t remotePort; - + unsigned long receiverFeedbackStartTime; bool doReceiverFeedback = false; - uint16_t sequenceNr; + + uint16_t sendSequenceNr = random(1, UINT16_MAX); // http://www.rfc-editor.org/rfc/rfc6295.txt , 2.1. RTP Header + uint16_t receiveSequenceNr; unsigned long lastSyncExchangeTime; #ifdef APPLEMIDI_INITIATOR From 1db81addc83c44f995a02decb85f835348fde074 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Mon, 21 Dec 2020 22:42:33 +0100 Subject: [PATCH 04/60] removed error callback, replace with Exception --- examples/ESP32_Callbacks/ESP32_Callbacks.ino | 24 ++++++++++++---- .../wESP32_NoteOnOffEverySec.ino | 3 -- keywords.txt | 1 - src/AppleMIDI.h | 7 ++--- src/AppleMIDI.hpp | 28 +++++++++---------- src/AppleMIDI_Defs.h | 1 - 6 files changed, 34 insertions(+), 30 deletions(-) diff --git a/examples/ESP32_Callbacks/ESP32_Callbacks.ino b/examples/ESP32_Callbacks/ESP32_Callbacks.ino index 5568e5c..30718da 100644 --- a/examples/ESP32_Callbacks/ESP32_Callbacks.ino +++ b/examples/ESP32_Callbacks/ESP32_Callbacks.ino @@ -26,9 +26,15 @@ void setup() { DBG(F("Select and then press the Connect button")); DBG(F("Then open a MIDI listener and monitor incoming notes")); - AppleMIDI.setHandleConnected(OnAppleMidiConnected); - AppleMIDI.setHandleDisconnected(OnAppleMidiDisconnected); - AppleMIDI.setHandleError(OnAppleMidiError); + AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { + isConnected = true; + DBG(F("Connected to session"), name); + }); + AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { + isConnected = false; + DBG(F("Disconnected")); + }); + AppleMIDI.setHandleException(OnAppleMidiException); MIDI.begin(); @@ -77,8 +83,8 @@ DBG(F("Disconnected")); // ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- -void OnAppleMidiError(const APPLEMIDI_NAMESPACE::ssrc_t& ssrc, int32_t err) { - switch (err) +void OnAppleMidiException(const APPLEMIDI_NAMESPACE::ssrc_t& ssrc, const APPLEMIDI_NAMESPACE::Exception& e, const int32_t value ) { + switch (e) { case APPLEMIDI_NAMESPACE::Exception::BufferFullException: DBG(F("*** BufferFullException")); @@ -93,7 +99,7 @@ void OnAppleMidiError(const APPLEMIDI_NAMESPACE::ssrc_t& ssrc, int32_t err) { DBG(F("*** UnexpectedInviteException")); break; case APPLEMIDI_NAMESPACE::Exception::ParticipantNotFoundException: - DBG(F("*** ParticipantNotFoundException")); + DBG(F("*** ParticipantNotFoundException"), value); break; case APPLEMIDI_NAMESPACE::Exception::ListenerTimeOutException: DBG(F("*** ListenerTimeOutException")); @@ -104,6 +110,12 @@ void OnAppleMidiError(const APPLEMIDI_NAMESPACE::ssrc_t& ssrc, int32_t err) { case APPLEMIDI_NAMESPACE::Exception::NoResponseFromConnectionRequestException: DBG(F("***:yyy did't respond to the connection request. Check the address and port, and any firewall or router settings. (time)")); break; + case APPLEMIDI_NAMESPACE::Exception::SendPacketsDropped: + DBG(F("*** SendPacketsDropped"), value); + break; + case APPLEMIDI_NAMESPACE::Exception::ReceivedPacketsDropped: + DBG(F("*** ReceivedPacketsDropped"), value); + break; } } diff --git a/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino b/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino index 11d793a..fc2b413 100644 --- a/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino +++ b/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino @@ -38,9 +38,6 @@ void setup() isConnected = false; DBG(F("Disconnected")); }); - AppleMIDI.setHandleError([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, int32_t e) { - DBG(F("______________Error"), e); - }); AppleMIDI.setHandleException([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const APPLEMIDI_NAMESPACE::Exception & e, const int32_t value) { DBG(F("______________Exception"), e, value); }); diff --git a/keywords.txt b/keywords.txt index f8577b8..aa7c88f 100644 --- a/keywords.txt +++ b/keywords.txt @@ -13,7 +13,6 @@ AppleMidi KEYWORD1 setHandleConnected KEYWORD2 setHandleDisconnected KEYWORD2 -setHandleError KEYWORD2 setHandleException KEYWORD2 setHandleStartReceivedMidi KEYWORD2 setHandleReceivedMidi KEYWORD2 diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index 6876d50..a6078f8 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -55,7 +55,6 @@ class AppleMIDISession void setHandleConnected(void (*fptr)(const ssrc_t&, const char*)) { _connectedCallback = fptr; } void setHandleDisconnected(void (*fptr)(const ssrc_t&)) { _disconnectedCallback = fptr; } - void setHandleError(void (*fptr)(const ssrc_t&, int32_t)) __attribute__ ((deprecated)) { _errorCallback = fptr; } // deprecated void setHandleException(void (*fptr)(const ssrc_t&, const Exception&, const int32_t value)) { _exceptionCallback = fptr; } void setHandleReceivedRtp(void (*fptr)(const ssrc_t&, const Rtp_t&, const int32_t&)) { _receivedRtpCallback = fptr; } void setHandleStartReceivedMidi(void (*fptr)(const ssrc_t&)) { _startReceivedMidiByteCallback = fptr; } @@ -151,8 +150,8 @@ class AppleMIDISession } else { - if (NULL != _errorCallback) - _errorCallback(ssrc, BufferFullException); + if (NULL != _exceptionCallback) + _exceptionCallback(ssrc, BufferFullException, 0); } } @@ -210,7 +209,6 @@ class AppleMIDISession UdpClass dataPort; private: - // reading from the network RtpBuffer_t controlBuffer; RtpBuffer_t dataBuffer; @@ -225,7 +223,6 @@ class AppleMIDISession endReceivedMidiByteCallback _endReceivedMidiByteCallback = nullptr; receivedRtpCallback _receivedRtpCallback = nullptr; disconnectedCallback _disconnectedCallback = nullptr; - errorCallback _errorCallback = nullptr; exceptionCallback _exceptionCallback = nullptr; // buffer for incoming and outgoing MIDI messages diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index 0a07a53..297eaf7 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -30,8 +30,8 @@ void AppleMIDISession::parseControlPackets() auto retVal = _appleMIDIParser.parse(controlBuffer, amPortType::Control); if (retVal == parserReturn::UnexpectedData) { - if (NULL != _errorCallback) - _errorCallback(ssrc, ParseException); + if (NULL != _exceptionCallback) + _exceptionCallback(ssrc, ParseException, 0); controlBuffer.pop_front(); } @@ -81,8 +81,8 @@ void AppleMIDISession::parseDataPackets() || retVal2 == parserReturn::NotSureGiveMeMoreData) break; // one or the other buffer does not have enough data - if (NULL != _errorCallback) - _errorCallback(ssrc, UnexpectedParseException); + if (NULL != _exceptionCallback) + _exceptionCallback(ssrc, UnexpectedParseException, 0); dataBuffer.pop_front(); } @@ -114,8 +114,8 @@ void AppleMIDISession::ReceivedControlInvitation(A { writeInvitation(controlPort, controlPort.remoteIP(), controlPort.remotePort(), invitation, amInvitationRejected); - if (NULL != _errorCallback) - _errorCallback(ssrc, TooManyParticipantsException); + if (NULL != _exceptionCallback) + _exceptionCallback(ssrc, TooManyParticipantsException, 0); return; } @@ -143,8 +143,8 @@ void AppleMIDISession::ReceivedDataInvitation(Appl { writeInvitation(dataPort, dataPort.remoteIP(), dataPort.remotePort(), invitation, amInvitationRejected); - if (NULL != _errorCallback) - _errorCallback(ssrc, ParticipantNotFoundException); + if (NULL != _exceptionCallback) + _exceptionCallback(ssrc, ParticipantNotFoundException, invitation.ssrc); return; } @@ -601,8 +601,8 @@ void AppleMIDISession::manageSynchronizationListen // otherwise the responder may assume that the initiator has died and terminate the session. if (now - participant->lastSyncExchangeTime > Settings::CK_MaxTimeOut) { - if (NULL != _errorCallback) - _errorCallback(ssrc, ListenerTimeOutException); + if (NULL != _exceptionCallback) + _exceptionCallback(ssrc, ListenerTimeOutException, 0); sendEndSession(participant); @@ -667,8 +667,8 @@ void AppleMIDISession::manageSynchronizationInitia { if (participant->synchronizationCount > DefaultSettings::MaxSynchronizationCK0Attempts) { - if (NULL != _errorCallback) - _errorCallback(ssrc, MaxAttemptsException); + if (NULL != _exceptionCallback) + _exceptionCallback(ssrc, MaxAttemptsException, 0); // After too many attempts, stop. sendEndSession(participant); @@ -726,8 +726,8 @@ void AppleMIDISession::manageSessionInvites() { if (participant->connectionAttempts >= DefaultSettings::MaxSessionInvitesAttempts) { - if (NULL != _errorCallback) - _errorCallback(ssrc, NoResponseFromConnectionRequestException); + if (NULL != _exceptionCallback) + _exceptionCallback(ssrc, NoResponseFromConnectionRequestException, 0); // After too many attempts, stop. sendEndSession(participant); diff --git a/src/AppleMIDI_Defs.h b/src/AppleMIDI_Defs.h index 7ae69f2..18a5dd7 100644 --- a/src/AppleMIDI_Defs.h +++ b/src/AppleMIDI_Defs.h @@ -108,7 +108,6 @@ using receivedMidiByteCallback = void (*)(const ssrc_t&, byte); using endReceivedMidiByteCallback = void (*)(const ssrc_t&); using receivedRtpCallback = void (*)(const ssrc_t&, const Rtp_t&, const int32_t&); using disconnectedCallback = void (*)(const ssrc_t&); -using errorCallback = void (*)(const ssrc_t&, int32_t); using exceptionCallback = void (*)(const ssrc_t&, const Exception&, const int32_t value); /* Signature "Magic Value" for Apple network MIDI session establishment */ From 4e5cba45f16704e3d19cf9cb01d36622c4f9dc5b Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Mon, 21 Dec 2020 23:20:05 +0100 Subject: [PATCH 05/60] NULL => nullptr --- src/AppleMIDI.h | 2 +- src/AppleMIDI.hpp | 56 +++++++++++++++++++++++------------------------ test/Arduino.h | 4 ++-- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index a6078f8..2c18d75 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -150,7 +150,7 @@ class AppleMIDISession } else { - if (NULL != _exceptionCallback) + if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, BufferFullException, 0); } } diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index 297eaf7..65d09af 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -30,7 +30,7 @@ void AppleMIDISession::parseControlPackets() auto retVal = _appleMIDIParser.parse(controlBuffer, amPortType::Control); if (retVal == parserReturn::UnexpectedData) { - if (NULL != _exceptionCallback) + if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, ParseException, 0); controlBuffer.pop_front(); @@ -81,7 +81,7 @@ void AppleMIDISession::parseDataPackets() || retVal2 == parserReturn::NotSureGiveMeMoreData) break; // one or the other buffer does not have enough data - if (NULL != _exceptionCallback) + if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, UnexpectedParseException, 0); dataBuffer.pop_front(); @@ -101,7 +101,7 @@ template void AppleMIDISession::ReceivedControlInvitation(AppleMIDI_Invitation_t &invitation) { // ignore invitation of a participant already in the participant list - if (NULL != getParticipantBySSRC(invitation.ssrc)) + if (nullptr != getParticipantBySSRC(invitation.ssrc)) return; // advertise our own session name @@ -114,7 +114,7 @@ void AppleMIDISession::ReceivedControlInvitation(A { writeInvitation(controlPort, controlPort.remoteIP(), controlPort.remotePort(), invitation, amInvitationRejected); - if (NULL != _exceptionCallback) + if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, TooManyParticipantsException, 0); return; @@ -139,11 +139,11 @@ template void AppleMIDISession::ReceivedDataInvitation(AppleMIDI_Invitation &invitation) { auto participant = getParticipantBySSRC(invitation.ssrc); - if (NULL == participant) + if (nullptr == participant) { writeInvitation(dataPort, dataPort.remoteIP(), dataPort.remotePort(), invitation, amInvitationRejected); - if (NULL != _exceptionCallback) + if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, ParticipantNotFoundException, invitation.ssrc); return; @@ -159,11 +159,11 @@ void AppleMIDISession::ReceivedDataInvitation(Appl participant->kind = Listener; // Inform that we have an established connection - if (NULL != _connectedCallback) + if (nullptr != _connectedCallback) #ifdef KEEP_SESSION_NAME _connectedCallback(ssrc_, invitation.sessionName); #else - _connectedCallback(ssrc_, NULL); + _connectedCallback(ssrc_, nullptr); #endif } @@ -185,7 +185,7 @@ template void AppleMIDISession::ReceivedControlInvitationAccepted(AppleMIDI_InvitationAccepted_t &invitationAccepted) { auto participant = this->getParticipantByInitiatorToken(invitationAccepted.initiatorToken); - if (NULL == participant) + if (nullptr == participant) { return; } @@ -204,7 +204,7 @@ template void AppleMIDISession::ReceivedDataInvitationAccepted(AppleMIDI_InvitationAccepted_t &invitationAccepted) { auto participant = this->getParticipantByInitiatorToken(invitationAccepted.initiatorToken); - if (NULL == participant) + if (nullptr == participant) { return; } @@ -257,7 +257,7 @@ template void AppleMIDISession::ReceivedSynchronization(AppleMIDI_Synchronization_t &synchronization) { auto participant = getParticipantBySSRC(synchronization.ssrc); - if (NULL == participant) + if (nullptr == participant) { return; } @@ -348,12 +348,12 @@ void AppleMIDISession::ReceivedReceiverFeedback(Ap // Here is where you would correct if packets are dropped (send them again) auto participant = getParticipantBySSRC(receiverFeedback.ssrc); - if (NULL != participant) { + if (nullptr != participant) { if (participant->sendSequenceNr != receiverFeedback.sequenceNr) { Serial.print("ERRORRORORORORORORRROROROROROROR"); - if (NULL != _exceptionCallback) + if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, SendPacketsDropped, participant->sendSequenceNr - receiverFeedback.sequenceNr); Serial.print(participant->sendSequenceNr); @@ -374,7 +374,7 @@ void AppleMIDISession::ReceivedEndSession(AppleMID participants.erase(i); - if (NULL != _disconnectedCallback) + if (nullptr != _disconnectedCallback) _disconnectedCallback(ssrc); return; @@ -388,7 +388,7 @@ Participant* AppleMIDISession::getPartic for (size_t i = 0; i < participants.size(); i++) if (ssrc == participants[i].ssrc) return &participants[i]; - return NULL; + return nullptr; } template @@ -397,7 +397,7 @@ Participant* AppleMIDISession::getPartic for (auto i = 0; i < participants.size(); i++) if (initiatorToken == participants[i].initiatorToken) return &participants[i]; - return NULL; + return nullptr; } template @@ -601,7 +601,7 @@ void AppleMIDISession::manageSynchronizationListen // otherwise the responder may assume that the initiator has died and terminate the session. if (now - participant->lastSyncExchangeTime > Settings::CK_MaxTimeOut) { - if (NULL != _exceptionCallback) + if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, ListenerTimeOutException, 0); sendEndSession(participant); @@ -667,7 +667,7 @@ void AppleMIDISession::manageSynchronizationInitia { if (participant->synchronizationCount > DefaultSettings::MaxSynchronizationCK0Attempts) { - if (NULL != _exceptionCallback) + if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, MaxAttemptsException, 0); // After too many attempts, stop. @@ -709,11 +709,11 @@ void AppleMIDISession::manageSessionInvites() if (participant->invitationStatus == DataInvitationAccepted) { // Inform that we have an established connection - if (NULL != _connectedCallback) + if (nullptr != _connectedCallback) #ifdef KEEP_SESSION_NAME _connectedCallback(participant->ssrc, participant->sessionName); #else - _connectedCallback(participant->ssrc, NULL); + _connectedCallback(participant->ssrc, nullptr); #endif participant->invitationStatus = Connected; } @@ -726,7 +726,7 @@ void AppleMIDISession::manageSessionInvites() { if (participant->connectionAttempts >= DefaultSettings::MaxSessionInvitesAttempts) { - if (NULL != _exceptionCallback) + if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, NoResponseFromConnectionRequestException, 0); // After too many attempts, stop. @@ -840,7 +840,7 @@ void AppleMIDISession::sendEndSession(Participant< endSession.ssrc = this->ssrc; writeEndSession(participant->remoteIP, participant->remotePort, endSession); - if (NULL != _disconnectedCallback) + if (nullptr != _disconnectedCallback) _disconnectedCallback(participant->ssrc); } @@ -849,7 +849,7 @@ void AppleMIDISession::ReceivedRtp(const Rtp_t& rt { auto participant = getParticipantBySSRC(rtp.ssrc); - if (NULL != participant) + if (nullptr != participant) { if (participant->doReceiverFeedback == false) participant->receiverFeedbackStartTime = now; @@ -864,7 +864,7 @@ void AppleMIDISession::ReceivedRtp(const Rtp_t& rt if (participant->receiveSequenceNr + 1 != rtp.sequenceNr) { - if (NULL != _exceptionCallback) + if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, ReceivedPacketsDropped, participant->receiveSequenceNr + 1 - rtp.sequenceNr); Serial.print("___ERROR____"); @@ -875,7 +875,7 @@ void AppleMIDISession::ReceivedRtp(const Rtp_t& rt participant->receiveSequenceNr = rtp.sequenceNr; - if (NULL != _receivedRtpCallback) + if (nullptr != _receivedRtpCallback) _receivedRtpCallback(0, rtp, latency); } else @@ -887,14 +887,14 @@ void AppleMIDISession::ReceivedRtp(const Rtp_t& rt template void AppleMIDISession::StartReceivedMidi() { - if (NULL != _startReceivedMidiByteCallback) + if (nullptr != _startReceivedMidiByteCallback) _startReceivedMidiByteCallback(0); } template void AppleMIDISession::ReceivedMidi(byte value) { - if (NULL != _receivedMidiByteCallback) + if (nullptr != _receivedMidiByteCallback) _receivedMidiByteCallback(0, value); inMidiBuffer.push_back(value); @@ -903,7 +903,7 @@ void AppleMIDISession::ReceivedMidi(byte value) template void AppleMIDISession::EndReceivedMidi() { - if (NULL != _endReceivedMidiByteCallback) + if (nullptr != _endReceivedMidiByteCallback) _endReceivedMidiByteCallback(0); } diff --git a/test/Arduino.h b/test/Arduino.h index afb5e0d..ccacad5 100644 --- a/test/Arduino.h +++ b/test/Arduino.h @@ -19,7 +19,7 @@ class _serial void print(long a, int format = DEC) { std::cout << (format == DEC ? std::dec : std::hex) << a; }; void print(unsigned long a, int format = DEC) { std::cout << (format == DEC ? std::dec : std::hex) << a; }; void print(double a, int = 2) { std::cout << a; }; - void print(struct tm * timeinfo, const char * format = NULL) {}; + void print(struct tm * timeinfo, const char * format = nullptr) {}; void print(IPAddress) {}; void println(const char a[]) { std::cout << a << "\n"; }; @@ -30,7 +30,7 @@ class _serial void println(long a, int format = DEC) { std::cout << (format == DEC ? std::dec : std::hex) << a << "\n"; }; void println(unsigned long a, int format = DEC) { std::cout << (format == DEC ? std::dec : std::hex) << a << "\n"; }; void println(double a, int format = 2) { std::cout << a << "\n"; }; - void println(struct tm * timeinfo, const char * format = NULL) {}; + void println(struct tm * timeinfo, const char * format = nullptr) {}; void println(IPAddress) {}; void println(void) { std::cout << "\n"; }; }; From a7917d163e262a2b9672df8bdb55489f5da33938 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Mon, 21 Dec 2020 23:20:18 +0100 Subject: [PATCH 06/60] Update library.properties prep v3 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index add0477..dc7f7f3 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AppleMIDI -version=2.2.0 +version=3.0.0 author=lathoub maintainer=lathoub sentence=AppleMIDI (aka rtpMIDI) MIDI I/Os for Arduino From 80624d7c98b45eb7a6b55c11181762d8bffdfedd Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Mon, 21 Dec 2020 23:27:03 +0100 Subject: [PATCH 07/60] Update ESP32_Callbacks.ino cleanup --- examples/ESP32_Callbacks/ESP32_Callbacks.ino | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/examples/ESP32_Callbacks/ESP32_Callbacks.ino b/examples/ESP32_Callbacks/ESP32_Callbacks.ino index 30718da..241f388 100644 --- a/examples/ESP32_Callbacks/ESP32_Callbacks.ino +++ b/examples/ESP32_Callbacks/ESP32_Callbacks.ino @@ -64,22 +64,6 @@ void loop() { MIDI.read(); } -// ----------------------------------------------------------------------------- -// -// ----------------------------------------------------------------------------- -void OnAppleMidiConnected(const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { - isConnected = true; - DBG(F("Connected to session"), name); -} - -// ----------------------------------------------------------------------------- -// -// ----------------------------------------------------------------------------- -void OnAppleMidiDisconnected(const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; -DBG(F("Disconnected")); -} - // ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- From 38a07cb0fadfd16caed9441ab03b28a90cd8c48a Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 22 Dec 2020 00:29:21 +0100 Subject: [PATCH 08/60] advance callbacks, added sendRtp --- examples/ESP32_Callbacks/ESP32_Callbacks.ino | 24 +++++++++++++++++++- keywords.txt | 1 + src/AppleMIDI.h | 4 +++- src/AppleMIDI.hpp | 11 ++++++--- src/AppleMIDI_Defs.h | 3 ++- 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/examples/ESP32_Callbacks/ESP32_Callbacks.ino b/examples/ESP32_Callbacks/ESP32_Callbacks.ino index 241f388..a0b6e25 100644 --- a/examples/ESP32_Callbacks/ESP32_Callbacks.ino +++ b/examples/ESP32_Callbacks/ESP32_Callbacks.ino @@ -1,4 +1,5 @@ #include +#include #define SerialMon Serial #define APPLEMIDI_DEBUG SerialMon @@ -21,6 +22,8 @@ void setup() { } DBG("Connected to network"); + MDNS.begin(AppleMIDI.getName()); + DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); DBG(F("Add device named Arduino with Host"), WiFi.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); DBG(F("Select and then press the Connect button")); @@ -34,6 +37,23 @@ void setup() { isConnected = false; DBG(F("Disconnected")); }); + + AppleMIDI.setHandleSendRtp([](const APPLEMIDI_NAMESPACE::Rtp_t& rtp) { + DBG(F("setHandleSendRtp"), rtp.sequenceNr); + }); + AppleMIDI.setHandleReceivedRtp([](const APPLEMIDI_NAMESPACE::Rtp_t& rtp, const int32_t& latency) { + DBG(F("setHandleReceivedRtp"), rtp.sequenceNr ,latency); + }); + AppleMIDI.setHandleStartReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t&) { + DBG(F("setHandleStartReceivedMidi")); + }); + AppleMIDI.setHandleReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t&, byte value) { + DBG(F("setHandleReceivedMidi"), value); + }); + AppleMIDI.setHandleEndReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t&) { + DBG(F("setHandleEndReceivedMidi")); + }); + AppleMIDI.setHandleException(OnAppleMidiException); MIDI.begin(); @@ -57,6 +77,8 @@ void setup() { MIDI.setHandleActiveSensing(OnActiveSensing); MIDI.setHandleSystemReset(OnSystemReset); + MDNS.addService("apple-midi", "udp", AppleMIDI.getPort()); + DBG(F("Ready")); } @@ -151,7 +173,7 @@ static void OnSongPosition(unsigned beats) { } static void OnSongSelect(byte songNumber) { - DBG(F("SongSelect"),songNumber); + DBG(F("SongSelect"), songNumber); } static void OnTuneRequest() { diff --git a/keywords.txt b/keywords.txt index aa7c88f..f25cf1d 100644 --- a/keywords.txt +++ b/keywords.txt @@ -18,6 +18,7 @@ setHandleStartReceivedMidi KEYWORD2 setHandleReceivedMidi KEYWORD2 setHandleEndReceivedMidi KEYWORD2 setHandleReceivedRtp KEYWORD2 +setHandleSendRtp KEYWORD2 ####################################### # Instances (KEYWORD3) diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index 2c18d75..0fee8f4 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -56,10 +56,11 @@ class AppleMIDISession void setHandleConnected(void (*fptr)(const ssrc_t&, const char*)) { _connectedCallback = fptr; } void setHandleDisconnected(void (*fptr)(const ssrc_t&)) { _disconnectedCallback = fptr; } void setHandleException(void (*fptr)(const ssrc_t&, const Exception&, const int32_t value)) { _exceptionCallback = fptr; } - void setHandleReceivedRtp(void (*fptr)(const ssrc_t&, const Rtp_t&, const int32_t&)) { _receivedRtpCallback = fptr; } + void setHandleReceivedRtp(void (*fptr)(const Rtp_t&, const int32_t&)) { _receivedRtpCallback = fptr; } void setHandleStartReceivedMidi(void (*fptr)(const ssrc_t&)) { _startReceivedMidiByteCallback = fptr; } void setHandleReceivedMidi(void (*fptr)(const ssrc_t&, byte)) { _receivedMidiByteCallback = fptr; } void setHandleEndReceivedMidi(void (*fptr)(const ssrc_t&)) { _endReceivedMidiByteCallback = fptr; } + void setHandleSendRtp(void (*fptr)(const Rtp_t&)) { _sendRtpCallback = fptr; } const char* getName() { return this->localName; }; const uint16_t getPort() { return this->port; }; @@ -224,6 +225,7 @@ class AppleMIDISession receivedRtpCallback _receivedRtpCallback = nullptr; disconnectedCallback _disconnectedCallback = nullptr; exceptionCallback _exceptionCallback = nullptr; + sendRtpCallback _sendRtpCallback = nullptr; // buffer for incoming and outgoing MIDI messages MidiBuffer_t inMidiBuffer; diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index 65d09af..64ac286 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -501,7 +501,6 @@ void AppleMIDISession::writeRtpMidiBuffer(Particip rtp.vpxcc = 0b10000000; // TODO: fun with flags rtp.mpayload = PAYLOADTYPE_RTPMIDI; // TODO: set or unset marker rtp.ssrc = ssrc; - rtp.ssrc = htonl(rtp.ssrc); // https://developer.apple.com/library/ios/documentation/CoreMidi/Reference/MIDIServices_Reference/#//apple_ref/doc/uid/TP40010316-CHMIDIServiceshFunctions-SW30 // The time at which the events occurred, if receiving MIDI, or, if sending MIDI, @@ -519,10 +518,15 @@ void AppleMIDISession::writeRtpMidiBuffer(Particip // rtp.timestamp = (Settings::TimestampRtpPackets) ? htonl(rtpMidiClock.Now()) : 0; - // increament the sequenceNr + // increment the sequenceNr participant->sendSequenceNr++; rtp.sequenceNr = participant->sendSequenceNr; + + if (_sendRtpCallback) + _sendRtpCallback(rtp); + + rtp.ssrc = htonl(rtp.ssrc); rtp.sequenceNr = htons(rtp.sequenceNr); dataPort.write((uint8_t *)&rtp, sizeof(rtp)); @@ -560,6 +564,7 @@ void AppleMIDISession::writeRtpMidiBuffer(Particip dataPort.endPacket(); dataPort.flush(); + } // @@ -876,7 +881,7 @@ void AppleMIDISession::ReceivedRtp(const Rtp_t& rt participant->receiveSequenceNr = rtp.sequenceNr; if (nullptr != _receivedRtpCallback) - _receivedRtpCallback(0, rtp, latency); + _receivedRtpCallback(rtp, latency); } else { diff --git a/src/AppleMIDI_Defs.h b/src/AppleMIDI_Defs.h index 18a5dd7..db4a749 100644 --- a/src/AppleMIDI_Defs.h +++ b/src/AppleMIDI_Defs.h @@ -106,9 +106,10 @@ using connectedCallback = void (*)(const ssrc_t&, const char *); using startReceivedMidiByteCallback = void (*)(const ssrc_t&); using receivedMidiByteCallback = void (*)(const ssrc_t&, byte); using endReceivedMidiByteCallback = void (*)(const ssrc_t&); -using receivedRtpCallback = void (*)(const ssrc_t&, const Rtp_t&, const int32_t&); +using receivedRtpCallback = void (*)(const Rtp_t&, const int32_t&); using disconnectedCallback = void (*)(const ssrc_t&); using exceptionCallback = void (*)(const ssrc_t&, const Exception&, const int32_t value); +using sendRtpCallback = void (*)(const Rtp_t&); /* Signature "Magic Value" for Apple network MIDI session establishment */ const byte amSignature[] = {0xff, 0xff}; From 4120625540af35caf74745e2bc8fcd268fed0b5a Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 22 Dec 2020 11:21:36 +0100 Subject: [PATCH 09/60] extented callbacks now optional to save weight --- .../EthernetShield_Callbacks.ino | 82 ++++++++++++++++++ src/AppleMIDI.h | 17 ++-- src/AppleMIDI.hpp | 83 ++++++++++--------- src/AppleMIDI_Defs.h | 19 +++-- src/AppleMIDI_Parser.h | 9 +- 5 files changed, 155 insertions(+), 55 deletions(-) create mode 100644 examples/EthernetShield_Callbacks/EthernetShield_Callbacks.ino diff --git a/examples/EthernetShield_Callbacks/EthernetShield_Callbacks.ino b/examples/EthernetShield_Callbacks/EthernetShield_Callbacks.ino new file mode 100644 index 0000000..e32e513 --- /dev/null +++ b/examples/EthernetShield_Callbacks/EthernetShield_Callbacks.ino @@ -0,0 +1,82 @@ +#include + +#define DISCARD_SESSION_NAME +#define NO_LATENCY_CALCULATION +#define NO_EXT_CALLBACKS +#define SerialMon Serial +#define APPLEMIDI_DEBUG SerialMon +#include + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; + +unsigned long t1 = millis(); +bool isConnected = false; + +APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +void setup() +{ + DBG_SETUP(115200); + DBG("Booting"); + + if (Ethernet.begin(mac) == 0) { + DBG(F("Failed DHCP, check network cable & reboot")); + for (;;); + } + + DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); + DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); + DBG(F("Select and then press the Connect button")); + DBG(F("Then open a MIDI listener and monitor incoming notes")); + + MIDI.begin(); + + // Stay informed on connection status + AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { + isConnected = true; + DBG(F("Connected to session"), name); + }); + AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { + isConnected = false; + DBG(F("Disconnected")); + }); + + MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { + DBG(F("NoteOn"), note); + }); + MIDI.setHandleNoteOff([](byte channel, byte note, byte velocity) { + DBG(F("NoteOff"), note); + }); + + DBG(F("Sending MIDI messages every second")); +} + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +void loop() +{ + // Listen to incoming notes + MIDI.read(); + + // send a note every second + // (dont cáll delay(1000) as it will stall the pipeline) + if (isConnected && (millis() - t1) > 1000) + { + t1 = millis(); + + byte note = random(1, 127); + byte velocity = 55; + byte channel = 1; + + MIDI.sendNoteOn(note, velocity, channel); +// MIDI.sendNoteOff(note, velocity, channel); + } +} diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index 0fee8f4..2d1a477 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -55,12 +55,14 @@ class AppleMIDISession void setHandleConnected(void (*fptr)(const ssrc_t&, const char*)) { _connectedCallback = fptr; } void setHandleDisconnected(void (*fptr)(const ssrc_t&)) { _disconnectedCallback = fptr; } - void setHandleException(void (*fptr)(const ssrc_t&, const Exception&, const int32_t value)) { _exceptionCallback = fptr; } +#ifdef USE_EXT_CALLBACKS + void setHandleException(void (*fptr)(const ssrc_t&, const Exception&, const int32_t value)) { _exceptionCallback = fptr; } void setHandleReceivedRtp(void (*fptr)(const Rtp_t&, const int32_t&)) { _receivedRtpCallback = fptr; } void setHandleStartReceivedMidi(void (*fptr)(const ssrc_t&)) { _startReceivedMidiByteCallback = fptr; } void setHandleReceivedMidi(void (*fptr)(const ssrc_t&, byte)) { _receivedMidiByteCallback = fptr; } void setHandleEndReceivedMidi(void (*fptr)(const ssrc_t&)) { _endReceivedMidiByteCallback = fptr; } void setHandleSendRtp(void (*fptr)(const Rtp_t&)) { _sendRtpCallback = fptr; } +#endif const char* getName() { return this->localName; }; const uint16_t getPort() { return this->port; }; @@ -74,6 +76,7 @@ class AppleMIDISession void sendEndSession(); public: + // Override default thruActivated static const bool thruActivated = false; void begin() @@ -91,7 +94,6 @@ class AppleMIDISession // this is our SSRC // // NOTE: Arduino random only goes to INT32_MAX (not UINT32_MAX) - this->ssrc = random(1, INT32_MAX) * 2; controlPort.begin(port); @@ -151,8 +153,10 @@ class AppleMIDISession } else { +#ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, BufferFullException, 0); +#endif } } @@ -219,14 +223,15 @@ class AppleMIDISession rtpMIDIParser _rtpMIDIParser; connectedCallback _connectedCallback = nullptr; + disconnectedCallback _disconnectedCallback = nullptr; +#ifdef USE_EXT_CALLBACKS startReceivedMidiByteCallback _startReceivedMidiByteCallback = nullptr; receivedMidiByteCallback _receivedMidiByteCallback = nullptr; endReceivedMidiByteCallback _endReceivedMidiByteCallback = nullptr; receivedRtpCallback _receivedRtpCallback = nullptr; - disconnectedCallback _disconnectedCallback = nullptr; - exceptionCallback _exceptionCallback = nullptr; sendRtpCallback _sendRtpCallback = nullptr; - + exceptionCallback _exceptionCallback = nullptr; +#endif // buffer for incoming and outgoing MIDI messages MidiBuffer_t inMidiBuffer; MidiBuffer_t outMidiBuffer; @@ -237,7 +242,7 @@ class AppleMIDISession char localName[DefaultSettings::MaxSessionNameLen + 1]; uint16_t port = DEFAULT_CONTROL_PORT; Deque, Settings::MaxNumberOfParticipants> participants; - int32_t latencyAdjustment = 0; +// int32_t latencyAdjustment = 0; // not used private: void readControlPackets(); diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index 64ac286..a172dca 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -30,9 +30,10 @@ void AppleMIDISession::parseControlPackets() auto retVal = _appleMIDIParser.parse(controlBuffer, amPortType::Control); if (retVal == parserReturn::UnexpectedData) { +#ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, ParseException, 0); - +#endif controlBuffer.pop_front(); } } @@ -81,9 +82,10 @@ void AppleMIDISession::parseDataPackets() || retVal2 == parserReturn::NotSureGiveMeMoreData) break; // one or the other buffer does not have enough data +#ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, UnexpectedParseException, 0); - +#endif dataBuffer.pop_front(); } } @@ -114,9 +116,10 @@ void AppleMIDISession::ReceivedControlInvitation(A { writeInvitation(controlPort, controlPort.remoteIP(), controlPort.remotePort(), invitation, amInvitationRejected); +#ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, TooManyParticipantsException, 0); - +#endif return; } @@ -143,9 +146,10 @@ void AppleMIDISession::ReceivedDataInvitation(Appl { writeInvitation(dataPort, dataPort.remoteIP(), dataPort.remotePort(), invitation, amInvitationRejected); +#ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, ParticipantNotFoundException, invitation.ssrc); - +#endif return; } @@ -259,6 +263,11 @@ void AppleMIDISession::ReceivedSynchronization(App auto participant = getParticipantBySSRC(synchronization.ssrc); if (nullptr == participant) { +#ifdef USE_EXT_CALLBACKS + if (nullptr != _exceptionCallback) + _exceptionCallback(ssrc, ParticipantNotFoundException, synchronization.ssrc); +#endif + return; } @@ -313,19 +322,6 @@ void AppleMIDISession::ReceivedSynchronization(App #ifdef LATENCY_CALCULATION // each party can estimate the offset between the two clocks using the following formula participant->offsetEstimate = (uint32_t)(((synchronization.timestamps[2] + synchronization.timestamps[0]) / 2) - synchronization.timestamps[1]); -/* - uint64_t remoteAverage = ((synchronization.timestamps[2] + synchronization.timestamps[0]) / 2); - uint64_t localAverage = synchronization.timestamps[1]; - - static uint64_t oldRemoteAverage = 0; - static uint64_t oldLocalAverage = 0; - - uint64_t r = (remoteAverage - oldRemoteAverage); - uint64_t l = (localAverage - oldLocalAverage); - - oldRemoteAverage = remoteAverage; - oldLocalAverage = localAverage; -*/ #endif break; } @@ -348,18 +344,20 @@ void AppleMIDISession::ReceivedReceiverFeedback(Ap // Here is where you would correct if packets are dropped (send them again) auto participant = getParticipantBySSRC(receiverFeedback.ssrc); - if (nullptr != participant) { - if (participant->sendSequenceNr != receiverFeedback.sequenceNr) - { - Serial.print("ERRORRORORORORORORRROROROROROROR"); - - if (nullptr != _exceptionCallback) - _exceptionCallback(ssrc, SendPacketsDropped, participant->sendSequenceNr - receiverFeedback.sequenceNr); + if (nullptr == participant) { +#ifdef USE_EXT_CALLBACKS + if (nullptr != _exceptionCallback) + _exceptionCallback(ssrc, ParticipantNotFoundException, receiverFeedback.ssrc); +#endif + return; + } - Serial.print(participant->sendSequenceNr); - Serial.print(" "); - Serial.println(receiverFeedback.sequenceNr); - } + if (participant->sendSequenceNr != receiverFeedback.sequenceNr) + { +#ifdef USE_EXT_CALLBACKS + if (nullptr != _exceptionCallback) + _exceptionCallback(ssrc, SendPacketsDropped, participant->sendSequenceNr - receiverFeedback.sequenceNr); +#endif } } @@ -516,16 +514,19 @@ void AppleMIDISession::writeRtpMidiBuffer(Particip // have an option to not transmit messages with future timestamps, to accommodate hardware not // prepared to defer rendering the messages until the proper time.) // - rtp.timestamp = (Settings::TimestampRtpPackets) ? htonl(rtpMidiClock.Now()) : 0; + rtp.timestamp = (Settings::TimestampRtpPackets) ? rtpMidiClock.Now() : 0; // increment the sequenceNr participant->sendSequenceNr++; rtp.sequenceNr = participant->sendSequenceNr; +#ifdef USE_EXT_CALLBACKS if (_sendRtpCallback) _sendRtpCallback(rtp); +#endif + rtp.timestamp = htonl(rtp.timestamp); rtp.ssrc = htonl(rtp.ssrc); rtp.sequenceNr = htons(rtp.sequenceNr); @@ -606,9 +607,10 @@ void AppleMIDISession::manageSynchronizationListen // otherwise the responder may assume that the initiator has died and terminate the session. if (now - participant->lastSyncExchangeTime > Settings::CK_MaxTimeOut) { +#ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, ListenerTimeOutException, 0); - +#endif sendEndSession(participant); participants.erase(i); @@ -672,9 +674,10 @@ void AppleMIDISession::manageSynchronizationInitia { if (participant->synchronizationCount > DefaultSettings::MaxSynchronizationCK0Attempts) { +#ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, MaxAttemptsException, 0); - +#endif // After too many attempts, stop. sendEndSession(participant); @@ -731,9 +734,10 @@ void AppleMIDISession::manageSessionInvites() { if (participant->connectionAttempts >= DefaultSettings::MaxSessionInvitesAttempts) { +#ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, NoResponseFromConnectionRequestException, 0); - +#endif // After too many attempts, stop. sendEndSession(participant); @@ -869,19 +873,18 @@ void AppleMIDISession::ReceivedRtp(const Rtp_t& rt if (participant->receiveSequenceNr + 1 != rtp.sequenceNr) { +#ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, ReceivedPacketsDropped, participant->receiveSequenceNr + 1 - rtp.sequenceNr); - - Serial.print("___ERROR____"); - Serial.print(participant->receiveSequenceNr); - Serial.print(" "); - Serial.println(rtp.sequenceNr); +#endif } participant->receiveSequenceNr = rtp.sequenceNr; +#ifdef USE_EXT_CALLBACKS if (nullptr != _receivedRtpCallback) _receivedRtpCallback(rtp, latency); +#endif } else { @@ -892,15 +895,19 @@ void AppleMIDISession::ReceivedRtp(const Rtp_t& rt template void AppleMIDISession::StartReceivedMidi() { +#ifdef USE_EXT_CALLBACKS if (nullptr != _startReceivedMidiByteCallback) _startReceivedMidiByteCallback(0); +#endif } template void AppleMIDISession::ReceivedMidi(byte value) { +#ifdef USE_EXT_CALLBACKS if (nullptr != _receivedMidiByteCallback) _receivedMidiByteCallback(0, value); +#endif inMidiBuffer.push_back(value); } @@ -908,8 +915,10 @@ void AppleMIDISession::ReceivedMidi(byte value) template void AppleMIDISession::EndReceivedMidi() { +#ifdef USE_EXT_CALLBACKS if (nullptr != _endReceivedMidiByteCallback) _endReceivedMidiByteCallback(0); +#endif } END_APPLEMIDI_NAMESPACE diff --git a/src/AppleMIDI_Defs.h b/src/AppleMIDI_Defs.h index db4a749..ae88f68 100644 --- a/src/AppleMIDI_Defs.h +++ b/src/AppleMIDI_Defs.h @@ -5,9 +5,9 @@ BEGIN_APPLEMIDI_NAMESPACE -#define APPLEMIDI_LIBRARY_VERSION 0x020100 -#define APPLEMIDI_LIBRARY_VERSION_MAJOR 2 -#define APPLEMIDI_LIBRARY_VERSION_MINOR 2 +#define APPLEMIDI_LIBRARY_VERSION 0x030000 +#define APPLEMIDI_LIBRARY_VERSION_MAJOR 3 +#define APPLEMIDI_LIBRARY_VERSION_MINOR 0 #define APPLEMIDI_LIBRARY_VERSION_PATCH 0 #define DEFAULT_CONTROL_PORT 5004 @@ -40,9 +40,16 @@ typedef const char* AppleMIDIConstStr; #define RtpBuffer_t Deque #define MidiBuffer_t Deque -#define APPLEMIDI_LISTENER +// Way to reduce memory usage, by giving up functionality +#ifndef DISCARD_SESSION_NAME #define KEEP_SESSION_NAME +#endif +#ifndef NO_LATENCY_CALCULATION #define LATENCY_CALCULATION +#endif +#ifndef NO_EXT_CALLBACKS +#define USE_EXT_CALLBACKS +#endif #define MIDI_SAMPLING_RATE_176K4HZ 176400 #define MIDI_SAMPLING_RATE_192KHZ 192000 @@ -103,13 +110,15 @@ enum Exception : uint8_t }; using connectedCallback = void (*)(const ssrc_t&, const char *); +using disconnectedCallback = void (*)(const ssrc_t&); +#ifdef USE_EXT_CALLBACKS using startReceivedMidiByteCallback = void (*)(const ssrc_t&); using receivedMidiByteCallback = void (*)(const ssrc_t&, byte); using endReceivedMidiByteCallback = void (*)(const ssrc_t&); using receivedRtpCallback = void (*)(const Rtp_t&, const int32_t&); -using disconnectedCallback = void (*)(const ssrc_t&); using exceptionCallback = void (*)(const ssrc_t&, const Exception&, const int32_t value); using sendRtpCallback = void (*)(const Rtp_t&); +#endif /* Signature "Magic Value" for Apple network MIDI session establishment */ const byte amSignature[] = {0xff, 0xff}; diff --git a/src/AppleMIDI_Parser.h b/src/AppleMIDI_Parser.h index cf5e9b0..74fbe8d 100644 --- a/src/AppleMIDI_Parser.h +++ b/src/AppleMIDI_Parser.h @@ -40,11 +40,7 @@ class AppleMIDIParser command[0] = buffer[i++]; command[1] = buffer[i++]; - if (false) - { - } -#ifdef APPLEMIDI_LISTENER - else if (0 == memcmp(command, amInvitation, sizeof(amInvitation))) + if (0 == memcmp(command, amInvitation, sizeof(amInvitation))) { byte protocolVersion[4]; @@ -232,7 +228,6 @@ class AppleMIDIParser return parserReturn::Processed; } -#endif #ifdef APPLEMIDI_INITIATOR else if (0 == memcmp(command, amInvitationAccepted, sizeof(amInvitationAccepted))) { @@ -270,7 +265,7 @@ class AppleMIDIParser cb.buffer[3] = buffer[i++]; invitationAccepted.ssrc = ntohl(cb.value32); - #ifdef KEEP_SESSION_NAME +#ifdef KEEP_SESSION_NAME uint16_t bi = 0; while ((i < buffer.size()) && (buffer[i] != 0x00)) { From 7bf2d0dd0ac84dd8b630efbc2f6194ebfffcc2dd Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 22 Dec 2020 11:36:35 +0100 Subject: [PATCH 10/60] minimum memory usage example --- .../EthernetShield_Callbacks.ino | 2 +- .../EthernetShield_MinMemUsage.ino | 65 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 examples/EthernetShield_MinMemUsage/EthernetShield_MinMemUsage.ino diff --git a/examples/EthernetShield_Callbacks/EthernetShield_Callbacks.ino b/examples/EthernetShield_Callbacks/EthernetShield_Callbacks.ino index e32e513..1ee20ae 100644 --- a/examples/EthernetShield_Callbacks/EthernetShield_Callbacks.ino +++ b/examples/EthernetShield_Callbacks/EthernetShield_Callbacks.ino @@ -34,7 +34,7 @@ void setup() DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); DBG(F("Select and then press the Connect button")); - DBG(F("Then open a MIDI listener and monitor incoming notes")); + DBG(F("Then open a MIDI listener and monitor incoming notes"));+- MIDI.begin(); diff --git a/examples/EthernetShield_MinMemUsage/EthernetShield_MinMemUsage.ino b/examples/EthernetShield_MinMemUsage/EthernetShield_MinMemUsage.ino new file mode 100644 index 0000000..c2d8db5 --- /dev/null +++ b/examples/EthernetShield_MinMemUsage/EthernetShield_MinMemUsage.ino @@ -0,0 +1,65 @@ +#include + +#define DISCARD_SESSION_NAME +#define NO_LATENCY_CALCULATION +#define NO_EXT_CALLBACKS +#include + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; + +unsigned long t1 = millis(); +bool isConnected = false; + +APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +void setup() +{ + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LOW); + + if (Ethernet.begin(mac) == 0) for (;;); + + MIDI.begin(); + + // Stay informed on connection status + AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char*) { + isConnected = true; + digitalWrite(LED_BUILTIN, HIGH); + }); + AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { + isConnected = false; + digitalWrite(LED_BUILTIN, LOW); + }); + + MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { + digitalWrite(LED_BUILTIN, LOW); + }); + MIDI.setHandleNoteOff([](byte channel, byte note, byte velocity) { + digitalWrite(LED_BUILTIN, HIGH); + }); +} + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +void loop() +{ + // Listen to incoming notes + MIDI.read(); + + // send a note every second + // (dont cáll delay(1000) as it will stall the pipeline) + if (isConnected && (millis() - t1) > 1000) + { + t1 = millis(); + + MIDI.sendNoteOn(54, 100, 1); + } +} From 397eab2afb74b1b1e224b3188e43616cee07eb6a Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 22 Dec 2020 23:05:37 +0100 Subject: [PATCH 11/60] renamed EthernetShield to AVR for AVR type Arduino's --- examples/AVR_Callbacks/AVR_Callbacks.ino | 134 ++++++++++++++++++ .../AVR_Initiator.ino} | 0 .../AVR_MinMemUsage.ino} | 0 .../AVR_MultipleSessions.ino} | 0 .../AVR_NonDefaultSession.ino} | 0 .../AVR_NoteOnOffEverySec.ino} | 0 .../AVR_ReceivedRawMidiData.ino} | 0 .../AVR_SysEx.ino} | 0 .../EthernetShield_Callbacks.ino | 82 ----------- .../SAMD_Bonjour.ino} | 0 10 files changed, 134 insertions(+), 82 deletions(-) create mode 100644 examples/AVR_Callbacks/AVR_Callbacks.ino rename examples/{EthernetShield_Initiator/EthernetShield_Initiator.ino => AVR_Initiator/AVR_Initiator.ino} (100%) rename examples/{EthernetShield_MinMemUsage/EthernetShield_MinMemUsage.ino => AVR_MinMemUsage/AVR_MinMemUsage.ino} (100%) rename examples/{EthernetShield_MultipleSessions/EthernetShield_MultipleSessions.ino => AVR_MultipleSessions/AVR_MultipleSessions.ino} (100%) rename examples/{EthernetShield_NonDefaultSession/EthernetShield_NonDefaultSession.ino => AVR_NonDefaultSession/AVR_NonDefaultSession.ino} (100%) rename examples/{EthernetShield_NoteOnOffEverySec/EthernetShield_NoteOnOffEverySec.ino => AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino} (100%) rename examples/{EthernetShield_ReceivedRawMidiData/EthernetShield_ReceivedRawMidiData.ino => AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino} (100%) rename examples/{EthernetShield_SysEx/EthernetShield_SysEx.ino => AVR_SysEx/AVR_SysEx.ino} (100%) delete mode 100644 examples/EthernetShield_Callbacks/EthernetShield_Callbacks.ino rename examples/{MKR_ETH_Bonjour/MKR_ETH_Bonjour.ino => SAMD_Bonjour/SAMD_Bonjour.ino} (100%) diff --git a/examples/AVR_Callbacks/AVR_Callbacks.ino b/examples/AVR_Callbacks/AVR_Callbacks.ino new file mode 100644 index 0000000..21e7fce --- /dev/null +++ b/examples/AVR_Callbacks/AVR_Callbacks.ino @@ -0,0 +1,134 @@ +#include + +#include + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; + +unsigned long t1 = millis(); +bool isConnected = false; + +APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +void setup() +{ + DBG_SETUP(115200); + DBG("Booting"); + + if (Ethernet.begin(mac) == 0) { + DBG(F("Failed DHCP, check network cable & reboot")); + for (;;); + } + + DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); + DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); + DBG(F("Select and then press the Connect button")); + DBG(F("Then open a MIDI listener and monitor incoming notes")); + + MIDI.begin(); + + // Stay informed on connection status + AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { + isConnected = true; + DBG(F("Connected to session"), name); + }); + AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { + isConnected = false; + DBG(F("Disconnected")); + }); + + AppleMIDI.setHandleSendRtp([](const APPLEMIDI_NAMESPACE::Rtp_t & rtp) { + DBG(F("setHandleSendRtp"), rtp.sequenceNr); + }); + AppleMIDI.setHandleReceivedRtp([](const APPLEMIDI_NAMESPACE::Rtp_t & rtp, const int32_t& latency) { + DBG(F("setHandleReceivedRtp"), rtp.sequenceNr , latency); + }); + AppleMIDI.setHandleStartReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t&) { + DBG(F("setHandleStartReceivedMidi")); + }); + AppleMIDI.setHandleReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t&, byte value) { + DBG(F("setHandleReceivedMidi"), value); + }); + AppleMIDI.setHandleEndReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t&) { + DBG(F("setHandleEndReceivedMidi")); + }); + + AppleMIDI.setHandleException(OnAppleMidiException); + + MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { + DBG(F("NoteOn"), note); + }); + MIDI.setHandleNoteOff([](byte channel, byte note, byte velocity) { + DBG(F("NoteOff"), note); + }); + + DBG(F("Sending MIDI messages every second")); +} + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +void loop() +{ + // Listen to incoming notes + MIDI.read(); + + // send a note every second + // (dont cáll delay(1000) as it will stall the pipeline) + if (isConnected && (millis() - t1) > 1000) + { + t1 = millis(); + + byte note = random(1, 127); + byte velocity = 55; + byte channel = 1; + + MIDI.sendNoteOn(note, velocity, channel); + // MIDI.sendNoteOff(note, velocity, channel); + } +} + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +void OnAppleMidiException(const APPLEMIDI_NAMESPACE::ssrc_t& ssrc, const APPLEMIDI_NAMESPACE::Exception& e, const int32_t value ) { + switch (e) + { + case APPLEMIDI_NAMESPACE::Exception::BufferFullException: + DBG(F("*** BufferFullException")); + break; + case APPLEMIDI_NAMESPACE::Exception::ParseException: + DBG(F("*** ParseException")); + break; + case APPLEMIDI_NAMESPACE::Exception::TooManyParticipantsException: + DBG(F("*** TooManyParticipantsException")); + break; + case APPLEMIDI_NAMESPACE::Exception::UnexpectedInviteException: + DBG(F("*** UnexpectedInviteException")); + break; + case APPLEMIDI_NAMESPACE::Exception::ParticipantNotFoundException: + DBG(F("*** ParticipantNotFoundException"), value); + break; + case APPLEMIDI_NAMESPACE::Exception::ListenerTimeOutException: + DBG(F("*** ListenerTimeOutException")); + break; + case APPLEMIDI_NAMESPACE::Exception::MaxAttemptsException: + DBG(F("*** MaxAttemptsException")); + break; + case APPLEMIDI_NAMESPACE::Exception::NoResponseFromConnectionRequestException: + DBG(F("***:yyy did't respond to the connection request. Check the address and port, and any firewall or router settings. (time)")); + break; + case APPLEMIDI_NAMESPACE::Exception::SendPacketsDropped: + DBG(F("*** SendPacketsDropped"), value); + break; + case APPLEMIDI_NAMESPACE::Exception::ReceivedPacketsDropped: + DBG(F("*** ReceivedPacketsDropped"), value); + break; + } +} diff --git a/examples/EthernetShield_Initiator/EthernetShield_Initiator.ino b/examples/AVR_Initiator/AVR_Initiator.ino similarity index 100% rename from examples/EthernetShield_Initiator/EthernetShield_Initiator.ino rename to examples/AVR_Initiator/AVR_Initiator.ino diff --git a/examples/EthernetShield_MinMemUsage/EthernetShield_MinMemUsage.ino b/examples/AVR_MinMemUsage/AVR_MinMemUsage.ino similarity index 100% rename from examples/EthernetShield_MinMemUsage/EthernetShield_MinMemUsage.ino rename to examples/AVR_MinMemUsage/AVR_MinMemUsage.ino diff --git a/examples/EthernetShield_MultipleSessions/EthernetShield_MultipleSessions.ino b/examples/AVR_MultipleSessions/AVR_MultipleSessions.ino similarity index 100% rename from examples/EthernetShield_MultipleSessions/EthernetShield_MultipleSessions.ino rename to examples/AVR_MultipleSessions/AVR_MultipleSessions.ino diff --git a/examples/EthernetShield_NonDefaultSession/EthernetShield_NonDefaultSession.ino b/examples/AVR_NonDefaultSession/AVR_NonDefaultSession.ino similarity index 100% rename from examples/EthernetShield_NonDefaultSession/EthernetShield_NonDefaultSession.ino rename to examples/AVR_NonDefaultSession/AVR_NonDefaultSession.ino diff --git a/examples/EthernetShield_NoteOnOffEverySec/EthernetShield_NoteOnOffEverySec.ino b/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino similarity index 100% rename from examples/EthernetShield_NoteOnOffEverySec/EthernetShield_NoteOnOffEverySec.ino rename to examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino diff --git a/examples/EthernetShield_ReceivedRawMidiData/EthernetShield_ReceivedRawMidiData.ino b/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino similarity index 100% rename from examples/EthernetShield_ReceivedRawMidiData/EthernetShield_ReceivedRawMidiData.ino rename to examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino diff --git a/examples/EthernetShield_SysEx/EthernetShield_SysEx.ino b/examples/AVR_SysEx/AVR_SysEx.ino similarity index 100% rename from examples/EthernetShield_SysEx/EthernetShield_SysEx.ino rename to examples/AVR_SysEx/AVR_SysEx.ino diff --git a/examples/EthernetShield_Callbacks/EthernetShield_Callbacks.ino b/examples/EthernetShield_Callbacks/EthernetShield_Callbacks.ino deleted file mode 100644 index 1ee20ae..0000000 --- a/examples/EthernetShield_Callbacks/EthernetShield_Callbacks.ino +++ /dev/null @@ -1,82 +0,0 @@ -#include - -#define DISCARD_SESSION_NAME -#define NO_LATENCY_CALCULATION -#define NO_EXT_CALLBACKS -#define SerialMon Serial -#define APPLEMIDI_DEBUG SerialMon -#include - -// Enter a MAC address for your controller below. -// Newer Ethernet shields have a MAC address printed on a sticker on the shield -byte mac[] = { - 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED -}; - -unsigned long t1 = millis(); -bool isConnected = false; - -APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); - -// ----------------------------------------------------------------------------- -// -// ----------------------------------------------------------------------------- -void setup() -{ - DBG_SETUP(115200); - DBG("Booting"); - - if (Ethernet.begin(mac) == 0) { - DBG(F("Failed DHCP, check network cable & reboot")); - for (;;); - } - - DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); - DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); - DBG(F("Select and then press the Connect button")); - DBG(F("Then open a MIDI listener and monitor incoming notes"));+- - - MIDI.begin(); - - // Stay informed on connection status - AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { - isConnected = true; - DBG(F("Connected to session"), name); - }); - AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; - DBG(F("Disconnected")); - }); - - MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { - DBG(F("NoteOn"), note); - }); - MIDI.setHandleNoteOff([](byte channel, byte note, byte velocity) { - DBG(F("NoteOff"), note); - }); - - DBG(F("Sending MIDI messages every second")); -} - -// ----------------------------------------------------------------------------- -// -// ----------------------------------------------------------------------------- -void loop() -{ - // Listen to incoming notes - MIDI.read(); - - // send a note every second - // (dont cáll delay(1000) as it will stall the pipeline) - if (isConnected && (millis() - t1) > 1000) - { - t1 = millis(); - - byte note = random(1, 127); - byte velocity = 55; - byte channel = 1; - - MIDI.sendNoteOn(note, velocity, channel); -// MIDI.sendNoteOff(note, velocity, channel); - } -} diff --git a/examples/MKR_ETH_Bonjour/MKR_ETH_Bonjour.ino b/examples/SAMD_Bonjour/SAMD_Bonjour.ino similarity index 100% rename from examples/MKR_ETH_Bonjour/MKR_ETH_Bonjour.ino rename to examples/SAMD_Bonjour/SAMD_Bonjour.ino From e29094ddba3f90e500f1a107a376d35e0897a73c Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 22 Dec 2020 23:38:01 +0100 Subject: [PATCH 12/60] min memory setup, #defines for add functions --- examples/AVR_Callbacks/AVR_Callbacks.ino | 4 ++++ examples/AVR_MinMemUsage/AVR_MinMemUsage.ino | 4 ++-- examples/ESP32_Callbacks/ESP32_Callbacks.ino | 2 ++ .../wESP32_NoteOnOffEverySec.ino | 1 + src/AppleMIDI_Defs.h | 13 +++---------- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/AVR_Callbacks/AVR_Callbacks.ino b/examples/AVR_Callbacks/AVR_Callbacks.ino index 21e7fce..c79155e 100644 --- a/examples/AVR_Callbacks/AVR_Callbacks.ino +++ b/examples/AVR_Callbacks/AVR_Callbacks.ino @@ -1,5 +1,9 @@ #include +#define LATENCY_CALCULATION +#define USE_EXT_CALLBACKS +#define SerialMon Serial +#define APPLEMIDI_DEBUG SerialMon #include // Enter a MAC address for your controller below. diff --git a/examples/AVR_MinMemUsage/AVR_MinMemUsage.ino b/examples/AVR_MinMemUsage/AVR_MinMemUsage.ino index c2d8db5..9324441 100644 --- a/examples/AVR_MinMemUsage/AVR_MinMemUsage.ino +++ b/examples/AVR_MinMemUsage/AVR_MinMemUsage.ino @@ -1,7 +1,7 @@ #include -#define DISCARD_SESSION_NAME -#define NO_LATENCY_CALCULATION +//#define DISCARD_SESSION_NAME +//#define NO_LATENCY_CALCULATION #define NO_EXT_CALLBACKS #include diff --git a/examples/ESP32_Callbacks/ESP32_Callbacks.ino b/examples/ESP32_Callbacks/ESP32_Callbacks.ino index a0b6e25..6245bdf 100644 --- a/examples/ESP32_Callbacks/ESP32_Callbacks.ino +++ b/examples/ESP32_Callbacks/ESP32_Callbacks.ino @@ -1,6 +1,8 @@ #include #include +#define LATENCY_CALCULATION +#define USE_EXT_CALLBACKS #define SerialMon Serial #define APPLEMIDI_DEBUG SerialMon #include diff --git a/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino b/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino index fc2b413..052bec4 100644 --- a/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino +++ b/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino @@ -1,3 +1,4 @@ +#define USE_EXT_CALLBACKS #define SerialMon Serial #define APPLEMIDI_DEBUG SerialMon #include diff --git a/src/AppleMIDI_Defs.h b/src/AppleMIDI_Defs.h index ae88f68..4192c40 100644 --- a/src/AppleMIDI_Defs.h +++ b/src/AppleMIDI_Defs.h @@ -40,16 +40,9 @@ typedef const char* AppleMIDIConstStr; #define RtpBuffer_t Deque #define MidiBuffer_t Deque -// Way to reduce memory usage, by giving up functionality -#ifndef DISCARD_SESSION_NAME -#define KEEP_SESSION_NAME -#endif -#ifndef NO_LATENCY_CALCULATION -#define LATENCY_CALCULATION -#endif -#ifndef NO_EXT_CALLBACKS -#define USE_EXT_CALLBACKS -#endif +// Add extended callbacks to enabling these #defines +// #define LATENCY_CALCULATION +// #define USE_EXT_CALLBACKS #define MIDI_SAMPLING_RATE_176K4HZ 176400 #define MIDI_SAMPLING_RATE_192KHZ 192000 From a87452132fe9809905e33043040c6c3507feb19c Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 22 Dec 2020 23:38:54 +0100 Subject: [PATCH 13/60] Update README.md --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f3828d7..3e69b00 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # AppleMIDI (aka rtpMIDI) for Arduino -[![arduino-library-badge](https://www.ardu-badge.com/badge/AppleMIDI.svg?)](https://www.ardu-badge.com/AppleMIDI) [![Build Status](https://travis-ci.org/lathoub/Arduino-AppleMIDI-Library.svg?branch=master)](https://travis-ci.org/lathoub/Arduino-AppleMIDI-Library) [![License: CC BY-SA 4.0](https://img.shields.io/badge/License-CC%20BY--SA%204.0-lightgrey.svg)](http://creativecommons.org/licenses/by-sa/4.0/) [![GitHub version](https://badge.fury.io/gh/lathoub%2FArduino-AppleMidi-Library.svg)](https://badge.fury.io/gh/lathoub%2FArduino-AppleMidi-Library) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/c8be2ccc3f104e0588572a39f8106070)](https://app.codacy.com/app/lathoub/Arduino-AppleMIDI-Library?utm_source=github.com&utm_medium=referral&utm_content=lathoub/Arduino-AppleMIDI-Library&utm_campaign=Badge_Grade_Dashboard) +[![arduino-library-badge](https://www.ardu-badge.com/badge/AppleMIDI.svg?)](https://www.ardu-badge.com/AppleMIDI) [![Build Status](https://travis-ci.org/lathoub/Arduino-AppleMIDI-Library.svg?branch=master)](https://travis-ci.org/lathoub/Arduino-AppleMIDI-Library) [![License: CC BY-SA 4.0](https://img.shields.io/badge/License-CC%20BY--SA%204.0-lightgrey.svg)](http://creativecommons.org/licenses/by-sa/4.0/) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/c8be2ccc3f104e0588572a39f8106070)](https://app.codacy.com/app/lathoub/Arduino-AppleMIDI-Library?utm_source=github.com&utm_medium=referral&utm_content=lathoub/Arduino-AppleMIDI-Library&utm_campaign=Badge_Grade_Dashboard) Enables an Arduino with IP/UDP capabilities (Ethernet shield, ESP8266, ESP32, ...) to particpate in an AppleMIDI session. @@ -59,6 +59,9 @@ More usages in the [examples](https://github.com/lathoub/Arduino-AppleMIDI-Libra * Adafruit Feather M0 WiFi - ATSAMD21 + ATWINC1500 ## Memory usage +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 (and +LATENCY_CALCULATION). See the callback examamples. + 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. 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. @@ -73,7 +76,7 @@ Beware: the number of sockets on the Arduino is limited. The W5100 support 4, th * Teensy WIZ820io W5200 ## Arduino IDE (arduino.cc) -* 1.8.10 +* 1.8.13 ## Contributing I would love to include your enhancements or bug fixes! In lieu of a formal styleguide, please take care to maintain the existing coding style. Please test your code before sending a pull request. It would be very helpful if you include a detailed explanation of your changes in the pull request. From 2777a9952fa8cd7d5b2d135ba348d6be3e5adf20 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 23 Dec 2020 06:31:48 +0100 Subject: [PATCH 14/60] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3e69b00..85897c9 100755 --- a/README.md +++ b/README.md @@ -68,6 +68,8 @@ The minimum buffer size (`MaxBufferSize`) should be set to 64 bytes (also the de `MaxNumberOfParticipants` is another way to cut memory - each particpants uses approx 300 bytes. Default number of participants is 1 (using 2 sockets). 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`) + +Reduce the memory footprint by a further 500 by `#define NO_SESSION_NAME` before `#include `. This will leave out all the code to manage the optional session name. By default the session name is kept. ## Network Shields * Arduino Ethernet shield (Wiznet W5100 and W5500) From cd5a8fd3c3394b5d38350b8cef597d282ae5536c Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 23 Dec 2020 06:32:07 +0100 Subject: [PATCH 15/60] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 85897c9..a78cbe5 100755 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ The minimum buffer size (`MaxBufferSize`) should be set to 64 bytes (also the de `MaxNumberOfParticipants` is another way to cut memory - each particpants uses approx 300 bytes. Default number of participants is 1 (using 2 sockets). 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`) -Reduce the memory footprint by a further 500 by `#define NO_SESSION_NAME` before `#include `. This will leave out all the code to manage the optional session name. By default the session name is kept. +Reduce the memory footprint by a further 500 bytes by `#define NO_SESSION_NAME` before `#include `. This will leave out all the code to manage the optional session name. By default the session name is kept. ## Network Shields * Arduino Ethernet shield (Wiznet W5100 and W5500) From d83529637e81946ec2a23b23ed2db96d4d2499a9 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 23 Dec 2020 12:33:50 +0100 Subject: [PATCH 16/60] further weight reduction #define ONE_PARTICIPANT --- examples/AVR_MinMemUsage/AVR_MinMemUsage.ino | 5 +- .../AVR_NoteOnOffEverySec.ino | 1 + src/AppleMIDI.h | 33 +- src/AppleMIDI.hpp | 355 ++++++++++++------ src/AppleMIDI_Debug.h | 2 + src/AppleMIDI_Defs.h | 23 +- src/AppleMIDI_Participant.h | 6 +- src/AppleMIDI_Settings.h | 2 + 8 files changed, 293 insertions(+), 134 deletions(-) diff --git a/examples/AVR_MinMemUsage/AVR_MinMemUsage.ino b/examples/AVR_MinMemUsage/AVR_MinMemUsage.ino index 9324441..1f7cee4 100644 --- a/examples/AVR_MinMemUsage/AVR_MinMemUsage.ino +++ b/examples/AVR_MinMemUsage/AVR_MinMemUsage.ino @@ -1,8 +1,7 @@ #include -//#define DISCARD_SESSION_NAME -//#define NO_LATENCY_CALCULATION -#define NO_EXT_CALLBACKS +#define ONE_PARTICIPANT +#define NO_SESSION_NAME #include // Enter a MAC address for your controller below. diff --git a/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino b/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino index 23d5f58..6489cd0 100644 --- a/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino +++ b/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino @@ -1,5 +1,6 @@ #include +//#define ONE_PARTICIPANT #define SerialMon Serial #define APPLEMIDI_DEBUG SerialMon #include diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index 2d1a477..4d8a60e 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -50,7 +50,9 @@ class AppleMIDISession AppleMIDISession(const char *sessionName, const uint16_t port = DEFAULT_CONTROL_PORT) { this->port = port; +#ifdef KEEP_SESSION_NAME strncpy(this->localName, sessionName, DefaultSettings::MaxSessionNameLen); +#endif }; void setHandleConnected(void (*fptr)(const ssrc_t&, const char*)) { _connectedCallback = fptr; } @@ -64,12 +66,16 @@ class AppleMIDISession void setHandleSendRtp(void (*fptr)(const Rtp_t&)) { _sendRtpCallback = fptr; } #endif +#ifdef KEEP_SESSION_NAME const char* getName() { return this->localName; }; + void setName(const char *sessionName) { strncpy(this->localName, sessionName, DefaultSettings::MaxSessionNameLen); }; +#else + const char* getName() { return nullptr; }; + void setName(const char *sessionName) { }; +#endif const uint16_t getPort() { return this->port; }; const ssrc_t getSynchronizationSource() { return this->ssrc; }; - void setName(const char *sessionName) { strncpy(this->localName, sessionName, DefaultSettings::MaxSessionNameLen); }; - #ifdef APPLEMIDI_INITIATOR bool sendInvite(IPAddress ip, uint16_t port = DEFAULT_CONTROL_PORT); #endif @@ -131,7 +137,11 @@ class AppleMIDISession // of what we are to send (The RtpMidi protocol start with writing the // length of the buffer). So we'll copy to a buffer in the 'write' method, // and actually serialize for real in the endTransmission method +#ifndef ONE_PARTICIPANT return (dataPort.remoteIP() != INADDR_NONE && participants.size() > 0); +#else + return (dataPort.remoteIP() != INADDR_NONE && participant.remoteIP != INADDR_NONE); +#endif }; void write(byte byte) @@ -239,11 +249,21 @@ class AppleMIDISession rtpMidi_Clock rtpMidiClock; ssrc_t ssrc = 0; - char localName[DefaultSettings::MaxSessionNameLen + 1]; uint16_t port = DEFAULT_CONTROL_PORT; + WhoCanConnectToMe whoCanConnectToMe = Anyone; +#ifdef ONE_PARTICIPANT + Participant participant; +#else Deque, Settings::MaxNumberOfParticipants> participants; -// int32_t latencyAdjustment = 0; // not used - +#endif +#ifdef USE_DIRECTORY + Deque directory; +#endif + +#ifdef KEEP_SESSION_NAME + char localName[DefaultSettings::MaxSessionNameLen + 1]; +#endif + private: void readControlPackets(); void readDataPackets(); @@ -285,15 +305,16 @@ class AppleMIDISession void manageSessionInvites(); void manageSynchronization(); - void manageSynchronizationListener(size_t); void manageSynchronizationInitiator(); void manageSynchronizationInitiatorHeartBeat(size_t); void manageSynchronizationInitiatorInvites(size_t); void sendSynchronization(Participant*); +#ifndef ONE_PARTICIPANT Participant* getParticipantBySSRC(const ssrc_t ssrc); Participant* getParticipantByInitiatorToken(const uint32_t initiatorToken); +#endif }; END_APPLEMIDI_NAMESPACE diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index a172dca..f10083f 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -93,7 +93,7 @@ void AppleMIDISession::parseDataPackets() template void AppleMIDISession::ReceivedInvitation(AppleMIDI_Invitation_t &invitation, const amPortType &portType) { - if (portType == amPortType::Control) + if (portType == amPortType::Control) ReceivedControlInvitation(invitation); else ReceivedDataInvitation(invitation); @@ -103,7 +103,11 @@ template void AppleMIDISession::ReceivedControlInvitation(AppleMIDI_Invitation_t &invitation) { // ignore invitation of a participant already in the participant list +#ifndef ONE_PARTICIPANT if (nullptr != getParticipantBySSRC(invitation.ssrc)) +#else + if (participant.ssrc == invitation.ssrc) +#endif return; // advertise our own session name @@ -112,7 +116,11 @@ void AppleMIDISession::ReceivedControlInvitation(A invitation.sessionName[DefaultSettings::MaxSessionNameLen] = '\0'; #endif +#ifndef ONE_PARTICIPANT if (participants.full()) +#else + if (participant.remoteIP != INADDR_NONE) +#endif { writeInvitation(controlPort, controlPort.remoteIP(), controlPort.remotePort(), invitation, amInvitationRejected); @@ -123,7 +131,9 @@ void AppleMIDISession::ReceivedControlInvitation(A return; } +#ifndef ONE_PARTICIPANT Participant participant; +#endif participant.kind = Listener; participant.ssrc = invitation.ssrc; participant.remoteIP = controlPort.remoteIP(); @@ -133,7 +143,9 @@ void AppleMIDISession::ReceivedControlInvitation(A strncpy(participant.sessionName, invitation.sessionName, DefaultSettings::MaxSessionNameLen); #endif +#ifndef ONE_PARTICIPANT participants.push_back(participant); +#endif writeInvitation(controlPort, participant.remoteIP, participant.remotePort, invitation, amInvitationAccepted); } @@ -141,8 +153,12 @@ void AppleMIDISession::ReceivedControlInvitation(A template void AppleMIDISession::ReceivedDataInvitation(AppleMIDI_Invitation &invitation) { - auto participant = getParticipantBySSRC(invitation.ssrc); - if (nullptr == participant) +#ifndef ONE_PARTICIPANT + auto pParticipant = getParticipantBySSRC(invitation.ssrc); +#else + auto pParticipant = (participant.ssrc == invitation.ssrc) ? &participant : nullptr; +#endif + if (nullptr == pParticipant) { writeInvitation(dataPort, dataPort.remoteIP(), dataPort.remotePort(), invitation, amInvitationRejected); @@ -158,9 +174,9 @@ void AppleMIDISession::ReceivedDataInvitation(Appl // of the ssrc here. auto ssrc_ = invitation.ssrc; - writeInvitation(dataPort, participant->remoteIP, participant->remotePort + 1, invitation, amInvitationAccepted); + writeInvitation(dataPort, pParticipant->remoteIP, pParticipant->remotePort + 1, invitation, amInvitationAccepted); - participant->kind = Listener; + pParticipant->kind = Listener; // Inform that we have an established connection if (nullptr != _connectedCallback) @@ -176,6 +192,7 @@ void AppleMIDISession::ReceivedBitrateReceiveLimit { } +#ifdef APPLEMIDI_INITIATOR template void AppleMIDISession::ReceivedInvitationAccepted(AppleMIDI_InvitationAccepted_t &invitationAccepted, const amPortType &portType) { @@ -188,32 +205,40 @@ void AppleMIDISession::ReceivedInvitationAccepted( template void AppleMIDISession::ReceivedControlInvitationAccepted(AppleMIDI_InvitationAccepted_t &invitationAccepted) { - auto participant = this->getParticipantByInitiatorToken(invitationAccepted.initiatorToken); - if (nullptr == participant) +#ifndef ONE_PARTICIPANT + auto pParticipant = this->getParticipantByInitiatorToken(invitationAccepted.initiatorToken); +#else + auto pParticipant = (participant.initiatorToken == invitationAccepted.initiatorToken) ? &participant : nullptr; +#endif + if (nullptr == pParticipant) { return; } - participant->ssrc = invitationAccepted.ssrc; - participant->lastInviteSentTime = now - 1000; // forces invite to be send - participant->connectionAttempts = 0; // reset back to 0 - participant->invitationStatus = ControlInvitationAccepted; // step it up + pParticipant->ssrc = invitationAccepted.ssrc; + pParticipant->lastInviteSentTime = now - 1000; // forces invite to be send + pParticipant->connectionAttempts = 0; // reset back to 0 + pParticipant->invitationStatus = ControlInvitationAccepted; // step it up #ifdef KEEP_SESSION_NAME - strncpy(participant->sessionName, invitationAccepted.sessionName, DefaultSettings::MaxSessionNameLen); - participant->sessionName[DefaultSettings::MaxSessionNameLen] = '\0'; + strncpy(pParticipant->sessionName, invitationAccepted.sessionName, DefaultSettings::MaxSessionNameLen); + pParticipant->sessionName[DefaultSettings::MaxSessionNameLen] = '\0'; #endif } template void AppleMIDISession::ReceivedDataInvitationAccepted(AppleMIDI_InvitationAccepted_t &invitationAccepted) { - auto participant = this->getParticipantByInitiatorToken(invitationAccepted.initiatorToken); - if (nullptr == participant) +#ifndef ONE_PARTICIPANT + auto pParticipant = this->getParticipantByInitiatorToken(invitationAccepted.initiatorToken); +#else + auto pParticipant = (participant.initiatorToken == invitationAccepted.initiatorToken) ? &participant : nullptr; +#endif + if (nullptr == pParticipant) { return; } - participant->invitationStatus = DataInvitationAccepted; + pParticipant->invitationStatus = DataInvitationAccepted; } template @@ -223,12 +248,17 @@ void AppleMIDISession::ReceivedInvitationRejected( { if (invitationRejected.ssrc == participants[i].ssrc) { +#ifndef ONE_PARTICIPANT participants.erase(i); - +#else + participant.ssrc = 0; + participant.remoteIP = INADDR_NONE; +#endif return; } } } +#endif /*! \brief . @@ -260,8 +290,12 @@ user to choose between a new connection attempt or closing the session. template void AppleMIDISession::ReceivedSynchronization(AppleMIDI_Synchronization_t &synchronization) { - auto participant = getParticipantBySSRC(synchronization.ssrc); - if (nullptr == participant) +#ifndef ONE_PARTICIPANT + auto pParticipant = getParticipantBySSRC(synchronization.ssrc); +#else + auto pParticipant = (participant.ssrc == synchronization.ssrc) ? &participant : nullptr; +#endif + if (nullptr == pParticipant) { #ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) @@ -307,28 +341,28 @@ void AppleMIDISession::ReceivedSynchronization(App case SYNC_CK0: /* From session APPLEMIDI_INITIATOR */ synchronization.timestamps[SYNC_CK1] = rtpMidiClock.Now(); synchronization.count = SYNC_CK1; - writeSynchronization(participant->remoteIP, participant->remotePort + 1, synchronization); + writeSynchronization(pParticipant->remoteIP, pParticipant->remotePort + 1, synchronization); break; case SYNC_CK1: /* From session LISTENER */ #ifdef APPLEMIDI_INITIATOR synchronization.timestamps[SYNC_CK2] = rtpMidiClock.Now(); synchronization.count = SYNC_CK2; - writeSynchronization(participant->remoteIP, participant->remotePort + 1, synchronization); - participant->synchronizing = false; + writeSynchronization(pParticipant->remoteIP, pParticipant->remotePort + 1, synchronization); + pParticipant->synchronizing = false; #endif break; case SYNC_CK2: /* From session APPLEMIDI_INITIATOR */ #ifdef LATENCY_CALCULATION // each party can estimate the offset between the two clocks using the following formula - participant->offsetEstimate = (uint32_t)(((synchronization.timestamps[2] + synchronization.timestamps[0]) / 2) - synchronization.timestamps[1]); + pParticipant->offsetEstimate = (uint32_t)(((synchronization.timestamps[2] + synchronization.timestamps[0]) / 2) - synchronization.timestamps[1]); #endif break; } // All particpants need to check in regularly, // failing to do so will result in a lost connection. - participant->lastSyncExchangeTime = now; + pParticipant->lastSyncExchangeTime = now; } // The recovery journal mechanism requires that the receiver periodically @@ -342,9 +376,12 @@ void AppleMIDISession::ReceivedReceiverFeedback(Ap { // We do not keep any recovery journals, no command history, nothing! // Here is where you would correct if packets are dropped (send them again) - - auto participant = getParticipantBySSRC(receiverFeedback.ssrc); - if (nullptr == participant) { +#ifndef ONE_PARTICIPANT + auto pParticipant = getParticipantBySSRC(receiverFeedback.ssrc); +#else + auto pParticipant = (participant.ssrc == receiverFeedback.ssrc) ? &participant : nullptr; +#endif + if (nullptr == pParticipant) { #ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, ParticipantNotFoundException, receiverFeedback.ssrc); @@ -352,11 +389,11 @@ void AppleMIDISession::ReceivedReceiverFeedback(Ap return; } - if (participant->sendSequenceNr != receiverFeedback.sequenceNr) + if (pParticipant->sendSequenceNr != receiverFeedback.sequenceNr) { #ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) - _exceptionCallback(ssrc, SendPacketsDropped, participant->sendSequenceNr - receiverFeedback.sequenceNr); + _exceptionCallback(ssrc, SendPacketsDropped, pParticipant->sendSequenceNr - receiverFeedback.sequenceNr); #endif } } @@ -364,14 +401,23 @@ void AppleMIDISession::ReceivedReceiverFeedback(Ap template void AppleMIDISession::ReceivedEndSession(AppleMIDI_EndSession_t &endSession) { +#ifndef ONE_PARTICIPANT for (size_t i = 0; i < participants.size(); i++) { - if (endSession.ssrc == participants[i].ssrc) + auto participant = participants[i]; +#else + { +#endif + if (endSession.ssrc == participant.ssrc) { - auto ssrc = participants[i].ssrc; + auto ssrc = participant.ssrc; +#ifndef ONE_PARTICIPANT participants.erase(i); - +#else + participant.ssrc = 0; + participant.remoteIP = INADDR_NONE; +#endif if (nullptr != _disconnectedCallback) _disconnectedCallback(ssrc); @@ -380,6 +426,7 @@ void AppleMIDISession::ReceivedEndSession(AppleMID } } +#ifndef ONE_PARTICIPANT template Participant* AppleMIDISession::getParticipantBySSRC(const ssrc_t ssrc) { @@ -397,6 +444,7 @@ Participant* AppleMIDISession::getPartic return &participants[i]; return nullptr; } +#endif template void AppleMIDISession::writeInvitation(UdpClass &port, IPAddress remoteIP, uint16_t remotePort, AppleMIDI_Invitation_t & invitation, const byte *command) @@ -478,16 +526,21 @@ void AppleMIDISession::writeEndSession(const IPAdd template void AppleMIDISession::writeRtpMidiToAllParticipants() { +#ifndef ONE_PARTICIPANT for (size_t i = 0; i < participants.size(); i++) { - auto participant = &participants[i]; - writeRtpMidiBuffer(participant); + auto pParticipant = &participants[i]; + + writeRtpMidiBuffer(pParticipant); } +#else + writeRtpMidiBuffer(&participant); +#endif outMidiBuffer.clear(); } template -void AppleMIDISession::writeRtpMidiBuffer(Participant * participant) +void AppleMIDISession::writeRtpMidiBuffer(Participant* participant) { const IPAddress remoteIP = participant->remoteIP; const uint16_t remotePort = participant->remotePort + 1; @@ -565,7 +618,6 @@ void AppleMIDISession::writeRtpMidiBuffer(Particip dataPort.endPacket(); dataPort.flush(); - } // @@ -574,50 +626,53 @@ void AppleMIDISession::writeRtpMidiBuffer(Particip template void AppleMIDISession::manageSynchronization() { +#ifndef ONE_PARTICIPANT for (size_t i = 0; i < participants.size(); i++) +#endif { +#ifndef ONE_PARTICIPANT + auto pParticipant = &participants[i]; + if (pParticipant->remoteIP == INADDR_NONE) continue; +#else + auto pParticipant = &participant; + if (pParticipant->remoteIP == INADDR_NONE) return; +#endif #ifdef APPLEMIDI_INITIATOR - auto participant = &participants[i]; - - if (participant->invitationStatus != Connected) + if (pParticipant->invitationStatus != Connected) continue; // Only for Initiators that are Connected - if (participant->kind == Listener) + if (pParticipant->kind == Listener) { #endif - manageSynchronizationListener(i); + // The initiator must check in with the listener at least once every 60 seconds; + // otherwise the responder may assume that the initiator has died and terminate the session. + if (now - pParticipant->lastSyncExchangeTime > Settings::CK_MaxTimeOut) + { +#ifdef USE_EXT_CALLBACKS + if (nullptr != _exceptionCallback) + _exceptionCallback(ssrc, ListenerTimeOutException, 0); +#endif + sendEndSession(pParticipant); +#ifndef ONE_PARTICIPANT + participants.erase(i); +#else + participant.ssrc = 0; + participant.remoteIP = INADDR_NONE; +#endif + } #ifdef APPLEMIDI_INITIATOR } else { - (participant->synchronizing) ? manageSynchronizationInitiatorInvites(i) - : manageSynchronizationInitiatorHeartBeat(i); + (pParticipant->synchronizing) ? manageSynchronizationInitiatorInvites(i) + : manageSynchronizationInitiatorHeartBeat(pParticipant); } #endif } } -template -void AppleMIDISession::manageSynchronizationListener(size_t i) -{ - auto participant = &participants[i]; - - // The initiator must check in with the listener at least once every 60 seconds; - // otherwise the responder may assume that the initiator has died and terminate the session. - if (now - participant->lastSyncExchangeTime > Settings::CK_MaxTimeOut) - { -#ifdef USE_EXT_CALLBACKS - if (nullptr != _exceptionCallback) - _exceptionCallback(ssrc, ListenerTimeOutException, 0); -#endif - sendEndSession(participant); - - participants.erase(i); - - return; - } -} +#ifdef APPLEMIDI_INITIATOR // // The initiator of the session polls if remote station is still alive. @@ -627,32 +682,30 @@ void AppleMIDISession::manageSynchronizationListen // otherwise the responder may assume that the initiator has died and terminate the session. // template -void AppleMIDISession::manageSynchronizationInitiatorHeartBeat(size_t i) +void AppleMIDISession::manageSynchronizationInitiatorHeartBeat(Participant* pParticipant) { - auto participant = &participants[i]; - // Note: During startup, the initiator should send synchronization exchanges more frequently; // empirical testing has determined that sending a few exchanges improves clock // synchronization accuracy. // (Here: twice every 0.5 seconds, then 6 times every 1.5 seconds, then every 10 seconds.) bool doSyncronize = false; - if (participant->synchronizationHeartBeats < 2) + if (pParticipant->synchronizationHeartBeats < 2) { - if (now - participant->lastInviteSentTime > 500) // 2 x every 0.5 seconds + if (now - pParticipant->lastInviteSentTime > 500) // 2 x every 0.5 seconds { - participant->synchronizationHeartBeats++; + pParticipant->synchronizationHeartBeats++; doSyncronize = true; } } - else if (participant->synchronizationHeartBeats < 7) + else if (pParticipant->synchronizationHeartBeats < 7) { - if (now - participant->lastInviteSentTime > 1500) // 5 x every 1.5 seconds + if (now - pParticipant->lastInviteSentTime > 1500) // 5 x every 1.5 seconds { - participant->synchronizationHeartBeats++; + pParticipant->synchronizationHeartBeats++; doSyncronize = true; } } - else if (now - participant->lastInviteSentTime > DefaultSettings::SynchronizationHeartBeat) + else if (now - pParticipant->lastInviteSentTime > DefaultSettings::SynchronizationHeartBeat) { doSyncronize = true; } @@ -660,34 +713,41 @@ void AppleMIDISession::manageSynchronizationInitia if (!doSyncronize) return; - participant->synchronizationCount = 0; - sendSynchronization(participant); + pParticipant->synchronizationCount = 0; + sendSynchronization(pParticipant); } // checks for template void AppleMIDISession::manageSynchronizationInitiatorInvites(size_t i) { - auto participant = &participants[i]; + auto pParticipant = &participants[i]; - if (now - participant->lastInviteSentTime > 10000) + if (now - pParticipant->lastInviteSentTime > 10000) { - if (participant->synchronizationCount > DefaultSettings::MaxSynchronizationCK0Attempts) + if (pParticipant->synchronizationCount > DefaultSettings::MaxSynchronizationCK0Attempts) { #ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, MaxAttemptsException, 0); #endif // After too many attempts, stop. - sendEndSession(participant); + sendEndSession(pParticipant); +#ifndef ONE_PARTICIPANT participants.erase(i); +#else + participant.ssrc = 0; + participant.remoteIP = INADDR_NONE; +#endif return; } - sendSynchronization(participant); + sendSynchronization(pParticipant); } } +#endif + template void AppleMIDISession::sendSynchronization(Participant* participant) { @@ -707,67 +767,88 @@ void AppleMIDISession::sendSynchronization(Partici template void AppleMIDISession::manageSessionInvites() { +#ifndef ONE_PARTICIPANT for (auto i = 0; i < participants.size(); i++) +#endif { - auto participant = &participants[i]; +#ifndef ONE_PARTICIPANT + auto pParticipant = &participants[i]; +#else + auto pParticipant = &participant; +#endif - if (participant->kind == Listener) + if (pParticipant->kind == Listener) +#ifndef ONE_PARTICIPANT continue; - - if (participant->invitationStatus == DataInvitationAccepted) +#else + return; +#endif + if (pParticipant->invitationStatus == DataInvitationAccepted) { // Inform that we have an established connection if (nullptr != _connectedCallback) #ifdef KEEP_SESSION_NAME - _connectedCallback(participant->ssrc, participant->sessionName); + _connectedCallback(pParticipant->ssrc, pParticipant->sessionName); #else - _connectedCallback(participant->ssrc, nullptr); + _connectedCallback(pParticipant->ssrc, nullptr); #endif - participant->invitationStatus = Connected; + pParticipant->invitationStatus = Connected; } - if (participant->invitationStatus == Connected) - continue; // We are done here + if (pParticipant->invitationStatus == Connected) +#ifndef ONE_PARTICIPANT + continue; +#else + return; +#endif // try to connect every 1 second (1000 ms) - if (now - participant->lastInviteSentTime > 1000) + if (now - pParticipant->lastInviteSentTime > 1000) { - if (participant->connectionAttempts >= DefaultSettings::MaxSessionInvitesAttempts) + if (pParticipant->connectionAttempts >= DefaultSettings::MaxSessionInvitesAttempts) { #ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, NoResponseFromConnectionRequestException, 0); #endif // After too many attempts, stop. - sendEndSession(participant); + sendEndSession(pParticipant); +#ifndef ONE_PARTICIPANT participants.erase(i); - +#else + participant.ssrc = 0; + pParticipant->remoteIP = INADDR_NONE; +#endif +#ifndef ONE_PARTICIPANT continue; +#else + return; +#endif } - participant->lastInviteSentTime = now; - participant->connectionAttempts++; + pParticipant->lastInviteSentTime = now; + pParticipant->connectionAttempts++; AppleMIDI_Invitation invitation; invitation.ssrc = this->ssrc; - invitation.initiatorToken = participant->initiatorToken; + invitation.initiatorToken = pParticipant->initiatorToken; #ifdef KEEP_SESSION_NAME strncpy(invitation.sessionName, this->localName, DefaultSettings::MaxSessionNameLen); invitation.sessionName[DefaultSettings::MaxSessionNameLen] = '\0'; #endif - if (participant->invitationStatus == Initiating - || participant->invitationStatus == AwaitingControlInvitationAccepted) + if (pParticipant->invitationStatus == Initiating + || pParticipant->invitationStatus == AwaitingControlInvitationAccepted) { - writeInvitation(controlPort, participant->remoteIP, participant->remotePort, invitation, amInvitation); - participant->invitationStatus = AwaitingControlInvitationAccepted; + writeInvitation(controlPort, pParticipant->remoteIP, pParticipant->remotePort, invitation, amInvitation); + pParticipant->invitationStatus = AwaitingControlInvitationAccepted; } else - if (participant->invitationStatus == ControlInvitationAccepted - || participant->invitationStatus == AwaitingDataInvitationAccepted) + if (pParticipant->invitationStatus == ControlInvitationAccepted + || pParticipant->invitationStatus == AwaitingDataInvitationAccepted) { - writeInvitation(dataPort, participant->remoteIP, participant->remotePort + 1, invitation, amInvitation); - participant->invitationStatus = AwaitingDataInvitationAccepted; + writeInvitation(dataPort, pParticipant->remoteIP, pParticipant->remotePort + 1, invitation, amInvitation); + pParticipant->invitationStatus = AwaitingDataInvitationAccepted; } } } @@ -783,22 +864,34 @@ void AppleMIDISession::manageSessionInvites() template void AppleMIDISession::manageReceiverFeedback() { - for (size_t i = 0; i < participants.size(); i++) +#ifndef ONE_PARTICIPANT + for (auto i = 0; i < participants.size(); i++) +#endif { - auto participant = &participants[i]; - - if (participant->doReceiverFeedback == false) +#ifndef ONE_PARTICIPANT + auto pParticipant = &participants[i]; + if (pParticipant->remoteIP == INADDR_NONE) continue; +#else + auto pParticipant = &participant; + if (pParticipant->remoteIP == INADDR_NONE) return; +#endif + + if (pParticipant->doReceiverFeedback == false) +#ifndef ONE_PARTICIPANT continue; +#else + return; +#endif - if ((now - participant->receiverFeedbackStartTime) > Settings::ReceiversFeedbackThreshold) + if ((now - pParticipant->receiverFeedbackStartTime) > Settings::ReceiversFeedbackThreshold) { AppleMIDI_ReceiverFeedback_t rf; rf.ssrc = ssrc; - rf.sequenceNr = participant->receiveSequenceNr; - writeReceiverFeedback(participant->remoteIP, participant->remotePort, rf); + rf.sequenceNr = pParticipant->receiveSequenceNr; + writeReceiverFeedback(pParticipant->remoteIP, pParticipant->remotePort, rf); // reset the clock. It is started when we receive MIDI - participant->doReceiverFeedback = false; + pParticipant->doReceiverFeedback = false; } } } @@ -808,12 +901,18 @@ void AppleMIDISession::manageReceiverFeedback() template bool AppleMIDISession::sendInvite(IPAddress ip, uint16_t port) { +#ifndef ONE_PARTICIPANT if (participants.full()) +#else + if (participant.remoteIP != INADDR_NONE) +#endif { return false; } - + +#ifndef ONE_PARTICIPANT Participant participant; +#endif participant.kind = Initiator; participant.remoteIP = ip; participant.remotePort = port; @@ -822,7 +921,9 @@ bool AppleMIDISession::sendInvite(IPAddress ip, ui participant.initiatorToken = random(1, INT32_MAX) * 2; participant.sequenceNr; +#ifndef ONE_PARTICIPANT participants.push_back(participant); +#endif return true; } @@ -832,6 +933,7 @@ bool AppleMIDISession::sendInvite(IPAddress ip, ui template void AppleMIDISession::sendEndSession() { +#ifndef ONE_PARTICIPANT while (participants.size() > 0) { auto participant = &participants.front(); @@ -839,6 +941,13 @@ void AppleMIDISession::sendEndSession() participants.pop_front(); } +#else + if (participant.remoteIP != INADDR_NONE) + { + sendEndSession(&participant); + participant.remoteIP = INADDR_NONE; + } +#endif } template @@ -856,13 +965,17 @@ void AppleMIDISession::sendEndSession(Participant< template void AppleMIDISession::ReceivedRtp(const Rtp_t& rtp) { - auto participant = getParticipantBySSRC(rtp.ssrc); +#ifndef ONE_PARTICIPANT + auto pParticipant = getParticipantBySSRC(rtp.ssrc); +#else + auto pParticipant = (participant.ssrc == rtp.ssrc) ? &participant : nullptr; +#endif - if (nullptr != participant) + if (nullptr != pParticipant) { - if (participant->doReceiverFeedback == false) - participant->receiverFeedbackStartTime = now; - participant->doReceiverFeedback = true; + if (pParticipant->doReceiverFeedback == false) + pParticipant->receiverFeedbackStartTime = now; + pParticipant->doReceiverFeedback = true; #ifdef LATENCY_CALCULATION auto offset = (rtp.timestamp - participant->offsetEstimate); @@ -871,15 +984,15 @@ void AppleMIDISession::ReceivedRtp(const Rtp_t& rt auto latency = 0; #endif - if (participant->receiveSequenceNr + 1 != rtp.sequenceNr) { + if (pParticipant->receiveSequenceNr + 1 != rtp.sequenceNr) { #ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) - _exceptionCallback(ssrc, ReceivedPacketsDropped, participant->receiveSequenceNr + 1 - rtp.sequenceNr); + _exceptionCallback(ssrc, ReceivedPacketsDropped, pParticipant->receiveSequenceNr + 1 - rtp.sequenceNr); #endif } - participant->receiveSequenceNr = rtp.sequenceNr; + pParticipant->receiveSequenceNr = rtp.sequenceNr; #ifdef USE_EXT_CALLBACKS if (nullptr != _receivedRtpCallback) diff --git a/src/AppleMIDI_Debug.h b/src/AppleMIDI_Debug.h index 3d65291..342cc81 100644 --- a/src/AppleMIDI_Debug.h +++ b/src/AppleMIDI_Debug.h @@ -2,7 +2,9 @@ namespace { static void DBG_SETUP(unsigned long baud) { APPLEMIDI_DEBUG.begin(baud); + #ifdef __AVR_ATmega32U4__ while (!APPLEMIDI_DEBUG); + #endif } template diff --git a/src/AppleMIDI_Defs.h b/src/AppleMIDI_Defs.h index 4192c40..b43db88 100644 --- a/src/AppleMIDI_Defs.h +++ b/src/AppleMIDI_Defs.h @@ -43,6 +43,13 @@ typedef const char* AppleMIDIConstStr; // Add extended callbacks to enabling these #defines // #define LATENCY_CALCULATION // #define USE_EXT_CALLBACKS +// #define ONE_PARTICIPANT // TODO +// #define USE_DIRECTORY + +// By defining NO_SESSION_NAME in the sketch, you can save 100 bytes +#ifndef NO_SESSION_NAME +#define KEEP_SESSION_NAME +#endif #define MIDI_SAMPLING_RATE_176K4HZ 176400 #define MIDI_SAMPLING_RATE_192KHZ 192000 @@ -51,6 +58,13 @@ typedef const char* AppleMIDIConstStr; struct Rtp; typedef Rtp Rtp_t; +enum WhoCanConnectToMe : uint8_t +{ + None, + OnlyComputersInMyDirectory, + Anyone, +}; + // from: https://en.wikipedia.org/wiki/RTP-MIDI // Apple decided to create their own protocol, imposing all parameters related to // synchronization like the sampling frequency. This session protocol is called "AppleMIDI" @@ -136,12 +150,19 @@ typedef struct PACKED AppleMIDI_Invitation { initiatorToken_t initiatorToken; ssrc_t ssrc; - char sessionName[DefaultSettings::MaxSessionNameLen + 1]; +#ifdef KEEP_SESSION_NAME + char sessionName[DefaultSettings::MaxSessionNameLen + 1]; const size_t getLength() const { return sizeof(AppleMIDI_Invitation) - (DefaultSettings::MaxSessionNameLen) + strlen(sessionName); } +#else + const size_t getLength() const + { + return sizeof(AppleMIDI_Invitation); + } +#endif } AppleMIDI_Invitation_t, AppleMIDI_InvitationAccepted_t, AppleMIDI_InvitationRejected_t; typedef struct PACKED AppleMIDI_BitrateReceiveLimit diff --git a/src/AppleMIDI_Participant.h b/src/AppleMIDI_Participant.h index 878dd8d..e0ba1a5 100644 --- a/src/AppleMIDI_Participant.h +++ b/src/AppleMIDI_Participant.h @@ -10,9 +10,9 @@ template struct Participant { ParticipantKind kind; - ssrc_t ssrc; - IPAddress remoteIP; - uint16_t remotePort; + ssrc_t ssrc = 0; + IPAddress remoteIP = INADDR_NONE; + uint16_t remotePort = 0; unsigned long receiverFeedbackStartTime; bool doReceiverFeedback = false; diff --git a/src/AppleMIDI_Settings.h b/src/AppleMIDI_Settings.h index c5a3e07..346c188 100644 --- a/src/AppleMIDI_Settings.h +++ b/src/AppleMIDI_Settings.h @@ -13,6 +13,8 @@ struct DefaultSettings static const size_t MaxSessionNameLen = 24; static const uint8_t MaxNumberOfParticipants = 2; + + static const uint8_t MaxNumberOfComputersInDirectory = 2; // The recovery journal mechanism requires that the receiver periodically // inform the sender of the sequence number of the most recently received packet. From cf1ba1a52fff45337ed92ca5cd9db7f6346feea4 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 23 Dec 2020 12:42:04 +0100 Subject: [PATCH 17/60] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index a78cbe5..1cf1289 100755 --- a/README.md +++ b/README.md @@ -70,6 +70,9 @@ The minimum buffer size (`MaxBufferSize`) should be set to 64 bytes (also the de 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`) Reduce the memory footprint by a further 500 bytes by `#define NO_SESSION_NAME` before `#include `. This will leave out all the code to manage the optional session name. By default the session name is kept. + +Even further reduce the memory footprint by `#define ONE_PARTICIPANT` limiting the number of particpants to just 1. +On an UNO the absolute minimum memory footprint is 22142 bytes (68%) and 946 global variables (46%). ## Network Shields * Arduino Ethernet shield (Wiznet W5100 and W5500) From f4251637c91dcb31c83b31c4af4afdfe73dfa675 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 23 Dec 2020 12:58:02 +0100 Subject: [PATCH 18/60] furtner memory reduction --- .../AVR_NoteOnOffEverySec.ino | 2 +- src/AppleMIDI.h | 2 +- src/AppleMIDI.hpp | 22 +++++++------------ 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino b/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino index 6489cd0..52c28d3 100644 --- a/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino +++ b/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino @@ -1,6 +1,6 @@ #include -//#define ONE_PARTICIPANT +#define ONE_PARTICIPANT #define SerialMon Serial #define APPLEMIDI_DEBUG SerialMon #include diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index 4d8a60e..95826be 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -140,7 +140,7 @@ class AppleMIDISession #ifndef ONE_PARTICIPANT return (dataPort.remoteIP() != INADDR_NONE && participants.size() > 0); #else - return (dataPort.remoteIP() != INADDR_NONE && participant.remoteIP != INADDR_NONE); + return (dataPort.remoteIP() != INADDR_NONE && participant.ssrc != 0); #endif }; diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index f10083f..b3b9ea2 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -110,7 +110,6 @@ void AppleMIDISession::ReceivedControlInvitation(A #endif return; - // advertise our own session name #ifdef KEEP_SESSION_NAME strncpy(invitation.sessionName, localName, DefaultSettings::MaxSessionNameLen); invitation.sessionName[DefaultSettings::MaxSessionNameLen] = '\0'; @@ -119,7 +118,7 @@ void AppleMIDISession::ReceivedControlInvitation(A #ifndef ONE_PARTICIPANT if (participants.full()) #else - if (participant.remoteIP != INADDR_NONE) + if (participant.ssrc != 0) #endif { writeInvitation(controlPort, controlPort.remoteIP(), controlPort.remotePort(), invitation, amInvitationRejected); @@ -252,7 +251,6 @@ void AppleMIDISession::ReceivedInvitationRejected( participants.erase(i); #else participant.ssrc = 0; - participant.remoteIP = INADDR_NONE; #endif return; } @@ -416,7 +414,6 @@ void AppleMIDISession::ReceivedEndSession(AppleMID participants.erase(i); #else participant.ssrc = 0; - participant.remoteIP = INADDR_NONE; #endif if (nullptr != _disconnectedCallback) _disconnectedCallback(ssrc); @@ -632,10 +629,10 @@ void AppleMIDISession::manageSynchronization() { #ifndef ONE_PARTICIPANT auto pParticipant = &participants[i]; - if (pParticipant->remoteIP == INADDR_NONE) continue; + if (pParticipant->ssrc == 0) continue; #else auto pParticipant = &participant; - if (pParticipant->remoteIP == INADDR_NONE) return; + if (pParticipant->ssrc == 0) return; #endif #ifdef APPLEMIDI_INITIATOR if (pParticipant->invitationStatus != Connected) @@ -658,7 +655,6 @@ void AppleMIDISession::manageSynchronization() participants.erase(i); #else participant.ssrc = 0; - participant.remoteIP = INADDR_NONE; #endif } #ifdef APPLEMIDI_INITIATOR @@ -738,7 +734,6 @@ void AppleMIDISession::manageSynchronizationInitia participants.erase(i); #else participant.ssrc = 0; - participant.remoteIP = INADDR_NONE; #endif return; } @@ -818,7 +813,6 @@ void AppleMIDISession::manageSessionInvites() participants.erase(i); #else participant.ssrc = 0; - pParticipant->remoteIP = INADDR_NONE; #endif #ifndef ONE_PARTICIPANT continue; @@ -870,10 +864,10 @@ void AppleMIDISession::manageReceiverFeedback() { #ifndef ONE_PARTICIPANT auto pParticipant = &participants[i]; - if (pParticipant->remoteIP == INADDR_NONE) continue; + if (pParticipant->ssrc == 0) continue; #else auto pParticipant = &participant; - if (pParticipant->remoteIP == INADDR_NONE) return; + if (pParticipant->ssrc == 0) return; #endif if (pParticipant->doReceiverFeedback == false) @@ -904,7 +898,7 @@ bool AppleMIDISession::sendInvite(IPAddress ip, ui #ifndef ONE_PARTICIPANT if (participants.full()) #else - if (participant.remoteIP != INADDR_NONE) + if (participant.ssrc != 0) #endif { return false; @@ -942,10 +936,10 @@ void AppleMIDISession::sendEndSession() participants.pop_front(); } #else - if (participant.remoteIP != INADDR_NONE) + if (participant.src != 0) { sendEndSession(&participant); - participant.remoteIP = INADDR_NONE; + participant.ssrc = 0; } #endif } From 952c31dfc478ff0d99b7dd62d139442b71b7921a Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 23 Dec 2020 12:59:27 +0100 Subject: [PATCH 19/60] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1cf1289..f5bbff9 100755 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Beware: the number of sockets on the Arduino is limited. The W5100 support 4, th Reduce the memory footprint by a further 500 bytes by `#define NO_SESSION_NAME` before `#include `. This will leave out all the code to manage the optional session name. By default the session name is kept. Even further reduce the memory footprint by `#define ONE_PARTICIPANT` limiting the number of particpants to just 1. -On an UNO the absolute minimum memory footprint is 22142 bytes (68%) and 946 global variables (46%). +On an UNO the absolute minimum memory footprint is 21976 bytes (68%) and 946 global variables (46%). ## Network Shields * Arduino Ethernet shield (Wiznet W5100 and W5500) From 8654ca3225d010a4dd59ea0fabd693b9bc0466f2 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 23 Dec 2020 14:53:18 +0100 Subject: [PATCH 20/60] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f5bbff9..d1ca3ec 100755 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Beware: the number of sockets on the Arduino is limited. The W5100 support 4, th Reduce the memory footprint by a further 500 bytes by `#define NO_SESSION_NAME` before `#include `. This will leave out all the code to manage the optional session name. By default the session name is kept. Even further reduce the memory footprint by `#define ONE_PARTICIPANT` limiting the number of particpants to just 1. -On an UNO the absolute minimum memory footprint is 21976 bytes (68%) and 946 global variables (46%). +On an UNO the absolute minimum memory footprint is 21976 bytes (68%) and 946 global variables (46%). For a Leonardo that is 24916 bytes (86%) and 1112 bytes (43%) of global variables. ## Network Shields * Arduino Ethernet shield (Wiznet W5100 and W5500) From 8a138d17f0486956255b2a7f96546df26f785aec Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 23 Dec 2020 14:56:19 +0100 Subject: [PATCH 21/60] Update README.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d1ca3ec..c7781a3 100755 --- a/README.md +++ b/README.md @@ -57,7 +57,13 @@ More usages in the [examples](https://github.com/lathoub/Arduino-AppleMIDI-Libra * ESP32 (Adafruit HUZZAH32 – ESP32 Feather Board) * Teensy 3.2 * Adafruit Feather M0 WiFi - ATSAMD21 + ATWINC1500 - + +## Network Shields +* Arduino Ethernet shield (Wiznet W5100 and W5500) +* Arduino Wifi R3 shield +* MKR ETH shield +* Teensy WIZ820io W5200 + ## Memory usage 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 (and LATENCY_CALCULATION). See the callback examamples. @@ -74,12 +80,6 @@ Reduce the memory footprint by a further 500 bytes by `#define NO_SESSION_NAME` Even further reduce the memory footprint by `#define ONE_PARTICIPANT` limiting the number of particpants to just 1. On an UNO the absolute minimum memory footprint is 21976 bytes (68%) and 946 global variables (46%). For a Leonardo that is 24916 bytes (86%) and 1112 bytes (43%) of global variables. -## Network Shields -* Arduino Ethernet shield (Wiznet W5100 and W5500) -* Arduino Wifi R3 shield -* MKR ETH shield -* Teensy WIZ820io W5200 - ## Arduino IDE (arduino.cc) * 1.8.13 From 777a69882bd989d18a932719f51619057d52ffe3 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 23 Dec 2020 20:33:35 +0100 Subject: [PATCH 22/60] Update AVR_NoteOnOffEverySec.ino --- examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino b/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino index 52c28d3..23d5f58 100644 --- a/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino +++ b/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino @@ -1,6 +1,5 @@ #include -#define ONE_PARTICIPANT #define SerialMon Serial #define APPLEMIDI_DEBUG SerialMon #include From df64cae89bd425e7a5e3d40c64b41c2a37605f81 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Thu, 24 Dec 2020 07:17:02 +0100 Subject: [PATCH 23/60] added Directory --- examples/AVR_Callbacks/AVR_Callbacks.ino | 6 + examples/AVR_Directory/AVR_Directory.ino | 86 ++++++++ examples/ESP32_Callbacks/ESP32_Callbacks.ino | 207 ------------------- src/AppleMIDI.h | 18 +- src/AppleMIDI.hpp | 53 ++++- src/AppleMIDI_Defs.h | 9 +- src/AppleMIDI_Settings.h | 2 +- 7 files changed, 152 insertions(+), 229 deletions(-) create mode 100644 examples/AVR_Directory/AVR_Directory.ino delete mode 100644 examples/ESP32_Callbacks/ESP32_Callbacks.ino diff --git a/examples/AVR_Callbacks/AVR_Callbacks.ino b/examples/AVR_Callbacks/AVR_Callbacks.ino index c79155e..bf76501 100644 --- a/examples/AVR_Callbacks/AVR_Callbacks.ino +++ b/examples/AVR_Callbacks/AVR_Callbacks.ino @@ -119,6 +119,12 @@ void OnAppleMidiException(const APPLEMIDI_NAMESPACE::ssrc_t& ssrc, const APPLEMI case APPLEMIDI_NAMESPACE::Exception::ParticipantNotFoundException: DBG(F("*** ParticipantNotFoundException"), value); break; + case APPLEMIDI_NAMESPACE::Exception::ComputerNotInDirectory: + DBG(F("*** ComputerNotInDirectory"), value); + break; + case APPLEMIDI_NAMESPACE::Exception::NotAcceptingAnyone: + DBG(F("*** NotAcceptingAnyone"), value); + break; case APPLEMIDI_NAMESPACE::Exception::ListenerTimeOutException: DBG(F("*** ListenerTimeOutException")); break; diff --git a/examples/AVR_Directory/AVR_Directory.ino b/examples/AVR_Directory/AVR_Directory.ino new file mode 100644 index 0000000..9487ef5 --- /dev/null +++ b/examples/AVR_Directory/AVR_Directory.ino @@ -0,0 +1,86 @@ +#include + +#define USE_DIRECTORY +#define SerialMon Serial +#define APPLEMIDI_DEBUG SerialMon +#include + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; + +unsigned long t1 = millis(); +bool isConnected = false; + +APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +void setup() +{ + DBG_SETUP(115200); + DBG("Booting"); + + if (Ethernet.begin(mac) == 0) { + DBG(F("Failed DHCP, check network cable & reboot")); + for (;;); + } + + AppleMIDI.directory.push_back(IPAddress(192, 168, 1, 63)); + AppleMIDI.directory.push_back(IPAddress(192, 168, 1, 66)); +// AppleMIDI.whoCanConnectToMe = APPLEMIDI_NAMESPACE::None; + AppleMIDI.whoCanConnectToMe = APPLEMIDI_NAMESPACE::OnlyComputersInMyDirectory; +// AppleMIDI.whoCanConnectToMe = APPLEMIDI_NAMESPACE::Anyone; + + DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); + DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); + DBG(F("Select and then press the Connect button")); + DBG(F("Then open a MIDI listener and monitor incoming notes")); + + MIDI.begin(); + + // Stay informed on connection status + AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { + isConnected = true; + DBG(F("Connected to session"), name); + }); + AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { + isConnected = false; + DBG(F("Disconnected")); + }); + + MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { + DBG(F("NoteOn"), note); + }); + MIDI.setHandleNoteOff([](byte channel, byte note, byte velocity) { + DBG(F("NoteOff"), note); + }); + + DBG(F("Sending MIDI messages every second")); +} + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +void loop() +{ + // Listen to incoming notes + MIDI.read(); + + // send a note every second + // (dont cáll delay(1000) as it will stall the pipeline) + if (isConnected && (millis() - t1) > 1000) + { + t1 = millis(); + + byte note = random(1, 127); + byte velocity = 55; + byte channel = 1; + + MIDI.sendNoteOn(note, velocity, channel); + // MIDI.sendNoteOff(note, velocity, channel); + } +} diff --git a/examples/ESP32_Callbacks/ESP32_Callbacks.ino b/examples/ESP32_Callbacks/ESP32_Callbacks.ino deleted file mode 100644 index 6245bdf..0000000 --- a/examples/ESP32_Callbacks/ESP32_Callbacks.ino +++ /dev/null @@ -1,207 +0,0 @@ -#include -#include - -#define LATENCY_CALCULATION -#define USE_EXT_CALLBACKS -#define SerialMon Serial -#define APPLEMIDI_DEBUG SerialMon -#include - -#include "arduino_secrets.h" // contains SECRET_SSID and SECRET_PASS - -bool isConnected = false; - -APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); - -void setup() { - DBG_SETUP(115200); - DBG("Booting"); - - WiFi.begin(SECRET_SSID, SECRET_PASS); - while (WiFi.status() != WL_CONNECTED) { - delay(1000); - DBG("Establishing connection to WiFi.."); - } - DBG("Connected to network"); - - MDNS.begin(AppleMIDI.getName()); - - DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); - DBG(F("Add device named Arduino with Host"), WiFi.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); - DBG(F("Select and then press the Connect button")); - DBG(F("Then open a MIDI listener and monitor incoming notes")); - - AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { - isConnected = true; - DBG(F("Connected to session"), name); - }); - AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; - DBG(F("Disconnected")); - }); - - AppleMIDI.setHandleSendRtp([](const APPLEMIDI_NAMESPACE::Rtp_t& rtp) { - DBG(F("setHandleSendRtp"), rtp.sequenceNr); - }); - AppleMIDI.setHandleReceivedRtp([](const APPLEMIDI_NAMESPACE::Rtp_t& rtp, const int32_t& latency) { - DBG(F("setHandleReceivedRtp"), rtp.sequenceNr ,latency); - }); - AppleMIDI.setHandleStartReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t&) { - DBG(F("setHandleStartReceivedMidi")); - }); - AppleMIDI.setHandleReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t&, byte value) { - DBG(F("setHandleReceivedMidi"), value); - }); - AppleMIDI.setHandleEndReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t&) { - DBG(F("setHandleEndReceivedMidi")); - }); - - AppleMIDI.setHandleException(OnAppleMidiException); - - MIDI.begin(); - - MIDI.setHandleNoteOff(OnMidiNoteOff); - MIDI.setHandleNoteOn(OnMidiNoteOn); - MIDI.setHandleAfterTouchPoly(OnAfterTouchPoly); - MIDI.setHandleControlChange(OnControlChange); - MIDI.setHandleProgramChange(OnProgramChange); - MIDI.setHandleAfterTouchChannel(OnAfterTouchChannel); - MIDI.setHandlePitchBend(OnPitchBend); - MIDI.setHandleSystemExclusive(OnSystemExclusive); - MIDI.setHandleTimeCodeQuarterFrame(OnTimeCodeQuarterFrame); - MIDI.setHandleSongPosition(OnSongPosition); - MIDI.setHandleSongSelect(OnSongSelect); - MIDI.setHandleTuneRequest(OnTuneRequest); - MIDI.setHandleClock(OnClock); - MIDI.setHandleStart(OnStart); - MIDI.setHandleContinue(OnContinue); - MIDI.setHandleStop(OnStop); - MIDI.setHandleActiveSensing(OnActiveSensing); - MIDI.setHandleSystemReset(OnSystemReset); - - MDNS.addService("apple-midi", "udp", AppleMIDI.getPort()); - - DBG(F("Ready")); -} - -void loop() { - MIDI.read(); -} - -// ----------------------------------------------------------------------------- -// -// ----------------------------------------------------------------------------- -void OnAppleMidiException(const APPLEMIDI_NAMESPACE::ssrc_t& ssrc, const APPLEMIDI_NAMESPACE::Exception& e, const int32_t value ) { - switch (e) - { - case APPLEMIDI_NAMESPACE::Exception::BufferFullException: - DBG(F("*** BufferFullException")); - break; - case APPLEMIDI_NAMESPACE::Exception::ParseException: - DBG(F("*** ParseException")); - break; - case APPLEMIDI_NAMESPACE::Exception::TooManyParticipantsException: - DBG(F("*** TooManyParticipantsException")); - break; - case APPLEMIDI_NAMESPACE::Exception::UnexpectedInviteException: - DBG(F("*** UnexpectedInviteException")); - break; - case APPLEMIDI_NAMESPACE::Exception::ParticipantNotFoundException: - DBG(F("*** ParticipantNotFoundException"), value); - break; - case APPLEMIDI_NAMESPACE::Exception::ListenerTimeOutException: - DBG(F("*** ListenerTimeOutException")); - break; - case APPLEMIDI_NAMESPACE::Exception::MaxAttemptsException: - DBG(F("*** MaxAttemptsException")); - break; - case APPLEMIDI_NAMESPACE::Exception::NoResponseFromConnectionRequestException: - DBG(F("***:yyy did't respond to the connection request. Check the address and port, and any firewall or router settings. (time)")); - break; - case APPLEMIDI_NAMESPACE::Exception::SendPacketsDropped: - DBG(F("*** SendPacketsDropped"), value); - break; - case APPLEMIDI_NAMESPACE::Exception::ReceivedPacketsDropped: - DBG(F("*** ReceivedPacketsDropped"), value); - break; - } -} - -//------ - -static void OnMidiNoteOff(byte channel, byte note, byte velocity) { - DBG(F("in\tNote off"), note, " Velocity", velocity, "\t", channel); -} - -static void OnMidiNoteOn(byte channel, byte note, byte velocity) { - DBG(F("in\tNote on"), note, " Velocity", velocity, "\t", channel); -} - -static void OnAfterTouchPoly(byte channel, byte note, byte velocity) { - DBG(F("AfterTouchPoly. Channel:"), channel, " Note:", note, " Velocity:", velocity); -} - -static void OnControlChange(byte channel, byte note, byte velocity) { - DBG(F("ControlChange. Channel:"), channel, " Note:", note, " Velocity:", velocity); -} - -static void OnProgramChange(byte channel, byte note) { - DBG(F("ProgramChange. Channel:"), channel, " Note:", note); -} - -static void OnAfterTouchChannel(byte channel, byte note) { - DBG(F("AfterTouchChannel. Channel:"), channel, " Note:", note); -} - -static void OnPitchBend(byte channel, int note) { - DBG(F("PitchBend. Channel:"), channel, " Note:", note); -} - -static void OnSystemExclusive(byte* data, unsigned size) { - DBG(F("System exclusive")); - for (int i = 0; i < size; i++) { - SerialMon.print(F(" 0x")); - SerialMon.print(data[i], HEX); - } - SerialMon.println(); -} - -static void OnTimeCodeQuarterFrame(byte data) { - DBG(F("TimeCodeQuarterFrame")); -} - -static void OnSongPosition(unsigned beats) { - DBG(F("SongPosition:"), beats); -} - -static void OnSongSelect(byte songNumber) { - DBG(F("SongSelect"), songNumber); -} - -static void OnTuneRequest() { - DBG(F("Tune request")); -} - -static void OnClock() { - DBG(F("Clock")); -} - -static void OnStart() { - DBG(F("Start")); -} - -static void OnContinue() { - DBG(F("Continue")); -} - -static void OnStop() { - DBG(F("Stop")); -} - -static void OnActiveSensing() { - DBG(F("ActiveSensing")); -} - -static void OnSystemReset() { - DBG(F("SystemReset")); -} diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index 95826be..6556c6e 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -85,6 +85,11 @@ class AppleMIDISession // Override default thruActivated static const bool thruActivated = false; +#ifdef USE_DIRECTORY + Deque directory; + WhoCanConnectToMe whoCanConnectToMe = Anyone; +#endif + void begin() { _appleMIDIParser.session = this; @@ -250,15 +255,11 @@ class AppleMIDISession ssrc_t ssrc = 0; uint16_t port = DEFAULT_CONTROL_PORT; - WhoCanConnectToMe whoCanConnectToMe = Anyone; #ifdef ONE_PARTICIPANT Participant participant; #else Deque, Settings::MaxNumberOfParticipants> participants; #endif -#ifdef USE_DIRECTORY - Deque directory; -#endif #ifdef KEEP_SESSION_NAME char localName[DefaultSettings::MaxSessionNameLen + 1]; @@ -291,7 +292,7 @@ class AppleMIDISession void EndReceivedMidi(); // Helpers - void writeInvitation (UdpClass &, IPAddress, uint16_t, AppleMIDI_Invitation_t &, const byte *command); + void writeInvitation (UdpClass &, const IPAddress &, const uint16_t &, AppleMIDI_Invitation_t &, const byte *command); void writeReceiverFeedback(const IPAddress &, const uint16_t &, AppleMIDI_ReceiverFeedback_t &); void writeSynchronization (const IPAddress &, const uint16_t &, AppleMIDI_Synchronization_t &); void writeEndSession (const IPAddress &, const uint16_t &, AppleMIDI_EndSession_t &); @@ -312,8 +313,11 @@ class AppleMIDISession void sendSynchronization(Participant*); #ifndef ONE_PARTICIPANT - Participant* getParticipantBySSRC(const ssrc_t ssrc); - Participant* getParticipantByInitiatorToken(const uint32_t initiatorToken); + Participant* getParticipantBySSRC(const ssrc_t&); + Participant* getParticipantByInitiatorToken(const uint32_t& initiatorToken); +#endif +#ifdef USE_DIRECTORY + bool IsComputerInDirectory(const IPAddress&); #endif }; diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index b3b9ea2..42e2bfd 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -102,6 +102,32 @@ void AppleMIDISession::ReceivedInvitation(AppleMID template void AppleMIDISession::ReceivedControlInvitation(AppleMIDI_Invitation_t &invitation) { +#ifdef KEEP_SESSION_NAME + strncpy(invitation.sessionName, localName, DefaultSettings::MaxSessionNameLen); + invitation.sessionName[DefaultSettings::MaxSessionNameLen] = '\0'; +#endif + +#ifdef USE_DIRECTORY + switch (whoCanConnectToMe) { + case None: + writeInvitation(controlPort, controlPort.remoteIP(), controlPort.remotePort(), invitation, amInvitationRejected); +#ifdef USE_EXT_CALLBACKS + if (nullptr != _exceptionCallback) + _exceptionCallback(ssrc, NotAcceptingAnyone, 0); +#endif + return; + case OnlyComputersInMyDirectory: + if (!IsComputerInDirectory(controlPort.remoteIP())) { + writeInvitation(controlPort, controlPort.remoteIP(), controlPort.remotePort(), invitation, amInvitationRejected); +#ifdef USE_EXT_CALLBACKS + if (nullptr != _exceptionCallback) + _exceptionCallback(ssrc, ComputerNotInDirectory, 0); +#endif + return; + } + } +#endif + // ignore invitation of a participant already in the participant list #ifndef ONE_PARTICIPANT if (nullptr != getParticipantBySSRC(invitation.ssrc)) @@ -109,20 +135,14 @@ void AppleMIDISession::ReceivedControlInvitation(A if (participant.ssrc == invitation.ssrc) #endif return; - -#ifdef KEEP_SESSION_NAME - strncpy(invitation.sessionName, localName, DefaultSettings::MaxSessionNameLen); - invitation.sessionName[DefaultSettings::MaxSessionNameLen] = '\0'; -#endif - + #ifndef ONE_PARTICIPANT if (participants.full()) #else if (participant.ssrc != 0) #endif { - writeInvitation(controlPort, controlPort.remoteIP(), controlPort.remotePort(), invitation, amInvitationRejected); - + writeInvitation(controlPort, controlPort.remoteIP(), controlPort.remotePort(), invitation, amInvitationRejected); #ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) _exceptionCallback(ssrc, TooManyParticipantsException, 0); @@ -423,9 +443,20 @@ void AppleMIDISession::ReceivedEndSession(AppleMID } } +#ifdef USE_DIRECTORY +template +bool AppleMIDISession::IsComputerInDirectory(const IPAddress& remoteIP) +{ + for (size_t i = 0; i < directory.size(); i++) + if (remoteIP == directory[i]) + return true; + return false; +} +#endif + #ifndef ONE_PARTICIPANT template -Participant* AppleMIDISession::getParticipantBySSRC(const ssrc_t ssrc) +Participant* AppleMIDISession::getParticipantBySSRC(const ssrc_t& ssrc) { for (size_t i = 0; i < participants.size(); i++) if (ssrc == participants[i].ssrc) @@ -434,7 +465,7 @@ Participant* AppleMIDISession::getPartic } template -Participant* AppleMIDISession::getParticipantByInitiatorToken(const uint32_t initiatorToken) +Participant* AppleMIDISession::getParticipantByInitiatorToken(const uint32_t& initiatorToken) { for (auto i = 0; i < participants.size(); i++) if (initiatorToken == participants[i].initiatorToken) @@ -444,7 +475,7 @@ Participant* AppleMIDISession::getPartic #endif template -void AppleMIDISession::writeInvitation(UdpClass &port, IPAddress remoteIP, uint16_t remotePort, AppleMIDI_Invitation_t & invitation, const byte *command) +void AppleMIDISession::writeInvitation(UdpClass &port, const IPAddress& remoteIP, const uint16_t& remotePort, AppleMIDI_Invitation_t & invitation, const byte *command) { if (port.beginPacket(remoteIP, remotePort)) { diff --git a/src/AppleMIDI_Defs.h b/src/AppleMIDI_Defs.h index b43db88..faa6087 100644 --- a/src/AppleMIDI_Defs.h +++ b/src/AppleMIDI_Defs.h @@ -40,10 +40,9 @@ typedef const char* AppleMIDIConstStr; #define RtpBuffer_t Deque #define MidiBuffer_t Deque -// Add extended callbacks to enabling these #defines -// #define LATENCY_CALCULATION // #define USE_EXT_CALLBACKS -// #define ONE_PARTICIPANT // TODO +// #define LATENCY_CALCULATION // only usefull when declaring USE_EXT_CALLBACKS +// #define ONE_PARTICIPANT // memory optimization // #define USE_DIRECTORY // By defining NO_SESSION_NAME in the sketch, you can save 100 bytes @@ -58,12 +57,14 @@ typedef const char* AppleMIDIConstStr; struct Rtp; typedef Rtp Rtp_t; +#ifdef USE_DIRECTORY enum WhoCanConnectToMe : uint8_t { None, OnlyComputersInMyDirectory, Anyone, }; +#endif // from: https://en.wikipedia.org/wiki/RTP-MIDI // Apple decided to create their own protocol, imposing all parameters related to @@ -107,6 +108,8 @@ enum Exception : uint8_t ParseException, UnexpectedParseException, TooManyParticipantsException, + ComputerNotInDirectory, + NotAcceptingAnyone, UnexpectedInviteException, ParticipantNotFoundException, ListenerTimeOutException, diff --git a/src/AppleMIDI_Settings.h b/src/AppleMIDI_Settings.h index 346c188..31bc41a 100644 --- a/src/AppleMIDI_Settings.h +++ b/src/AppleMIDI_Settings.h @@ -14,7 +14,7 @@ struct DefaultSettings static const uint8_t MaxNumberOfParticipants = 2; - static const uint8_t MaxNumberOfComputersInDirectory = 2; + static const uint8_t MaxNumberOfComputersInDirectory = 5; // The recovery journal mechanism requires that the receiver periodically // inform the sender of the sequence number of the most recently received packet. From b4a0b24e0f002fc86a2355042a8c67f646028abf Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Thu, 24 Dec 2020 14:50:13 +0100 Subject: [PATCH 24/60] joined USE_EXT_CALLBACKS, LATENCY_CALCULATION --- README.md | 3 +-- examples/AVR_Callbacks/AVR_Callbacks.ino | 1 - src/AppleMIDI.hpp | 15 +++++++-------- src/AppleMIDI_Defs.h | 1 - src/AppleMIDI_Participant.h | 2 +- src/rtpMIDI_Parser_JournalSection.hpp | 2 +- 6 files changed, 10 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index c7781a3..f1651a0 100755 --- a/README.md +++ b/README.md @@ -65,8 +65,7 @@ More usages in the [examples](https://github.com/lathoub/Arduino-AppleMIDI-Libra * Teensy WIZ820io W5200 ## Memory usage -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 (and -LATENCY_CALCULATION). See the callback examamples. +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. 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. diff --git a/examples/AVR_Callbacks/AVR_Callbacks.ino b/examples/AVR_Callbacks/AVR_Callbacks.ino index bf76501..7b728bf 100644 --- a/examples/AVR_Callbacks/AVR_Callbacks.ino +++ b/examples/AVR_Callbacks/AVR_Callbacks.ino @@ -1,6 +1,5 @@ #include -#define LATENCY_CALCULATION #define USE_EXT_CALLBACKS #define SerialMon Serial #define APPLEMIDI_DEBUG SerialMon diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index 42e2bfd..d6ceb79 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -125,6 +125,8 @@ void AppleMIDISession::ReceivedControlInvitation(A #endif return; } + case Anyone: + break; } #endif @@ -371,7 +373,7 @@ void AppleMIDISession::ReceivedSynchronization(App break; case SYNC_CK2: /* From session APPLEMIDI_INITIATOR */ -#ifdef LATENCY_CALCULATION +#ifdef USE_EXT_CALLBACKS // each party can estimate the offset between the two clocks using the following formula pParticipant->offsetEstimate = (uint32_t)(((synchronization.timestamps[2] + synchronization.timestamps[0]) / 2) - synchronization.timestamps[1]); #endif @@ -445,7 +447,7 @@ void AppleMIDISession::ReceivedEndSession(AppleMID #ifdef USE_DIRECTORY template -bool AppleMIDISession::IsComputerInDirectory(const IPAddress& remoteIP) +bool AppleMIDISession::IsComputerInDirectory(IPAddress remoteIP) const { for (size_t i = 0; i < directory.size(); i++) if (remoteIP == directory[i]) @@ -890,7 +892,7 @@ template void AppleMIDISession::manageReceiverFeedback() { #ifndef ONE_PARTICIPANT - for (auto i = 0; i < participants.size(); i++) + for (uint8_t i = 0; i < participants.size(); i++) #endif { #ifndef ONE_PARTICIPANT @@ -1002,13 +1004,10 @@ void AppleMIDISession::ReceivedRtp(const Rtp_t& rt pParticipant->receiverFeedbackStartTime = now; pParticipant->doReceiverFeedback = true; -#ifdef LATENCY_CALCULATION - auto offset = (rtp.timestamp - participant->offsetEstimate); +#ifdef USE_EXT_CALLBACKS + auto offset = (rtp.timestamp - pParticipant->offsetEstimate); auto latency = (int32_t)(rtpMidiClock.Now() - offset); -#else - auto latency = 0; #endif - if (pParticipant->receiveSequenceNr + 1 != rtp.sequenceNr) { #ifdef USE_EXT_CALLBACKS diff --git a/src/AppleMIDI_Defs.h b/src/AppleMIDI_Defs.h index faa6087..ba99a4c 100644 --- a/src/AppleMIDI_Defs.h +++ b/src/AppleMIDI_Defs.h @@ -41,7 +41,6 @@ typedef const char* AppleMIDIConstStr; #define MidiBuffer_t Deque // #define USE_EXT_CALLBACKS -// #define LATENCY_CALCULATION // only usefull when declaring USE_EXT_CALLBACKS // #define ONE_PARTICIPANT // memory optimization // #define USE_DIRECTORY diff --git a/src/AppleMIDI_Participant.h b/src/AppleMIDI_Participant.h index e0ba1a5..28dcfcf 100644 --- a/src/AppleMIDI_Participant.h +++ b/src/AppleMIDI_Participant.h @@ -32,7 +32,7 @@ struct Participant bool synchronizing = false; #endif -#ifdef LATENCY_CALCULATION +#ifdef USE_EXT_CALLBACKS uint32_t offsetEstimate; #endif diff --git a/src/rtpMIDI_Parser_JournalSection.hpp b/src/rtpMIDI_Parser_JournalSection.hpp index 41b0def..1606224 100644 --- a/src/rtpMIDI_Parser_JournalSection.hpp +++ b/src/rtpMIDI_Parser_JournalSection.hpp @@ -48,7 +48,7 @@ parserReturn decodeJournalSection(RtpBuffer_t &buffer) // stream (modulo 2^16). cb.buffer[0] = buffer[i++]; cb.buffer[1] = buffer[i++]; - uint16_t checkPoint = ntohs(cb.value16); // unused + // uint16_t checkPoint = ntohs(cb.value16); ; // unused // (RFC 4695, 5 Recovery Journal Format) // If A and Y are both zero, the recovery journal only contains its 3- From 68c9082a89ab7b20f84cc89905bff0dde8d97e2a Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Thu, 24 Dec 2020 14:50:45 +0100 Subject: [PATCH 25/60] Update AppleMIDI.h cast INADDR_NONE to avoid compilation errors --- src/AppleMIDI.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index 6556c6e..4ea6d82 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -143,9 +143,9 @@ class AppleMIDISession // length of the buffer). So we'll copy to a buffer in the 'write' method, // and actually serialize for real in the endTransmission method #ifndef ONE_PARTICIPANT - return (dataPort.remoteIP() != INADDR_NONE && participants.size() > 0); + return (dataPort.remoteIP() != (IPAddress)INADDR_NONE && participants.size() > 0); #else - return (dataPort.remoteIP() != INADDR_NONE && participant.ssrc != 0); + return (dataPort.remoteIP() != (IPAddress)INADDR_NONE && participant.ssrc != 0); #endif }; @@ -317,7 +317,7 @@ class AppleMIDISession Participant* getParticipantByInitiatorToken(const uint32_t& initiatorToken); #endif #ifdef USE_DIRECTORY - bool IsComputerInDirectory(const IPAddress&); + bool IsComputerInDirectory(IPAddress) const; #endif }; From 88850b3e0ad9fa2468f6fde2bde20c883366f335 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Mon, 28 Dec 2020 11:16:56 +0100 Subject: [PATCH 26/60] fixed crash when session name is too long (> MaxSessionName) --- src/AppleMIDI_Parser.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/AppleMIDI_Parser.h b/src/AppleMIDI_Parser.h index 74fbe8d..6c4dd8a 100644 --- a/src/AppleMIDI_Parser.h +++ b/src/AppleMIDI_Parser.h @@ -80,7 +80,7 @@ class AppleMIDIParser uint16_t bi = 0; while ((i < buffer.size()) && (buffer[i] != 0x00)) { - if (bi <= DefaultSettings::MaxSessionNameLen) + if (bi < DefaultSettings::MaxSessionNameLen) invitation.sessionName[bi++] = buffer[i]; i++; } @@ -269,7 +269,7 @@ class AppleMIDIParser uint16_t bi = 0; while ((i < buffer.size()) && (buffer[i] != 0x00)) { - if (bi <= DefaultSettings::MaxSessionNameLen) + if (bi < DefaultSettings::MaxSessionNameLen) invitationAccepted.sessionName[bi++] = buffer[i]; i++; } @@ -331,7 +331,7 @@ class AppleMIDIParser uint16_t bi = 0; while ((i < buffer.size()) && (buffer[i] != 0x00)) { - if (bi <= DefaultSettings::MaxSessionNameLen) + if (bi < DefaultSettings::MaxSessionNameLen) invitationRejected.sessionName[bi++] = buffer[i]; i++; } From 095e6d402ef517a7b104c61539f4ebc0e1cf0af4 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Mon, 28 Dec 2020 11:18:41 +0100 Subject: [PATCH 27/60] Create ESP32_NoteOnOffEverySec.ino --- .../ESP32_NoteOnOffEverySec.ino | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino diff --git a/examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino b/examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino new file mode 100644 index 0000000..0368967 --- /dev/null +++ b/examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino @@ -0,0 +1,82 @@ +#include +#include +#include + +#define NO_SESSION_NAME +#define SerialMon Serial +#define APPLEMIDI_DEBUG SerialMon +#include + +char ssid[] = "ssid"; // your network SSID (name) +char pass[] = "password"; // your network password (use for WPA, or use as key for WEP) + +unsigned long t0 = millis(); +bool isConnected = false; + +APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +void setup() +{ + DBG_SETUP(115200); + DBG("Booting"); + + WiFi.begin(ssid, pass); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + DBG("Establishing connection to WiFi.."); + } + DBG("Connected to network"); + + DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); + DBG(F("Add device named Arduino with Host"), WiFi.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); + DBG(F("Select and then press the Connect button")); + DBG(F("Then open a MIDI listener and monitor incoming notes")); + DBG(F("Listen to incoming MIDI commands")); + + MIDI.begin(); + + AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { + isConnected = true; + DBG(F("Connected to session"), name); + }); + AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { + isConnected = false; + DBG(F("Disconnected")); + }); + + MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { + DBG(F("NoteOn"), note); + }); + MIDI.setHandleNoteOff([](byte channel, byte note, byte velocity) { + DBG(F("NoteOff"), note); + }); + + DBG(F("Sending NoteOn/Off of note 45, every second")); +} + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +void loop() +{ + // Listen to incoming notes + MIDI.read(); + + // send a note every second + // (dont cáll delay(1000) as it will stall the pipeline) + if (isConnected && (millis() - t0) > 1000) + { + t0 = millis(); + + byte note = 45; + byte velocity = 55; + byte channel = 1; + + MIDI.sendNoteOn(note, velocity, channel); + MIDI.sendNoteOff(note, velocity, channel); + } +} From 2f6d510ce8ace7d2a3deb7a326235e2895fffd83 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Mon, 28 Dec 2020 11:19:11 +0100 Subject: [PATCH 28/60] get* as const functions --- src/AppleMIDI.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index 4ea6d82..82d0edf 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -67,14 +67,14 @@ class AppleMIDISession #endif #ifdef KEEP_SESSION_NAME - const char* getName() { return this->localName; }; + const char* getName() const { return this->localName; }; void setName(const char *sessionName) { strncpy(this->localName, sessionName, DefaultSettings::MaxSessionNameLen); }; #else - const char* getName() { return nullptr; }; + const char* getName() const { return nullptr; }; void setName(const char *sessionName) { }; #endif - const uint16_t getPort() { return this->port; }; - const ssrc_t getSynchronizationSource() { return this->ssrc; }; + const uint16_t getPort() const { return this->port; }; + const ssrc_t getSynchronizationSource() const { return this->ssrc; }; #ifdef APPLEMIDI_INITIATOR bool sendInvite(IPAddress ip, uint16_t port = DEFAULT_CONTROL_PORT); From 613b7672f992a71c4faebe3a385733650850f254 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Mon, 28 Dec 2020 11:39:01 +0100 Subject: [PATCH 29/60] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f1651a0..127d277 100755 --- a/README.md +++ b/README.md @@ -78,7 +78,10 @@ Reduce the memory footprint by a further 500 bytes by `#define NO_SESSION_NAME` Even further reduce the memory footprint by `#define ONE_PARTICIPANT` limiting the number of particpants to just 1. On an UNO the absolute minimum memory footprint is 21976 bytes (68%) and 946 global variables (46%). For a Leonardo that is 24916 bytes (86%) and 1112 bytes (43%) of global variables. - + +## Notes +Session names can get really long on Macs (eg 'Macbook Pro of Johann Gambolputty de von Ausfern-schplenden-schlitter-crasscrenbon-fried-digger-dingle-dangle-dongle-dungle-burstein-von-knacker-thrasher-apple-banger-horowitz-ticolensic-grander-knotty-spelltinkle-grandlich-grumblemeyer-spelterwasser-kurstlich-himbleeisen-bahnwagen-gutenabend-bitte-ein-nürnburger-bratwustle-gerspurten-mitzweimache-luber-hundsfut-gumberaber-shönendanker-kalbsfleisch-mittler-aucher von Hautkopft of Ulm') and will be trunctated to the `MaxSessionNameLen` (as set in the settings file). + ## Arduino IDE (arduino.cc) * 1.8.13 From 4526bfbbdd5885ee3a22992b530b40a238b1f60d Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Mon, 28 Dec 2020 13:59:20 +0100 Subject: [PATCH 30/60] Update AppleMIDI.h --- src/AppleMIDI.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index 82d0edf..786836f 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -55,15 +55,15 @@ class AppleMIDISession #endif }; - void setHandleConnected(void (*fptr)(const ssrc_t&, const char*)) { _connectedCallback = fptr; } - void setHandleDisconnected(void (*fptr)(const ssrc_t&)) { _disconnectedCallback = fptr; } + void setHandleConnected (void (*fptr)(const ssrc_t&, const char*)) { _connectedCallback = fptr; } + void setHandleDisconnected (void (*fptr)(const ssrc_t&)) { _disconnectedCallback = fptr; } #ifdef USE_EXT_CALLBACKS - void setHandleException(void (*fptr)(const ssrc_t&, const Exception&, const int32_t value)) { _exceptionCallback = fptr; } - void setHandleReceivedRtp(void (*fptr)(const Rtp_t&, const int32_t&)) { _receivedRtpCallback = fptr; } - void setHandleStartReceivedMidi(void (*fptr)(const ssrc_t&)) { _startReceivedMidiByteCallback = fptr; } - void setHandleReceivedMidi(void (*fptr)(const ssrc_t&, byte)) { _receivedMidiByteCallback = fptr; } - void setHandleEndReceivedMidi(void (*fptr)(const ssrc_t&)) { _endReceivedMidiByteCallback = fptr; } - void setHandleSendRtp(void (*fptr)(const Rtp_t&)) { _sendRtpCallback = fptr; } + void setHandleException (void (*fptr)(const ssrc_t&, const Exception&, const int32_t value)) { _exceptionCallback = fptr; } + void setHandleReceivedRtp (void (*fptr)(const Rtp_t&, const int32_t&)) { _receivedRtpCallback = fptr; } + void setHandleStartReceivedMidi (void (*fptr)(const ssrc_t&)) { _startReceivedMidiByteCallback = fptr; } + void setHandleReceivedMidi (void (*fptr)(const ssrc_t&, byte)) { _receivedMidiByteCallback = fptr; } + void setHandleEndReceivedMidi (void (*fptr)(const ssrc_t&)) { _endReceivedMidiByteCallback = fptr; } + void setHandleSendRtp (void (*fptr)(const Rtp_t&)) { _sendRtpCallback = fptr; } #endif #ifdef KEEP_SESSION_NAME @@ -82,7 +82,7 @@ class AppleMIDISession void sendEndSession(); public: - // Override default thruActivated + // Override default thruActivated. Must be false for all packet based messages static const bool thruActivated = false; #ifdef USE_DIRECTORY From 93039452dd3a4f925613bd565a0a0b06f8ddb679 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Mon, 28 Dec 2020 13:59:41 +0100 Subject: [PATCH 31/60] removed extented callback from wESP32 demo --- .../wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino b/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino index 052bec4..7285659 100644 --- a/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino +++ b/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino @@ -1,4 +1,3 @@ -#define USE_EXT_CALLBACKS #define SerialMon Serial #define APPLEMIDI_DEBUG SerialMon #include @@ -39,9 +38,6 @@ void setup() isConnected = false; DBG(F("Disconnected")); }); - AppleMIDI.setHandleException([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const APPLEMIDI_NAMESPACE::Exception & e, const int32_t value) { - DBG(F("______________Exception"), e, value); - }); MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { DBG(F("NoteOn"), note); From 49e5121fdf62f478d7fc92354f88cface1fb879d Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Mon, 28 Dec 2020 15:48:35 +0100 Subject: [PATCH 32/60] added sentRtpMidiCallback, renamed send -> sent --- examples/AVR_Callbacks/AVR_Callbacks.ino | 28 ++++++++++++++---------- src/AppleMIDI.h | 6 +++-- src/AppleMIDI.hpp | 11 +++++++--- src/AppleMIDI_Defs.h | 6 ++++- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/examples/AVR_Callbacks/AVR_Callbacks.ino b/examples/AVR_Callbacks/AVR_Callbacks.ino index 7b728bf..b6fd907 100644 --- a/examples/AVR_Callbacks/AVR_Callbacks.ino +++ b/examples/AVR_Callbacks/AVR_Callbacks.ino @@ -22,7 +22,7 @@ APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); void setup() { DBG_SETUP(115200); - DBG("Booting"); + DBG("Das Booting"); if (Ethernet.begin(mac) == 0) { DBG(F("Failed DHCP, check network cable & reboot")); @@ -36,6 +36,7 @@ void setup() MIDI.begin(); + // Normal callbacks - always available // Stay informed on connection status AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { isConnected = true; @@ -45,23 +46,26 @@ void setup() isConnected = false; DBG(F("Disconnected")); }); - - AppleMIDI.setHandleSendRtp([](const APPLEMIDI_NAMESPACE::Rtp_t & rtp) { - DBG(F("setHandleSendRtp"), rtp.sequenceNr); + + // Extended callback, only available when defining USE_EXT_CALLBACKS + AppleMIDI.setHandleSentRtp([](const APPLEMIDI_NAMESPACE::Rtp_t & rtp) { + DBG(F("an rtpMessage has been sent with sequenceNr"), rtp.sequenceNr); + }); + AppleMIDI.setHandleSentRtpMidi([](const APPLEMIDI_NAMESPACE::RtpMIDI_t& rtpMidi) { + DBG(F("an rtpMidiMessage has been sent"), rtpMidi.flags); }); AppleMIDI.setHandleReceivedRtp([](const APPLEMIDI_NAMESPACE::Rtp_t & rtp, const int32_t& latency) { - DBG(F("setHandleReceivedRtp"), rtp.sequenceNr , latency); + DBG(F("setHandleReceivedRtp"), rtp.sequenceNr , "with", latency, "ms latency"); }); - AppleMIDI.setHandleStartReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t&) { - DBG(F("setHandleStartReceivedMidi")); + AppleMIDI.setHandleStartReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t& ssrc) { + DBG(F("setHandleStartReceivedMidi from SSRC"), ssrc); }); - AppleMIDI.setHandleReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t&, byte value) { - DBG(F("setHandleReceivedMidi"), value); + AppleMIDI.setHandleReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t& ssrc, byte value) { + DBG(F("setHandleReceivedMidi from SSRC"), ssrc, ", value:", value); }); - AppleMIDI.setHandleEndReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t&) { - DBG(F("setHandleEndReceivedMidi")); + AppleMIDI.setHandleEndReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t& ssrc) { + DBG(F("setHandleEndReceivedMidi from SSRC"), ssrc); }); - AppleMIDI.setHandleException(OnAppleMidiException); MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index 786836f..133288e 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -63,7 +63,8 @@ class AppleMIDISession void setHandleStartReceivedMidi (void (*fptr)(const ssrc_t&)) { _startReceivedMidiByteCallback = fptr; } void setHandleReceivedMidi (void (*fptr)(const ssrc_t&, byte)) { _receivedMidiByteCallback = fptr; } void setHandleEndReceivedMidi (void (*fptr)(const ssrc_t&)) { _endReceivedMidiByteCallback = fptr; } - void setHandleSendRtp (void (*fptr)(const Rtp_t&)) { _sendRtpCallback = fptr; } + void setHandleSentRtp (void (*fptr)(const Rtp_t&)) { _sentRtpCallback = fptr; } + void setHandleSentRtpMidi (void (*fptr)(const RtpMIDI_t&)) { _sentRtpMidiCallback = fptr; } #endif #ifdef KEEP_SESSION_NAME @@ -244,7 +245,8 @@ class AppleMIDISession receivedMidiByteCallback _receivedMidiByteCallback = nullptr; endReceivedMidiByteCallback _endReceivedMidiByteCallback = nullptr; receivedRtpCallback _receivedRtpCallback = nullptr; - sendRtpCallback _sendRtpCallback = nullptr; + sentRtpCallback _sentRtpCallback = nullptr; + sentRtpMidiCallback _sentRtpMidiCallback = nullptr; exceptionCallback _exceptionCallback = nullptr; #endif // buffer for incoming and outgoing MIDI messages diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index d6ceb79..5b03834 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -605,8 +605,8 @@ void AppleMIDISession::writeRtpMidiBuffer(Particip rtp.sequenceNr = participant->sendSequenceNr; #ifdef USE_EXT_CALLBACKS - if (_sendRtpCallback) - _sendRtpCallback(rtp); + if (_sentRtpCallback) + _sentRtpCallback(rtp); #endif rtp.timestamp = htonl(rtp.timestamp); @@ -643,8 +643,13 @@ void AppleMIDISession::writeRtpMidiBuffer(Particip // write out the MIDI Section for (size_t i = 0; i < bufferLen; i++) dataPort.write(outMidiBuffer[i]); - + // *No* journal section (Not supported) + +#ifdef USE_EXT_CALLBACKS + if (_sentRtpMidiCallback) + _sentRtpMidiCallback(rtpMidi); +#endif dataPort.endPacket(); dataPort.flush(); diff --git a/src/AppleMIDI_Defs.h b/src/AppleMIDI_Defs.h index ba99a4c..902cb6e 100644 --- a/src/AppleMIDI_Defs.h +++ b/src/AppleMIDI_Defs.h @@ -56,6 +56,9 @@ typedef const char* AppleMIDIConstStr; struct Rtp; typedef Rtp Rtp_t; +struct RtpMIDI; +typedef RtpMIDI RtpMIDI_t; + #ifdef USE_DIRECTORY enum WhoCanConnectToMe : uint8_t { @@ -126,7 +129,8 @@ using receivedMidiByteCallback = void (*)(const ssrc_t&, byte); using endReceivedMidiByteCallback = void (*)(const ssrc_t&); using receivedRtpCallback = void (*)(const Rtp_t&, const int32_t&); using exceptionCallback = void (*)(const ssrc_t&, const Exception&, const int32_t value); -using sendRtpCallback = void (*)(const Rtp_t&); +using sentRtpCallback = void (*)(const Rtp_t&); +using sentRtpMidiCallback = void (*)(const RtpMIDI_t&); #endif /* Signature "Magic Value" for Apple network MIDI session establishment */ From 2467d2d8add48b9dd093c5cd69f98a1e27104b89 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Mon, 28 Dec 2020 16:19:11 +0100 Subject: [PATCH 33/60] added ssrc to ReceiveMidi calls (private functions) --- src/AppleMIDI.h | 6 +++--- src/AppleMIDI.hpp | 12 +++++------ src/rtpMIDI_Parser_MidiCommandSection.hpp | 26 +++++++++++------------ 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index 133288e..b57bb31 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -289,9 +289,9 @@ class AppleMIDISession // rtpMIDI callback from parser void ReceivedRtp(const Rtp_t &); - void StartReceivedMidi(); - void ReceivedMidi(byte data); - void EndReceivedMidi(); + void StartReceivedMidi(const ssrc_t&); + void ReceivedMidi(const ssrc_t&, byte data); + void EndReceivedMidi(const ssrc_t&); // Helpers void writeInvitation (UdpClass &, const IPAddress &, const uint16_t &, AppleMIDI_Invitation_t &, const byte *command); diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index 5b03834..7a2f4e4 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -1035,31 +1035,31 @@ void AppleMIDISession::ReceivedRtp(const Rtp_t& rt } template -void AppleMIDISession::StartReceivedMidi() +void AppleMIDISession::StartReceivedMidi(const ssrc_t& ssrc) { #ifdef USE_EXT_CALLBACKS if (nullptr != _startReceivedMidiByteCallback) - _startReceivedMidiByteCallback(0); + _startReceivedMidiByteCallback(ssrc); #endif } template -void AppleMIDISession::ReceivedMidi(byte value) +void AppleMIDISession::ReceivedMidi(const ssrc_t& ssrc, byte value) { #ifdef USE_EXT_CALLBACKS if (nullptr != _receivedMidiByteCallback) - _receivedMidiByteCallback(0, value); + _receivedMidiByteCallback(ssrc, value); #endif inMidiBuffer.push_back(value); } template -void AppleMIDISession::EndReceivedMidi() +void AppleMIDISession::EndReceivedMidi(const ssrc_t& ssrc) { #ifdef USE_EXT_CALLBACKS if (nullptr != _endReceivedMidiByteCallback) - _endReceivedMidiByteCallback(0); + _endReceivedMidiByteCallback(ssrc); #endif } diff --git a/src/rtpMIDI_Parser_MidiCommandSection.hpp b/src/rtpMIDI_Parser_MidiCommandSection.hpp index 2f3711e..d4b5407 100644 --- a/src/rtpMIDI_Parser_MidiCommandSection.hpp +++ b/src/rtpMIDI_Parser_MidiCommandSection.hpp @@ -77,9 +77,9 @@ size_t decodeMidi(RtpBuffer_t &buffer, uint8_t &runningstatus) * not be intermingled with other MIDI-commands, so we handle this case right here and return */ if (octet >= 0xf8) { - session->StartReceivedMidi(); - session->ReceivedMidi(buffer[0]); - session->EndReceivedMidi(); + session->StartReceivedMidi(session->getSynchronizationSource()); + session->ReceivedMidi(session->getSynchronizationSource(), buffer[0]); + session->EndReceivedMidi(session->getSynchronizationSource()); return 1; } @@ -145,10 +145,10 @@ size_t decodeMidi(RtpBuffer_t &buffer, uint8_t &runningstatus) break; } - session->StartReceivedMidi(); + session->StartReceivedMidi(session->getSynchronizationSource()); for (size_t j = 0; j < consumed; j++) - session->ReceivedMidi(buffer[j]); - session->EndReceivedMidi(); + session->ReceivedMidi(session->getSynchronizationSource(), buffer[j]); + session->EndReceivedMidi(session->getSynchronizationSource()); return consumed; } @@ -175,10 +175,10 @@ size_t decodeMidi(RtpBuffer_t &buffer, uint8_t &runningstatus) break; } - session->StartReceivedMidi(); + session->StartReceivedMidi(session->getSynchronizationSource()); for (size_t j = 0; j < consumed; j++) - session->ReceivedMidi(buffer[j]); - session->EndReceivedMidi(); + session->ReceivedMidi(session->getSynchronizationSource(), buffer[j]); + session->EndReceivedMidi(session->getSynchronizationSource()); return consumed; } @@ -208,11 +208,11 @@ size_t decodeMidiSysEx(RtpBuffer_t &buffer) consumed--; // send MIDI data - session->StartReceivedMidi(); + session->StartReceivedMidi(session->getSynchronizationSource()); for (size_t j = 0; j < consumed; j++) - session->ReceivedMidi(buffer[j]); - session->ReceivedMidi(MIDI_NAMESPACE::MidiType::SystemExclusiveStart); - session->EndReceivedMidi(); + session->ReceivedMidi(session->getSynchronizationSource(), buffer[j]); + session->ReceivedMidi(session->getSynchronizationSource(), MIDI_NAMESPACE::MidiType::SystemExclusiveStart); + session->EndReceivedMidi(session->getSynchronizationSource()); // Remove the bytes that were submitted for (size_t j = 0; j < consumed; j++) From 5e3678d3cc47f2dfa64145136767d4ae76896bc1 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 13:52:43 +0100 Subject: [PATCH 34/60] receiverFeedback test is < not != --- examples/AVR_Callbacks/AVR_Callbacks.ino | 12 ++++---- examples/AVR_Directory/AVR_Directory.ino | 8 ++--- examples/AVR_Initiator/AVR_Initiator.ino | 8 ++--- examples/AVR_MinMemUsage/AVR_MinMemUsage.ino | 8 ++--- .../AVR_MultipleSessions.ino | 8 ++--- .../AVR_NonDefaultSession.ino | 8 ++--- .../AVR_NoteOnOffEverySec.ino | 8 ++--- .../AVR_ReceivedRawMidiData.ino | 6 ++-- examples/AVR_SysEx/AVR_SysEx.ino | 10 +++---- .../ESP32_NoteOnOffEverySec.ino | 8 ++--- .../ESP8266_NoteOnOffEverySec.ino | 8 ++--- .../wESP32_NoteOnOffEverySec.ino | 8 ++--- src/AppleMIDI.h | 22 +++++++------- src/AppleMIDI.hpp | 10 +++---- src/rtpMIDI_Parser_MidiCommandSection.hpp | 30 +++++++++---------- test/NoteOn.cpp | 8 ++--- 16 files changed, 87 insertions(+), 83 deletions(-) diff --git a/examples/AVR_Callbacks/AVR_Callbacks.ino b/examples/AVR_Callbacks/AVR_Callbacks.ino index b6fd907..dc4c270 100644 --- a/examples/AVR_Callbacks/AVR_Callbacks.ino +++ b/examples/AVR_Callbacks/AVR_Callbacks.ino @@ -12,7 +12,7 @@ byte mac[] = { }; unsigned long t1 = millis(); -bool isConnected = false; +int8_t isConnected = 0; APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); @@ -39,11 +39,11 @@ void setup() // Normal callbacks - always available // Stay informed on connection status AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { - isConnected = true; + isConnected++; DBG(F("Connected to session"), name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; + isConnected--; DBG(F("Disconnected")); }); @@ -88,7 +88,7 @@ void loop() // send a note every second // (dont cáll delay(1000) as it will stall the pipeline) - if (isConnected && (millis() - t1) > 1000) + if ((isConnected > 0) && (millis() - t1) > 1000) { t1 = millis(); @@ -96,8 +96,10 @@ void loop() byte velocity = 55; byte channel = 1; + DBG(F("\nsendNoteOn"), note, velocity, channel); MIDI.sendNoteOn(note, velocity, channel); - // MIDI.sendNoteOff(note, velocity, channel); + //MIDI.sendNoteOff(note, velocity, channel); + } } diff --git a/examples/AVR_Directory/AVR_Directory.ino b/examples/AVR_Directory/AVR_Directory.ino index 9487ef5..597c6c4 100644 --- a/examples/AVR_Directory/AVR_Directory.ino +++ b/examples/AVR_Directory/AVR_Directory.ino @@ -12,7 +12,7 @@ byte mac[] = { }; unsigned long t1 = millis(); -bool isConnected = false; +int8_t isConnected = 0; APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); @@ -44,11 +44,11 @@ void setup() // Stay informed on connection status AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { - isConnected = true; + isConnected++; DBG(F("Connected to session"), name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; + isConnected--; DBG(F("Disconnected")); }); @@ -72,7 +72,7 @@ void loop() // send a note every second // (dont cáll delay(1000) as it will stall the pipeline) - if (isConnected && (millis() - t1) > 1000) + if ((isConnected > 0) && (millis() - t1) > 1000) { t1 = millis(); diff --git a/examples/AVR_Initiator/AVR_Initiator.ino b/examples/AVR_Initiator/AVR_Initiator.ino index 1201965..46ab35c 100644 --- a/examples/AVR_Initiator/AVR_Initiator.ino +++ b/examples/AVR_Initiator/AVR_Initiator.ino @@ -12,7 +12,7 @@ byte mac[] = { }; unsigned long t1 = millis(); -bool isConnected = false; +int8_t isConnected = 0; APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); @@ -34,11 +34,11 @@ void setup() MIDI.begin(); AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { - isConnected = true; + isConnected++; DBG(F("Connected to session"), name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; + isConnected--; DBG(F("Disconnected")); }); @@ -70,7 +70,7 @@ void loop() // send note on/off every second // (dont cáll delay(1000) as it will stall the pipeline) - if (isConnected && (millis() - t1) > 1000) + if ((isConnected > 0) && (millis() - t1) > 1000) { t1 = millis(); diff --git a/examples/AVR_MinMemUsage/AVR_MinMemUsage.ino b/examples/AVR_MinMemUsage/AVR_MinMemUsage.ino index 1f7cee4..165a8cb 100644 --- a/examples/AVR_MinMemUsage/AVR_MinMemUsage.ino +++ b/examples/AVR_MinMemUsage/AVR_MinMemUsage.ino @@ -11,7 +11,7 @@ byte mac[] = { }; unsigned long t1 = millis(); -bool isConnected = false; +int8_t isConnected = 0; APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); @@ -29,11 +29,11 @@ void setup() // Stay informed on connection status AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char*) { - isConnected = true; + isConnected++; digitalWrite(LED_BUILTIN, HIGH); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; + isConnected--; digitalWrite(LED_BUILTIN, LOW); }); @@ -55,7 +55,7 @@ void loop() // send a note every second // (dont cáll delay(1000) as it will stall the pipeline) - if (isConnected && (millis() - t1) > 1000) + if ((isConnected > 0) && (millis() - t1) > 1000) { t1 = millis(); diff --git a/examples/AVR_MultipleSessions/AVR_MultipleSessions.ino b/examples/AVR_MultipleSessions/AVR_MultipleSessions.ino index 95cbb8b..dda747e 100644 --- a/examples/AVR_MultipleSessions/AVR_MultipleSessions.ino +++ b/examples/AVR_MultipleSessions/AVR_MultipleSessions.ino @@ -11,7 +11,7 @@ byte mac[] = { }; unsigned long t1 = millis(); -bool isConnected = false; +int8_t isConnected = 0; APPLEMIDI_CREATE_INSTANCE(EthernetUDP, MIDI1, "Arduino1", DEFAULT_CONTROL_PORT); APPLEMIDI_CREATE_INSTANCE(EthernetUDP, MIDI2, "Arduino2", DEFAULT_CONTROL_PORT + 2); @@ -63,7 +63,7 @@ void loop() // send note on/off every second // (dont cáll delay(1000) as it will stall the pipeline) - if (isConnected && (millis() - t1) > 1000) + if ((isConnected > 0) && (millis() - t1) > 1000) { t1 = millis(); @@ -83,7 +83,7 @@ void loop() // rtpMIDI session. Device connected // ----------------------------------------------------------------------------- void OnAppleMidiConnected(const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { - isConnected = true; + isConnected++; DBG(F("Connected to session"), name); } @@ -91,7 +91,7 @@ void OnAppleMidiConnected(const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* // rtpMIDI session. Device disconnected // ----------------------------------------------------------------------------- void OnAppleMidiDisconnected(const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; + isConnected--; DBG(F("Disconnected")); } diff --git a/examples/AVR_NonDefaultSession/AVR_NonDefaultSession.ino b/examples/AVR_NonDefaultSession/AVR_NonDefaultSession.ino index 797cb07..b988d02 100644 --- a/examples/AVR_NonDefaultSession/AVR_NonDefaultSession.ino +++ b/examples/AVR_NonDefaultSession/AVR_NonDefaultSession.ino @@ -11,7 +11,7 @@ byte mac[] = { }; unsigned long t1 = millis(); -bool isConnected = false; +int8_t isConnected = 0; // Non default portnr APPLEMIDI_CREATE_INSTANCE(EthernetUDP, MIDI, "MyNamedArduino", 5200); @@ -37,11 +37,11 @@ void setup() MIDI.begin(); AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { - isConnected = true; + isConnected++; DBG(F("Connected to session"), name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; + isConnected--; DBG(F("Disconnected")); }); @@ -58,7 +58,7 @@ void loop() // send a note every second // (dont cáll delay(1000) as it will stall the pipeline) - if (isConnected && (millis() - t1) > 1000) + if ((isConnected > 0) && (millis() - t1) > 1000) { t1 = millis(); diff --git a/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino b/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino index 23d5f58..df29e87 100644 --- a/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino +++ b/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino @@ -11,7 +11,7 @@ byte mac[] = { }; unsigned long t1 = millis(); -bool isConnected = false; +int8_t isConnected = 0; APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); @@ -37,11 +37,11 @@ void setup() // Stay informed on connection status AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { - isConnected = true; + isConnected++; DBG(F("Connected to session"), name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; + isConnected--; DBG(F("Disconnected")); }); @@ -65,7 +65,7 @@ void loop() // send a note every second // (dont cáll delay(1000) as it will stall the pipeline) - if (isConnected && (millis() - t1) > 1000) + if ((isConnected > 0) && (millis() - t1) > 1000) { t1 = millis(); diff --git a/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino b/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino index ba61901..0b5e0d4 100644 --- a/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino +++ b/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino @@ -11,7 +11,7 @@ byte mac[] = { }; unsigned long t1 = millis(); -bool isConnected = false; +int8_t isConnected = 0; APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); @@ -37,11 +37,11 @@ void setup() // check: zien we de connecttion binnenkomen?? Anders terug een ref van maken AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { - isConnected = true; + isConnected++; DBG(F("Connected to session"), name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; + isConnected--; DBG(F("Disconnected")); }); AppleMIDI.setHandleStartReceivedMidi(OnAppleMidiStartReceived); diff --git a/examples/AVR_SysEx/AVR_SysEx.ino b/examples/AVR_SysEx/AVR_SysEx.ino index eb023aa..d22046b 100644 --- a/examples/AVR_SysEx/AVR_SysEx.ino +++ b/examples/AVR_SysEx/AVR_SysEx.ino @@ -11,7 +11,7 @@ byte mac[] = { }; unsigned long t1 = millis(); -bool isConnected; +int8_t isConnected = 0; byte sysex14[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0x20, 0x38, 0x39, 0x37, 0x33, 0x50, 0xF7 }; byte sysex15[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0x20, 0x38, 0x39, 0x37, 0x33, 0x50, 0x4D, 0xF7 }; @@ -49,11 +49,11 @@ void setup() DBG(F("Then open a MIDI listener and monitor incoming notes")); AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { - isConnected = true; + isConnected++; DBG(F("Connected to session"), name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; + isConnected--; DBG(F("Disconnected")); }); @@ -73,9 +73,9 @@ void loop() // send a note every second // (dont cáll delay(1000) as it will stall the pipeline) - if (isConnected && (millis() - t1) > 1000) + if ((isConnected > 0) && (millis() - t1) > 1000) { - MIDI.sendSysEx(sizeof(sysexBig), sysexBig, true); + // MIDI.sendSysEx(sizeof(sysexBig), sysexBig, true); t1 = millis(); } } diff --git a/examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino b/examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino index 0368967..856f57f 100644 --- a/examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino +++ b/examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino @@ -11,7 +11,7 @@ char ssid[] = "ssid"; // your network SSID (name) char pass[] = "password"; // your network password (use for WPA, or use as key for WEP) unsigned long t0 = millis(); -bool isConnected = false; +int8_t isConnected = 0; APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); @@ -40,11 +40,11 @@ void setup() MIDI.begin(); AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { - isConnected = true; + isConnected++; DBG(F("Connected to session"), name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; + isConnected--; DBG(F("Disconnected")); }); @@ -68,7 +68,7 @@ void loop() // send a note every second // (dont cáll delay(1000) as it will stall the pipeline) - if (isConnected && (millis() - t0) > 1000) + if ((isConnected > 0) && (millis() - t0) > 1000) { t0 = millis(); diff --git a/examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino b/examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino index c45e9fb..dd3ea14 100644 --- a/examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino +++ b/examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino @@ -10,7 +10,7 @@ char ssid[] = "yourNetwork"; // your network SSID (name) char pass[] = "password"; // your network password (use for WPA, or use as key for WEP) unsigned long t0 = millis(); -bool isConnected = false; +int8_t isConnected = 0; APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); @@ -39,11 +39,11 @@ void setup() MIDI.begin(); AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { - isConnected = true; + isConnected++; DBG(F("Connected to session"), name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; + isConnected--; DBG(F("Disconnected")); }); @@ -67,7 +67,7 @@ void loop() // send a note every second // (dont cáll delay(1000) as it will stall the pipeline) - if (isConnected && (millis() - t0) > 1000) + if ((isConnected > 0) && (millis() - t0) > 1000) { t0 = millis(); diff --git a/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino b/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino index 7285659..48a2864 100644 --- a/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino +++ b/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino @@ -5,7 +5,7 @@ #include "ETH_Helper.h" unsigned long t0 = millis(); -bool isConnected = false; +int8_t isConnected = 0; APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); @@ -31,11 +31,11 @@ void setup() MIDI.begin(); AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { - isConnected = true; + isConnected++; DBG(F("Connected to session"), name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; + isConnected--; DBG(F("Disconnected")); }); @@ -59,7 +59,7 @@ void loop() // send a note every second // (dont cáll delay(1000) as it will stall the pipeline) - if (isConnected && (millis() - t0) > 1000) + if ((isConnected > 0) && (millis() - t0) > 1000) { t0 = millis(); diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index b57bb31..e519b15 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -64,7 +64,7 @@ class AppleMIDISession void setHandleReceivedMidi (void (*fptr)(const ssrc_t&, byte)) { _receivedMidiByteCallback = fptr; } void setHandleEndReceivedMidi (void (*fptr)(const ssrc_t&)) { _endReceivedMidiByteCallback = fptr; } void setHandleSentRtp (void (*fptr)(const Rtp_t&)) { _sentRtpCallback = fptr; } - void setHandleSentRtpMidi (void (*fptr)(const RtpMIDI_t&)) { _sentRtpMidiCallback = fptr; } + void setHandleSentRtpMidi (void (*fptr)(const RtpMIDI_t&)) { _sentRtpMidiCallback = fptr; } #endif #ifdef KEEP_SESSION_NAME @@ -203,13 +203,15 @@ class AppleMIDISession if (inMidiBuffer.size() > 0) return true; - // read packets from both UDP sockets - readDataPackets(); // from socket into dataBuffer - readControlPackets(); // from socket into controlBuffer + { + // read packets from both UDP sockets + readDataPackets(); // from socket into dataBuffer + readControlPackets(); // from socket into controlBuffer - // parses buffer and places MIDI into inMidiBuffer - parseDataPackets(); // from dataBuffer into inMidiBuffer - parseControlPackets(); // from controlBuffer + // parses buffer and places MIDI into inMidiBuffer + parseDataPackets(); // from dataBuffer into inMidiBuffer + parseControlPackets(); // from controlBuffer + } manageReceiverFeedback(); manageSynchronization(); @@ -289,9 +291,9 @@ class AppleMIDISession // rtpMIDI callback from parser void ReceivedRtp(const Rtp_t &); - void StartReceivedMidi(const ssrc_t&); - void ReceivedMidi(const ssrc_t&, byte data); - void EndReceivedMidi(const ssrc_t&); + void StartReceivedMidi(); + void ReceivedMidi(byte data); + void EndReceivedMidi(); // Helpers void writeInvitation (UdpClass &, const IPAddress &, const uint16_t &, AppleMIDI_Invitation_t &, const byte *command); diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index 7a2f4e4..e6cd76f 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -409,11 +409,11 @@ void AppleMIDISession::ReceivedReceiverFeedback(Ap return; } - if (pParticipant->sendSequenceNr != receiverFeedback.sequenceNr) + if (pParticipant->sendSequenceNr < receiverFeedback.sequenceNr) { #ifdef USE_EXT_CALLBACKS if (nullptr != _exceptionCallback) - _exceptionCallback(ssrc, SendPacketsDropped, pParticipant->sendSequenceNr - receiverFeedback.sequenceNr); + _exceptionCallback(pParticipant->ssrc, SendPacketsDropped, pParticipant->sendSequenceNr - receiverFeedback.sequenceNr); #endif } } @@ -1035,7 +1035,7 @@ void AppleMIDISession::ReceivedRtp(const Rtp_t& rt } template -void AppleMIDISession::StartReceivedMidi(const ssrc_t& ssrc) +void AppleMIDISession::StartReceivedMidi() { #ifdef USE_EXT_CALLBACKS if (nullptr != _startReceivedMidiByteCallback) @@ -1044,7 +1044,7 @@ void AppleMIDISession::StartReceivedMidi(const ssr } template -void AppleMIDISession::ReceivedMidi(const ssrc_t& ssrc, byte value) +void AppleMIDISession::ReceivedMidi(byte value) { #ifdef USE_EXT_CALLBACKS if (nullptr != _receivedMidiByteCallback) @@ -1055,7 +1055,7 @@ void AppleMIDISession::ReceivedMidi(const ssrc_t& } template -void AppleMIDISession::EndReceivedMidi(const ssrc_t& ssrc) +void AppleMIDISession::EndReceivedMidi() { #ifdef USE_EXT_CALLBACKS if (nullptr != _endReceivedMidiByteCallback) diff --git a/src/rtpMIDI_Parser_MidiCommandSection.hpp b/src/rtpMIDI_Parser_MidiCommandSection.hpp index d4b5407..9063066 100644 --- a/src/rtpMIDI_Parser_MidiCommandSection.hpp +++ b/src/rtpMIDI_Parser_MidiCommandSection.hpp @@ -77,9 +77,9 @@ size_t decodeMidi(RtpBuffer_t &buffer, uint8_t &runningstatus) * not be intermingled with other MIDI-commands, so we handle this case right here and return */ if (octet >= 0xf8) { - session->StartReceivedMidi(session->getSynchronizationSource()); - session->ReceivedMidi(session->getSynchronizationSource(), buffer[0]); - session->EndReceivedMidi(session->getSynchronizationSource()); + session->StartReceivedMidi(); + session->ReceivedMidi(buffer[0]); + session->EndReceivedMidi(); return 1; } @@ -145,10 +145,10 @@ size_t decodeMidi(RtpBuffer_t &buffer, uint8_t &runningstatus) break; } - session->StartReceivedMidi(session->getSynchronizationSource()); + session->StartReceivedMidi(); for (size_t j = 0; j < consumed; j++) - session->ReceivedMidi(session->getSynchronizationSource(), buffer[j]); - session->EndReceivedMidi(session->getSynchronizationSource()); + session->ReceivedMidi(buffer[j]); + session->EndReceivedMidi(); return consumed; } @@ -175,10 +175,10 @@ size_t decodeMidi(RtpBuffer_t &buffer, uint8_t &runningstatus) break; } - session->StartReceivedMidi(session->getSynchronizationSource()); + session->StartReceivedMidi(); for (size_t j = 0; j < consumed; j++) - session->ReceivedMidi(session->getSynchronizationSource(), buffer[j]); - session->EndReceivedMidi(session->getSynchronizationSource()); + session->ReceivedMidi(buffer[j]); + session->EndReceivedMidi(); return consumed; } @@ -206,13 +206,13 @@ size_t decodeMidiSysEx(RtpBuffer_t &buffer) // to compensate for adding the sysex at the end. consumed--; - + // send MIDI data - session->StartReceivedMidi(session->getSynchronizationSource()); + session->StartReceivedMidi(); for (size_t j = 0; j < consumed; j++) - session->ReceivedMidi(session->getSynchronizationSource(), buffer[j]); - session->ReceivedMidi(session->getSynchronizationSource(), MIDI_NAMESPACE::MidiType::SystemExclusiveStart); - session->EndReceivedMidi(session->getSynchronizationSource()); + session->ReceivedMidi(buffer[j]); + session->ReceivedMidi(MIDI_NAMESPACE::MidiType::SystemExclusiveStart); + session->EndReceivedMidi(); // Remove the bytes that were submitted for (size_t j = 0; j < consumed; j++) @@ -221,7 +221,7 @@ size_t decodeMidiSysEx(RtpBuffer_t &buffer) midiCommandLength -= consumed; midiCommandLength += 1; // adding the manual SysEx SystemExclusiveEnd - + // indicates split SysEx return buffer.max_size() + 1; } diff --git a/test/NoteOn.cpp b/test/NoteOn.cpp index b36d3b0..262b217 100644 --- a/test/NoteOn.cpp +++ b/test/NoteOn.cpp @@ -6,7 +6,7 @@ #include "AppleMIDI.h" unsigned long t0 = millis(); -bool isConnected = false; +bool isConnected--; byte sysex14[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0x20, 0x38, 0x39, 0x37, 0x33, 0x50, 0xF7 }; byte sysex15[] = { 0xF0, 0x43, 0x20, 0x7E, 0x4C, 0x4D, 0x20, 0x20, 0x38, 0x39, 0x37, 0x33, 0x50, 0x4D, 0xF7 }; @@ -33,7 +33,7 @@ APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); // rtpMIDI session. Device connected // ----------------------------------------------------------------------------- void OnAppleMidiConnected(const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { - isConnected = true; + isConnected++; DBG(F("Connected to session"), name); } @@ -41,7 +41,7 @@ void OnAppleMidiConnected(const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* // rtpMIDI session. Device disconnected // ----------------------------------------------------------------------------- void OnAppleMidiDisconnected(const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { - isConnected = false; + isConnected--; DBG(F("Disconnected")); } @@ -123,7 +123,7 @@ void loop() // send a note every second // (dont cáll delay(1000) as it will stall the pipeline) - if (isConnected && (millis() - t0) > 10000) + if ((isConnected > 0) && (millis() - t0) > 10000) { t0 = millis(); From ce7e8a714b9a31c5078273594b6416dedb04e603 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 15:43:21 +0100 Subject: [PATCH 35/60] receivedRtpCallback with ssrc, disconnect with ssrc --- examples/AVR_Callbacks/AVR_Callbacks.ino | 8 ++++---- examples/AVR_Directory/AVR_Directory.ino | 4 ++-- examples/AVR_Initiator/AVR_Initiator.ino | 4 ++-- examples/AVR_MultipleSessions/AVR_MultipleSessions.ino | 4 ++-- examples/AVR_NonDefaultSession/AVR_NonDefaultSession.ino | 4 ++-- examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino | 4 ++-- .../AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino | 4 ++-- examples/AVR_SysEx/AVR_SysEx.ino | 4 ++-- .../ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino | 4 ++-- .../ESP8266_NoteOnOffEverySec.ino | 4 ++-- .../wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino | 4 ++-- src/AppleMIDI.h | 2 +- src/AppleMIDI.hpp | 2 +- src/AppleMIDI_Defs.h | 2 +- test/NoteOn.cpp | 4 ++-- 15 files changed, 29 insertions(+), 29 deletions(-) diff --git a/examples/AVR_Callbacks/AVR_Callbacks.ino b/examples/AVR_Callbacks/AVR_Callbacks.ino index dc4c270..41568a0 100644 --- a/examples/AVR_Callbacks/AVR_Callbacks.ino +++ b/examples/AVR_Callbacks/AVR_Callbacks.ino @@ -40,11 +40,11 @@ void setup() // Stay informed on connection status AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { isConnected++; - DBG(F("Connected to session"), name); + DBG(F("Connected to session"), ssrc, name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { isConnected--; - DBG(F("Disconnected")); + DBG(F("Disconnected"), ssrc); }); // Extended callback, only available when defining USE_EXT_CALLBACKS @@ -54,8 +54,8 @@ void setup() AppleMIDI.setHandleSentRtpMidi([](const APPLEMIDI_NAMESPACE::RtpMIDI_t& rtpMidi) { DBG(F("an rtpMidiMessage has been sent"), rtpMidi.flags); }); - AppleMIDI.setHandleReceivedRtp([](const APPLEMIDI_NAMESPACE::Rtp_t & rtp, const int32_t& latency) { - DBG(F("setHandleReceivedRtp"), rtp.sequenceNr , "with", latency, "ms latency"); + AppleMIDI.setHandleReceivedRtp([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const APPLEMIDI_NAMESPACE::Rtp_t & rtp, const int32_t& latency) { + DBG(F("setHandleReceivedRtp"), ssrc, rtp.sequenceNr , "with", latency, "ms latency"); }); AppleMIDI.setHandleStartReceivedMidi([](const APPLEMIDI_NAMESPACE::ssrc_t& ssrc) { DBG(F("setHandleStartReceivedMidi from SSRC"), ssrc); diff --git a/examples/AVR_Directory/AVR_Directory.ino b/examples/AVR_Directory/AVR_Directory.ino index 597c6c4..7d0f1b8 100644 --- a/examples/AVR_Directory/AVR_Directory.ino +++ b/examples/AVR_Directory/AVR_Directory.ino @@ -45,11 +45,11 @@ void setup() // Stay informed on connection status AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { isConnected++; - DBG(F("Connected to session"), name); + DBG(F("Connected to session"), ssrc, name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { isConnected--; - DBG(F("Disconnected")); + DBG(F("Disconnected"), ssrc); }); MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { diff --git a/examples/AVR_Initiator/AVR_Initiator.ino b/examples/AVR_Initiator/AVR_Initiator.ino index 46ab35c..095ca04 100644 --- a/examples/AVR_Initiator/AVR_Initiator.ino +++ b/examples/AVR_Initiator/AVR_Initiator.ino @@ -35,11 +35,11 @@ void setup() AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { isConnected++; - DBG(F("Connected to session"), name); + DBG(F("Connected to session"), ssrc, name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { isConnected--; - DBG(F("Disconnected")); + DBG(F("Disconnected"), ssrc); }); MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { diff --git a/examples/AVR_MultipleSessions/AVR_MultipleSessions.ino b/examples/AVR_MultipleSessions/AVR_MultipleSessions.ino index dda747e..cc4a1d3 100644 --- a/examples/AVR_MultipleSessions/AVR_MultipleSessions.ino +++ b/examples/AVR_MultipleSessions/AVR_MultipleSessions.ino @@ -84,7 +84,7 @@ void loop() // ----------------------------------------------------------------------------- void OnAppleMidiConnected(const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { isConnected++; - DBG(F("Connected to session"), name); + DBG(F("Connected to session"), ssrc, name); } // ----------------------------------------------------------------------------- @@ -92,7 +92,7 @@ void OnAppleMidiConnected(const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* // ----------------------------------------------------------------------------- void OnAppleMidiDisconnected(const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { isConnected--; - DBG(F("Disconnected")); + DBG(F("Disconnected"), ssrc); } // ----------------------------------------------------------------------------- diff --git a/examples/AVR_NonDefaultSession/AVR_NonDefaultSession.ino b/examples/AVR_NonDefaultSession/AVR_NonDefaultSession.ino index b988d02..fef1455 100644 --- a/examples/AVR_NonDefaultSession/AVR_NonDefaultSession.ino +++ b/examples/AVR_NonDefaultSession/AVR_NonDefaultSession.ino @@ -38,11 +38,11 @@ void setup() AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { isConnected++; - DBG(F("Connected to session"), name); + DBG(F("Connected to session"), ssrc, name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { isConnected--; - DBG(F("Disconnected")); + DBG(F("Disconnected"), ssrc); }); DBG(F("Send MIDI messages every second")); diff --git a/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino b/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino index df29e87..d5fd0b1 100644 --- a/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino +++ b/examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino @@ -38,11 +38,11 @@ void setup() // Stay informed on connection status AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { isConnected++; - DBG(F("Connected to session"), name); + DBG(F("Connected to session"), ssrc, name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { isConnected--; - DBG(F("Disconnected")); + DBG(F("Disconnected"), ssrc); }); MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { diff --git a/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino b/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino index 0b5e0d4..fb815bd 100644 --- a/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino +++ b/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino @@ -38,11 +38,11 @@ void setup() // check: zien we de connecttion binnenkomen?? Anders terug een ref van maken AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { isConnected++; - DBG(F("Connected to session"), name); + DBG(F("Connected to session"), ssrc, name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { isConnected--; - DBG(F("Disconnected")); + DBG(F("Disconnected"), ssrc); }); AppleMIDI.setHandleStartReceivedMidi(OnAppleMidiStartReceived); AppleMIDI.setHandleReceivedMidi(OnAppleMidiReceivedByte); diff --git a/examples/AVR_SysEx/AVR_SysEx.ino b/examples/AVR_SysEx/AVR_SysEx.ino index d22046b..e258848 100644 --- a/examples/AVR_SysEx/AVR_SysEx.ino +++ b/examples/AVR_SysEx/AVR_SysEx.ino @@ -50,11 +50,11 @@ void setup() AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { isConnected++; - DBG(F("Connected to session"), name); + DBG(F("Connected to session"), ssrc, name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { isConnected--; - DBG(F("Disconnected")); + DBG(F("Disconnected"), ssrc); }); MIDI.begin(); diff --git a/examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino b/examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino index 856f57f..1fee9a5 100644 --- a/examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino +++ b/examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino @@ -41,11 +41,11 @@ void setup() AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { isConnected++; - DBG(F("Connected to session"), name); + DBG(F("Connected to session"), ssrc, name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { isConnected--; - DBG(F("Disconnected")); + DBG(F("Disconnected"), ssrc); }); MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { diff --git a/examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino b/examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino index dd3ea14..3385371 100644 --- a/examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino +++ b/examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino @@ -40,11 +40,11 @@ void setup() AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { isConnected++; - DBG(F("Connected to session"), name); + DBG(F("Connected to session"), ssrc, name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { isConnected--; - DBG(F("Disconnected")); + DBG(F("Disconnected"), ssrc); }); MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { diff --git a/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino b/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino index 48a2864..75f0ed2 100644 --- a/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino +++ b/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino @@ -32,11 +32,11 @@ void setup() AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { isConnected++; - DBG(F("Connected to session"), name); + DBG(F("Connected to session"), ssrc, name); }); AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { isConnected--; - DBG(F("Disconnected")); + DBG(F("Disconnected"), ssrc); }); MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index e519b15..3b1dce8 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -59,7 +59,7 @@ class AppleMIDISession void setHandleDisconnected (void (*fptr)(const ssrc_t&)) { _disconnectedCallback = fptr; } #ifdef USE_EXT_CALLBACKS void setHandleException (void (*fptr)(const ssrc_t&, const Exception&, const int32_t value)) { _exceptionCallback = fptr; } - void setHandleReceivedRtp (void (*fptr)(const Rtp_t&, const int32_t&)) { _receivedRtpCallback = fptr; } + void setHandleReceivedRtp (void (*fptr)(const ssrc_t&, const Rtp_t&, const int32_t&)) { _receivedRtpCallback = fptr; } void setHandleStartReceivedMidi (void (*fptr)(const ssrc_t&)) { _startReceivedMidiByteCallback = fptr; } void setHandleReceivedMidi (void (*fptr)(const ssrc_t&, byte)) { _receivedMidiByteCallback = fptr; } void setHandleEndReceivedMidi (void (*fptr)(const ssrc_t&)) { _endReceivedMidiByteCallback = fptr; } diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index e6cd76f..1efe2d5 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -1025,7 +1025,7 @@ void AppleMIDISession::ReceivedRtp(const Rtp_t& rt #ifdef USE_EXT_CALLBACKS if (nullptr != _receivedRtpCallback) - _receivedRtpCallback(rtp, latency); + _receivedRtpCallback(pParticipant->ssrc, rtp, latency); #endif } else diff --git a/src/AppleMIDI_Defs.h b/src/AppleMIDI_Defs.h index 902cb6e..0fc7541 100644 --- a/src/AppleMIDI_Defs.h +++ b/src/AppleMIDI_Defs.h @@ -127,7 +127,7 @@ using disconnectedCallback = void (*)(const ssrc_t&); using startReceivedMidiByteCallback = void (*)(const ssrc_t&); using receivedMidiByteCallback = void (*)(const ssrc_t&, byte); using endReceivedMidiByteCallback = void (*)(const ssrc_t&); -using receivedRtpCallback = void (*)(const Rtp_t&, const int32_t&); +using receivedRtpCallback = void (*)(const ssrc_t&, const Rtp_t&, const int32_t&); using exceptionCallback = void (*)(const ssrc_t&, const Exception&, const int32_t value); using sentRtpCallback = void (*)(const Rtp_t&); using sentRtpMidiCallback = void (*)(const RtpMIDI_t&); diff --git a/test/NoteOn.cpp b/test/NoteOn.cpp index 262b217..ccec4d7 100644 --- a/test/NoteOn.cpp +++ b/test/NoteOn.cpp @@ -34,7 +34,7 @@ APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); // ----------------------------------------------------------------------------- void OnAppleMidiConnected(const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { isConnected++; - DBG(F("Connected to session"), name); + DBG(F("Connected to session"), ssrc, name); } // ----------------------------------------------------------------------------- @@ -42,7 +42,7 @@ void OnAppleMidiConnected(const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* // ----------------------------------------------------------------------------- void OnAppleMidiDisconnected(const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { isConnected--; - DBG(F("Disconnected")); + DBG(F("Disconnected"), ssrc); } // ----------------------------------------------------------------------------- From 296717cf13fc5de0dc64659aa38579575fef4848 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 16:30:01 +0100 Subject: [PATCH 36/60] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f189e73..f1f886e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,4 +13,4 @@ install: - platformio lib -g install 62@5.0.0 870 872 script: -- pio ci --board=uno --lib=. examples/EthernetShield_NoteOnOffEverySec/EthernetShield_NoteOnOffEverySec.ino; +- pio ci --board=uno --lib=. examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino; From 8117dd35246cba0abb6a2b8e92f40e6803f92882 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 16:38:35 +0100 Subject: [PATCH 37/60] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 127d277..55a6c61 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # AppleMIDI (aka rtpMIDI) for Arduino -[![arduino-library-badge](https://www.ardu-badge.com/badge/AppleMIDI.svg?)](https://www.ardu-badge.com/AppleMIDI) [![Build Status](https://travis-ci.org/lathoub/Arduino-AppleMIDI-Library.svg?branch=master)](https://travis-ci.org/lathoub/Arduino-AppleMIDI-Library) [![License: CC BY-SA 4.0](https://img.shields.io/badge/License-CC%20BY--SA%204.0-lightgrey.svg)](http://creativecommons.org/licenses/by-sa/4.0/) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/c8be2ccc3f104e0588572a39f8106070)](https://app.codacy.com/app/lathoub/Arduino-AppleMIDI-Library?utm_source=github.com&utm_medium=referral&utm_content=lathoub/Arduino-AppleMIDI-Library&utm_campaign=Badge_Grade_Dashboard) +[![arduino-library-badge](https://www.ardu-badge.com/badge/AppleMIDI.svg?)](https://www.ardu-badge.com/AppleMIDI) [![Build Status](https://travis-ci.com/lathoub/Arduino-AppleMIDI-Library.svg?branch=master)](https://travis-ci.com/lathoub/Arduino-AppleMIDI-Library) [![License: CC BY-SA 4.0](https://img.shields.io/badge/License-CC%20BY--SA%204.0-lightgrey.svg)](http://creativecommons.org/licenses/by-sa/4.0/) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/c8be2ccc3f104e0588572a39f8106070)](https://app.codacy.com/app/lathoub/Arduino-AppleMIDI-Library?utm_source=github.com&utm_medium=referral&utm_content=lathoub/Arduino-AppleMIDI-Library&utm_campaign=Badge_Grade_Dashboard) Enables an Arduino with IP/UDP capabilities (Ethernet shield, ESP8266, ESP32, ...) to particpate in an AppleMIDI session. From 9294a504a3e7f7c70c1dd6c4f31297a5854559d2 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 16:39:08 +0100 Subject: [PATCH 38/60] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 55a6c61..127d277 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # AppleMIDI (aka rtpMIDI) for Arduino -[![arduino-library-badge](https://www.ardu-badge.com/badge/AppleMIDI.svg?)](https://www.ardu-badge.com/AppleMIDI) [![Build Status](https://travis-ci.com/lathoub/Arduino-AppleMIDI-Library.svg?branch=master)](https://travis-ci.com/lathoub/Arduino-AppleMIDI-Library) [![License: CC BY-SA 4.0](https://img.shields.io/badge/License-CC%20BY--SA%204.0-lightgrey.svg)](http://creativecommons.org/licenses/by-sa/4.0/) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/c8be2ccc3f104e0588572a39f8106070)](https://app.codacy.com/app/lathoub/Arduino-AppleMIDI-Library?utm_source=github.com&utm_medium=referral&utm_content=lathoub/Arduino-AppleMIDI-Library&utm_campaign=Badge_Grade_Dashboard) +[![arduino-library-badge](https://www.ardu-badge.com/badge/AppleMIDI.svg?)](https://www.ardu-badge.com/AppleMIDI) [![Build Status](https://travis-ci.org/lathoub/Arduino-AppleMIDI-Library.svg?branch=master)](https://travis-ci.org/lathoub/Arduino-AppleMIDI-Library) [![License: CC BY-SA 4.0](https://img.shields.io/badge/License-CC%20BY--SA%204.0-lightgrey.svg)](http://creativecommons.org/licenses/by-sa/4.0/) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/c8be2ccc3f104e0588572a39f8106070)](https://app.codacy.com/app/lathoub/Arduino-AppleMIDI-Library?utm_source=github.com&utm_medium=referral&utm_content=lathoub/Arduino-AppleMIDI-Library&utm_campaign=Badge_Grade_Dashboard) Enables an Arduino with IP/UDP capabilities (Ethernet shield, ESP8266, ESP32, ...) to particpate in an AppleMIDI session. From 299004cd99e58bbc1a4e74be57295276685d96cb Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 16:42:16 +0100 Subject: [PATCH 39/60] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f1f886e..96a3952 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,4 +13,4 @@ install: - platformio lib -g install 62@5.0.0 870 872 script: -- pio ci --board=uno --lib=. examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino; +- pio ci --board=uno --lib=. examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino examples/AVR_MinMemUsage/AVR_MinMemUsage.ino; From 2739ce6368c226e77606e462b60681750899c8d1 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 16:51:05 +0100 Subject: [PATCH 40/60] Update .travis.yml --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 96a3952..498d9d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,4 +13,5 @@ install: - platformio lib -g install 62@5.0.0 870 872 script: -- pio ci --board=uno --lib=. examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino examples/AVR_MinMemUsage/AVR_MinMemUsage.ino; +- pio ci --board=uno --lib=. examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino +- pio ci --board=uno --lib=. examples/AVR_MinMemUsage/AVR_MinMemUsage.ino From 3c95ee1840008d352b53f8e7078619339ebf59b8 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 17:20:16 +0100 Subject: [PATCH 41/60] Update .travis.yml --- .travis.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 498d9d1..6e3d79e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,5 +13,12 @@ install: - platformio lib -g install 62@5.0.0 870 872 script: -- pio ci --board=uno --lib=. examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino +- pio ci --board=uno --lib=. examples/AVR_Callbacks/AVR_Callbacks.ino +- pio ci --board=uno --lib=. examples/AVR_Directory/AVR_Directory.ino +- pio ci --board=uno --lib=. examples/AVR_Initiator/AVR_Initiator.ino - pio ci --board=uno --lib=. examples/AVR_MinMemUsage/AVR_MinMemUsage.ino +- pio ci --board=uno --lib=. examples/AVR_MultipleSessions/AVR_MultipleSessions.ino +- pio ci --board=uno --lib=. examples/AVR_NonDefaultSession/AVR_NonDefaultSession.ino +- pio ci --board=uno --lib=. examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino +- pio ci --board=uno --lib=. examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino +- pio ci --board=uno --lib=. examples/AVR_SysEx/AVR_SysEx.ino From 4f7f9ab61f1cb7418b257f0402a51dae398f0a9f Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 17:28:36 +0100 Subject: [PATCH 42/60] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 6e3d79e..89a1bd4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,3 +22,4 @@ script: - pio ci --board=uno --lib=. examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino - pio ci --board=uno --lib=. examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino - pio ci --board=uno --lib=. examples/AVR_SysEx/AVR_SysEx.ino +- pio ci --board=zero --lib=. examples/SAMD_Bonjour/SAMD_Bonjour.ino From 5aa8c69f1ba40df8434fe022a160ebf980895bb8 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 19:12:16 +0100 Subject: [PATCH 43/60] update examples --- examples/AVR_Initiator/AVR_Initiator.ino | 8 ++++---- .../AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino | 1 + src/AppleMIDI.h | 2 +- src/AppleMIDI.hpp | 1 - 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/AVR_Initiator/AVR_Initiator.ino b/examples/AVR_Initiator/AVR_Initiator.ino index 095ca04..b116c22 100644 --- a/examples/AVR_Initiator/AVR_Initiator.ino +++ b/examples/AVR_Initiator/AVR_Initiator.ino @@ -1,8 +1,8 @@ #include +#define APPLEMIDI_INITIATOR #define SerialMon Serial #define APPLEMIDI_DEBUG SerialMon -#define APPLEMIDI_INITIATOR #include // Enter a MAC address for your controller below. @@ -41,7 +41,7 @@ void setup() isConnected--; DBG(F("Disconnected"), ssrc); }); - + MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { DBG(F("NoteOn"), note); }); @@ -78,7 +78,7 @@ void loop() byte velocity = 55; byte channel = 1; - // MIDI.sendNoteOn(note, velocity, channel); - // MIDI.sendNoteOff(note, velocity, channel); + MIDI.sendNoteOn(note, velocity, channel); + MIDI.sendNoteOff(note, velocity, channel); } } diff --git a/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino b/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino index fb815bd..db54cad 100644 --- a/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino +++ b/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino @@ -1,5 +1,6 @@ #include +#define USE_EXT_CALLBACKS #define SerialMon Serial #define APPLEMIDI_DEBUG SerialMon #include diff --git a/src/AppleMIDI.h b/src/AppleMIDI.h index 3b1dce8..dc52ca4 100644 --- a/src/AppleMIDI.h +++ b/src/AppleMIDI.h @@ -311,7 +311,7 @@ class AppleMIDISession void manageSessionInvites(); void manageSynchronization(); void manageSynchronizationInitiator(); - void manageSynchronizationInitiatorHeartBeat(size_t); + void manageSynchronizationInitiatorHeartBeat(Participant*); void manageSynchronizationInitiatorInvites(size_t); void sendSynchronization(Participant*); diff --git a/src/AppleMIDI.hpp b/src/AppleMIDI.hpp index 1efe2d5..aa4d656 100644 --- a/src/AppleMIDI.hpp +++ b/src/AppleMIDI.hpp @@ -951,7 +951,6 @@ bool AppleMIDISession::sendInvite(IPAddress ip, ui participant.lastInviteSentTime = now - 1000; // forces invite to be send immediately participant.lastSyncExchangeTime = now; participant.initiatorToken = random(1, INT32_MAX) * 2; - participant.sequenceNr; #ifndef ONE_PARTICIPANT participants.push_back(participant); From 9c6d4c3fbb207a92730d6b4d98b412cb5c6eb99e Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 19:27:20 +0100 Subject: [PATCH 44/60] Update .travis.yml --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 89a1bd4..6e3d79e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,4 +22,3 @@ script: - pio ci --board=uno --lib=. examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino - pio ci --board=uno --lib=. examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino - pio ci --board=uno --lib=. examples/AVR_SysEx/AVR_SysEx.ino -- pio ci --board=zero --lib=. examples/SAMD_Bonjour/SAMD_Bonjour.ino From 33be4a494eccde71ff26ad6f4a6caef1d09d33bc Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 19:34:22 +0100 Subject: [PATCH 45/60] fixing examples --- examples/AVR_Callbacks/AVR_Callbacks.ino | 2 ++ examples/AVR_MultipleSessions/AVR_MultipleSessions.ino | 4 ++++ examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/examples/AVR_Callbacks/AVR_Callbacks.ino b/examples/AVR_Callbacks/AVR_Callbacks.ino index 41568a0..6ca0634 100644 --- a/examples/AVR_Callbacks/AVR_Callbacks.ino +++ b/examples/AVR_Callbacks/AVR_Callbacks.ino @@ -16,6 +16,8 @@ int8_t isConnected = 0; APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); +void OnAppleMidiException(const APPLEMIDI_NAMESPACE::ssrc_t&, const APPLEMIDI_NAMESPACE::Exception&, const int32_t); + // ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- diff --git a/examples/AVR_MultipleSessions/AVR_MultipleSessions.ino b/examples/AVR_MultipleSessions/AVR_MultipleSessions.ino index cc4a1d3..2f49232 100644 --- a/examples/AVR_MultipleSessions/AVR_MultipleSessions.ino +++ b/examples/AVR_MultipleSessions/AVR_MultipleSessions.ino @@ -16,6 +16,10 @@ int8_t isConnected = 0; APPLEMIDI_CREATE_INSTANCE(EthernetUDP, MIDI1, "Arduino1", DEFAULT_CONTROL_PORT); APPLEMIDI_CREATE_INSTANCE(EthernetUDP, MIDI2, "Arduino2", DEFAULT_CONTROL_PORT + 2); +void OnAppleMidiConnected(const APPLEMIDI_NAMESPACE::ssrc_t&, const char*); +void OnAppleMidiDisconnected(const APPLEMIDI_NAMESPACE::ssrc_t &); +void OnMidiNoteOn(byte channel, byte note, byte velocity); + // ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- diff --git a/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino b/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino index db54cad..e4c1bad 100644 --- a/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino +++ b/examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino @@ -16,6 +16,10 @@ int8_t isConnected = 0; APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); +void OnAppleMidiStartReceived(const APPLEMIDI_NAMESPACE::ssrc_t&); +void OnAppleMidiReceivedByte(const APPLEMIDI_NAMESPACE::ssrc_t&, byte); +void OnAppleMidiEndReceive(const APPLEMIDI_NAMESPACE::ssrc_t&); + // ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- From 8936cd72abf42509a2fa1c07105535fb7cb83b34 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 20:21:54 +0100 Subject: [PATCH 46/60] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 6e3d79e..73b46ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,3 +22,4 @@ script: - pio ci --board=uno --lib=. examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino - pio ci --board=uno --lib=. examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino - pio ci --board=uno --lib=. examples/AVR_SysEx/AVR_SysEx.ino +- pio ci --board=esp8266:esp8266:generic:xtal=80,eesz=4M1M,FlashMode=qio,FlashFreq=80,dbg=Serial,lvl=CORE examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino From 08366e5250d4788e087b7b59fb3b92672911c2db Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 20:56:57 +0100 Subject: [PATCH 47/60] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 73b46ef..1468d55 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,4 +22,4 @@ script: - pio ci --board=uno --lib=. examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino - pio ci --board=uno --lib=. examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino - pio ci --board=uno --lib=. examples/AVR_SysEx/AVR_SysEx.ino -- pio ci --board=esp8266:esp8266:generic:xtal=80,eesz=4M1M,FlashMode=qio,FlashFreq=80,dbg=Serial,lvl=CORE examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino +- pio ci --platform=espressif8266 --board=huzzah examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino From ca50b41c37df8c47a19c9694f01e6738d236e335 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 20:59:11 +0100 Subject: [PATCH 48/60] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1468d55..3882b7a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,4 +22,4 @@ script: - pio ci --board=uno --lib=. examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino - pio ci --board=uno --lib=. examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino - pio ci --board=uno --lib=. examples/AVR_SysEx/AVR_SysEx.ino -- pio ci --platform=espressif8266 --board=huzzah examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino +- pio ci --board=huzzah examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino From e069ffbc8d6a89dfa42c0368fb3c9a19ce83ed41 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 21:22:47 +0100 Subject: [PATCH 49/60] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 3882b7a..62de280 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,3 +23,4 @@ script: - pio ci --board=uno --lib=. examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino - pio ci --board=uno --lib=. examples/AVR_SysEx/AVR_SysEx.ino - pio ci --board=huzzah examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino +- pio ci --board=featheresp32 examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino From 0fc91fd0071690d8a126845fe8edc041ab1b820b Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 21:23:08 +0100 Subject: [PATCH 50/60] Update .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 62de280..c00fc45 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,5 +22,5 @@ script: - pio ci --board=uno --lib=. examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino - pio ci --board=uno --lib=. examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino - pio ci --board=uno --lib=. examples/AVR_SysEx/AVR_SysEx.ino -- pio ci --board=huzzah examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino -- pio ci --board=featheresp32 examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino +- pio ci --board=huzzah --lib=. examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino +- pio ci --board=featheresp32 --lib=. examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino From 122f77874ae204a3c23ab73b2cd5d3f3edd9d7bc Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Tue, 29 Dec 2020 23:24:53 +0100 Subject: [PATCH 51/60] Create AVR_E3_NoteOnOffEverySec.ino --- .../AVR_E3_NoteOnOffEverySec.ino | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 examples/AVR_E3_NoteOnOffEverySec/AVR_E3_NoteOnOffEverySec.ino diff --git a/examples/AVR_E3_NoteOnOffEverySec/AVR_E3_NoteOnOffEverySec.ino b/examples/AVR_E3_NoteOnOffEverySec/AVR_E3_NoteOnOffEverySec.ino new file mode 100644 index 0000000..28517b4 --- /dev/null +++ b/examples/AVR_E3_NoteOnOffEverySec/AVR_E3_NoteOnOffEverySec.ino @@ -0,0 +1,79 @@ +#include // from https://github.com/sstaub/Ethernet3 + +#define SerialMon Serial +#define APPLEMIDI_DEBUG SerialMon +#include + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED +}; + +unsigned long t1 = millis(); +int8_t isConnected = 0; + +APPLEMIDI_CREATE_DEFAULTSESSION_INSTANCE(); + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +void setup() +{ + DBG_SETUP(115200); + DBG("Booting"); + + if (Ethernet.begin(mac) == 0) { + DBG(F("Failed DHCP, check network cable & reboot")); + for (;;); + } + + DBG(F("OK, now make sure you an rtpMIDI session that is Enabled")); + DBG(F("Add device named Arduino with Host"), Ethernet.localIP(), "Port", AppleMIDI.getPort(), "(Name", AppleMIDI.getName(), ")"); + DBG(F("Select and then press the Connect button")); + DBG(F("Then open a MIDI listener and monitor incoming notes")); + + MIDI.begin(); + + // Stay informed on connection status + AppleMIDI.setHandleConnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc, const char* name) { + isConnected++; + DBG(F("Connected to session"), ssrc, name); + }); + AppleMIDI.setHandleDisconnected([](const APPLEMIDI_NAMESPACE::ssrc_t & ssrc) { + isConnected--; + DBG(F("Disconnected"), ssrc); + }); + + MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) { + DBG(F("NoteOn"), note); + }); + MIDI.setHandleNoteOff([](byte channel, byte note, byte velocity) { + DBG(F("NoteOff"), note); + }); + + DBG(F("Sending MIDI messages every second")); +} + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +void loop() +{ + // Listen to incoming notes + MIDI.read(); + + // send a note every second + // (dont cáll delay(1000) as it will stall the pipeline) + if ((isConnected > 0) && (millis() - t1) > 1000) + { + t1 = millis(); + + byte note = random(1, 127); + byte velocity = 55; + byte channel = 1; + + MIDI.sendNoteOn(note, velocity, channel); +// MIDI.sendNoteOff(note, velocity, channel); + } +} From c0a99a5f6f37b42e699d04f1e83b2ea77522a0ca Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 30 Dec 2020 06:58:45 +0100 Subject: [PATCH 52/60] Update .travis.yml --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c00fc45..13a86d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ cache: install: - pip install -U platformio - platformio update - - platformio lib -g install 62@5.0.0 870 872 + - platformio lib -g install 62@5.0.0 870 872 236 script: - pio ci --board=uno --lib=. examples/AVR_Callbacks/AVR_Callbacks.ino @@ -22,5 +22,7 @@ script: - pio ci --board=uno --lib=. examples/AVR_NoteOnOffEverySec/AVR_NoteOnOffEverySec.ino - pio ci --board=uno --lib=. examples/AVR_ReceivedRawMidiData/AVR_ReceivedRawMidiData.ino - pio ci --board=uno --lib=. examples/AVR_SysEx/AVR_SysEx.ino +- pio ci --board=mkrzero --lib=. examples/SAMD_Bonjour/SAMD_Bonjour.ino - pio ci --board=huzzah --lib=. examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino - pio ci --board=featheresp32 --lib=. examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino +- pio ci --board=wesp32 --lib=. examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino From 09f5f1674d8e265c335af3c8061373c4eae895ae Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 30 Dec 2020 07:07:02 +0100 Subject: [PATCH 53/60] Update wESP32_NoteOnOffEverySec.ino --- examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino b/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino index 75f0ed2..c7bc21d 100644 --- a/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino +++ b/examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino @@ -2,7 +2,7 @@ #define APPLEMIDI_DEBUG SerialMon #include -#include "ETH_Helper.h" +#include "./ETH_Helper.h" unsigned long t0 = millis(); int8_t isConnected = 0; From 79cbccf8bed605ff142be21ab32847e5b12a9e78 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 30 Dec 2020 07:10:07 +0100 Subject: [PATCH 54/60] Update .travis.yml --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 13a86d5..0446ebf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,4 +25,3 @@ script: - pio ci --board=mkrzero --lib=. examples/SAMD_Bonjour/SAMD_Bonjour.ino - pio ci --board=huzzah --lib=. examples/ESP8266_NoteOnOffEverySec/ESP8266_NoteOnOffEverySec.ino - pio ci --board=featheresp32 --lib=. examples/ESP32_NoteOnOffEverySec/ESP32_NoteOnOffEverySec.ino -- pio ci --board=wesp32 --lib=. examples/wESP32_NoteOnOffEverySec/wESP32_NoteOnOffEverySec.ino From ebf3cb531e40c6a50218947e1dc562305a7b9b4c Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 30 Dec 2020 07:16:34 +0100 Subject: [PATCH 55/60] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 127d277..d528db5 100755 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ Beware: the number of sockets on the Arduino is limited. The W5100 support 4, th Reduce the memory footprint by a further 500 bytes by `#define NO_SESSION_NAME` before `#include `. This will leave out all the code to manage the optional session name. By default the session name is kept. Even further reduce the memory footprint by `#define ONE_PARTICIPANT` limiting the number of particpants to just 1. -On an UNO the absolute minimum memory footprint is 21976 bytes (68%) and 946 global variables (46%). For a Leonardo that is 24916 bytes (86%) and 1112 bytes (43%) of global variables. +On an UNO the absolute minimum memory footprint is 21966 bytes (68%) and 945 global variables (46%). For a Leonardo that is 24916 bytes (86%) and 1112 bytes (43%) of global variables. ## Notes Session names can get really long on Macs (eg 'Macbook Pro of Johann Gambolputty de von Ausfern-schplenden-schlitter-crasscrenbon-fried-digger-dingle-dangle-dongle-dungle-burstein-von-knacker-thrasher-apple-banger-horowitz-ticolensic-grander-knotty-spelltinkle-grandlich-grumblemeyer-spelterwasser-kurstlich-himbleeisen-bahnwagen-gutenabend-bitte-ein-nürnburger-bratwustle-gerspurten-mitzweimache-luber-hundsfut-gumberaber-shönendanker-kalbsfleisch-mittler-aucher von Hautkopft of Ulm') and will be trunctated to the `MaxSessionNameLen` (as set in the settings file). From 2bb78db3416ff9a78ea8b43ce3e6c3f310570ca9 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 30 Dec 2020 07:17:21 +0100 Subject: [PATCH 56/60] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d528db5..8d3d510 100755 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ Beware: the number of sockets on the Arduino is limited. The W5100 support 4, th Reduce the memory footprint by a further 500 bytes by `#define NO_SESSION_NAME` before `#include `. This will leave out all the code to manage the optional session name. By default the session name is kept. Even further reduce the memory footprint by `#define ONE_PARTICIPANT` limiting the number of particpants to just 1. -On an UNO the absolute minimum memory footprint is 21966 bytes (68%) and 945 global variables (46%). For a Leonardo that is 24916 bytes (86%) and 1112 bytes (43%) of global variables. +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. ## Notes Session names can get really long on Macs (eg 'Macbook Pro of Johann Gambolputty de von Ausfern-schplenden-schlitter-crasscrenbon-fried-digger-dingle-dangle-dongle-dungle-burstein-von-knacker-thrasher-apple-banger-horowitz-ticolensic-grander-knotty-spelltinkle-grandlich-grumblemeyer-spelterwasser-kurstlich-himbleeisen-bahnwagen-gutenabend-bitte-ein-nürnburger-bratwustle-gerspurten-mitzweimache-luber-hundsfut-gumberaber-shönendanker-kalbsfleisch-mittler-aucher von Hautkopft of Ulm') and will be trunctated to the `MaxSessionNameLen` (as set in the settings file). From c9a3e81308e7fcf33dff04136c4260b8a43a3013 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 30 Dec 2020 07:20:51 +0100 Subject: [PATCH 57/60] Update README.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d3d510..fae754b 100755 --- a/README.md +++ b/README.md @@ -5,12 +5,17 @@ Enables an Arduino with IP/UDP capabilities (Ethernet shield, ESP8266, ESP32, .. ## Features * Build on top of the popular [FortySevenEffects MIDI library](https://github.com/FortySevenEffects/arduino_midi_library) -* Tested with AppleMIDI on Mac OS (Catalina) and using [rtpMIDI](https://www.tobias-erichsen.de/software/rtpmidi.html) from Tobias Erichsen on Windows 10 +* 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 * Send and receive all MIDI messages * Uses callbacks to receive MIDI commands (no need for polling) * Automatic instantiation of AppleMIDI object (see at the end of 'AppleMidi.h') * Compiles on Arduino, MacOS (XCode) and Windows (MSVS) +## New in 3.0.0 +* Bug Fixes (long session names get cropped) +* Reduced memory footprint (see AVR_MinMemUsage example) +* Extended and revised callbacks to receive AppleMIDI protocol feedback + ## Installation From the Arduino IDE Library Manager, search for AppleMIDI From 24e92b8ec07c2ef62afb14375d99f799669f3c98 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 30 Dec 2020 07:35:46 +0100 Subject: [PATCH 58/60] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fae754b..6321efe 100755 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Enables an Arduino with IP/UDP capabilities (Ethernet shield, ESP8266, ESP32, .. * Bug Fixes (long session names get cropped) * Reduced memory footprint (see AVR_MinMemUsage example) * Extended and revised callbacks to receive AppleMIDI protocol feedback +* Who may connect to me (Directory) (see AVR_Directory example) ## Installation From the Arduino IDE Library Manager, search for AppleMIDI From 299286b50ff4646a7995a356fec80e1d3a0dbe56 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 30 Dec 2020 07:37:27 +0100 Subject: [PATCH 59/60] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6321efe..221e4f4 100755 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Enables an Arduino with IP/UDP capabilities (Ethernet shield, ESP8266, ESP32, .. ## New in 3.0.0 * Bug Fixes (long session names get cropped) -* Reduced memory footprint (see AVR_MinMemUsage example) +* Reduced memory footprint (see AVR_MinMemUsage example and note below) * Extended and revised callbacks to receive AppleMIDI protocol feedback * Who may connect to me (Directory) (see AVR_Directory example) @@ -86,7 +86,7 @@ Even further reduce the memory footprint by `#define ONE_PARTICIPANT` limiting t 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. ## Notes -Session names can get really long on Macs (eg 'Macbook Pro of Johann Gambolputty de von Ausfern-schplenden-schlitter-crasscrenbon-fried-digger-dingle-dangle-dongle-dungle-burstein-von-knacker-thrasher-apple-banger-horowitz-ticolensic-grander-knotty-spelltinkle-grandlich-grumblemeyer-spelterwasser-kurstlich-himbleeisen-bahnwagen-gutenabend-bitte-ein-nürnburger-bratwustle-gerspurten-mitzweimache-luber-hundsfut-gumberaber-shönendanker-kalbsfleisch-mittler-aucher von Hautkopft of Ulm') and will be trunctated to the `MaxSessionNameLen` (as set in the settings file). +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). ## Arduino IDE (arduino.cc) * 1.8.13 From 4dd5446945d86e398dd565ab67e3311c869b4dd9 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Wed, 30 Dec 2020 07:39:38 +0100 Subject: [PATCH 60/60] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 221e4f4..ab438c2 100755 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Enables an Arduino with IP/UDP capabilities (Ethernet shield, ESP8266, ESP32, .. ## New in 3.0.0 * Bug Fixes (long session names get cropped) * Reduced memory footprint (see AVR_MinMemUsage example and note below) -* Extended and revised callbacks to receive AppleMIDI protocol feedback +* Extended and revised callbacks to receive AppleMIDI protocol feedback (see AVR_Callbacks example) * Who may connect to me (Directory) (see AVR_Directory example) ## Installation