Skip to content

Commit d42ebc8

Browse files
committed
large journal section parsing (in small buffer)
1 parent 0f64273 commit d42ebc8

File tree

3 files changed

+187
-93
lines changed

3 files changed

+187
-93
lines changed

src/rtpMIDI_Parser.h

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,13 @@ class rtpMIDIParser
2121
private:
2222
bool _rtpHeadersComplete = false;
2323
bool _journalSectionComplete = false;
24+
bool _channelJournalSectionComplete = false;
2425
uint16_t midiCommandLength;
2526
uint8_t _journalTotalChannels;
2627
uint8_t rtpMidi_Flags = 0;
28+
int cmdCount = 0;
29+
uint8_t runningstatus = 0;
30+
size_t _bytesToFlush = 0;
2731

2832
public:
2933
AppleMIDISession<UdpClass, Settings, Platform> * session;
@@ -38,6 +42,15 @@ class rtpMIDIParser
3842
//
3943
parserReturn parse(RtpBuffer_t &buffer)
4044
{
45+
Serial.print("bufferSize: ");
46+
Serial.println(buffer.size());
47+
for (int i = 0; i < buffer.size(); i++)
48+
{
49+
Serial.print(" 0x");
50+
Serial.print(buffer[i], HEX);
51+
}
52+
Serial.println("");
53+
4154
conversionBuffer cb;
4255

4356
// [RFC3550] provides a complete description of the RTP header fields.
@@ -63,6 +76,8 @@ class rtpMIDIParser
6376

6477
if (_rtpHeadersComplete == false)
6578
{
79+
Serial.println("Parsing header");
80+
6681
auto minimumLen = sizeof(Rtp_t);
6782
if (buffer.size() < minimumLen)
6883
return parserReturn::NotSureGiveMeMoreData;
@@ -140,29 +155,25 @@ class rtpMIDIParser
140155
midiCommandLength = (midiCommandLength << 8) | octet;
141156
}
142157

158+
cmdCount = 0;
159+
runningstatus = 0;
160+
143161
while (i--)
144162
buffer.pop_front();
145163

146164
_rtpHeadersComplete = true;
147165

148166
// initialize the Journal Section
149167
_journalSectionComplete = false;
168+
_channelJournalSectionComplete = false;
150169
_journalTotalChannels = 0;
151170
}
152171

153172
// Always a MIDI section
154173
if (midiCommandLength > 0)
155174
{
156-
auto retVal = decodeMidiSection(buffer);
157-
switch (retVal) {
158-
case parserReturn::Processed:
159-
break;
160-
case parserReturn::UnexpectedMidiData:
161-
// already processed MIDI data will be played
162-
_rtpHeadersComplete = false;
163-
default:
164-
return retVal;
165-
}
175+
auto retVal = decodeMIDICommandSection(buffer);
176+
if (retVal != parserReturn::Processed) return retVal;
166177
}
167178

168179
// The payload MAY also contain a journal section. The journal section
@@ -172,10 +183,15 @@ class rtpMIDIParser
172183

