OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/midi/midi_message_queue.h" | 5 #include "media/midi/midi_message_queue.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "media/midi/midi_message_util.h" | 10 #include "media/midi/message_util.h" |
11 | 11 |
12 namespace midi { | 12 namespace midi { |
13 namespace { | |
14 | |
15 const uint8_t kSysEx = 0xf0; | |
16 const uint8_t kEndOfSysEx = 0xf7; | |
17 | |
18 bool IsDataByte(uint8_t data) { | |
19 return (data & 0x80) == 0; | |
20 } | |
21 | |
22 bool IsSystemRealTimeMessage(uint8_t data) { | |
23 return 0xf8 <= data; | |
24 } | |
25 | |
26 bool IsSystemMessage(uint8_t data) { | |
27 return 0xf0 <= data; | |
28 } | |
29 | |
30 } // namespace | |
31 | 13 |
32 MidiMessageQueue::MidiMessageQueue(bool allow_running_status) | 14 MidiMessageQueue::MidiMessageQueue(bool allow_running_status) |
33 : allow_running_status_(allow_running_status) {} | 15 : allow_running_status_(allow_running_status) {} |
34 | 16 |
35 MidiMessageQueue::~MidiMessageQueue() {} | 17 MidiMessageQueue::~MidiMessageQueue() {} |
36 | 18 |
37 void MidiMessageQueue::Add(const std::vector<uint8_t>& data) { | 19 void MidiMessageQueue::Add(const std::vector<uint8_t>& data) { |
38 queue_.insert(queue_.end(), data.begin(), data.end()); | 20 queue_.insert(queue_.end(), data.begin(), data.end()); |
39 } | 21 } |
40 | 22 |
41 void MidiMessageQueue::Add(const uint8_t* data, size_t length) { | 23 void MidiMessageQueue::Add(const uint8_t* data, size_t length) { |
42 queue_.insert(queue_.end(), data, data + length); | 24 queue_.insert(queue_.end(), data, data + length); |
43 } | 25 } |
44 | 26 |
45 void MidiMessageQueue::Get(std::vector<uint8_t>* message) { | 27 void MidiMessageQueue::Get(std::vector<uint8_t>* message) { |
46 message->clear(); | 28 message->clear(); |
47 | 29 |
48 while (true) { | 30 while (true) { |
49 // Check if |next_message_| is already a complete MIDI message or not. | 31 // Check if |next_message_| is already a complete MIDI message or not. |
50 if (!next_message_.empty()) { | 32 if (!next_message_.empty()) { |
51 const uint8_t status_byte = next_message_.front(); | 33 const uint8_t status_byte = next_message_.front(); |
52 const size_t target_len = GetMidiMessageLength(status_byte); | 34 const size_t target_len = GetMessageLength(status_byte); |
53 if (target_len == 0) { | 35 if (target_len == 0) { |
54 DCHECK_EQ(kSysEx, status_byte); | 36 DCHECK_EQ(kSysExByte, status_byte); |
55 if (next_message_.back() == kEndOfSysEx) { | 37 if (next_message_.back() == kEndOfSysExByte) { |
56 // OK, this is a complete SysEx message. | 38 // OK, this is a complete SysEx message. |
57 std::swap(*message, next_message_); | 39 std::swap(*message, next_message_); |
58 DCHECK(next_message_.empty()); | 40 DCHECK(next_message_.empty()); |
59 return; | 41 return; |
60 } | 42 } |
61 } else if (next_message_.size() == target_len) { | 43 } else if (next_message_.size() == target_len) { |
62 // OK, this is a complete non-SysEx message. | 44 // OK, this is a complete non-SysEx message. |
63 std::swap(*message, next_message_); | 45 std::swap(*message, next_message_); |
64 DCHECK(next_message_.empty()); | 46 DCHECK(next_message_.empty()); |
65 if (allow_running_status_ && !IsSystemMessage(status_byte)) { | 47 if (allow_running_status_ && !IsSystemMessage(status_byte)) { |
66 // Speculatively keep the status byte in case of running status. | 48 // Speculatively keep the status byte in case of running status. |
67 // If this assumption is not true, |next_message_| will be cleared | 49 // If this assumption is not true, |next_message_| will be cleared |
68 // anyway. Note that system common messages should reset the | 50 // anyway. Note that system common messages should reset the |
(...skipping 14 matching lines...) Expand all Loading... |
83 // "System Real Time Messages" prior to |next_message_| so that each message | 65 // "System Real Time Messages" prior to |next_message_| so that each message |
84 // can be clearly separated as a complete MIDI message. | 66 // can be clearly separated as a complete MIDI message. |
85 const uint8_t next = queue_.front(); | 67 const uint8_t next = queue_.front(); |
86 if (IsSystemRealTimeMessage(next)) { | 68 if (IsSystemRealTimeMessage(next)) { |
87 message->push_back(next); | 69 message->push_back(next); |
88 queue_.pop_front(); | 70 queue_.pop_front(); |
89 return; | 71 return; |
90 } | 72 } |
91 | 73 |
92 if (next_message_.empty()) { | 74 if (next_message_.empty()) { |
93 const size_t target_len = GetMidiMessageLength(next); | 75 const size_t target_len = GetMessageLength(next); |
94 // If |target_len| is zero, it means either |next| is not a valid status | 76 // If |target_len| is zero, it means either |next| is not a valid status |
95 // byte or |next| is a valid status byte but the message length is | 77 // byte or |next| is a valid status byte but the message length is |
96 // unpredictable. For the latter case, only SysEx can be accepted. | 78 // unpredictable. For the latter case, only SysEx can be accepted. |
97 if (target_len > 0 || next == kSysEx) { | 79 if (target_len > 0 || next == kSysExByte) { |
98 next_message_.push_back(next); | 80 next_message_.push_back(next); |
99 } | 81 } |
100 // Consume |next| always, since if |next| isn't status byte, which means | 82 // Consume |next| always, since if |next| isn't status byte, which means |
101 // that |next| is just corrupted data, or a data byte followed by | 83 // that |next| is just corrupted data, or a data byte followed by |
102 // reserved message, which we are unable to understand and deal with | 84 // reserved message, which we are unable to understand and deal with |
103 // anyway. | 85 // anyway. |
104 queue_.pop_front(); | 86 queue_.pop_front(); |
105 continue; | 87 continue; |
106 } | 88 } |
107 | 89 |
108 const uint8_t status_byte = next_message_.front(); | 90 const uint8_t status_byte = next_message_.front(); |
109 | 91 |
110 // If we receive a new non-data byte before completing the pending message, | 92 // If we receive a new non-data byte before completing the pending message, |
111 // drop the pending message and respin the loop to re-evaluate |next|. | 93 // drop the pending message and respin the loop to re-evaluate |next|. |
112 // This also clears the running status byte speculatively added above, as | 94 // This also clears the running status byte speculatively added above, as |
113 // well as any broken incomplete messages. | 95 // well as any broken incomplete messages. |
114 if (!IsDataByte(next) && !(status_byte == kSysEx && next == kEndOfSysEx)) { | 96 if (!IsDataByte(next) && |
| 97 !(status_byte == kSysExByte && next == kEndOfSysExByte)) { |
115 next_message_.clear(); | 98 next_message_.clear(); |
116 continue; | 99 continue; |
117 } | 100 } |
118 | 101 |
119 // OK to consume this byte. | 102 // OK to consume this byte. |
120 next_message_.push_back(next); | 103 next_message_.push_back(next); |
121 queue_.pop_front(); | 104 queue_.pop_front(); |
122 } | 105 } |
123 } | 106 } |
124 | 107 |
125 } // namespace midi | 108 } // namespace midi |
OLD | NEW |