Bug 1733673 [wpt PR 31066] - Annotate CSS Transforms WPT reftests as fuzzy where...
[gecko.git] / dom / midi / MIDIUtils.cpp
blob6e2a7f75af1191eea9bea8bae74b7b6ee929e12e
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/MIDITypes.h"
8 #include "mozilla/dom/MIDIUtils.h"
9 #include "mozilla/UniquePtr.h"
11 // Taken from MIDI IMPLEMENTATION CHART INSTRUCTIONS, MIDI Spec v1.0, Pg. 97
12 static const uint8_t kCommandByte = 0x80;
13 static const uint8_t kSysexMessageStart = 0xF0;
14 static const uint8_t kSystemMessage = 0xF0;
15 static const uint8_t kSysexMessageEnd = 0xF7;
16 static const uint8_t kSystemRealtimeMessage = 0xF8;
17 // Represents the length of all possible command messages.
18 // Taken from MIDI Spec, Pg. 101v 1.0, Table 2
19 static const uint8_t kCommandLengths[] = {3, 3, 3, 3, 2, 2, 3};
20 // Represents the length of all possible system messages. The length of sysex
21 // messages is variable, so we just put zero since it won't be checked anyways.
22 // Taken from MIDI Spec v1.0, Pg. 105, Table 5
23 static const uint8_t kSystemLengths[] = {0, 2, 3, 2, 1, 1, 1, 1};
25 namespace mozilla::dom::MIDIUtils {
27 // Checks validity of MIDIMessage passed to it. Throws debug warnings and
28 // returns false if message is not valid.
29 bool IsValidMessage(const MIDIMessage* aMsg) {
30 if (NS_WARN_IF(!aMsg)) {
31 return false;
33 // Assert on parser problems
34 MOZ_ASSERT(aMsg->data().Length() > 0,
35 "Created a MIDI Message of Length 0. This should never happen!");
36 uint8_t cmd = aMsg->data()[0];
37 // If first byte isn't a command, something is definitely wrong.
38 MOZ_ASSERT((cmd & kCommandByte) == kCommandByte,
39 "Constructed a MIDI packet where first byte is not command!");
40 if (cmd == kSysexMessageStart) {
41 // All we can do with sysex is make sure it starts and ends with the
42 // correct command bytes.
43 if (aMsg->data()[aMsg->data().Length() - 1] != kSysexMessageEnd) {
44 NS_WARNING("Last byte of Sysex Message not 0xF7!");
45 return false;
47 return true;
49 // For system realtime messages, the length should always be 1.
50 if ((cmd & kSystemRealtimeMessage) == kSystemRealtimeMessage) {
51 return aMsg->data().Length() == 1;
53 // Otherwise, just use the correct array for testing lengths. We can't tell
54 // much about message validity other than that.
55 if ((cmd & kSystemMessage) == kSystemMessage) {
56 if (cmd - kSystemMessage >=
57 static_cast<uint8_t>(ArrayLength(kSystemLengths))) {
58 NS_WARNING("System Message Command byte not valid!");
59 return false;
61 return aMsg->data().Length() == kSystemLengths[cmd - kSystemMessage];
63 // For non system commands, we only care about differences in the high nibble
64 // of the first byte. Shift this down to give the index of the expected packet
65 // length.
66 uint8_t cmdIndex = (cmd - kCommandByte) >> 4;
67 if (cmdIndex >= ArrayLength(kCommandLengths)) {
68 // If our index is bigger than our array length, command byte is unknown;
69 NS_WARNING("Unknown MIDI command!");
70 return false;
72 return aMsg->data().Length() == kCommandLengths[cmdIndex];
75 uint32_t ParseMessages(const nsTArray<uint8_t>& aByteBuffer,
76 const TimeStamp& aTimestamp,
77 nsTArray<MIDIMessage>& aMsgArray) {
78 uint32_t bytesRead = 0;
79 bool inSysexMessage = false;
80 UniquePtr<MIDIMessage> currentMsg;
81 for (auto& byte : aByteBuffer) {
82 bytesRead++;
83 if ((byte & kSystemRealtimeMessage) == kSystemRealtimeMessage) {
84 MIDIMessage rt_msg;
85 rt_msg.data().AppendElement(byte);
86 rt_msg.timestamp() = aTimestamp;
87 aMsgArray.AppendElement(rt_msg);
88 continue;
90 if (byte == kSysexMessageEnd) {
91 if (!inSysexMessage) {
92 MOZ_ASSERT(inSysexMessage);
93 NS_WARNING(
94 "Got sysex message end with no sysex message being processed!");
96 inSysexMessage = false;
97 } else if (byte & kCommandByte) {
98 if (currentMsg && IsValidMessage(currentMsg.get())) {
99 aMsgArray.AppendElement(*currentMsg);
101 currentMsg = MakeUnique<MIDIMessage>();
102 currentMsg->timestamp() = aTimestamp;
104 currentMsg->data().AppendElement(byte);
105 if (byte == kSysexMessageStart) {
106 inSysexMessage = true;
109 if (currentMsg && IsValidMessage(currentMsg.get())) {
110 aMsgArray.AppendElement(*currentMsg);
112 return bytesRead;
115 bool IsSysexMessage(const MIDIMessage& aMsg) {
116 if (aMsg.data().Length() == 0) {
117 return false;
119 if (aMsg.data()[0] == kSysexMessageStart) {
120 return true;
122 return false;
124 } // namespace mozilla::dom::MIDIUtils