00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <memory>
00021 #include <stdexcept>
00022
00023 #include "JackMidiUtil.h"
00024 #include "JackTime.h"
00025 #include "JackWinMMEOutputPort.h"
00026 #include "JackGlobals.h"
00027 #include "JackEngineControl.h"
00028
00029 using Jack::JackWinMMEOutputPort;
00030
00032
00034
00035 void CALLBACK
00036 JackWinMMEOutputPort::HandleMessageEvent(HMIDIOUT handle, UINT message,
00037 DWORD_PTR port, DWORD_PTR param1,
00038 DWORD_PTR param2)
00039 {
00040 ((JackWinMMEOutputPort *) port)->HandleMessage(message, param1, param2);
00041 }
00042
00044
00046
00047 JackWinMMEOutputPort::JackWinMMEOutputPort(const char *alias_name,
00048 const char *client_name,
00049 const char *driver_name,
00050 UINT index,
00051 size_t max_bytes,
00052 size_t max_messages)
00053 {
00054 read_queue = new JackMidiBufferReadQueue();
00055 std::auto_ptr<JackMidiBufferReadQueue> read_queue_ptr(read_queue);
00056 thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages);
00057 std::auto_ptr<JackMidiAsyncQueue> thread_queue_ptr(thread_queue);
00058 thread = new JackThread(this);
00059 std::auto_ptr<JackThread> thread_ptr(thread);
00060 char error_message[MAXERRORLENGTH];
00061 MMRESULT result = midiOutOpen(&handle, index, (DWORD_PTR)HandleMessageEvent,
00062 (DWORD_PTR)this, CALLBACK_FUNCTION);
00063 if (result != MMSYSERR_NOERROR) {
00064 GetOutErrorString(result, error_message);
00065 goto raise_exception;
00066 }
00067 thread_queue_semaphore = CreateSemaphore(NULL, 0, max_messages, NULL);
00068 if (thread_queue_semaphore == NULL) {
00069 GetOSErrorString(error_message);
00070 goto close_handle;
00071 }
00072 sysex_semaphore = CreateSemaphore(NULL, 0, 1, NULL);
00073 if (sysex_semaphore == NULL) {
00074 GetOSErrorString(error_message);
00075 goto destroy_thread_queue_semaphore;
00076 }
00077 MIDIOUTCAPS capabilities;
00078 char *name_tmp;
00079 result = midiOutGetDevCaps(index, &capabilities, sizeof(capabilities));
00080 if (result != MMSYSERR_NOERROR) {
00081 WriteOutError("JackWinMMEOutputPort [constructor]", "midiOutGetDevCaps",
00082 result);
00083 name_tmp = (char*)driver_name;
00084 } else {
00085 name_tmp = capabilities.szPname;
00086 }
00087 snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", alias_name, name_tmp,
00088 index + 1);
00089 snprintf(name, sizeof(name) - 1, "%s:playback_%d", client_name, index + 1);
00090 read_queue_ptr.release();
00091 thread_queue_ptr.release();
00092 thread_ptr.release();
00093 return;
00094
00095 destroy_thread_queue_semaphore:
00096 if (! CloseHandle(thread_queue_semaphore)) {
00097 WriteOSError("JackWinMMEOutputPort [constructor]", "CloseHandle");
00098 }
00099 close_handle:
00100 result = midiOutClose(handle);
00101 if (result != MMSYSERR_NOERROR) {
00102 WriteOutError("JackWinMMEOutputPort [constructor]", "midiOutClose",
00103 result);
00104 }
00105 raise_exception:
00106 throw std::runtime_error(error_message);
00107 }
00108
00109 JackWinMMEOutputPort::~JackWinMMEOutputPort()
00110 {
00111 MMRESULT result = midiOutReset(handle);
00112 if (result != MMSYSERR_NOERROR) {
00113 WriteOutError("JackWinMMEOutputPort [destructor]", "midiOutReset",
00114 result);
00115 }
00116 result = midiOutClose(handle);
00117 if (result != MMSYSERR_NOERROR) {
00118 WriteOutError("JackWinMMEOutputPort [destructor]", "midiOutClose",
00119 result);
00120 }
00121 if (! CloseHandle(sysex_semaphore)) {
00122 WriteOSError("JackWinMMEOutputPort [destructor]", "CloseHandle");
00123 }
00124 if (! CloseHandle(thread_queue_semaphore)) {
00125 WriteOSError("JackWinMMEOutputPort [destructor]", "CloseHandle");
00126 }
00127 delete read_queue;
00128 delete thread_queue;
00129 delete thread;
00130 }
00131
00132 bool
00133 JackWinMMEOutputPort::Execute()
00134 {
00135 for (;;) {
00136 if (! Wait(thread_queue_semaphore)) {
00137 jack_log("JackWinMMEOutputPort::Execute BREAK");
00138
00139 break;
00140 }
00141 jack_midi_event_t *event = thread_queue->DequeueEvent();
00142 if (! event) {
00143 break;
00144 }
00145 jack_time_t frame_time = GetTimeFromFrames(event->time);
00146 jack_time_t current_time = GetMicroSeconds();
00147 if (frame_time > current_time) {
00148 LARGE_INTEGER due_time;
00149
00150
00151 due_time.QuadPart =
00152 -((LONGLONG) ((frame_time - current_time) * 10));
00153 if (! SetWaitableTimer(timer, &due_time, 0, NULL, NULL, 0)) {
00154 WriteOSError("JackWinMMEOutputPort::Execute",
00155 "SetWaitableTimer");
00156 break;
00157 }
00158
00159
00160 jack_log("JackWinMMEOutputPort::Execute - waiting at %f for %f "
00161 "milliseconds before sending message (current frame: %d, "
00162 "send frame: %d)",
00163 ((double) current_time) / 1000.0,
00164 ((double) (frame_time - current_time)) / 1000.0,
00165 GetFramesFromTime(current_time), event->time);
00166
00167
00168 if (! Wait(timer)) {
00169 break;
00170 }
00171
00172
00173 jack_time_t wakeup_time = GetMicroSeconds();
00174 jack_log("JackWinMMEOutputPort::Execute - woke up at %f.",
00175 ((double) wakeup_time) / 1000.0);
00176 if (wakeup_time > frame_time) {
00177 jack_log("JackWinMMEOutputPort::Execute - overslept by %f "
00178 "milliseconds.",
00179 ((double) (wakeup_time - frame_time)) / 1000.0);
00180 } else if (wakeup_time < frame_time) {
00181 jack_log("JackWinMMEOutputPort::Execute - woke up %f "
00182 "milliseconds too early.",
00183 ((double) (frame_time - wakeup_time)) / 1000.0);
00184 }
00185
00186
00187 }
00188 jack_midi_data_t *data = event->buffer;
00189 DWORD message = 0;
00190 MMRESULT result;
00191 size_t size = event->size;
00192 switch (size) {
00193 case 3:
00194 message |= (((DWORD) data[2]) << 16);
00195
00196 case 2:
00197 message |= (((DWORD) data[1]) << 8);
00198
00199 case 1:
00200 message |= (DWORD) data[0];
00201 result = midiOutShortMsg(handle, message);
00202 if (result != MMSYSERR_NOERROR) {
00203 WriteOutError("JackWinMMEOutputPort::Execute",
00204 "midiOutShortMsg", result);
00205 }
00206 continue;
00207 }
00208 MIDIHDR header;
00209 header.dwBufferLength = size;
00210 header.dwFlags = 0;
00211 header.lpData = (LPSTR) data;
00212 result = midiOutPrepareHeader(handle, &header, sizeof(MIDIHDR));
00213 if (result != MMSYSERR_NOERROR) {
00214 WriteOutError("JackWinMMEOutputPort::Execute",
00215 "midiOutPrepareHeader", result);
00216 continue;
00217 }
00218 result = midiOutLongMsg(handle, &header, sizeof(MIDIHDR));
00219 if (result != MMSYSERR_NOERROR) {
00220 WriteOutError("JackWinMMEOutputPort::Execute", "midiOutLongMsg",
00221 result);
00222 continue;
00223 }
00224
00225
00226
00227
00228 if (! Wait(sysex_semaphore)) {
00229 break;
00230 }
00231
00232 result = midiOutUnprepareHeader(handle, &header, sizeof(MIDIHDR));
00233 if (result != MMSYSERR_NOERROR) {
00234 WriteOutError("JackWinMMEOutputPort::Execute",
00235 "midiOutUnprepareHeader", result);
00236 break;
00237 }
00238 }
00239 return false;
00240 }
00241
00242 void
00243 JackWinMMEOutputPort::GetOutErrorString(MMRESULT error, LPTSTR text)
00244 {
00245 MMRESULT result = midiOutGetErrorText(error, text, MAXERRORLENGTH);
00246 if (result != MMSYSERR_NOERROR) {
00247 snprintf(text, MAXERRORLENGTH, "Unknown MM error code '%d'", error);
00248 }
00249 }
00250
00251 void
00252 JackWinMMEOutputPort::HandleMessage(UINT message, DWORD_PTR param1,
00253 DWORD_PTR param2)
00254 {
00255 set_threaded_log_function();
00256 switch (message) {
00257 case MOM_CLOSE:
00258 jack_info("JackWinMMEOutputPort::HandleMessage - MIDI device closed.");
00259 break;
00260 case MOM_DONE:
00261 Signal(sysex_semaphore);
00262 break;
00263 case MOM_OPEN:
00264 jack_info("JackWinMMEOutputPort::HandleMessage - MIDI device opened.");
00265 break;
00266 case MOM_POSITIONCB:
00267 LPMIDIHDR header = (LPMIDIHDR) param1;
00268 jack_info("JackWinMMEOutputPort::HandleMessage - %d bytes out of %d "
00269 "bytes of the current sysex message have been sent.",
00270 header->dwOffset, header->dwBytesRecorded);
00271 }
00272 }
00273
00274 bool
00275 JackWinMMEOutputPort::Init()
00276 {
00277 set_threaded_log_function();
00278
00279
00280 if (thread->AcquireSelfRealTime(GetEngineControl()->fServerPriority)) {
00281 jack_error("JackWinMMEOutputPort::Init - could not acquire realtime "
00282 "scheduling. Continuing anyway.");
00283 }
00284 return true;
00285 }
00286
00287 void
00288 JackWinMMEOutputPort::ProcessJack(JackMidiBuffer *port_buffer,
00289 jack_nframes_t frames)
00290 {
00291 read_queue->ResetMidiBuffer(port_buffer);
00292 for (jack_midi_event_t *event = read_queue->DequeueEvent(); event;
00293 event = read_queue->DequeueEvent()) {
00294
00295 switch (thread_queue->EnqueueEvent(event, frames)) {
00296 case JackMidiWriteQueue::BUFFER_FULL:
00297 jack_error("JackWinMMEOutputPort::ProcessJack - The thread queue "
00298 "buffer is full. Dropping event.");
00299 break;
00300 case JackMidiWriteQueue::BUFFER_TOO_SMALL:
00301 jack_error("JackWinMMEOutputPort::ProcessJack - The thread queue "
00302 "couldn't enqueue a %d-byte event. Dropping event.",
00303 event->size);
00304 break;
00305 default:
00306 Signal(thread_queue_semaphore);
00307 }
00308 }
00309 }
00310
00311 bool
00312 JackWinMMEOutputPort::Signal(HANDLE semaphore)
00313 {
00314 bool result = (bool) ReleaseSemaphore(semaphore, 1, NULL);
00315 if (! result) {
00316 WriteOSError("JackWinMMEOutputPort::Signal", "ReleaseSemaphore");
00317 }
00318 return result;
00319 }
00320
00321 bool
00322 JackWinMMEOutputPort::Start()
00323 {
00324 if (thread->GetStatus() != JackThread::kIdle) {
00325 return true;
00326 }
00327 timer = CreateWaitableTimer(NULL, FALSE, NULL);
00328 if (! timer) {
00329 WriteOSError("JackWinMMEOutputPort::Start", "CreateWaitableTimer");
00330 return false;
00331 }
00332 if (! thread->StartSync()) {
00333 return true;
00334 }
00335 jack_error("JackWinMMEOutputPort::Start - failed to start MIDI processing "
00336 "thread.");
00337 if (! CloseHandle(timer)) {
00338 WriteOSError("JackWinMMEOutputPort::Start", "CloseHandle");
00339 }
00340 return false;
00341 }
00342
00343 bool
00344 JackWinMMEOutputPort::Stop()
00345 {
00346 jack_info("JackWinMMEOutputPort::Stop - stopping MIDI output port "
00347 "processing thread.");
00348
00349 int result;
00350 const char *verb;
00351 switch (thread->GetStatus()) {
00352 case JackThread::kIniting:
00353 case JackThread::kStarting:
00354 result = thread->Kill();
00355 verb = "kill";
00356 break;
00357 case JackThread::kRunning:
00358 Signal(thread_queue_semaphore);
00359 result = thread->Stop();
00360 verb = "stop";
00361 break;
00362 default:
00363 return true;
00364 }
00365 if (result) {
00366 jack_error("JackWinMMEOutputPort::Stop - could not %s MIDI processing "
00367 "thread.", verb);
00368 }
00369 if (! CloseHandle(timer)) {
00370 WriteOSError("JackWinMMEOutputPort::Stop", "CloseHandle");
00371 result = -1;
00372 }
00373 return ! result;
00374 }
00375
00376 bool
00377 JackWinMMEOutputPort::Wait(HANDLE semaphore)
00378 {
00379 DWORD result = WaitForSingleObject(semaphore, INFINITE);
00380 switch (result) {
00381 case WAIT_FAILED:
00382 WriteOSError("JackWinMMEOutputPort::Wait", "WaitForSingleObject");
00383 break;
00384 case WAIT_OBJECT_0:
00385 return true;
00386 default:
00387 jack_error("JackWinMMEOutputPort::Wait - unexpected result from "
00388 "'WaitForSingleObject'.");
00389 }
00390 return false;
00391 }
00392
00393 void
00394 JackWinMMEOutputPort::WriteOutError(const char *jack_func, const char *mm_func,
00395 MMRESULT result)
00396 {
00397 char error_message[MAXERRORLENGTH];
00398 GetOutErrorString(result, error_message);
00399 jack_error("%s - %s: %s", jack_func, mm_func, error_message);
00400 }