openMSX
MidiOutDevice.cc
Go to the documentation of this file.
1 #include "MidiOutDevice.hh"
2 #include "unreachable.hh"
3 
4 
5 namespace openmsx {
6 
7 constexpr uint8_t MIDI_MSG_SYSEX = 0xF0;
8 constexpr uint8_t MIDI_MSG_SYSEX_END = 0xF7;
9 constexpr uint8_t MIDI_MSG_RESET = 0xFF;
10 
13 [[nodiscard]] static size_t midiMessageLength(uint8_t status)
14 {
15  if (status < 0x80) {
16  assert(false);
17  return 0;
18  } else if (status < 0xC0) {
19  return 3;
20  } else if (status < 0xE0) {
21  return 2;
22  } else if (status < 0xF0) {
23  return 3;
24  } else {
25  switch (status) {
26  case MIDI_MSG_SYSEX:
27  // Limit to force sending large SysEx messages in chunks.
29  case MIDI_MSG_SYSEX_END:
30  assert(false);
31  return 0;
32  case 0xF1:
33  case 0xF3:
34  return 2;
35  case 0xF2:
36  return 3;
37  case 0xF4:
38  case 0xF5:
39  case 0xF9:
40  case 0xFD:
41  // Data size unknown
42  return 1;
43  default:
44  return 1;
45  }
46  }
47 }
48 
49 std::string_view MidiOutDevice::getClass() const
50 {
51  return "midi out";
52 }
53 
55 {
56  buffer.clear();
57  isSysEx = false;
58 }
59 
60 void MidiOutDevice::recvByte(byte value, EmuTime::param time)
61 {
62  if (value & 0x80) { // status byte
63  if (value == MIDI_MSG_SYSEX_END) {
64  if (isSysEx) {
65  buffer.push_back(value);
66  recvMessage(buffer, time);
67  } else {
68  // Ignoring SysEx end without start
69  }
70  buffer.clear();
71  isSysEx = false;
72  } else if (value >= 0xF8) {
73  // Realtime message, send immediately.
74  std::vector<uint8_t> realtimeMessage = { value };
75  recvMessage(realtimeMessage, time);
76  if (value == MIDI_MSG_RESET) {
77  buffer.clear();
78  }
79  return;
80  } else {
81  // Replace any message in progress.
82  if (isSysEx) {
83  // Discarding incomplete MIDI SysEx message
84  } else if (buffer.size() >= 2) {
85  #if 0
86  std::cerr << "Discarding incomplete MIDI message with status "
87  "0x" << std::hex << int(buffer[0]) << std::dec <<
88  ", at " << buffer.size() << " of " <<
89  midiMessageLength(buffer[0]) << " bytes\n";
90  #endif
91  }
92  buffer = { value };
93  isSysEx = value == MIDI_MSG_SYSEX;
94  }
95  } else { // data byte
96  if (buffer.empty() && !isSysEx) {
97  // Ignoring MIDI data without preceding status
98  } else {
99  buffer.push_back(value);
100  }
101  }
102 
103  // Is the message complete?
104  if (!buffer.empty()) {
105  uint8_t status = isSysEx ? MIDI_MSG_SYSEX : buffer[0];
106  size_t len = midiMessageLength(status);
107  if (buffer.size() >= len) {
108  recvMessage(buffer, time);
109  if (status >= 0xF0 && status < 0xF8) {
110  buffer.clear();
111  } else {
112  // Keep last status, to support running status.
113  buffer.resize(1);
114  }
115  }
116  }
117 }
118 
120  const std::vector<uint8_t>& /*message*/, EmuTime::param /*time*/)
121 {
122  UNREACHABLE;
123 }
124 
126 {
127  // ignore
128 }
129 
131 {
132  // ignore
133 }
134 
135 void MidiOutDevice::setParityBit(bool /*enable*/, ParityBit /*parity*/)
136 {
137  // ignore
138 }
139 
140 } // namespace openmsx
openmsx::MidiOutDevice::setParityBit
void setParityBit(bool enable, ParityBit parity) override
Definition: MidiOutDevice.cc:135
openmsx::MIDI_MSG_RESET
constexpr uint8_t MIDI_MSG_RESET
Definition: MidiOutDevice.cc:9
openmsx::MidiOutDevice::getClass
std::string_view getClass() const final
A pluggable belongs to a certain class.
Definition: MidiOutDevice.cc:49
openmsx::MidiOutDevice::recvByte
void recvByte(byte value, EmuTime::param time) override
Definition: MidiOutDevice.cc:60
openmsx::MidiOutDevice::clearBuffer
void clearBuffer()
Discard any buffered partial MIDI message.
Definition: MidiOutDevice.cc:54
UNREACHABLE
#define UNREACHABLE
Definition: unreachable.hh:38
openmsx::SerialDataInterface::StopBits
StopBits
Definition: SerialDataInterface.hh:15
openmsx::MIDI_MSG_SYSEX_END
constexpr uint8_t MIDI_MSG_SYSEX_END
Definition: MidiOutDevice.cc:8
openmsx::SerialDataInterface::DataBits
DataBits
Definition: SerialDataInterface.hh:12
openmsx::MidiOutDevice::MAX_MESSAGE_SIZE
static constexpr size_t MAX_MESSAGE_SIZE
The limit for the amount of data we'll put into one MIDI message.
Definition: MidiOutDevice.hh:21
openmsx::MIDI_MSG_SYSEX
constexpr uint8_t MIDI_MSG_SYSEX
Definition: MidiOutDevice.cc:7
openmsx::MidiOutDevice::setDataBits
void setDataBits(DataBits bits) override
Definition: MidiOutDevice.cc:125
openmsx::SerialDataInterface::ParityBit
ParityBit
Definition: SerialDataInterface.hh:19
openmsx::MidiOutDevice::setStopBits
void setStopBits(StopBits bits) override
Definition: MidiOutDevice.cc:130
unreachable.hh
MidiOutDevice.hh
openmsx
This file implemented 3 utility functions:
Definition: Autofire.cc:5
openmsx::MidiOutDevice::recvMessage
virtual void recvMessage(const std::vector< uint8_t > &message, EmuTime::param time)
Called when a full MIDI message is ready to be sent.
Definition: MidiOutDevice.cc:119