Loading...
Searching...
No Matches
MidiText.hpp
1#pragma once
2#include <libremidi/message.hpp>
3
4#include <QString>
5
6#include <cstdint>
7
12namespace Ui::Monitor
13{
15inline QString midiNoteName(int pitch)
16{
17 static constexpr const char* names[12]
18 = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
19 if(pitch < 0 || pitch > 127)
20 return QStringLiteral("?");
21 return QString::fromLatin1(names[pitch % 12]) + QString::number(pitch / 12 - 1);
22}
23
29constexpr libremidi::message_type
30midiMessageType(uint8_t status, uint8_t d1, uint8_t d2) noexcept
31{
32 using T = libremidi::message_type;
33 if(status < 0x80)
34 return T::INVALID;
35 if(status >= 0xF0)
36 return T(status);
37 if(d1 >= 0x80 || d2 >= 0x80)
38 return T::INVALID;
39 const auto t = T(status & 0xF0);
40 if(t == T::NOTE_ON && d2 == 0)
41 return T::NOTE_OFF;
42 return t;
43}
44
46constexpr bool isChannelMessage(libremidi::message_type t) noexcept
47{
48 return uint8_t(t) >= 0x80 && uint8_t(t) < 0xF0;
49}
50
56inline QString
57describeMidi(uint8_t status, uint8_t d1, uint8_t d2, uint32_t size, bool aligned)
58{
59 using T = libremidi::message_type;
60 const auto type = midiMessageType(status, d1, d2);
61 const QString sep = aligned ? QStringLiteral(" ") : QStringLiteral(" ");
62 const int vw = aligned ? 3 : 0;
63 // Explicitly QString: an operator+ chain is a QStringBuilder, which would
64 // refer to the lambda's locals once returned
65 const auto line = [&](const char* kind, const QString& args) -> QString {
66 QString out;
67 if(isChannelMessage(type))
68 out = QStringLiteral("ch%1").arg((status & 0x0F) + 1, aligned ? 2 : 0) + sep;
69 else if(aligned)
70 out = QStringLiteral(" ") + sep;
71 QString k = QString::fromLatin1(kind);
72 if(aligned)
73 k = k.leftJustified(10);
74 out += k;
75 out += sep;
76 out += args;
77 return out;
78 };
79 const auto note = [&]() -> QString {
80 return QStringLiteral("%1 (%2)").arg(int(d1), vw).arg(midiNoteName(d1));
81 };
82
83 switch(type)
84 {
85 case T::NOTE_ON:
86 return line("Note On", note() + QStringLiteral(" vel %1").arg(int(d2)));
87 case T::NOTE_OFF:
88 return line("Note Off", note() + QStringLiteral(" vel %1").arg(int(d2)));
89 case T::POLY_PRESSURE:
90 return line("Poly Aft.", note() + QStringLiteral(" -> %1").arg(int(d2)));
91 case T::CONTROL_CHANGE:
92 return line("CC", QStringLiteral("%1 -> %2").arg(int(d1), vw).arg(int(d2)));
93 case T::PROGRAM_CHANGE:
94 return line("Program", QString::number(int(d1)).rightJustified(vw));
95 case T::AFTERTOUCH:
96 return line("Aftertouch", QString::number(int(d1)).rightJustified(vw));
97 case T::PITCH_BEND:
98 return line("Pitch Bend", QString::number(int(d1) + (int(d2) << 7) - 8192));
99 case T::SYSTEM_EXCLUSIVE:
100 return line("SysEx", QStringLiteral("%1 bytes").arg(size));
101 case T::TIME_CODE:
102 return line("Time code", QString::number(int(d1)));
103 case T::SONG_POS_POINTER:
104 return line("Song pos.", QString::number(int(d1) + (int(d2) << 7)));
105 case T::SONG_SELECT:
106 return line("Song", QString::number(int(d1)));
107 case T::TUNE_REQUEST:
108 return line("Tune req.", {});
109 case T::TIME_CLOCK:
110 return line("Clock", {});
111 case T::START:
112 return line("Start", {});
113 case T::CONTINUE:
114 return line("Continue", {});
115 case T::STOP:
116 return line("Stop", {});
117 case T::ACTIVE_SENSING:
118 return line("Sensing", {});
119 case T::SYSTEM_RESET:
120 return line("Reset", {});
121 case T::INVALID:
122 return line(
123 "Invalid", QStringLiteral("%1 %2 %3")
124 .arg(int(status), 2, 16, QLatin1Char('0'))
125 .arg(int(d1), 2, 16, QLatin1Char('0'))
126 .arg(int(d2), 2, 16, QLatin1Char('0')));
127 default:
128 return line(
129 "System", QStringLiteral("%1 %2 %3")
130 .arg(int(status), 2, 16, QLatin1Char('0'))
131 .arg(int(d1), 3)
132 .arg(int(d2), 3));
133 }
134}
135
137inline QString midiBytesText(uint8_t status, uint8_t d1, uint8_t d2, uint32_t size)
138{
139 if(status == 0xF0)
140 return QStringLiteral("SysEx %1 bytes").arg(size);
141 return QStringLiteral("%1 %2 %3")
142 .arg(int(status), 2, 16, QLatin1Char('0'))
143 .arg(int(d1), 2, 16, QLatin1Char('0'))
144 .arg(int(d2), 2, 16, QLatin1Char('0'))
145 .toUpper();
146}
147}
Definition BufferDecode.hpp:16
QString midiBytesText(uint8_t status, uint8_t d1, uint8_t d2, uint32_t size)
The bytes of a message in hexadecimal, or its size for a SysEx.
Definition MidiText.hpp:137
QString describeMidi(uint8_t status, uint8_t d1, uint8_t d2, uint32_t size, bool aligned)
Definition MidiText.hpp:57
constexpr bool isChannelMessage(libremidi::message_type t) noexcept
Whether the message belongs to a channel, as opposed to the system ones.
Definition MidiText.hpp:46
constexpr libremidi::message_type midiMessageType(uint8_t status, uint8_t d1, uint8_t d2) noexcept
Definition MidiText.hpp:30
QString midiNoteName(int pitch)
The name of a MIDI note, middle C (60) being C4; "?" out of 0 to 127.
Definition MidiText.hpp:15