yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 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. |
| 4 | |
| 5 | #include "media/midi/midi_message_queue.h" |
| 6 | |
| 7 | #include <algorithm> |
| 8 | |
Hans Wennborg | 5f6a461 | 2020-04-24 20:55:49 +0000 | [diff] [blame] | 9 | #include "base/check_op.h" |
| 10 | #include "base/notreached.h" |
toyoshim | bb2750c | 2016-10-20 05:13:24 -0700 | [diff] [blame] | 11 | #include "media/midi/message_util.h" |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 12 | |
toyoshim | e147c5e | 2015-05-07 21:58:31 -0700 | [diff] [blame] | 13 | namespace midi { |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 14 | |
toyoshim@chromium.org | c82e66e | 2014-02-04 07:05:47 +0000 | [diff] [blame] | 15 | MidiMessageQueue::MidiMessageQueue(bool allow_running_status) |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 16 | : allow_running_status_(allow_running_status) {} |
| 17 | |
Chris Watkins | c6cbcf6 | 2017-12-01 03:08:01 +0000 | [diff] [blame] | 18 | MidiMessageQueue::~MidiMessageQueue() = default; |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 19 | |
Avi Drissman | 3528fd0 | 2015-12-18 20:11:31 -0500 | [diff] [blame] | 20 | void MidiMessageQueue::Add(const std::vector<uint8_t>& data) { |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 21 | queue_.insert(queue_.end(), data.begin(), data.end()); |
| 22 | } |
| 23 | |
Avi Drissman | 3528fd0 | 2015-12-18 20:11:31 -0500 | [diff] [blame] | 24 | void MidiMessageQueue::Add(const uint8_t* data, size_t length) { |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 25 | queue_.insert(queue_.end(), data, data + length); |
| 26 | } |
| 27 | |
Avi Drissman | 3528fd0 | 2015-12-18 20:11:31 -0500 | [diff] [blame] | 28 | void MidiMessageQueue::Get(std::vector<uint8_t>* message) { |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 29 | message->clear(); |
| 30 | |
| 31 | while (true) { |
yukawa | a0920f1 | 2015-10-08 00:09:59 -0700 | [diff] [blame] | 32 | // Check if |next_message_| is already a complete MIDI message or not. |
| 33 | if (!next_message_.empty()) { |
Avi Drissman | 3528fd0 | 2015-12-18 20:11:31 -0500 | [diff] [blame] | 34 | const uint8_t status_byte = next_message_.front(); |
toyoshim | bb2750c | 2016-10-20 05:13:24 -0700 | [diff] [blame] | 35 | const size_t target_len = GetMessageLength(status_byte); |
yukawa | a0920f1 | 2015-10-08 00:09:59 -0700 | [diff] [blame] | 36 | if (target_len == 0) { |
toyoshim | bb2750c | 2016-10-20 05:13:24 -0700 | [diff] [blame] | 37 | DCHECK_EQ(kSysExByte, status_byte); |
| 38 | if (next_message_.back() == kEndOfSysExByte) { |
| 39 | // OK, this is a complete SysEx message. |
| 40 | std::swap(*message, next_message_); |
| 41 | DCHECK(next_message_.empty()); |
yukawa | a0920f1 | 2015-10-08 00:09:59 -0700 | [diff] [blame] | 42 | return; |
| 43 | } |
| 44 | } else if (next_message_.size() == target_len) { |
| 45 | // OK, this is a complete non-SysEx message. |
| 46 | std::swap(*message, next_message_); |
| 47 | DCHECK(next_message_.empty()); |
| 48 | if (allow_running_status_ && !IsSystemMessage(status_byte)) { |
| 49 | // Speculatively keep the status byte in case of running status. |
| 50 | // If this assumption is not true, |next_message_| will be cleared |
| 51 | // anyway. Note that system common messages should reset the |
| 52 | // running status. |
| 53 | next_message_.push_back(status_byte); |
| 54 | } |
| 55 | return; |
| 56 | } else if (next_message_.size() > target_len) { |
| 57 | NOTREACHED(); |
| 58 | } |
| 59 | } |
| 60 | |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 61 | if (queue_.empty()) |
| 62 | return; |
| 63 | |
yukawa | a0920f1 | 2015-10-08 00:09:59 -0700 | [diff] [blame] | 64 | // "System Real Time Messages" is a special MIDI message, which can appear |
| 65 | // at an arbitrary byte position of MIDI stream. Here we reorder |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 66 | // "System Real Time Messages" prior to |next_message_| so that each message |
| 67 | // can be clearly separated as a complete MIDI message. |
Avi Drissman | 3528fd0 | 2015-12-18 20:11:31 -0500 | [diff] [blame] | 68 | const uint8_t next = queue_.front(); |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 69 | if (IsSystemRealTimeMessage(next)) { |
| 70 | message->push_back(next); |
yukawa | a0920f1 | 2015-10-08 00:09:59 -0700 | [diff] [blame] | 71 | queue_.pop_front(); |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 72 | return; |
| 73 | } |
| 74 | |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 75 | if (next_message_.empty()) { |
toyoshim | bb2750c | 2016-10-20 05:13:24 -0700 | [diff] [blame] | 76 | const size_t target_len = GetMessageLength(next); |
yukawa | a0920f1 | 2015-10-08 00:09:59 -0700 | [diff] [blame] | 77 | // If |target_len| is zero, it means either |next| is not a valid status |
| 78 | // byte or |next| is a valid status byte but the message length is |
| 79 | // unpredictable. For the latter case, only SysEx can be accepted. |
toyoshim | bb2750c | 2016-10-20 05:13:24 -0700 | [diff] [blame] | 80 | if (target_len > 0 || next == kSysExByte) { |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 81 | next_message_.push_back(next); |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 82 | } |
yukawa | a0920f1 | 2015-10-08 00:09:59 -0700 | [diff] [blame] | 83 | // Consume |next| always, since if |next| isn't status byte, which means |
| 84 | // that |next| is just corrupted data, or a data byte followed by |
| 85 | // reserved message, which we are unable to understand and deal with |
| 86 | // anyway. |
| 87 | queue_.pop_front(); |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 88 | continue; |
| 89 | } |
| 90 | |
Avi Drissman | 3528fd0 | 2015-12-18 20:11:31 -0500 | [diff] [blame] | 91 | const uint8_t status_byte = next_message_.front(); |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 92 | |
yukawa | a0920f1 | 2015-10-08 00:09:59 -0700 | [diff] [blame] | 93 | // If we receive a new non-data byte before completing the pending message, |
| 94 | // drop the pending message and respin the loop to re-evaluate |next|. |
| 95 | // This also clears the running status byte speculatively added above, as |
| 96 | // well as any broken incomplete messages. |
toyoshim | bb2750c | 2016-10-20 05:13:24 -0700 | [diff] [blame] | 97 | if (!IsDataByte(next) && |
| 98 | !(status_byte == kSysExByte && next == kEndOfSysExByte)) { |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 99 | next_message_.clear(); |
yukawa | a0920f1 | 2015-10-08 00:09:59 -0700 | [diff] [blame] | 100 | continue; |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 101 | } |
| 102 | |
yukawa | a0920f1 | 2015-10-08 00:09:59 -0700 | [diff] [blame] | 103 | // OK to consume this byte. |
| 104 | next_message_.push_back(next); |
| 105 | queue_.pop_front(); |
yukawa@chromium.org | 09ef89a | 2013-11-29 06:27:41 +0000 | [diff] [blame] | 106 | } |
| 107 | } |
| 108 | |
toyoshim | e147c5e | 2015-05-07 21:58:31 -0700 | [diff] [blame] | 109 | } // namespace midi |