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
) {
30 bool IsSystemMessage(uint8 data
) {
36 MidiMessageQueue::MidiMessageQueue(bool allow_running_status
)
37 : allow_running_status_(allow_running_status
) {}
39 MidiMessageQueue::~MidiMessageQueue() {}
41 void MidiMessageQueue::Add(const std::vector
<uint8
>& data
) {
42 queue_
.insert(queue_
.end(), data
.begin(), data
.end());
45 void MidiMessageQueue::Add(const uint8
* data
, size_t length
) {
46 queue_
.insert(queue_
.end(), data
, data
+ length
);
49 void MidiMessageQueue::Get(std::vector
<uint8
>* message
) {
56 const uint8 next
= queue_
.front();
59 // "System Real Time Messages" is a special kind of MIDI messages, which can
60 // appear at arbitrary byte position of MIDI stream. Here we reorder
61 // "System Real Time Messages" prior to |next_message_| so that each message
62 // can be clearly separated as a complete MIDI message.
63 if (IsSystemRealTimeMessage(next
)) {
64 message
->push_back(next
);
68 // Here |next_message_[0]| may contain the previous status byte when
69 // |allow_running_status_| is true. Following condition fixes up
70 // |next_message_| if running status condition is not fulfilled.
71 if (!next_message_
.empty() &&
72 ((next_message_
[0] == kSysEx
&& IsFirstStatusByte(next
)) ||
73 (next_message_
[0] != kSysEx
&& !IsDataByte(next
)))) {
74 // An invalid data sequence is found or running status condition is not
76 next_message_
.clear();
79 if (next_message_
.empty()) {
80 if (IsFirstStatusByte(next
)) {
81 next_message_
.push_back(next
);
83 // MIDI protocol doesn't provide any error correction mechanism in
84 // physical layers, and incoming messages can be corrupted, and should
90 // Here we can assume |next_message_| starts with a valid status byte.
91 const uint8 status_byte
= next_message_
[0];
92 next_message_
.push_back(next
);
94 if (status_byte
== kSysEx
) {
95 if (next
== kEndOfSysEx
) {
96 std::swap(*message
, next_message_
);
97 next_message_
.clear();
103 DCHECK(IsDataByte(next
));
104 DCHECK_NE(kSysEx
, status_byte
);
105 const size_t target_len
= GetMidiMessageLength(status_byte
);
106 if (next_message_
.size() < target_len
)
108 if (next_message_
.size() == target_len
) {
109 std::swap(*message
, next_message_
);
110 next_message_
.clear();
111 if (allow_running_status_
&& !IsSystemMessage(status_byte
)) {
112 // Speculatively keep the status byte in case of running status. If this
113 // assumption is not true, |next_message_| will be cleared anyway.
114 // Note that system common messages should reset the running status.
115 next_message_
.push_back(status_byte
);