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