12#include <mach/mach_time.h>
20void MidiInCoreMIDI::registerAll(EventDistributor& eventDistributor,
22 PluggingController& controller)
24 for (
auto i :
xrange(MIDIGetNumberOfSources())) {
25 if (MIDIEndpointRef endpoint = MIDIGetSource(i)) {
26 controller.registerPluggable(std::make_unique<MidiInCoreMIDI>(
27 eventDistributor, scheduler, endpoint));
32MidiInCoreMIDI::MidiInCoreMIDI(EventDistributor& eventDistributor_,
33 Scheduler& scheduler_, MIDIEndpointRef endpoint_)
34 : eventDistributor(eventDistributor_)
35 , scheduler(scheduler_)
39 CFStringRef midiDeviceName;
40 OSStatus status = MIDIObjectGetStringProperty(
41 endpoint, kMIDIPropertyDisplayName, &midiDeviceName);
43 status = MIDIObjectGetStringProperty(
44 endpoint, kMIDIPropertyName, &midiDeviceName);
47 name =
"Nameless endpoint";
49 name =
strCat(StringOp::fromCFString(midiDeviceName),
" IN");
50 CFRelease(midiDeviceName);
53 eventDistributor.registerEventListener(
54 EventType::MIDI_IN_COREMIDI, *
this);
57MidiInCoreMIDI::~MidiInCoreMIDI()
59 eventDistributor.unregisterEventListener(
60 EventType::MIDI_IN_COREMIDI, *
this);
63void MidiInCoreMIDI::plugHelper(
Connector& , EmuTime::param )
66 if (OSStatus status = MIDIClientCreate(
67 CFSTR(
"openMSX"),
nullptr,
nullptr, &client)) {
68 throw PlugException(
"Failed to create MIDI client (", status,
')');
71 if (OSStatus status = MIDIInputPortCreate(
72 client, CFSTR(
"Input"), sendPacketList,
this, &port)) {
73 MIDIClientDispose(client);
75 throw PlugException(
"Failed to create MIDI port (", status,
')');
78 MIDIPortConnectSource(port, endpoint,
nullptr);
81void MidiInCoreMIDI::unplugHelper(EmuTime::param )
84 if (OSStatus status = MIDIClientDispose(client)) {
85 fprintf(stderr,
"Failed to dispose of MIDI client (%d)\n",
int(status));
96std::string_view MidiInCoreMIDI::getDescription()
const
98 return "Receives MIDI events from an existing CoreMIDI source.";
101void MidiInCoreMIDI::sendPacketList(
const MIDIPacketList *packetList,
102 void *readProcRefCon,
void *srcConnRefCon)
104 static_cast<MidiInCoreMIDI*
>(readProcRefCon)
105 ->sendPacketList(packetList, srcConnRefCon);
108void MidiInCoreMIDI::sendPacketList(
const MIDIPacketList *packetList,
111 std::lock_guard<std::mutex> lock(mutex);
112 const MIDIPacket* packet = &packetList->packet[0];
113 repeat(packetList->numPackets, [&] {
114 for (auto j : xrange(packet->length)) {
115 queue.push_back(packet->data[j]);
117 packet = MIDIPacketNext(packet);
120 eventDistributor.distributeEvent(
121 Event::create<MidiInCoreMidiEvent>());
125void MidiInCoreMIDI::signal(EmuTime::param time)
128 if (!connector->acceptsData()) {
129 std::lock_guard<std::mutex> lock(mutex);
133 if (!connector->ready()) {
139 std::lock_guard<std::mutex> lock(mutex);
140 if (queue.empty())
return;
141 data = queue.pop_front();
143 connector->recvByte(data, time);
147int MidiInCoreMIDI::signalEvent(
const Event& )
150 signal(scheduler.getCurrentTime());
152 std::lock_guard<std::mutex> lock(mutex);
158template<
typename Archive>
168MidiInCoreMIDIVirtual::MidiInCoreMIDIVirtual(EventDistributor& eventDistributor_,
170 : eventDistributor(eventDistributor_)
171 , scheduler(scheduler_)
175 eventDistributor.registerEventListener(
176 EventType::MIDI_IN_COREMIDI_VIRTUAL, *
this);
179MidiInCoreMIDIVirtual::~MidiInCoreMIDIVirtual()
181 eventDistributor.unregisterEventListener(
182 EventType::MIDI_IN_COREMIDI_VIRTUAL, *
this);
185void MidiInCoreMIDIVirtual::plugHelper(
Connector& ,
189 if (OSStatus status = MIDIClientCreate(CFSTR(
"openMSX"),
190 nullptr,
nullptr, &client)) {
191 throw PlugException(
"Failed to create MIDI client (", status,
')');
194 if (OSStatus status = MIDIDestinationCreate(client, CFSTR(
"openMSX"),
195 sendPacketList,
this,
197 MIDIClientDispose(client);
198 throw PlugException(
"Failed to create MIDI endpoint (", status,
')');
202void MidiInCoreMIDIVirtual::unplugHelper(EmuTime::param )
204 if (OSStatus status = MIDIEndpointDispose(endpoint)) {
205 fprintf(stderr,
"Failed to dispose of MIDI port (%d)\n",
int(status));
208 if (OSStatus status = MIDIClientDispose(client)) {
209 fprintf(stderr,
"Failed to dispose of MIDI client (%d)\n",
int(status));
219std::string_view MidiInCoreMIDIVirtual::getDescription()
const
221 return "Sends MIDI events from a newly created CoreMIDI virtual source.";
224void MidiInCoreMIDIVirtual::sendPacketList(
const MIDIPacketList *packetList,
225 void *readProcRefCon,
228 static_cast<MidiInCoreMIDIVirtual*
>(readProcRefCon)
229 ->sendPacketList(packetList, srcConnRefCon);
232void MidiInCoreMIDIVirtual::sendPacketList(
const MIDIPacketList *packetList,
236 std::lock_guard<std::mutex> lock(mutex);
237 const MIDIPacket* packet = &packetList->packet[0];
238 repeat(packetList->numPackets, [&] {
239 for (auto j : xrange(packet->length)) {
240 queue.push_back(packet->data[j]);
242 packet = MIDIPacketNext(packet);
245 eventDistributor.distributeEvent(
246 Event::create<MidiInCoreMidiVirtualEvent>());
250void MidiInCoreMIDIVirtual::signal(EmuTime::param time)
253 if (!connector->acceptsData()) {
254 std::lock_guard<std::mutex> lock(mutex);
258 if (!connector->ready()) {
264 std::lock_guard<std::mutex> lock(mutex);
265 if (queue.empty())
return;
266 data = queue.pop_front();
268 connector->recvByte(data, time);
272int MidiInCoreMIDIVirtual::signalEvent(
const Event& )
275 signal(scheduler.getCurrentTime());
277 std::lock_guard<std::mutex> lock(mutex);
283template<
typename Archive>
std::string getName(KeyCode keyCode)
Translate key code to key name.
This file implemented 3 utility functions:
void serialize(Archive &ar, T &t, unsigned version)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
std::string strCat(Ts &&...ts)
constexpr void repeat(T n, Op op)
Repeat the given operation 'op' 'n' times.
constexpr auto xrange(T e)