Line data Source code
1 : #pragma once 2 : 3 : #include <Settings/NamespaceSettings.hpp> 4 : 5 : #include "BLERingBuf.hpp" 6 : #include <MIDI_Parsers/AnyMIDI_Message.hpp> 7 : #include <MIDI_Parsers/BLEMIDIParser.hpp> 8 : #include <MIDI_Parsers/SerialMIDI_Parser.hpp> 9 : 10 : BEGIN_CS_NAMESPACE 11 : 12 : /// FIFO buffer that you can push BLE packets into, and pop MIDI messages out of. 13 : /// If @p SizeT is chosen to be atomic, one thread can push packets, and another 14 : /// thread can pop MIDI messages, without additional synchronization. 15 : template <uint16_t Capacity, class SizeT = NonatomicBLERingBufSize<uint16_t>> 16 : class BufferedBLEMIDIParser { 17 : private: 18 : /// Contains incoming data to be parsed. 19 : BLERingBuf<Capacity, SizeT> ble_buffer {}; 20 : /// Parses the (chunked) BLE packet obtained from @ref ble_buffer. 21 : BLEMIDIParser ble_parser {nullptr, 0}; 22 : /// Parser for MIDI data extracted from the BLE packet by @ref ble_parser. 23 : SerialMIDI_Parser parser {false}; 24 : 25 : public: 26 : using IncomingMIDIMessage = AnyMIDIMessage; 27 : 28 : /// Add a new BLE packet or chunk to the buffer. 29 15 : bool pushPacket(BLEDataView packet, 30 : BLEDataType type = BLEDataType::Packet) { 31 15 : return ble_buffer.push(packet, type); 32 : } 33 : 34 : /// Retrieve and remove a single incoming MIDI message from the buffer. 35 52 : bool popMessage(IncomingMIDIMessage &incomingMessage) { 36 : // Try reading a MIDI message from the parser 37 306 : auto try_read = [&] { 38 134 : MIDIReadEvent event = parser.pull(ble_parser); 39 67 : switch (event) { 40 33 : case MIDIReadEvent::CHANNEL_MESSAGE: 41 132 : incomingMessage = {parser.getChannelMessage(), 42 33 : ble_parser.getTimestamp()}; 43 33 : return true; 44 4 : case MIDIReadEvent::SYSEX_CHUNK: // fallthrough 45 : case MIDIReadEvent::SYSEX_MESSAGE: 46 16 : incomingMessage = {parser.getSysExMessage(), 47 4 : ble_parser.getTimestamp()}; 48 4 : return true; 49 2 : case MIDIReadEvent::REALTIME_MESSAGE: 50 8 : incomingMessage = {parser.getRealTimeMessage(), 51 2 : ble_parser.getTimestamp()}; 52 2 : return true; 53 1 : case MIDIReadEvent::SYSCOMMON_MESSAGE: 54 4 : incomingMessage = {parser.getSysCommonMessage(), 55 1 : ble_parser.getTimestamp()}; 56 1 : return true; 57 27 : case MIDIReadEvent::NO_MESSAGE: return false; 58 : default: break; // LCOV_EXCL_LINE 59 : } 60 0 : return false; 61 : }; 62 15 : while (true) { 63 : // Try reading a MIDI message from the current buffer 64 67 : if (try_read()) 65 40 : return true; // success, incomingMessage updated 66 : // Get the next chunk of the BLE packet (if available) 67 27 : BLEDataView chunk; 68 27 : auto popped = ble_buffer.pop(chunk); 69 27 : if (popped == BLEDataType::None) 70 12 : return false; // no more BLE data available 71 15 : else if (popped == BLEDataType::Continuation) 72 0 : ble_parser.extend(chunk.data, chunk.length); // same BLE packet 73 15 : else if (popped == BLEDataType::Packet) 74 15 : ble_parser = {chunk.data, chunk.length}; // new BLE packet 75 : } 76 : } 77 : }; 78 : 79 : END_CS_NAMESPACE