173184
if (rtpMidi_Flags & RTP_MIDI_CS_FLAG_J)
174185
{
186+
Serial.println("decoding Journal section");
187+
175188
auto retVal = decodeJournalSection(buffer);
176189
switch (retVal) {
177190
case parserReturn::Processed:
178191
break;
192+
case parserReturn::NotEnoughData:
193+
Serial.println("not enough joournal section");
194+
return parserReturn::NotEnoughData;
179195
case parserReturn::UnexpectedJournalData:
180196
_rtpHeadersComplete = false;
181197
default:
@@ -190,7 +206,7 @@ class rtpMIDIParser
190206

191207
#include "rtpMIDI_Parser_JournalSection.hpp"
192208

193-
#include "rtpMIDI_Parser_MidiCommandSection.hpp"
209+
#include "rtpMIDI_Parser_CommandSection.hpp"
194210
};
195211

196212
END_APPLEMIDI_NAMESPACE
Lines changed: 54 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
// https://www.ietf.org/rfc/rfc4695.html#section-3
22

3-
parserReturn decodeMidiSection(RtpBuffer_t &buffer)
3+
parserReturn decodeMIDICommandSection(RtpBuffer_t &buffer)
44
{
5-
int cmdCount = 0;
6-
75
// https://www.ietf.org/rfc/rfc4695.html#section-3.2
86
//
97
// The first MIDI channel command in the MIDI list MUST include a status
@@ -39,92 +37,90 @@ parserReturn decodeMidiSection(RtpBuffer_t &buffer)
3937
// line.
4038

4139
// (lathoub: RTP_MIDI_CS_FLAG_P((phantom) not implemented
42-
43-
uint8_t runningstatus = 0;
4440

4541
/* Multiple MIDI-commands might follow - the exact number can only be discovered by really decoding the commands! */
4642
while (midiCommandLength)
4743
{
44+
Serial.print("midiCommandLength: ");
45+
Serial.print(midiCommandLength);
46+
Serial.print(" cmdCount: ");
47+
Serial.println(cmdCount);
48+
4849
/* for the first command we only have a delta-time if Z-Flag is set */
4950
if ((cmdCount) || (rtpMidi_Flags & RTP_MIDI_CS_FLAG_Z))
5051
{
51-
auto consumed = decodeTime(buffer);
52+
Serial.println("decoding time");
5253

53-
midiCommandLength -= consumed;
54+
size_t consumed = 0;
55+
auto retVal = decodeTime(buffer, consumed);
56+
if (retVal != parserReturn::Processed) return retVal;
5457

58+
midiCommandLength -= consumed;
5559
while (consumed--)
5660
buffer.pop_front();
57-
58-
if (midiCommandLength > 0 && 0 >= buffer.size())
59-
return parserReturn::NotEnoughData;
6061
}
6162

6263
if (midiCommandLength > 0)
6364
{
64-
/* Decode a MIDI-command - if 0 is returned something went wrong */
65-
size_t consumed = decodeMidi(buffer, runningstatus);
66-
if (consumed == 0)
67-
{
68-
}
69-
else if (consumed > buffer.size())
70-
{
71-
// sysex split in decodeMidi
72-
return parserReturn::NotEnoughData;
73-
}
65+
Serial.println("decoding MIDIcommand section");
66+
67+
cmdCount++;
7468

75-
if (consumed > midiCommandLength) {
76-
buffer.clear();
77-
return parserReturn::UnexpectedMidiData;
69+
size_t consumed = 0;
70+
auto retVal = decodeMidi(buffer, runningstatus, consumed);
71+
if (retVal == parserReturn::NotEnoughData) {
72+
cmdCount = 0; // avoid first command again
73+
return retVal;
7874
}
7975

8076
midiCommandLength -= consumed;
81-
8277
while (consumed--)
8378
buffer.pop_front();
84-
85-
if (midiCommandLength > 0 && 0 >= buffer.size())
86-
return parserReturn::NotEnoughData;
87-
88-
cmdCount++;
8979
}
9080
}
9181

9282
return parserReturn::Processed;
9383
}
9484

95-
size_t decodeTime(RtpBuffer_t &buffer)
85+
parserReturn decodeTime(RtpBuffer_t &buffer, size_t &consumed)
9686
{
97-
uint8_t consumed = 0;
9887
uint32_t deltatime = 0;
9988

10089
/* RTP-MIDI deltatime is "compressed" using only the necessary amount of octets */
10190
for (uint8_t j = 0; j < 4; j++)
10291
{
92+
if (buffer.size() < 1)
93+
return parserReturn::NotEnoughData;
94+
10395
uint8_t octet = buffer[consumed];
10496
deltatime = (deltatime << 7) | (octet & RTP_MIDI_DELTA_TIME_OCTET_MASK);
10597
consumed++;
10698

10799
if ((octet & RTP_MIDI_DELTA_TIME_EXTENSION) == 0)
108100
break;
109101
}
110-
return consumed;
102+
103+
return parserReturn::Processed;
111104
}
112105

113-
size_t decodeMidi(RtpBuffer_t &buffer, uint8_t &runningstatus)
106+
parserReturn decodeMidi(RtpBuffer_t &buffer, uint8_t &runningstatus, size_t &consumed)
114107
{
115-
size_t consumed = 0;
108+
if (buffer.size() < 1)
109+
return parserReturn::NotEnoughData;
116110

117-
auto octet = buffer[0];
111+
auto octet = buffer.front();
118112

119113
/* MIDI realtime-data -> one octet -- unlike serial-wired MIDI realtime-commands in RTP-MIDI will
120114
* not be intermingled with other MIDI-commands, so we handle this case right here and return */
121115
if (octet >= 0xf8)
122116
{
117+
consumed = 1;
118+
123119
session->StartReceivedMidi();
124-
session->ReceivedMidi(buffer[0]);
120+
session->ReceivedMidi(octet);
125121
session->EndReceivedMidi();
126122

127-
return 1;
123+
return parserReturn::Processed;
128124
}
129125

130126
/* see if this first octet is a status message */
@@ -133,7 +129,7 @@ size_t decodeMidi(RtpBuffer_t &buffer, uint8_t &runningstatus)
133129
/* if we have no running status yet -> error */
134130
if (((runningstatus)&RTP_MIDI_COMMAND_STATUS_FLAG) == 0)
135131
{
136-
return 0;
132+
return parserReturn::Processed;
137133
}
138134
/* our first octet is "virtual" coming from a preceding MIDI-command,
139135
* so actually we have not really consumed anything yet */
@@ -160,10 +156,8 @@ size_t decodeMidi(RtpBuffer_t &buffer, uint8_t &runningstatus)
160156
/* non-system MIDI-commands encode the command in the high nibble and the channel
161157
* in the low nibble - so we will take care of those cases next */
162158
if (octet < 0xf0)
163-
{
164-
uint8_t type = (octet & 0xf0);
165-
166-
switch (type)
159+
{
160+
switch (octet & 0xf0)
167161
{
168162
case MIDI_NAMESPACE::MidiType::NoteOff:
169163
consumed += 2;
@@ -188,22 +182,25 @@ size_t decodeMidi(RtpBuffer_t &buffer, uint8_t &runningstatus)
188182
break;
189183
}
190184

185+
if (buffer.size() < consumed)
186+
return parserReturn::NotEnoughData;
187+
191188
session->StartReceivedMidi();
192189
for (size_t j = 0; j < consumed; j++)
193190
session->ReceivedMidi(buffer[j]);
194191
session->EndReceivedMidi();
195192

196-
return consumed;
193+
return parserReturn::Processed;
197194
}
198195

199196
/* Here we catch the remaining system-common commands */
200197
switch (octet)
201198
{
202199
case MIDI_NAMESPACE::MidiType::SystemExclusiveStart:
203200
case MIDI_NAMESPACE::MidiType::SystemExclusiveEnd:
204-
consumed = decodeMidiSysEx(buffer);
205-
if (consumed > buffer.max_size())
206-
return consumed;
201+
consumed = decodeMidiSysEx(buffer, consumed);
202+
// if (consumed > buffer.max_size())
203+
// return consumed;
207204
break;
208205
case MIDI_NAMESPACE::MidiType::TimeCodeQuarterFrame:
209206
consumed += 1;
@@ -218,17 +215,20 @@ size_t decodeMidi(RtpBuffer_t &buffer, uint8_t &runningstatus)
218215
break;
219216
}
220217

218+
if (buffer.size() < consumed)
219+
return parserReturn::NotEnoughData;
220+
221221
session->StartReceivedMidi();
222222
for (size_t j = 0; j < consumed; j++)
223223
session->ReceivedMidi(buffer[j]);
224224
session->EndReceivedMidi();
225225

226-
return consumed;
226+
return parserReturn::Processed;
227227
}
228228

229-
size_t decodeMidiSysEx(RtpBuffer_t &buffer)
229+
parserReturn decodeMidiSysEx(RtpBuffer_t &buffer, size_t &consumed)
230230
{
231-
size_t consumed = 1; // beginning SysEx Token is not counted (as it could remain)
231+
consumed = 1; // beginning SysEx Token is not counted (as it could remain)
232232
size_t i = 0;
233233
auto octet = buffer[++i];
234234

@@ -237,9 +237,9 @@ size_t decodeMidiSysEx(RtpBuffer_t &buffer)
237237
consumed++;
238238
octet = buffer[i++];
239239
if (octet == MIDI_NAMESPACE::MidiType::SystemExclusiveEnd) // Complete message
240-
return consumed;
240+
return parserReturn::Processed;
241241
else if (octet == MIDI_NAMESPACE::MidiType::SystemExclusiveStart) // Start
242-
return consumed;
242+
return parserReturn::Processed;
243243
}
244244

245245
// begin of the SysEx is found, not the end.
@@ -266,5 +266,7 @@ size_t decodeMidiSysEx(RtpBuffer_t &buffer)
266266
midiCommandLength += 1; // adding the manual SysEx SystemExclusiveEnd
267267

268268
// indicates split SysEx
269-
return buffer.max_size() + 1;
269+
consumed = buffer.max_size() + 1;
270+
271+
return parserReturn::Processed;
270272
}

0 commit comments

Comments
 (0)