#include <cmath>
#include "pbd/compose.h"
+#include "pbd/windows_timer_utils.h"
+#include "pbd/windows_mmcss.h"
-#include "win_utils.h"
#include "midi_util.h"
#include "debug.h"
WinMMEMidiInputDevice::WinMMEMidiInputDevice (int index)
: m_handle(0)
+ , m_started(false)
, m_midi_buffer(new RingBuffer<uint8_t>(MIDI_BUFFER_SIZE))
, m_sysex_buffer(new uint8_t[SYSEX_BUFFER_SIZE])
{
{
m_sysex_header.dwBufferLength = SYSEX_BUFFER_SIZE;
m_sysex_header.dwFlags = 0;
+ m_sysex_header.dwBytesRecorded = 0;
m_sysex_header.lpData = (LPSTR)m_sysex_buffer.get ();
MMRESULT result = midiInPrepareHeader (m_handle, &m_sysex_header, sizeof(MIDIHDR));
error_msg = get_error_string (result);
DEBUG_MIDI (error_msg);
return false;
+ } else {
+ DEBUG_MIDI ("Added Initial WinMME sysex buffer\n");
}
return true;
}
{
WinMMEMidiInputDevice* midi_input = (WinMMEMidiInputDevice*)instance;
+#ifdef USE_MMCSS_THREAD_PRIORITIES
+
+ static HANDLE input_thread = GetCurrentThread ();
+ static bool priority_boosted = false;
+
+#if 0 // GetThreadId() is Vista or later only.
+ if (input_thread != GetCurrentThread ()) {
+ DWORD otid = GetThreadId (input_thread);
+ DWORD ntid = GetThreadId (GetCurrentThread ());
+ // There was a reference on the internet somewhere that it is possible
+ // for the callback to come from different threads(thread pool) this
+ // could be problematic but I haven't seen this behaviour yet
+ DEBUG_THREADS (string_compose (
+ "WinMME input Thread ID Changed: was %1, now %2\n", otid, ntid));
+ }
+#endif
+
+ HANDLE task_handle;
+
+ if (!priority_boosted) {
+ PBD::MMCSS::set_thread_characteristics ("Pro Audio", &task_handle);
+ PBD::MMCSS::set_thread_priority (task_handle, PBD::MMCSS::AVRT_PRIORITY_HIGH);
+ priority_boosted = true;
+ }
+#endif
+
switch (msg) {
case MIM_OPEN:
case MIM_CLOSE:
+ DEBUG_MIDI("WinMME: devices changed callback\n");
// devices_changed_callback
break;
case MIM_MOREDATA:
+ DEBUG_MIDI("WinMME: more data ..\n");
// passing MIDI_IO_STATUS to midiInOpen means that MIM_MOREDATA
// will be sent when the callback isn't processing MIM_DATA messages
// fast enough to keep up with messages arriving at input device
// driver. I'm not sure what could be done differently if that occurs
// so just handle MIM_DATA as per normal
case MIM_DATA:
+ DEBUG_MIDI(string_compose ("WinMME: short msg @ %1\n", (uint32_t) timestamp));
midi_input->handle_short_msg ((const uint8_t*)&midi_msg, (uint32_t)timestamp);
break;
case MIM_LONGDATA:
- midi_input->handle_sysex_msg ((MIDIHDR*)&midi_msg, (uint32_t)timestamp);
+ DEBUG_MIDI(string_compose ("WinMME: long msg @ %1\n", (uint32_t) timestamp));
+ midi_input->handle_sysex_msg ((MIDIHDR*)midi_msg, (uint32_t)timestamp);
break;
case MIM_ERROR:
DEBUG_MIDI ("WinMME: Driver sent an invalid MIDI message\n");
case MIM_LONGERROR:
DEBUG_MIDI ("WinMME: Driver sent an invalid or incomplete SYSEX message\n");
break;
+ default:
+ DEBUG_MIDI ("WinMME: Driver sent an unknown message\n");
+ break;
}
}
WinMMEMidiInputDevice::handle_sysex_msg (MIDIHDR* const midi_header,
uint32_t timestamp)
{
-#ifdef ENABLE_SYSEX
- LPMIDIHDR header = (LPMIDIHDR)midi_header;
- size_t byte_count = header->dwBytesRecorded;
+ size_t byte_count = midi_header->dwBytesRecorded;
- if (!byte_count) {
- DEBUG_MIDI (
- "ERROR: WinMME driver has returned sysex header to us with no bytes\n");
+ if (byte_count == 0) {
+ if ((midi_header->dwFlags & WHDR_DONE) != 0) {
+ DEBUG_MIDI("WinMME: In midi reset\n");
+ // unprepare handled by close
+ } else {
+ DEBUG_MIDI(
+ "ERROR: WinMME driver has returned sysex header to us with no bytes\n");
+ }
return;
}
- uint8_t* data = (uint8_t*)header->lpData;
+ uint8_t* data = (uint8_t*)midi_header->lpData;
+
+ DEBUG_MIDI(string_compose("WinMME sysex flags: %1\n", midi_header->dwFlags));
if ((data[0] != 0xf0) || (data[byte_count - 1] != 0xf7)) {
- DEBUG_MIDI (string_compose ("Discarding %1 byte sysex chunk\n", byte_count));
+ DEBUG_MIDI(string_compose("Discarding %1 byte sysex chunk\n", byte_count));
} else {
enqueue_midi_msg (data, byte_count, timestamp);
}
- MMRESULT result = midiInAddBuffer (m_handle, &m_sysex_header, sizeof(MIDIHDR));
+ DEBUG_MIDI("Adding sysex buffer back to WinMME buffer pool\n");
+
+ midi_header->dwFlags = 0;
+ midi_header->dwBytesRecorded = 0;
+
+ MMRESULT result = midiInPrepareHeader(m_handle, midi_header, sizeof(MIDIHDR));
+
if (result != MMSYSERR_NOERROR) {
- DEBUG_MIDI (get_error_string (result));
+ DEBUG_MIDI(string_compose("Unable to prepare header: %1\n",
+ get_error_string(result)));
+ return;
+ }
+
+ result = midiInAddBuffer(m_handle, midi_header, sizeof(MIDIHDR));
+ if (result != MMSYSERR_NOERROR) {
+ DEBUG_MIDI(string_compose("Unable to add sysex buffer to buffer pool : %1\n",
+ get_error_string(result)));
}
-#endif
}
// fix param order
}
// don't use winmme timestamps for now
- uint64_t ts = utils::get_microseconds ();
+ uint64_t ts = PBD::get_microseconds ();
DEBUG_TIMING (string_compose (
"Enqueing MIDI data device: %1 with timestamp: %2 and size %3\n",