1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/midi/midi_message_queue.h"
9 #include "base/logging.h"
10 #include "media/midi/midi_message_util.h"
15 const uint8 kSysEx
= 0xf0;
16 const uint8 kEndOfSysEx
= 0xf7;
18 bool IsDataByte(uint8 data
) {
19 return (data
& 0x80) == 0;
22 bool IsFirstStatusByte(uint8 data
) {
23 return !IsDataByte(data
) && data
!= kEndOfSysEx
;
26 bool IsSystemRealTimeMessage(uint8 data
) {
32 MidiMessageQueue::MidiMessageQueue(bool allow_running_status
)
33 : allow_running_status_(allow_running_status
) {}
35 MidiMessageQueue::~MidiMessageQueue() {}
37 void MidiMessageQueue::Add(const std::vector
<uint8
>& data
) {
38 queue_
.insert(queue_
.end(), data
.begin(), data
.end());
41 void MidiMessageQueue::Add(const uint8
* data
, size_t length
) {
42 queue_
.insert(queue_
.end(), data
, data
+ length
);
45 void MidiMessageQueue::Get(std::vector
<uint8
>* message
) {
52 const uint8 next
= queue_
.front();
55 // "System Real Time Messages" is a special kind of MIDI messages, which can
56 // appear at arbitrary byte position of MIDI stream. Here we reorder
57 // "System Real Time Messages" prior to |next_message_| so that each message
58 // can be clearly separated as a complete MIDI message.
59 if (IsSystemRealTimeMessage(next
)) {
60 message
->push_back(next
);
64 // Here |next_message_[0]| may contain the previous status byte when
65 // |allow_running_status_| is true. Following condition fixes up
66 // |next_message_| if running status condition is not fulfilled.
67 if (!next_message_
.empty() &&
68 ((next_message_
[0] == kSysEx
&& IsFirstStatusByte(next
)) ||
69 (next_message_
[0] != kSysEx
&& !IsDataByte(next
)))) {
70 // An invalid data sequence is found or running status condition is not
72 next_message_
.clear();
75 if (next_message_
.empty()) {
76 if (IsFirstStatusByte(next
)) {
77 next_message_
.push_back(next
);
79 // MIDI protocol doesn't provide any error correction mechanism in
80 // physical layers, and incoming messages can be corrupted, and should
86 // Here we can assume |next_message_| starts with a valid status byte.
87 const uint8 status_byte
= next_message_
[0];
88 next_message_
.push_back(next
);
90 if (status_byte
== kSysEx
) {
91 if (next
== kEndOfSysEx
) {
92 std::swap(*message
, next_message_
);
93 next_message_
.clear();
99 DCHECK(IsDataByte(next
));
100 DCHECK_NE(kSysEx
, status_byte
);
101 const size_t target_len
= GetMidiMessageLength(status_byte
);
102 if (next_message_
.size() < target_len
)
104 if (next_message_
.size() == target_len
) {
105 std::swap(*message
, next_message_
);
106 next_message_
.clear();
107 if (allow_running_status_
) {
108 // Speculatively keep the status byte in case of running status. If this
109 // assumption is not true, |next_message_| will be cleared anyway.
110 next_message_
.push_back(status_byte
);