14#ifndef WIN32_LEAN_AND_MEAN
15#define WIN32_LEAN_AND_MEAN
25void MidiInWindows::registerAll(EventDistributor& eventDistributor,
27 PluggingController& controller)
30 for (
auto i :
xrange(w32_midiInGetVFNsNum())) {
31 controller.registerPluggable(std::make_unique<MidiInWindows>(
32 eventDistributor, scheduler, i));
37MidiInWindows::MidiInWindows(EventDistributor& eventDistributor_,
38 Scheduler& scheduler_,
unsigned num)
39 : eventDistributor(eventDistributor_), scheduler(scheduler_)
41 name = w32_midiInGetVFN(num);
42 desc = w32_midiInGetRDN(num);
44 eventDistributor.registerEventListener(EventType::MIDI_IN_WINDOWS, *
this);
47MidiInWindows::~MidiInWindows()
49 eventDistributor.unregisterEventListener(EventType::MIDI_IN_WINDOWS, *
this);
55void MidiInWindows::plugHelper(Connector& connector_, EmuTime::param )
58 midiConnector.setDataBits(SerialDataInterface::DataBits::D8);
59 midiConnector.setStopBits(SerialDataInterface::StopBits::S1);
60 midiConnector.setParityBit(
false, SerialDataInterface::Parity::EVEN);
62 setConnector(&connector_);
66 std::unique_lock threadIdLock(threadIdMutex);
67 thread = std::thread([
this]() { run(); });
68 threadIdCond.wait(threadIdLock);
71 std::scoped_lock devIdxLock(devIdxMutex);
72 devIdx = w32_midiInOpen(name.c_str(), threadId);
74 devIdxCond.notify_all();
75 if (devIdx ==
unsigned(-1)) {
76 throw PlugException(
"Failed to open " + name);
80void MidiInWindows::unplugHelper(EmuTime::param )
82 assert(devIdx !=
unsigned(-1));
83 w32_midiInClose(devIdx);
84 devIdx = unsigned(-1);
88std::string_view MidiInWindows::getName()
const
93std::string_view MidiInWindows::getDescription()
const
98void MidiInWindows::procLongMsg(LPMIDIHDR p)
100 if (p->dwBytesRecorded) {
102 std::scoped_lock lock(queueMutex);
103 for (
auto i :
xrange(p->dwBytesRecorded)) {
104 queue.push_back(p->lpData[i]);
107 eventDistributor.distributeEvent(MidiInWindowsEvent());
111void MidiInWindows::procShortMsg(DWORD param)
114 switch (param & 0xF0) {
115 case 0x80:
case 0x90:
case 0xA0:
case 0xB0:
case 0xE0:
117 case 0xC0:
case 0xD0:
122 std::scoped_lock lock(queueMutex);
124 queue.push_back(param & 0xFF);
127 eventDistributor.distributeEvent(MidiInWindowsEvent());
130void MidiInWindows::run()
132 assert(isPluggedIn());
135 std::scoped_lock threadIdLock(threadIdMutex);
136 threadId = GetCurrentThreadId();
140 std::unique_lock devIdxLock(devIdxMutex);
141 threadIdCond.notify_all();
142 devIdxCond.wait(devIdxLock);
145 bool fexit = devIdx == unsigned(-1);
148 if (GetMessage(&msg,
nullptr, 0, 0) ==
one_of(0, -1)) {
151 switch (msg.message) {
155 case MM_MIM_MOREDATA:
156 procShortMsg(DWORD(msg.lParam));
158 case MM_MIM_LONGDATA:
159 procLongMsg(
reinterpret_cast<LPMIDIHDR
>(msg.lParam));
162 case MM_MIM_LONGERROR:
174void MidiInWindows::signal(EmuTime::param time)
177 if (!conn->acceptsData()) {
178 std::scoped_lock lock(queueMutex);
182 if (!conn->ready())
return;
186 std::scoped_lock lock(queueMutex);
187 if (queue.empty())
return;
188 data = queue.pop_front();
190 conn->recvByte(data, time);
194bool MidiInWindows::signalEvent(
const Event& )
197 signal(scheduler.getCurrentTime());
199 std::scoped_lock lock(queueMutex);
205template<
typename Archive>
206void MidiInWindows::serialize(Archive& ,
unsigned )
This file implemented 3 utility functions:
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)