Skip to content

Commit 7d65b18

Browse files
committed
winmidi: do not use raw API on windows. Tentative fix for #194
1 parent 1388992 commit 7d65b18

2 files changed

Lines changed: 85 additions & 67 deletions

File tree

include/libremidi/backends/winmidi/midi_in.hpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -157,22 +157,13 @@ class midi_in_impl final
157157
// Add the virtual device as a message processing plugin to receive messages
158158
m_endpoint.AddMessageProcessingPlugin(m_virtual);
159159

160-
#if !LIBREMIDI_WINMIDI_HAS_COM_EXTENSIONS
161160
// Register message received event handler
162161
m_revoke_token = m_endpoint.MessageReceived(
163162
[this](
164163
const winrt::Microsoft::Windows::Devices::Midi2::IMidiMessageReceivedEventSource&,
165164
const winrt::Microsoft::Windows::Devices::Midi2::MidiMessageReceivedEventArgs& args) {
166165
process_message(args);
167166
});
168-
#else
169-
// Use COM interface for raw callback
170-
m_endpoint.as(libremidi::IID_IMidiEndpointConnectionRaw, m_raw_endpoint.put_void());
171-
if (m_raw_endpoint)
172-
{
173-
m_raw_endpoint->SetMessagesReceivedCallback(&raw_callback);
174-
}
175-
#endif
176167

177168
m_endpoint.Open();
178169

@@ -249,21 +240,26 @@ class midi_in_impl final
249240
if(!m_endpoint)
250241
return std::errc::not_connected;
251242

252-
#if !LIBREMIDI_WINMIDI_HAS_COM_EXTENSIONS
253-
m_endpoint.MessageReceived(m_revoke_token);
254-
#else
243+
#if LIBREMIDI_WINMIDI_HAS_COM_EXTENSIONS
255244
if(m_raw_endpoint) {
256245
m_raw_endpoint->RemoveMessagesReceivedCallback();
257246
m_raw_endpoint = nullptr;
258247
}
248+
// When no raw API: everything goes through revoke_token.
249+
// Otherwise: only virtual ports.
250+
else if(m_virtual)
259251
#endif
252+
m_endpoint.MessageReceived(m_revoke_token);
253+
260254
m_session.DisconnectEndpointConnection(m_endpoint.ConnectionId());
261255

256+
#if LIBREMIDI_WINMIDI_HAS_VIRTUAL_DEVICE
262257
if (m_virtual)
263258
{
264259
m_virtual.Cleanup();
265260
m_virtual = nullptr;
266261
}
262+
#endif
267263
return stdx::error{};
268264
}
269265

include/libremidi/backends/winmidi/midi_out.hpp

Lines changed: 77 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,6 @@ class midi_out_impl final
8383
if (!m_endpoint)
8484
return std::errc::device_or_resource_busy;
8585

86-
#if LIBREMIDI_WINMIDI_HAS_COM_EXTENSIONS
87-
m_endpoint.as(libremidi::IID_IMidiEndpointConnectionRaw, m_raw_endpoint.put_void());
88-
#endif
89-
9086
m_endpoint.Open();
9187

9288
return stdx::error{};
@@ -104,70 +100,96 @@ class midi_out_impl final
104100
return std::errc::not_connected;
105101

106102
m_session.DisconnectEndpointConnection(m_endpoint.ConnectionId());
103+
#if LIBREMIDI_WINMIDI_HAS_VIRTUAL_DEVICE
107104
if (m_virtual)
108105
{
109106
m_virtual.Cleanup();
110107
m_virtual = nullptr;
111108
}
109+
#endif
112110
return stdx::error{};
113111
}
114112

