Line data Source code
1 : #include "GenericBLEMIDI_Interface.hpp"
2 :
3 : BEGIN_CS_NAMESPACE
4 :
5 : // -------------------------------------------------------------------------- //
6 :
7 : // The following section implements the MIDI sending functions.
8 :
9 : template <class BackendT>
10 : template <class L, class F>
11 18 : void GenericBLEMIDI_Interface<BackendT>::sendImpl(L &lck, F add_to_buffer) {
12 : // BLE packets are sent asynchronously, so we need a lock to access the
13 : // packet buffer
14 : // assert(lck.lck.owns_lock());
15 :
16 : // Try adding the message to the current packet
17 18 : if (!add_to_buffer()) {
18 : // If that doesn't work, flush the packet (send it now and wait until
19 : // it is sent)
20 4 : backend.sendNow(lck);
21 : // And then add it to the (now emtpy) buffer
22 4 : add_to_buffer();
23 : }
24 : // Notify the sending thread that data has been added to the buffer
25 18 : backend.releasePacketAndNotify(lck);
26 18 : }
27 :
28 : template <class BackendT>
29 11 : void GenericBLEMIDI_Interface<BackendT>::sendChannelMessageImpl(
30 : ChannelMessage msg) {
31 11 : uint16_t timestamp = millis(); // BLE MIDI timestamp
32 11 : auto lck = backend.acquirePacket();
33 11 : if (msg.hasTwoDataBytes()) {
34 8 : sendImpl(lck, [&] {
35 9 : return lck.packet->add3B(msg.header, msg.data1, msg.data2,
36 9 : timestamp);
37 : });
38 : } else {
39 3 : sendImpl(lck, [&] {
40 4 : return lck.packet->add2B(msg.header, msg.data1, timestamp);
41 : });
42 : }
43 22 : }
44 :
45 : template <class BackendT>
46 4 : void GenericBLEMIDI_Interface<BackendT>::sendRealTimeImpl(RealTimeMessage msg) {
47 4 : uint16_t timestamp = millis(); // BLE MIDI timestamp
48 4 : auto lck = backend.acquirePacket();
49 4 : sendImpl(lck,
50 5 : [&] { return lck.packet->addRealTime(msg.message, timestamp); });
51 8 : }
52 :
53 : template <class BackendT>
54 3 : void GenericBLEMIDI_Interface<BackendT>::sendSysCommonImpl(
55 : SysCommonMessage msg) {
56 3 : uint16_t timestamp = millis(); // BLE MIDI timestamp
57 3 : auto lck = backend.acquirePacket();
58 3 : sendImpl(lck, [&] {
59 8 : return lck.packet->addSysCommon(msg.getNumberOfDataBytes(), msg.header,
60 8 : msg.data1, msg.data2, timestamp);
61 : });
62 6 : }
63 :
64 : template <class BackendT>
65 3 : void GenericBLEMIDI_Interface<BackendT>::sendSysExImpl(SysExMessage msg) {
66 3 : uint16_t timestamp = millis(); // BLE MIDI timestamp
67 3 : size_t length = msg.length;
68 3 : const uint8_t *data = msg.data;
69 :
70 : // BLE packets are sent asynchronously, so we need a lock to access the
71 : // packet buffer
72 3 : auto lck = backend.acquirePacket();
73 :
74 : // TODO: I have no idea why, but the last byte gets cut off when the LSB
75 : // of the timestamp is 0x77 ... (Problem is probably in the BlueZ parser)
76 3 : if ((timestamp & 0x77) == 0x77)
77 0 : timestamp &= 0xFFFE;
78 :
79 : // Try adding at least the SysExStart header to the current packet
80 3 : if (!lck.packet->addSysEx(data, length, timestamp)) {
81 : // If that didn't fit, flush the packet
82 1 : backend.sendNow(lck);
83 : // Add the first part of the SysEx message to this packet
84 1 : lck.packet->addSysEx(data, length, timestamp);
85 : }
86 : // As long as there's data to be sent in the next packet
87 7 : while (data) {
88 : // Send the previous (full) packet
89 4 : backend.sendNow(lck);
90 : // And add the next part of the SysEx message to a continuation packet
91 4 : lck.packet->continueSysEx(data, length, timestamp);
92 : }
93 : // Notify the sending thread that data has been added to the buffer
94 3 : backend.releasePacketAndNotify(lck);
95 6 : }
96 :
97 : template <class BackendT>
98 12 : void GenericBLEMIDI_Interface<BackendT>::sendNowImpl() {
99 12 : auto lck = backend.acquirePacket();
100 12 : backend.sendNow(lck);
101 24 : }
102 :
103 : // -------------------------------------------------------------------------- //
104 :
105 : template <class BackendT>
106 52 : MIDIReadEvent GenericBLEMIDI_Interface<BackendT>::read() {
107 : // Pop a new message from the queue
108 52 : if (!backend.popMessage(incomingMessage))
109 12 : return MIDIReadEvent::NO_MESSAGE;
110 40 : return incomingMessage.eventType;
111 : }
112 :
113 : template <class BackendT>
114 33 : ChannelMessage GenericBLEMIDI_Interface<BackendT>::getChannelMessage() const {
115 33 : return incomingMessage.eventType == MIDIReadEvent::CHANNEL_MESSAGE
116 33 : ? incomingMessage.message.channelmessage
117 33 : : ChannelMessage(0, 0, 0);
118 : }
119 :
120 : template <class BackendT>
121 : SysCommonMessage
122 1 : GenericBLEMIDI_Interface<BackendT>::getSysCommonMessage() const {
123 1 : return incomingMessage.eventType == MIDIReadEvent::SYSCOMMON_MESSAGE
124 1 : ? incomingMessage.message.syscommonmessage
125 1 : : SysCommonMessage(0, 0, 0);
126 : }
127 :
128 : template <class BackendT>
129 2 : RealTimeMessage GenericBLEMIDI_Interface<BackendT>::getRealTimeMessage() const {
130 2 : return incomingMessage.eventType == MIDIReadEvent::REALTIME_MESSAGE
131 2 : ? incomingMessage.message.realtimemessage
132 2 : : RealTimeMessage(0);
133 : }
134 :
135 : template <class BackendT>
136 8 : SysExMessage GenericBLEMIDI_Interface<BackendT>::getSysExMessage() const {
137 8 : auto evt = incomingMessage.eventType;
138 8 : bool hasSysEx = evt == MIDIReadEvent::SYSEX_MESSAGE ||
139 : evt == MIDIReadEvent::SYSEX_CHUNK;
140 8 : return hasSysEx ? incomingMessage.message.sysexmessage
141 8 : : SysExMessage(nullptr, 0);
142 : }
143 :
144 : template <class BackendT>
145 13 : uint16_t GenericBLEMIDI_Interface<BackendT>::getTimestamp() const {
146 13 : return incomingMessage.timestamp;
147 : }
148 :
149 : // -------------------------------------------------------------------------- //
150 :
151 : template <class BackendT>
152 : void GenericBLEMIDI_Interface<BackendT>::setName(const char *name) {
153 : ble_settings.device_name = name;
154 : }
155 :
156 : template <class BackendT>
157 : void GenericBLEMIDI_Interface<BackendT>::requireEncryption(bool require) {
158 : ble_settings.require_encryption = require;
159 : }
160 :
161 : template <class BackendT>
162 28 : void GenericBLEMIDI_Interface<BackendT>::begin() {
163 28 : backend.begin(ble_settings);
164 28 : }
165 :
166 : template <class BackendT>
167 : void GenericBLEMIDI_Interface<BackendT>::end() {
168 : backend.end();
169 : }
170 :
171 : // -------------------------------------------------------------------------- //
172 :
173 : END_CS_NAMESPACE
|