openMSX
MidiOutCoreMIDI.cc
Go to the documentation of this file.
1 #if defined(__APPLE__)
2 
3 #include "MidiOutCoreMIDI.hh"
4 #include "PluggingController.hh"
5 #include "PlugException.hh"
6 #include "serialize.hh"
7 #include "openmsx.hh"
8 #include "StringOp.hh"
9 
10 #include <mach/mach_time.h>
11 #include <cassert>
12 #include <memory>
13 
14 
15 namespace openmsx {
16 
17 // MidiOutMessageBuffer ======================================================
18 
19 void MidiOutMessageBuffer::recvMessage(
20  const std::vector<uint8_t>& message, EmuTime::param /*time*/)
21 {
22  // TODO: It would be better to schedule events based on EmuTime.
23  MIDITimeStamp abstime = mach_absolute_time();
24 
25  MIDIPacketList packetList;
26  MIDIPacket *curPacket = MIDIPacketListInit(&packetList);
27  curPacket = MIDIPacketListAdd(&packetList, sizeof(packetList),
28  curPacket, abstime, message.size(), message.data());
29  if (!curPacket) {
30  fprintf(stderr, "Failed to package MIDI data\n");
31  } else if (OSStatus status = sendPacketList(&packetList)) {
32  fprintf(stderr, "Failed to send MIDI data (%d)\n", int(status));
33  } else {
34  //fprintf(stderr, "MIDI send OK: %02X\n", value);
35  }
36 }
37 
38 
39 // MidiOutCoreMIDI ===========================================================
40 
41 void MidiOutCoreMIDI::registerAll(PluggingController& controller)
42 {
43  ItemCount numberOfEndpoints = MIDIGetNumberOfDestinations();
44  for (ItemCount i = 0; i < numberOfEndpoints; i++) {
45  MIDIEndpointRef endpoint = MIDIGetDestination(i);
46  if (endpoint) {
47  controller.registerPluggable(
48  std::make_unique<MidiOutCoreMIDI>(endpoint));
49  }
50  }
51 }
52 
53 MidiOutCoreMIDI::MidiOutCoreMIDI(MIDIEndpointRef endpoint_)
54  : endpoint(endpoint_)
55 {
56  // Get a user-presentable name for the endpoint.
57  CFStringRef midiDeviceName;
58  OSStatus status = MIDIObjectGetStringProperty(
59  endpoint, kMIDIPropertyDisplayName, &midiDeviceName);
60  if (status) {
61  status = MIDIObjectGetStringProperty(
62  endpoint, kMIDIPropertyName, &midiDeviceName);
63  }
64  if (status) {
65  name = "Nameless endpoint";
66  } else {
67  name = strCat(StringOp::fromCFString(midiDeviceName), " OUT");
68  CFRelease(midiDeviceName);
69  }
70 }
71 
72 void MidiOutCoreMIDI::plugHelper(Connector& /*connector*/,
73  EmuTime::param /*time*/)
74 {
75  // Create client.
76  if (OSStatus status = MIDIClientCreate(CFSTR("openMSX"), nullptr, nullptr, &client)) {
77  throw PlugException("Failed to create MIDI client (", status, ')');
78  }
79  // Create output port.
80  if (OSStatus status = MIDIOutputPortCreate(client, CFSTR("Output"), &port)) {
81  MIDIClientDispose(client);
82  client = 0;
83  throw PlugException("Failed to create MIDI port (", status, ')');
84  }
85 }
86 
87 void MidiOutCoreMIDI::unplugHelper(EmuTime::param /*time*/)
88 {
89  clearBuffer();
90 
91  // Dispose of the client; this automatically disposes of the port as well.
92  if (OSStatus status = MIDIClientDispose(client)) {
93  fprintf(stderr, "Failed to dispose of MIDI client (%d)\n", int(status));
94  }
95  port = 0;
96  client = 0;
97 }
98 
99 const std::string& MidiOutCoreMIDI::getName() const
100 {
101  return name;
102 }
103 
104 std::string_view MidiOutCoreMIDI::getDescription() const
105 {
106  return "Sends MIDI events to an existing CoreMIDI destination.";
107 }
108 
109 OSStatus MidiOutCoreMIDI::sendPacketList(MIDIPacketList *myPacketList)
110 {
111  return MIDISend(port, endpoint, myPacketList);
112 }
113 
114 template<typename Archive>
115 void MidiOutCoreMIDI::serialize(Archive& /*ar*/, unsigned /*version*/)
116 {
117 }
118 INSTANTIATE_SERIALIZE_METHODS(MidiOutCoreMIDI);
119 REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, MidiOutCoreMIDI, "MidiOutCoreMIDI");
120 
121 
122 // MidiOutCoreMIDIVirtual ====================================================
123 
124 MidiOutCoreMIDIVirtual:: MidiOutCoreMIDIVirtual()
125  : client(0)
126  , endpoint(0)
127 {
128 }
129 
130 void MidiOutCoreMIDIVirtual::plugHelper(Connector& /*connector*/,
131  EmuTime::param /*time*/)
132 {
133  // Create client.
134  if (OSStatus status = MIDIClientCreate(CFSTR("openMSX"), nullptr, nullptr, &client)) {
135  throw PlugException("Failed to create MIDI client (", status, ')');
136  }
137  // Create endpoint.
138  if (OSStatus status = MIDISourceCreate(client, CFSTR("openMSX"), &endpoint)) {
139  MIDIClientDispose(client);
140  throw PlugException("Failed to create MIDI endpoint (", status, ')');
141  }
142 }
143 
144 void MidiOutCoreMIDIVirtual::unplugHelper(EmuTime::param /*time*/)
145 {
146  clearBuffer();
147 
148  if (OSStatus status = MIDIEndpointDispose(endpoint)) {
149  fprintf(stderr, "Failed to dispose of MIDI port (%d)\n", int(status));
150  }
151  endpoint = 0;
152  if (OSStatus status = MIDIClientDispose(client)) {
153  fprintf(stderr, "Failed to dispose of MIDI client (%d)\n", int(status));
154  }
155  client = 0;
156 }
157 
158 const std::string& MidiOutCoreMIDIVirtual::getName() const
159 {
160  static const std::string name("Virtual OUT");
161  return name;
162 }
163 
164 std::string_view MidiOutCoreMIDIVirtual::getDescription() const
165 {
166  return "Sends MIDI events from a newly created CoreMIDI virtual source.";
167 }
168 
169 OSStatus MidiOutCoreMIDIVirtual::sendPacketList(MIDIPacketList *myPacketList)
170 {
171  return MIDIReceived(endpoint, myPacketList);
172 }
173 
174 template<typename Archive>
175 void MidiOutCoreMIDIVirtual::serialize(Archive& /*ar*/, unsigned /*version*/)
176 {
177 }
178 INSTANTIATE_SERIALIZE_METHODS(MidiOutCoreMIDIVirtual);
179 REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, MidiOutCoreMIDIVirtual, "MidiOutCoreMIDIVirtual");
180 
181 } // namespace openmsx
182 
183 #endif // defined(__APPLE__)
openmsx.hh
serialize.hh
PlugException.hh
PluggingController.hh
openmsx::Keys::getName
string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:742
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:982
StringOp.hh
openmsx::serialize
void serialize(Archive &ar, T &t, unsigned version)
Definition: serialize_core.hh:41
strCat
std::string strCat(Ts &&...ts)
Definition: strCat.hh:573
openmsx
This file implemented 3 utility functions:
Definition: Autofire.cc:5
openmsx::REGISTER_POLYMORPHIC_INITIALIZER
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")
MidiOutCoreMIDI.hh
openmsx::Connector
Connector
Definition: Connector.cc:83