2 * Copyright (C) 2015 Tim Mayberry <mojofunk@gmail.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include "winmmemidi_output_device.h"
23 #include "pbd/debug.h"
24 #include "pbd/compose.h"
26 #include "rt_thread.h"
27 #include "win_utils.h"
28 #include "midi_util.h"
33 // remove dup with input_device
34 static const uint32_t MIDI_BUFFER_SIZE = 32768;
35 static const uint32_t MAX_MIDI_MSG_SIZE = 256; // fix this for sysex
36 static const uint32_t MAX_QUEUE_SIZE = 4096;
40 WinMMEMidiOutputDevice::WinMMEMidiOutputDevice (int index)
42 , m_queue_semaphore(0)
43 , m_sysex_semaphore(0)
47 , m_thread_running(false)
48 , m_thread_quit(false)
49 , m_midi_buffer(new RingBuffer<uint8_t>(MIDI_BUFFER_SIZE))
51 DEBUG_MIDI (string_compose ("Creating midi output device index: %1\n", index));
53 std::string error_msg;
55 if (!open (index, error_msg)) {
56 DEBUG_MIDI (error_msg);
57 throw std::runtime_error (error_msg);
60 set_device_name (index);
63 WinMMEMidiOutputDevice::~WinMMEMidiOutputDevice ()
65 std::string error_msg;
66 if (!close (error_msg)) {
67 DEBUG_MIDI (error_msg);
72 WinMMEMidiOutputDevice::enqueue_midi_event (uint64_t timestamp,
76 const uint32_t total_bytes = sizeof(MidiEventHeader) + size;
77 if (m_midi_buffer->write_space () < total_bytes) {
78 DEBUG_MIDI ("WinMMEMidiOutput: ring buffer overflow\n");
82 MidiEventHeader h (timestamp, size);
83 m_midi_buffer->write ((uint8_t*)&h, sizeof(MidiEventHeader));
84 m_midi_buffer->write (data, size);
86 signal (m_queue_semaphore);
91 WinMMEMidiOutputDevice::open (UINT index, std::string& error_msg)
93 MMRESULT result = midiOutOpen (&m_handle,
95 (DWORD_PTR)winmm_output_callback,
98 if (result != MMSYSERR_NOERROR) {
99 error_msg = get_error_string (result);
103 m_queue_semaphore = CreateSemaphore (NULL, 0, MAX_QUEUE_SIZE, NULL);
104 if (m_queue_semaphore == NULL) {
105 DEBUG_MIDI ("WinMMEMidiOutput: Unable to create queue semaphore\n");
108 m_sysex_semaphore = CreateSemaphore (NULL, 0, 1, NULL);
109 if (m_sysex_semaphore == NULL) {
110 DEBUG_MIDI ("WinMMEMidiOutput: Unable to create sysex semaphore\n");
117 WinMMEMidiOutputDevice::close (std::string& error_msg)
119 // return error message for first error encountered?
121 MMRESULT result = midiOutReset (m_handle);
122 if (result != MMSYSERR_NOERROR) {
123 error_msg = get_error_string (result);
124 DEBUG_MIDI (error_msg);
127 result = midiOutClose (m_handle);
128 if (result != MMSYSERR_NOERROR) {
129 error_msg = get_error_string (result);
130 DEBUG_MIDI (error_msg);
134 if (m_sysex_semaphore) {
135 if (!CloseHandle (m_sysex_semaphore)) {
136 DEBUG_MIDI ("WinMMEMidiOut Unable to close sysex semaphore\n");
139 m_sysex_semaphore = 0;
142 if (m_queue_semaphore) {
143 if (!CloseHandle (m_queue_semaphore)) {
144 DEBUG_MIDI ("WinMMEMidiOut Unable to close queue semaphore\n");
147 m_queue_semaphore = 0;
156 WinMMEMidiOutputDevice::set_device_name (UINT index)
158 MIDIOUTCAPS capabilities;
160 midiOutGetDevCaps (index, &capabilities, sizeof(capabilities));
162 if (result != MMSYSERR_NOERROR) {
163 DEBUG_MIDI (get_error_string (result));
164 m_name = "Unknown Midi Output Device";
167 m_name = capabilities.szPname;
173 WinMMEMidiOutputDevice::get_error_string (MMRESULT error_code)
175 char error_msg[MAXERRORLENGTH];
176 MMRESULT result = midiOutGetErrorText (error_code, error_msg, MAXERRORLENGTH);
177 if (result != MMSYSERR_NOERROR) {
180 return "WinMMEMidiOutput: Unknown Error code";
184 WinMMEMidiOutputDevice::start ()
186 if (m_thread_running) {
188 string_compose ("WinMMEMidiOutput: device %1 already started\n", m_name));
192 m_timer = CreateWaitableTimer (NULL, FALSE, NULL);
195 DEBUG_MIDI ("WinMMEMidiOutput: unable to create waitable timer\n");
199 if (!start_midi_output_thread ()) {
200 DEBUG_MIDI ("WinMMEMidiOutput: Failed to start MIDI output thread\n");
202 if (!CloseHandle (m_timer)) {
203 DEBUG_MIDI ("WinMMEMidiOutput: unable to close waitable timer\n");
211 WinMMEMidiOutputDevice::stop ()
213 if (!m_thread_running) {
214 DEBUG_MIDI ("WinMMEMidiOutputDevice: device already stopped\n");
218 if (!stop_midi_output_thread ()) {
219 DEBUG_MIDI ("WinMMEMidiOutput: Failed to start MIDI output thread\n");
223 if (!CloseHandle (m_timer)) {
224 DEBUG_MIDI ("WinMMEMidiOutput: unable to close waitable timer\n");
232 WinMMEMidiOutputDevice::start_midi_output_thread ()
234 m_thread_quit = false;
236 //pthread_attr_t attr;
237 size_t stacksize = 100000;
239 // TODO Use native threads
240 if (_realtime_pthread_create (SCHED_FIFO, -21, stacksize,
241 &m_output_thread_handle, midi_output_thread, this)) {
246 while (!m_thread_running && --timeout > 0) { Glib::usleep (1000); }
247 if (timeout == 0 || !m_thread_running) {
248 DEBUG_MIDI (string_compose ("Unable to start midi output device thread: %1\n",
256 WinMMEMidiOutputDevice::stop_midi_output_thread ()
259 m_thread_quit = true;
261 while (m_thread_running && --timeout > 0) { Glib::usleep (1000); }
262 if (timeout == 0 || m_thread_running) {
263 DEBUG_MIDI (string_compose ("Unable to stop midi output device thread: %1\n",
269 if (pthread_join (m_output_thread_handle, &status)) {
270 DEBUG_MIDI (string_compose ("Unable to join midi output device thread: %1\n",
278 WinMMEMidiOutputDevice::signal (HANDLE semaphore)
280 bool result = (bool)ReleaseSemaphore (semaphore, 1, NULL);
282 DEBUG_MIDI ("WinMMEMidiOutDevice: Cannot release semaphore\n");
288 WinMMEMidiOutputDevice::wait (HANDLE semaphore)
290 DWORD result = WaitForSingleObject (semaphore, INFINITE);
293 DEBUG_MIDI ("WinMMEMidiOutDevice: WaitForSingleObject Failed\n");
298 DEBUG_MIDI ("WinMMEMidiOutDevice: Unexpected result from WaitForSingleObject\n");
304 WinMMEMidiOutputDevice::winmm_output_callback (HMIDIOUT handle,
310 ((WinMMEMidiOutputDevice*)instance)
311 ->midi_output_callback (msg, midi_data, timestamp);
315 WinMMEMidiOutputDevice::midi_output_callback (UINT message,
321 DEBUG_MIDI ("WinMMEMidiOutput - MIDI device closed\n");
324 signal (m_sysex_semaphore);
327 DEBUG_MIDI ("WinMMEMidiOutput - MIDI device opened\n");
330 LPMIDIHDR header = (LPMIDIHDR)midi_data;
331 DEBUG_MIDI (string_compose ("WinMMEMidiOut - %1 bytes out of %2 bytes of "
332 "the current sysex message have been sent.\n",
334 header->dwBytesRecorded));
339 WinMMEMidiOutputDevice::midi_output_thread (void *arg)
341 WinMMEMidiOutputDevice* output_device = reinterpret_cast<WinMMEMidiOutputDevice*> (arg);
342 output_device->midi_output_thread ();
347 WinMMEMidiOutputDevice::midi_output_thread ()
349 m_thread_running = true;
351 DEBUG_MIDI ("WinMMEMidiOut: MIDI output thread started\n");
353 #ifdef USE_MMCSS_THREAD_PRIORITIES
356 mmcss::set_thread_characteristics ("Pro Audio", &task_handle);
357 mmcss::set_thread_priority (task_handle, mmcss::AVRT_PRIORITY_HIGH);
360 while (!m_thread_quit) {
361 if (!wait (m_queue_semaphore)) {
365 MidiEventHeader h (0, 0);
366 uint8_t data[MAX_MIDI_MSG_SIZE];
368 const uint32_t read_space = m_midi_buffer->read_space ();
370 if (read_space > sizeof(MidiEventHeader)) {
371 if (m_midi_buffer->read ((uint8_t*)&h, sizeof(MidiEventHeader)) !=
372 sizeof(MidiEventHeader)) {
373 DEBUG_MIDI ("WinMMEMidiOut: Garbled MIDI EVENT HEADER!!\n");
376 assert (read_space >= h.size);
378 if (h.size > MAX_MIDI_MSG_SIZE) {
379 m_midi_buffer->increment_read_idx (h.size);
380 DEBUG_MIDI ("WinMMEMidiOut: MIDI event too large!\n");
383 if (m_midi_buffer->read (&data[0], h.size) != h.size) {
384 DEBUG_MIDI ("WinMMEMidiOut: Garbled MIDI EVENT DATA!!\n");
389 DEBUG_MIDI ("WinMMEMidiOut: MIDI buffer underrun, shouldn't occur\n");
392 uint64_t current_time = utils::get_microseconds ();
394 DEBUG_TIMING (string_compose (
395 "WinMMEMidiOut: h.time = %1, current_time = %2\n", h.time, current_time));
397 if (h.time > current_time) {
399 DEBUG_TIMING (string_compose ("WinMMEMidiOut: waiting at %1 for %2 "
400 "milliseconds before sending message\n",
401 ((double)current_time) / 1000.0,
402 ((double)(h.time - current_time)) / 1000.0));
404 if (!wait_for_microseconds (h.time - current_time))
406 DEBUG_MIDI ("WinMMEMidiOut: Error waiting for timer\n");
410 uint64_t wakeup_time = utils::get_microseconds ();
411 DEBUG_TIMING (string_compose ("WinMMEMidiOut: woke up at %1(ms)\n",
412 ((double)wakeup_time) / 1000.0));
413 if (wakeup_time > h.time) {
414 DEBUG_TIMING (string_compose ("WinMMEMidiOut: overslept by %1(ms)\n",
415 ((double)(wakeup_time - h.time)) / 1000.0));
416 } else if (wakeup_time < h.time) {
417 DEBUG_TIMING (string_compose ("WinMMEMidiOut: woke up %1(ms) too early\n",
418 ((double)(h.time - wakeup_time)) / 1000.0));
421 } else if (h.time < current_time) {
422 DEBUG_TIMING (string_compose (
423 "WinMMEMidiOut: MIDI event at sent to driver %1(ms) late\n",
424 ((double)(current_time - h.time)) / 1000.0));
431 message |= (((DWORD)data[2]) << 16);
432 // Fallthrough on purpose.
434 message |= (((DWORD)data[1]) << 8);
435 // Fallthrough on purpose.
437 message |= (DWORD)data[0];
438 result = midiOutShortMsg (m_handle, message);
439 if (result != MMSYSERR_NOERROR) {
441 string_compose ("WinMMEMidiOutput: %1\n", get_error_string (result)));
448 header.dwBufferLength = h.size;
450 header.lpData = (LPSTR)data;
452 result = midiOutPrepareHeader (m_handle, &header, sizeof(MIDIHDR));
453 if (result != MMSYSERR_NOERROR) {
454 DEBUG_MIDI (string_compose ("WinMMEMidiOutput: midiOutPrepareHeader %1\n",
455 get_error_string (result)));
459 result = midiOutLongMsg (m_handle, &header, sizeof(MIDIHDR));
460 if (result != MMSYSERR_NOERROR) {
461 DEBUG_MIDI (string_compose ("WinMMEMidiOutput: midiOutLongMsg %1\n",
462 get_error_string (result)));
466 // Sysex messages may be sent synchronously or asynchronously. The
467 // choice is up to the WinMME driver. So, we wait until the message is
468 // sent, regardless of the driver's choice.
469 if (!wait (m_sysex_semaphore)) {
473 result = midiOutUnprepareHeader (m_handle, &header, sizeof(MIDIHDR));
474 if (result != MMSYSERR_NOERROR) {
475 DEBUG_MIDI (string_compose ("WinMMEMidiOutput: midiOutUnprepareHeader %1\n",
476 get_error_string (result)));
482 #ifdef USE_MMCSS_THREAD_PRIORITIES
483 mmcss::revert_thread_characteristics (task_handle);
486 m_thread_running = false;
490 WinMMEMidiOutputDevice::wait_for_microseconds (int64_t wait_us)
492 LARGE_INTEGER due_time;
495 due_time.QuadPart = -((LONGLONG)(wait_us * 10));
496 if (!SetWaitableTimer (m_timer, &due_time, 0, NULL, NULL, 0)) {
497 DEBUG_MIDI ("WinMMEMidiOut: Error waiting for timer\n");
501 if (!wait (m_timer)) {
508 } // namespace ARDOUR