23 #include "JackMidiUtil.h"    25 #include "JackWinMMEOutputPort.h"    26 #include "JackGlobals.h"    27 #include "JackEngineControl.h"    36 JackWinMMEOutputPort::HandleMessageEvent(HMIDIOUT handle, UINT message,
    37                                          DWORD_PTR port, DWORD_PTR param1,
    47 JackWinMMEOutputPort::JackWinMMEOutputPort(
const char *alias_name,
    48                                            const char *client_name,
    49                                            const char *driver_name,
    54     read_queue = 
new JackMidiBufferReadQueue();
    55     std::auto_ptr<JackMidiBufferReadQueue> read_queue_ptr(read_queue);
    56     thread_queue = 
new JackMidiAsyncQueue(max_bytes, max_messages);
    57     std::auto_ptr<JackMidiAsyncQueue> thread_queue_ptr(thread_queue);
    58     thread = 
new JackThread(
this);
    59     std::auto_ptr<JackThread> thread_ptr(thread);
    60     char error_message[MAXERRORLENGTH];
    61     MMRESULT result = midiOutOpen(&handle, index, (DWORD_PTR)HandleMessageEvent,
    62                                   (DWORD_PTR)
this, CALLBACK_FUNCTION);
    63     if (result != MMSYSERR_NOERROR) {
    64         GetOutErrorString(result, error_message);
    67     thread_queue_semaphore = CreateSemaphore(NULL, 0, max_messages, NULL);
    68     if (thread_queue_semaphore == NULL) {
    69         GetOSErrorString(error_message);
    72     sysex_semaphore = CreateSemaphore(NULL, 0, 1, NULL);
    73     if (sysex_semaphore == NULL) {
    74         GetOSErrorString(error_message);
    75         goto destroy_thread_queue_semaphore;
    77     MIDIOUTCAPS capabilities;
    79     result = midiOutGetDevCaps(index, &capabilities, 
sizeof(capabilities));
    80     if (result != MMSYSERR_NOERROR) {
    81         WriteOutError(
"JackWinMMEOutputPort [constructor]", 
"midiOutGetDevCaps",
    83         name_tmp = (
char*)driver_name;
    85         name_tmp = capabilities.szPname;
    87     snprintf(alias, 
sizeof(alias) - 1, 
"%s:%s:out%d", alias_name, name_tmp,
    89     snprintf(name, 
sizeof(name) - 1, 
"%s:playback_%d", client_name, index + 1);
    90     read_queue_ptr.release();
    91     thread_queue_ptr.release();
    95  destroy_thread_queue_semaphore:
    96     if (! CloseHandle(thread_queue_semaphore)) {
    97         WriteOSError(
"JackWinMMEOutputPort [constructor]", 
"CloseHandle");
   100     result = midiOutClose(handle);
   101     if (result != MMSYSERR_NOERROR) {
   102         WriteOutError(
"JackWinMMEOutputPort [constructor]", 
"midiOutClose",
   106     throw std::runtime_error(error_message);
   109 JackWinMMEOutputPort::~JackWinMMEOutputPort()
   111     MMRESULT result = midiOutReset(handle);
   112     if (result != MMSYSERR_NOERROR) {
   113         WriteOutError(
"JackWinMMEOutputPort [destructor]", 
"midiOutReset",
   116     result = midiOutClose(handle);
   117     if (result != MMSYSERR_NOERROR) {
   118         WriteOutError(
"JackWinMMEOutputPort [destructor]", 
"midiOutClose",
   121     if (! CloseHandle(sysex_semaphore)) {
   122         WriteOSError(
"JackWinMMEOutputPort [destructor]", 
"CloseHandle");
   124     if (! CloseHandle(thread_queue_semaphore)) {
   125         WriteOSError(
"JackWinMMEOutputPort [destructor]", 
"CloseHandle");
   133 JackWinMMEOutputPort::Execute()
   136         if (! Wait(thread_queue_semaphore)) {
   137             jack_log(
"JackWinMMEOutputPort::Execute BREAK");
   145         jack_time_t frame_time = GetTimeFromFrames(event->time);
   146         jack_time_t current_time = GetMicroSeconds();
   147         if (frame_time > current_time) {
   148             LARGE_INTEGER due_time;
   152                 -((LONGLONG) ((frame_time - current_time) * 10));
   153             if (! SetWaitableTimer(timer, &due_time, 0, NULL, NULL, 0)) {
   154                 WriteOSError(
"JackWinMMEOutputPort::Execute",
   160             jack_log(
"JackWinMMEOutputPort::Execute - waiting at %f for %f "   161                      "milliseconds before sending message (current frame: %d, "   163                      ((
double) current_time) / 1000.0,
   164                      ((
double) (frame_time - current_time)) / 1000.0,
   165                      GetFramesFromTime(current_time), event->time);
   173             jack_time_t wakeup_time = GetMicroSeconds();
   174             jack_log(
"JackWinMMEOutputPort::Execute - woke up at %f.",
   175                      ((
double) wakeup_time) / 1000.0);
   176             if (wakeup_time > frame_time) {
   177                 jack_log(
"JackWinMMEOutputPort::Execute - overslept by %f "   179                          ((
double) (wakeup_time - frame_time)) / 1000.0);
   180             } 
else if (wakeup_time < frame_time) {
   181                 jack_log(
"JackWinMMEOutputPort::Execute - woke up %f "   182                          "milliseconds too early.",
   183                          ((
double) (frame_time - wakeup_time)) / 1000.0);
   188         jack_midi_data_t *data = 
event->buffer;
   191         size_t size = 
event->size;
   194             message |= (((DWORD) data[2]) << 16);
   197             message |= (((DWORD) data[1]) << 8);
   200             message |= (DWORD) data[0];
   201             result = midiOutShortMsg(handle, message);
   202             if (result != MMSYSERR_NOERROR) {
   203                 WriteOutError(
"JackWinMMEOutputPort::Execute",
   204                               "midiOutShortMsg", result);
   209         header.dwBufferLength = size;
   211         header.lpData = (LPSTR) data;
   212         result = midiOutPrepareHeader(handle, &header, 
sizeof(MIDIHDR));
   213         if (result != MMSYSERR_NOERROR) {
   214             WriteOutError(
"JackWinMMEOutputPort::Execute",
   215                           "midiOutPrepareHeader", result);
   218         result = midiOutLongMsg(handle, &header, 
sizeof(MIDIHDR));
   219         if (result != MMSYSERR_NOERROR) {
   220             WriteOutError(
"JackWinMMEOutputPort::Execute", 
"midiOutLongMsg",
   228         if (! Wait(sysex_semaphore)) {
   232         result = midiOutUnprepareHeader(handle, &header, 
sizeof(MIDIHDR));
   233         if (result != MMSYSERR_NOERROR) {
   234             WriteOutError(
"JackWinMMEOutputPort::Execute",
   235                           "midiOutUnprepareHeader", result);
   243 JackWinMMEOutputPort::GetOutErrorString(MMRESULT error, LPTSTR text)
   245     MMRESULT result = midiOutGetErrorText(error, text, MAXERRORLENGTH);
   246     if (result != MMSYSERR_NOERROR) {
   247         snprintf(text, MAXERRORLENGTH, 
"Unknown MM error code '%d'", error);
   252 JackWinMMEOutputPort::HandleMessage(UINT message, DWORD_PTR param1,
   255     set_threaded_log_function();
   258         jack_log(
"JackWinMMEOutputPort::HandleMessage - MIDI device closed.");
   261         Signal(sysex_semaphore);
   264         jack_log(
"JackWinMMEOutputPort::HandleMessage - MIDI device opened.");
   267         LPMIDIHDR header = (LPMIDIHDR) param1;
   268         jack_log(
"JackWinMMEOutputPort::HandleMessage - %d bytes out of %d "   269                   "bytes of the current sysex message have been sent.",
   270                   header->dwOffset, header->dwBytesRecorded);
   277     set_threaded_log_function();
   280     if (thread->AcquireSelfRealTime(GetEngineControl()->fServerPriority)) {
   281         jack_error(
"JackWinMMEOutputPort::Init - could not acquire realtime "   282                    "scheduling. Continuing anyway.");
   289                                   jack_nframes_t frames)
   296         case JackMidiWriteQueue::BUFFER_FULL:
   297             jack_error(
"JackWinMMEOutputPort::ProcessJack - The thread queue "   298                        "buffer is full.  Dropping event.");
   300         case JackMidiWriteQueue::BUFFER_TOO_SMALL:
   301             jack_error(
"JackWinMMEOutputPort::ProcessJack - The thread queue "   302                        "couldn't enqueue a %d-byte event.  Dropping event.",
   306             Signal(thread_queue_semaphore);
   312 JackWinMMEOutputPort::Signal(HANDLE semaphore)
   314     bool result = (bool) ReleaseSemaphore(semaphore, 1, NULL);
   316         WriteOSError(
"JackWinMMEOutputPort::Signal", 
"ReleaseSemaphore");
   322 JackWinMMEOutputPort::Start()
   324     if (thread->GetStatus() != JackThread::kIdle) {
   327     timer = CreateWaitableTimer(NULL, FALSE, NULL);
   329         WriteOSError(
"JackWinMMEOutputPort::Start", 
"CreateWaitableTimer");
   332     if (! thread->StartSync()) {
   335     jack_error(
"JackWinMMEOutputPort::Start - failed to start MIDI processing "   337     if (! CloseHandle(timer)) {
   338         WriteOSError(
"JackWinMMEOutputPort::Start", 
"CloseHandle");
   344 JackWinMMEOutputPort::Stop()
   346     jack_log(
"JackWinMMEOutputPort::Stop - stopping MIDI output port "   347               "processing thread.");
   351     switch (thread->GetStatus()) {
   352     case JackThread::kIniting:
   353     case JackThread::kStarting:
   354         result = thread->Kill();
   357     case JackThread::kRunning:
   358         Signal(thread_queue_semaphore);
   359         result = thread->Stop();
   366         jack_error(
"JackWinMMEOutputPort::Stop - could not %s MIDI processing "   369     if (! CloseHandle(timer)) {
   370         WriteOSError(
"JackWinMMEOutputPort::Stop", 
"CloseHandle");
   377 JackWinMMEOutputPort::Wait(HANDLE semaphore)
   379     DWORD result = WaitForSingleObject(semaphore, INFINITE);
   382         WriteOSError(
"JackWinMMEOutputPort::Wait", 
"WaitForSingleObject");
   387         jack_error(
"JackWinMMEOutputPort::Wait - unexpected result from "   388                    "'WaitForSingleObject'.");
   394 JackWinMMEOutputPort::WriteOutError(
const char *jack_func, 
const char *mm_func,
   397     char error_message[MAXERRORLENGTH];
   398     GetOutErrorString(result, error_message);
   399     jack_error(
"%s - %s: %s", jack_func, mm_func, error_message);
 jack_midi_event_t * DequeueEvent()
void ResetMidiBuffer(JackMidiBuffer *buffer)
SERVER_EXPORT void jack_error(const char *fmt,...)
virtual jack_midi_event_t * DequeueEvent()
SERVER_EXPORT void jack_log(const char *fmt,...)
virtual EnqueueResult EnqueueEvent(jack_nframes_t time, size_t size, jack_midi_data_t *buffer)