openMSX
MidiOutCoreMIDI.cc
Go to the documentation of this file.
1#if defined(__APPLE__)
2
3#include "MidiOutCoreMIDI.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
15namespace openmsx {
16
17// MidiOutMessageBuffer ======================================================
18
19void 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
41void MidiOutCoreMIDI::registerAll(PluggingController& controller)
42{
43 for (auto i : xrange(MIDIGetNumberOfDestinations())) {
44 if (MIDIEndpointRef endpoint = MIDIGetDestination(i)) {
45 controller.registerPluggable(
46 std::make_unique<MidiOutCoreMIDI>(endpoint));
47 }
48 }
49}
50
51MidiOutCoreMIDI::MidiOutCoreMIDI(MIDIEndpointRef endpoint_)
52 : endpoint(endpoint_)
53{
54 // Get a user-presentable name for the endpoint.
55 CFStringRef midiDeviceName;
56 OSStatus status = MIDIObjectGetStringProperty(
57 endpoint, kMIDIPropertyDisplayName, &midiDeviceName);
58 if (status) {
59 status = MIDIObjectGetStringProperty(
60 endpoint, kMIDIPropertyName, &midiDeviceName);
61 }
62 if (status) {
63 name = "Nameless endpoint";
64 } else {
65 name = strCat(StringOp::fromCFString(midiDeviceName), " OUT");
66 CFRelease(midiDeviceName);
67 }
68}
69
70void MidiOutCoreMIDI::plugHelper(Connector& /*connector*/,
71 EmuTime::param /*time*/)
72{
73 // Create client.
74 if (OSStatus status = MIDIClientCreate(CFSTR("openMSX"), nullptr, nullptr, &client)) {
75 throw PlugException("Failed to create MIDI client (", status, ')');
76 }
77 // Create output port.
78 if (OSStatus status = MIDIOutputPortCreate(client, CFSTR("Output"), &port)) {
79 MIDIClientDispose(client);
80 client = 0;
81 throw PlugException("Failed to create MIDI port (", status, ')');
82 }
83}
84
85void MidiOutCoreMIDI::unplugHelper(EmuTime::param /*time*/)
86{
87 clearBuffer();
88
89 // Dispose of the client; this automatically disposes of the port as well.
90 if (OSStatus status = MIDIClientDispose(client)) {
91 fprintf(stderr, "Failed to dispose of MIDI client (%d)\n", int(status));
92 }
93 port = 0;
94 client = 0;
95}
96
97std::string_view MidiOutCoreMIDI::getName() const
98{
99 return name;
100}
101
102std::string_view MidiOutCoreMIDI::getDescription() const
103{
104 return "Sends MIDI events to an existing CoreMIDI destination.";
105}
106
107OSStatus MidiOutCoreMIDI::sendPacketList(MIDIPacketList *myPacketList)
108{
109 return MIDISend(port, endpoint, myPacketList);
110}
111
112template<typename Archive>
113void MidiOutCoreMIDI::serialize(Archive& /*ar*/, unsigned /*version*/)
114{
115}
116INSTANTIATE_SERIALIZE_METHODS(MidiOutCoreMIDI);
117REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, MidiOutCoreMIDI, "MidiOutCoreMIDI");
118
119
120// MidiOutCoreMIDIVirtual ====================================================
121
122MidiOutCoreMIDIVirtual:: MidiOutCoreMIDIVirtual()
123 : client(0)
124 , endpoint(0)
125{
126}
127
128void MidiOutCoreMIDIVirtual::plugHelper(Connector& /*connector*/,
129 EmuTime::param /*time*/)
130{
131 // Create client.
132 if (OSStatus status = MIDIClientCreate(CFSTR("openMSX"), nullptr, nullptr, &client)) {
133 throw PlugException("Failed to create MIDI client (", status, ')');
134 }
135 // Create endpoint.
136 if (OSStatus status = MIDISourceCreate(client, CFSTR("openMSX"), &endpoint)) {
137 MIDIClientDispose(client);
138 throw PlugException("Failed to create MIDI endpoint (", status, ')');
139 }
140}
141
142void MidiOutCoreMIDIVirtual::unplugHelper(EmuTime::param /*time*/)
143{
144 clearBuffer();
145
146 if (OSStatus status = MIDIEndpointDispose(endpoint)) {
147 fprintf(stderr, "Failed to dispose of MIDI port (%d)\n", int(status));
148 }
149 endpoint = 0;
150 if (OSStatus status = MIDIClientDispose(client)) {
151 fprintf(stderr, "Failed to dispose of MIDI client (%d)\n", int(status));
152 }
153 client = 0;
154}
155
156std::string_view MidiOutCoreMIDIVirtual::getName() const
157{
158 return "Virtual OUT";
159}
160
161std::string_view MidiOutCoreMIDIVirtual::getDescription() const
162{
163 return "Sends MIDI events from a newly created CoreMIDI virtual source.";
164}
165
166OSStatus MidiOutCoreMIDIVirtual::sendPacketList(MIDIPacketList *myPacketList)
167{
168 return MIDIReceived(endpoint, myPacketList);
169}
170
171template<typename Archive>
172void MidiOutCoreMIDIVirtual::serialize(Archive& /*ar*/, unsigned /*version*/)
173{
174}
175INSTANTIATE_SERIALIZE_METHODS(MidiOutCoreMIDIVirtual);
176REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, MidiOutCoreMIDIVirtual, "MidiOutCoreMIDIVirtual");
177
178} // namespace openmsx
179
180#endif // defined(__APPLE__)
This file implemented 3 utility functions:
Definition Autofire.cc:11
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
#define REGISTER_POLYMORPHIC_INITIALIZER(BASE, CLASS, NAME)
std::string strCat()
Definition strCat.hh:703
constexpr auto xrange(T e)
Definition xrange.hh:132