24 #include "JackError.h"
26 #include "JackMidiUtil.h"
27 #include "JackWinMMEInputPort.h"
28 #include "JackMidiWriteQueue.h"
37 JackWinMMEInputPort::HandleMidiInputEvent(HMIDIIN handle, UINT message,
38 DWORD port, DWORD param1,
48 JackWinMMEInputPort::JackWinMMEInputPort(
const char *alias_name,
49 const char *client_name,
50 const char *driver_name, UINT index,
51 size_t max_bytes,
size_t max_messages)
53 thread_queue =
new JackMidiAsyncQueue(max_bytes, max_messages);
54 std::auto_ptr<JackMidiAsyncQueue> thread_queue_ptr(thread_queue);
55 write_queue =
new JackMidiBufferWriteQueue();
56 std::auto_ptr<JackMidiBufferWriteQueue> write_queue_ptr(write_queue);
57 sysex_buffer =
new jack_midi_data_t[max_bytes];
58 char error_message[MAXERRORLENGTH];
59 MMRESULT result = midiInOpen(&handle, index,
60 (DWORD_PTR) HandleMidiInputEvent,
62 CALLBACK_FUNCTION | MIDI_IO_STATUS);
63 if (result != MMSYSERR_NOERROR) {
64 GetInErrorString(result, error_message);
65 goto delete_sysex_buffer;
67 sysex_header.dwBufferLength = max_bytes;
68 sysex_header.dwFlags = 0;
69 sysex_header.lpData = (LPSTR)sysex_buffer;
70 result = midiInPrepareHeader(handle, &sysex_header,
sizeof(MIDIHDR));
71 if (result != MMSYSERR_NOERROR) {
72 GetInErrorString(result, error_message);
75 result = midiInAddBuffer(handle, &sysex_header,
sizeof(MIDIHDR));
76 if (result != MMSYSERR_NOERROR) {
77 GetInErrorString(result, error_message);
78 goto unprepare_header;
81 MIDIINCAPS capabilities;
83 result = midiInGetDevCaps(index, &capabilities,
sizeof(capabilities));
84 if (result != MMSYSERR_NOERROR) {
85 WriteInError(
"JackWinMMEInputPort [constructor]",
"midiInGetDevCaps",
87 name_tmp = (
char*) driver_name;
89 name_tmp = capabilities.szPname;
92 snprintf(alias,
sizeof(alias) - 1,
"%s:%s:in%d", alias_name, name_tmp,
94 snprintf(name,
sizeof(name) - 1,
"%s:capture_%d", client_name, index + 1);
97 write_queue_ptr.release();
98 thread_queue_ptr.release();
102 result = midiInUnprepareHeader(handle, &sysex_header,
sizeof(MIDIHDR));
103 if (result != MMSYSERR_NOERROR) {
104 WriteInError(
"JackWinMMEInputPort [constructor]",
105 "midiInUnprepareHeader", result);
108 result = midiInClose(handle);
109 if (result != MMSYSERR_NOERROR) {
110 WriteInError(
"JackWinMMEInputPort [constructor]",
"midiInClose",
114 delete[] sysex_buffer;
115 throw std::runtime_error(error_message);
118 JackWinMMEInputPort::~JackWinMMEInputPort()
120 MMRESULT result = midiInReset(handle);
121 if (result != MMSYSERR_NOERROR) {
122 WriteInError(
"JackWinMMEInputPort [destructor]",
"midiInReset", result);
124 result = midiInUnprepareHeader(handle, &sysex_header,
sizeof(MIDIHDR));
125 if (result != MMSYSERR_NOERROR) {
126 WriteInError(
"JackWinMMEInputPort [destructor]",
127 "midiInUnprepareHeader", result);
129 result = midiInClose(handle);
130 if (result != MMSYSERR_NOERROR) {
131 WriteInError(
"JackWinMMEInputPort [destructor]",
"midiInClose", result);
133 delete[] sysex_buffer;
139 JackWinMMEInputPort::EnqueueMessage(DWORD timestamp,
size_t length,
140 jack_midi_data_t *data)
142 jack_nframes_t frame =
143 GetFramesFromTime(start_time + (((jack_time_t) timestamp) * 1000));
146 jack_time_t current_time = GetMicroSeconds();
147 jack_log(
"JackWinMMEInputPort::EnqueueMessage - enqueueing event at %f "
148 "(frame: %d) with start offset '%d' scheduled for frame '%d'",
149 ((
double) current_time) / 1000.0, GetFramesFromTime(current_time),
153 switch (thread_queue->
EnqueueEvent(frame, length, data)) {
154 case JackMidiWriteQueue::BUFFER_FULL:
155 jack_error(
"JackWinMMEInputPort::EnqueueMessage - The thread queue "
156 "cannot currently accept a %d-byte event. Dropping event.",
159 case JackMidiWriteQueue::BUFFER_TOO_SMALL:
160 jack_error(
"JackWinMMEInputPort::EnqueueMessage - The thread queue "
161 "buffer is too small to enqueue a %d-byte event. Dropping "
170 JackWinMMEInputPort::GetInErrorString(MMRESULT error, LPTSTR text)
172 MMRESULT result = midiInGetErrorText(error, text, MAXERRORLENGTH);
173 if (result != MMSYSERR_NOERROR) {
174 snprintf(text, MAXERRORLENGTH,
"Unknown error code '%d'", error);
179 JackWinMMEInputPort::ProcessJack(JackMidiBuffer *port_buffer,
180 jack_nframes_t frames)
186 for (; jack_event; jack_event = thread_queue->
DequeueEvent()) {
187 switch (write_queue->
EnqueueEvent(jack_event, frames)) {
188 case JackMidiWriteQueue::BUFFER_TOO_SMALL:
189 jack_error(
"JackWinMMEMidiInputPort::Process - The buffer write "
190 "queue couldn't enqueue a %d-byte event. Dropping "
191 "event.", jack_event->
size);
193 case JackMidiWriteQueue::OK:
203 JackWinMMEInputPort::ProcessWinMME(UINT message, DWORD param1, DWORD param2)
205 set_threaded_log_function();
208 jack_info(
"JackWinMMEInputPort::ProcessWinMME - MIDI device closed.");
211 jack_info(
"JackWinMMEInputPort::ProcessWinMME - The MIDI input device "
212 "driver thinks that JACK is not processing messages fast "
216 jack_midi_data_t message_buffer[3];
217 jack_midi_data_t status = param1 & 0xff;
218 int length = GetMessageLength(status);
222 message_buffer[2] = (param1 >> 16) & 0xff;
225 message_buffer[1] = (param1 >> 8) & 0xff;
228 message_buffer[0] = status;
231 jack_error(
"JackWinMMEInputPort::ProcessWinMME - **BUG** MIDI "
232 "input driver sent an MIM_DATA message with a sysex "
236 jack_error(
"JackWinMMEInputPort::ProcessWinMME - **BUG** MIDI "
237 "input driver sent an MIM_DATA message with an invalid "
241 EnqueueMessage(param2, (
size_t) length, message_buffer);
245 LPMIDIHDR header = (LPMIDIHDR) param1;
246 size_t byte_count = header->dwBytesRecorded;
248 jack_info(
"JackWinMMEInputPort::ProcessWinMME - WinMME driver has "
249 "returned sysex header to us with no bytes. The JACK "
250 "driver is probably being stopped.");
253 jack_midi_data_t *data = (jack_midi_data_t *) header->lpData;
254 if ((data[0] != 0xf0) || (data[byte_count - 1] != 0xf7)) {
255 jack_error(
"JackWinMMEInputPort::ProcessWinMME - Discarding "
256 "%d-byte sysex chunk.", byte_count);
258 EnqueueMessage(param2, byte_count, data);
263 MMRESULT result = midiInAddBuffer(handle, &sysex_header,
265 if (result != MMSYSERR_NOERROR) {
266 WriteInError(
"JackWinMMEInputPort::ProcessWinMME",
267 "midiInAddBuffer", result);
272 jack_error(
"JackWinMMEInputPort::ProcessWinMME - Invalid or "
273 "incomplete sysex message received.");
276 jack_info(
"JackWinMMEInputPort::ProcessWinMME - MIDI device opened.");
281 JackWinMMEInputPort::Start()
284 start_time = GetMicroSeconds();
285 MMRESULT result = midiInStart(handle);
286 started = result == MMSYSERR_NOERROR;
288 WriteInError(
"JackWinMMEInputPort::Start",
"midiInStart", result);
295 JackWinMMEInputPort::Stop()
298 MMRESULT result = midiInStop(handle);
299 started = result != MMSYSERR_NOERROR;
301 WriteInError(
"JackWinMMEInputPort::Stop",
"midiInStop", result);
308 JackWinMMEInputPort::WriteInError(
const char *jack_func,
const char *mm_func,
311 char error_message[MAXERRORLENGTH];
312 GetInErrorString(result, error_message);
313 jack_error(
"%s - %s: %s", jack_func, mm_func, error_message);
EnqueueResult EnqueueEvent(jack_nframes_t time, size_t size, jack_midi_data_t *buffer)
SERVER_EXPORT void jack_error(const char *fmt,...)
SERVER_EXPORT void jack_info(const char *fmt,...)
void ResetMidiBuffer(JackMidiBuffer *buffer, jack_nframes_t frames)
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)