X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fbackends%2Fportaudio%2Fwinmmemidi_output_device.cc;h=8acf3d7135a10d6aaec681ba555da8fbdee0d2be;hb=7adb1297cd45e41d3d5d39c28358ed4f4f941616;hp=a1d76cd2360121b540b2937689368b2d7ccb3a75;hpb=4ffe8ffc0faef8ea4bb17e27963bf3998a006995;p=ardour.git diff --git a/libs/backends/portaudio/winmmemidi_output_device.cc b/libs/backends/portaudio/winmmemidi_output_device.cc index a1d76cd236..8acf3d7135 100644 --- a/libs/backends/portaudio/winmmemidi_output_device.cc +++ b/libs/backends/portaudio/winmmemidi_output_device.cc @@ -22,17 +22,16 @@ #include "pbd/debug.h" #include "pbd/compose.h" +#include "pbd/pthread_utils.h" +#include "pbd/windows_timer_utils.h" +#include "pbd/windows_mmcss.h" -#include "rt_thread.h" -#include "win_utils.h" #include "midi_util.h" -#include "mmcss.h" #include "debug.h" // remove dup with input_device static const uint32_t MIDI_BUFFER_SIZE = 32768; -static const uint32_t MAX_MIDI_MSG_SIZE = 256; // fix this for sysex static const uint32_t MAX_QUEUE_SIZE = 4096; namespace ARDOUR { @@ -46,7 +45,7 @@ WinMMEMidiOutputDevice::WinMMEMidiOutputDevice (int index) , m_enabled(false) , m_thread_running(false) , m_thread_quit(false) - , m_midi_buffer(new RingBuffer(MIDI_BUFFER_SIZE)) + , m_midi_buffer(new PBD::RingBuffer(MIDI_BUFFER_SIZE)) { DEBUG_MIDI (string_compose ("Creating midi output device index: %1\n", index)); @@ -70,8 +69,8 @@ WinMMEMidiOutputDevice::~WinMMEMidiOutputDevice () bool WinMMEMidiOutputDevice::enqueue_midi_event (uint64_t timestamp, - const uint8_t* data, - size_t size) + const uint8_t* data, + size_t size) { const uint32_t total_bytes = sizeof(MidiEventHeader) + size; if (m_midi_buffer->write_space () < total_bytes) { @@ -91,10 +90,10 @@ bool WinMMEMidiOutputDevice::open (UINT index, std::string& error_msg) { MMRESULT result = midiOutOpen (&m_handle, - index, - (DWORD_PTR)winmm_output_callback, - (DWORD_PTR) this, - CALLBACK_FUNCTION); + index, + (DWORD_PTR)winmm_output_callback, + (DWORD_PTR) this, + CALLBACK_FUNCTION); if (result != MMSYSERR_NOERROR) { error_msg = get_error_string (result); return false; @@ -118,13 +117,7 @@ WinMMEMidiOutputDevice::close (std::string& error_msg) { // return error message for first error encountered? bool success = true; - MMRESULT result = midiOutReset (m_handle); - if (result != MMSYSERR_NOERROR) { - error_msg = get_error_string (result); - DEBUG_MIDI (error_msg); - success = false; - } - result = midiOutClose (m_handle); + MMRESULT result = midiOutClose (m_handle); if (result != MMSYSERR_NOERROR) { error_msg = get_error_string (result); DEBUG_MIDI (error_msg); @@ -237,7 +230,7 @@ WinMMEMidiOutputDevice::start_midi_output_thread () size_t stacksize = 100000; // TODO Use native threads - if (_realtime_pthread_create (SCHED_FIFO, -21, stacksize, + if (pbd_realtime_pthread_create (PBD_SCHED_FIFO, -21, stacksize, &m_output_thread_handle, midi_output_thread, this)) { return false; } @@ -246,7 +239,7 @@ WinMMEMidiOutputDevice::start_midi_output_thread () while (!m_thread_running && --timeout > 0) { Glib::usleep (1000); } if (timeout == 0 || !m_thread_running) { DEBUG_MIDI (string_compose ("Unable to start midi output device thread: %1\n", - m_name)); + m_name)); return false; } return true; @@ -262,14 +255,14 @@ WinMMEMidiOutputDevice::stop_midi_output_thread () while (m_thread_running && --timeout > 0) { Glib::usleep (1000); } if (timeout == 0 || m_thread_running) { DEBUG_MIDI (string_compose ("Unable to stop midi output device thread: %1\n", - m_name)); + m_name)); return false; } void *status; if (pthread_join (m_output_thread_handle, &status)) { DEBUG_MIDI (string_compose ("Unable to join midi output device thread: %1\n", - m_name)); + m_name)); return false; } return true; @@ -303,10 +296,10 @@ WinMMEMidiOutputDevice::wait (HANDLE semaphore) void CALLBACK WinMMEMidiOutputDevice::winmm_output_callback (HMIDIOUT handle, - UINT msg, - DWORD_PTR instance, - DWORD_PTR midi_data, - DWORD_PTR timestamp) + UINT msg, + DWORD_PTR instance, + DWORD_PTR midi_data, + DWORD_PTR timestamp) { ((WinMMEMidiOutputDevice*)instance) ->midi_output_callback (msg, midi_data, timestamp); @@ -314,8 +307,8 @@ WinMMEMidiOutputDevice::winmm_output_callback (HMIDIOUT handle, void WinMMEMidiOutputDevice::midi_output_callback (UINT message, - DWORD_PTR midi_data, - DWORD_PTR timestamp) + DWORD_PTR midi_data, + DWORD_PTR timestamp) { switch (message) { case MOM_CLOSE: @@ -330,9 +323,9 @@ WinMMEMidiOutputDevice::midi_output_callback (UINT message, case MOM_POSITIONCB: LPMIDIHDR header = (LPMIDIHDR)midi_data; DEBUG_MIDI (string_compose ("WinMMEMidiOut - %1 bytes out of %2 bytes of " - "the current sysex message have been sent.\n", - header->dwOffset, - header->dwBytesRecorded)); + "the current sysex message have been sent.\n", + header->dwOffset, + header->dwBytesRecorded)); } } @@ -354,20 +347,25 @@ WinMMEMidiOutputDevice::midi_output_thread () #ifdef USE_MMCSS_THREAD_PRIORITIES HANDLE task_handle; - mmcss::set_thread_characteristics ("Pro Audio", &task_handle); - mmcss::set_thread_priority (task_handle, mmcss::AVRT_PRIORITY_HIGH); + PBD::MMCSS::set_thread_characteristics ("Pro Audio", &task_handle); + PBD::MMCSS::set_thread_priority (task_handle, PBD::MMCSS::AVRT_PRIORITY_HIGH); #endif while (!m_thread_quit) { if (!wait (m_queue_semaphore)) { + DEBUG_MIDI ("WinMMEMidiOut: output thread waiting for semaphore failed\n"); break; } + DEBUG_MIDI ("WinMMEMidiOut: output thread woken by semaphore\n"); + MidiEventHeader h (0, 0); - uint8_t data[MAX_MIDI_MSG_SIZE]; + uint8_t data[MaxWinMidiEventSize]; const uint32_t read_space = m_midi_buffer->read_space (); + DEBUG_MIDI (string_compose ("WinMMEMidiOut: total readable MIDI data %1\n", read_space)); + if (read_space > sizeof(MidiEventHeader)) { if (m_midi_buffer->read ((uint8_t*)&h, sizeof(MidiEventHeader)) != sizeof(MidiEventHeader)) { @@ -376,7 +374,7 @@ WinMMEMidiOutputDevice::midi_output_thread () } assert (read_space >= h.size); - if (h.size > MAX_MIDI_MSG_SIZE) { + if (h.size > MaxWinMidiEventSize) { m_midi_buffer->increment_read_idx (h.size); DEBUG_MIDI ("WinMMEMidiOut: MIDI event too large!\n"); continue; @@ -398,9 +396,9 @@ WinMMEMidiOutputDevice::midi_output_thread () if (h.time > current_time) { DEBUG_TIMING (string_compose ("WinMMEMidiOut: waiting at %1 for %2 " - "milliseconds before sending message\n", - ((double)current_time) / 1000.0, - ((double)(h.time - current_time)) / 1000.0)); + "milliseconds before sending message\n", + ((double)current_time) / 1000.0, + ((double)(h.time - current_time)) / 1000.0)); if (!wait_for_microseconds (h.time - current_time)) { @@ -410,13 +408,13 @@ WinMMEMidiOutputDevice::midi_output_thread () uint64_t wakeup_time = PBD::get_microseconds (); DEBUG_TIMING (string_compose ("WinMMEMidiOut: woke up at %1(ms)\n", - ((double)wakeup_time) / 1000.0)); + ((double)wakeup_time) / 1000.0)); if (wakeup_time > h.time) { DEBUG_TIMING (string_compose ("WinMMEMidiOut: overslept by %1(ms)\n", - ((double)(wakeup_time - h.time)) / 1000.0)); + ((double)(wakeup_time - h.time)) / 1000.0)); } else if (wakeup_time < h.time) { DEBUG_TIMING (string_compose ("WinMMEMidiOut: woke up %1(ms) too early\n", - ((double)(h.time - wakeup_time)) / 1000.0)); + ((double)(h.time - wakeup_time)) / 1000.0)); } } else if (h.time < current_time) { @@ -425,6 +423,8 @@ WinMMEMidiOutputDevice::midi_output_thread () ((double)(current_time - h.time)) / 1000.0)); } + DEBUG_MIDI (string_compose ("WinMMEMidiOut: MIDI event size: %1 time %2 now %3\n", h.size, h.time, current_time)); + DWORD message = 0; MMRESULT result; switch (h.size) { @@ -444,7 +444,6 @@ WinMMEMidiOutputDevice::midi_output_thread () continue; } -#if ENABLE_SYSEX MIDIHDR header; header.dwBufferLength = h.size; header.dwFlags = 0; @@ -453,35 +452,38 @@ WinMMEMidiOutputDevice::midi_output_thread () result = midiOutPrepareHeader (m_handle, &header, sizeof(MIDIHDR)); if (result != MMSYSERR_NOERROR) { DEBUG_MIDI (string_compose ("WinMMEMidiOutput: midiOutPrepareHeader %1\n", - get_error_string (result))); + get_error_string (result))); continue; } result = midiOutLongMsg (m_handle, &header, sizeof(MIDIHDR)); if (result != MMSYSERR_NOERROR) { DEBUG_MIDI (string_compose ("WinMMEMidiOutput: midiOutLongMsg %1\n", - get_error_string (result))); + get_error_string (result))); continue; } // Sysex messages may be sent synchronously or asynchronously. The // choice is up to the WinMME driver. So, we wait until the message is // sent, regardless of the driver's choice. + + DEBUG_MIDI ("WinMMEMidiOut: wait for sysex semaphore\n"); + if (!wait (m_sysex_semaphore)) { + DEBUG_MIDI ("WinMMEMidiOut: wait for sysex semaphore - failed!\n"); break; } result = midiOutUnprepareHeader (m_handle, &header, sizeof(MIDIHDR)); if (result != MMSYSERR_NOERROR) { DEBUG_MIDI (string_compose ("WinMMEMidiOutput: midiOutUnprepareHeader %1\n", - get_error_string (result))); + get_error_string (result))); break; } -#endif } #ifdef USE_MMCSS_THREAD_PRIORITIES - mmcss::revert_thread_characteristics (task_handle); + PBD::MMCSS::revert_thread_characteristics (task_handle); #endif m_thread_running = false;