115-
stdx::error send_ump(const uint32_t* message, size_t size) override
113+
std::errc write_raw(const uint32_t* ump, int64_t bytes)
116114
{
117-
auto write_func = [this](const uint32_t* ump, int64_t bytes) -> std::errc {
118-
119-
#if !LIBREMIDI_WINMIDI_HAS_COM_EXTENSIONS
120-
MidiSendMessageResults ret{};
121-
switch (bytes / 4)
122-
{
123-
case 1:
124-
ret = m_endpoint.SendSingleMessagePacket(MidiMessage32(0, ump[0]));
125-
break;
126-
case 2:
127-
ret = m_endpoint.SendSingleMessagePacket(MidiMessage64(0, ump[0], ump[1]));
128-
break;
129-
case 3:
130-
ret = m_endpoint.SendSingleMessagePacket(MidiMessage96(0, ump[0], ump[1], ump[2]));
131-
break;
132-
case 4:
133-
ret = m_endpoint.SendSingleMessagePacket(
134-
MidiMessage128(0, ump[0], ump[1], ump[2], ump[3]));
135-
break;
136-
default:
137-
return std::errc::bad_message;
138-
}
139-
if (ret != MidiSendMessageResults::Succeeded)
115+
#if LIBREMIDI_WINMIDI_HAS_COM_EXTENSIONS
116+
HRESULT ret{};
117+
switch (bytes / 4)
118+
{
119+
case 1:
120+
assert(m_raw_endpoint->ValidateBufferHasOnlyCompleteUmps(1, (UINT32*)ump));
121+
ret = m_raw_endpoint->SendMidiMessagesRaw(0, 1, (UINT32*)ump);
122+
break;
123+
case 2:
124+
assert(m_raw_endpoint->ValidateBufferHasOnlyCompleteUmps(2, (UINT32*)ump));
125+
ret = m_raw_endpoint->SendMidiMessagesRaw(0, 2, (UINT32*)ump);
126+
break;
127+
case 3:
128+
assert(m_raw_endpoint->ValidateBufferHasOnlyCompleteUmps(3, (UINT32*)ump));
129+
ret = m_raw_endpoint->SendMidiMessagesRaw(0, 3, (UINT32*)ump);
130+
break;
131+
case 4:
132+
assert(m_raw_endpoint->ValidateBufferHasOnlyCompleteUmps(4, (UINT32*)ump));
133+
ret = m_raw_endpoint->SendMidiMessagesRaw(0, 4, (UINT32*)ump);
134+
break;
135+
default:
140136
return std::errc::bad_message;
137+
}
138+
if(ret < 0)
139+
return std::errc::io_error;
140+
return std::errc{};
141141
#else
142-
HRESULT ret{};
143-
switch (bytes / 4)
144-
{
145-
case 1:
146-
assert(m_raw_endpoint->ValidateBufferHasOnlyCompleteUmps(1, (UINT32*)ump));
147-
ret = m_raw_endpoint->SendMidiMessagesRaw(0, 1, (UINT32*)ump);
148-
break;
149-
case 2:
150-
assert(m_raw_endpoint->ValidateBufferHasOnlyCompleteUmps(2, (UINT32*)ump));
151-
ret = m_raw_endpoint->SendMidiMessagesRaw(0, 2, (UINT32*)ump);
152-
break;
153-
case 3:
154-
assert(m_raw_endpoint->ValidateBufferHasOnlyCompleteUmps(3, (UINT32*)ump));
155-
ret = m_raw_endpoint->SendMidiMessagesRaw(0, 3, (UINT32*)ump);
156-
break;
157-
case 4:
158-
assert(m_raw_endpoint->ValidateBufferHasOnlyCompleteUmps(4, (UINT32*)ump));
159-
ret = m_raw_endpoint->SendMidiMessagesRaw(0, 4, (UINT32*)ump);
160-
break;
161-
default:
162-
return std::errc::bad_message;
163-
}
142+
return write(ump, bytes);
164143
#endif
165-
if(ret < 0)
166-
return std::errc::io_error;
167-
return std::errc{0};
168-
};
144+
}
145+
146+
std::errc write(const uint32_t* ump, int64_t bytes)
147+
{
148+
MidiSendMessageResults ret{};
149+
switch (bytes / 4)
150+
{
151+
case 1:
152+
ret = m_endpoint.SendSingleMessagePacket(MidiMessage32(0, ump[0]));
153+
break;
154+
case 2:
155+
ret = m_endpoint.SendSingleMessagePacket(MidiMessage64(0, ump[0], ump[1]));
156+
break;
157+
case 3:
158+
ret = m_endpoint.SendSingleMessagePacket(MidiMessage96(0, ump[0], ump[1], ump[2]));
159+
break;
160+
case 4:
161+
ret = m_endpoint.SendSingleMessagePacket(
162+
MidiMessage128(0, ump[0], ump[1], ump[2], ump[3]));
163+
break;
164+
default:
165+
return std::errc::bad_message;
166+
}
167+
if (ret != MidiSendMessageResults::Succeeded)
168+
return std::errc::io_error;
169+
return std::errc{};
170+
}
171+
172+
stdx::error send_ump(const uint32_t* message, size_t size) override
173+
{
174+
#if LIBREMIDI_WINMIDI_HAS_VIRTUAL_DEVICE
175+
if(m_virtual)
176+
{
177+
// Virtual port does not support raw API per
178+
// https://github.com/celtera/libremidi/issues/194#issuecomment-4156127901
169179

170-
return segment_ump_stream(message, size, write_func, []() { });
180+
return segment_ump_stream(message, size,
181+
[this](const uint32_t* ump, int64_t bytes) -> std::errc {
182+
return write(ump, bytes);
183+
}, []() { });
184+
}
185+
else
186+
#endif
187+
{
188+
return segment_ump_stream(message, size,
189+
[this](const uint32_t* ump, int64_t bytes) -> std::errc {
190+
return write_raw(ump, bytes);
191+
}, []() { });
192+
}
171193
}
172194

173195
private:

0 commit comments

Comments
 (0)