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_info(
"JackWinMMEOutputPort::HandleMessage - MIDI device closed.");
261 Signal(sysex_semaphore);
264 jack_info(
"JackWinMMEOutputPort::HandleMessage - MIDI device opened.");
267 LPMIDIHDR header = (LPMIDIHDR) param1;
268 jack_info(
"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_info(
"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,...)
SERVER_EXPORT void jack_info(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)