author | ohair |
Tue, 11 Sep 2012 13:40:59 -0700 | |
changeset 13678 | 5c8001201f98 |
parent 5506 | 202f599c92aa |
child 23010 | 6dadb192ad81 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
5506 | 2 |
* Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. |
2 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 10 |
* |
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
5506 | 21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
2 | 24 |
*/ |
25 |
||
26 |
#define USE_ERROR |
|
27 |
#define USE_TRACE |
|
28 |
||
29 |
#include "PLATFORM_API_WinOS_Util.h" |
|
30 |
||
31 |
#if USE_PLATFORM_MIDI_OUT == TRUE |
|
32 |
||
33 |
||
34 |
#ifdef USE_ERROR |
|
35 |
#include <stdio.h> |
|
13678
5c8001201f98
7197771: Adjust jdk sources to avoid use of implementation defined value of __FILE__
ohair
parents:
5506
diff
changeset
|
36 |
|
5c8001201f98
7197771: Adjust jdk sources to avoid use of implementation defined value of __FILE__
ohair
parents:
5506
diff
changeset
|
37 |
/* Use THIS_FILE when it is available. */ |
5c8001201f98
7197771: Adjust jdk sources to avoid use of implementation defined value of __FILE__
ohair
parents:
5506
diff
changeset
|
38 |
#ifndef THIS_FILE |
5c8001201f98
7197771: Adjust jdk sources to avoid use of implementation defined value of __FILE__
ohair
parents:
5506
diff
changeset
|
39 |
#define THIS_FILE __FILE__ |
5c8001201f98
7197771: Adjust jdk sources to avoid use of implementation defined value of __FILE__
ohair
parents:
5506
diff
changeset
|
40 |
#endif |
5c8001201f98
7197771: Adjust jdk sources to avoid use of implementation defined value of __FILE__
ohair
parents:
5506
diff
changeset
|
41 |
|
2 | 42 |
#define MIDIOUT_CHECK_ERROR { \ |
43 |
if (err != MMSYSERR_NOERROR) \ |
|
13678
5c8001201f98
7197771: Adjust jdk sources to avoid use of implementation defined value of __FILE__
ohair
parents:
5506
diff
changeset
|
44 |
ERROR3("MIDI OUT Error in %s:%d : %s\n", THIS_FILE, __LINE__, MIDI_OUT_GetErrorStr((INT32) err)); \ |
2 | 45 |
} |
46 |
#else |
|
47 |
#define MIDIOUT_CHECK_ERROR |
|
48 |
#endif |
|
49 |
||
50 |
/* *************************** MidiOutDeviceProvider implementation *********************************** */ |
|
51 |
||
52 |
/* not thread safe */ |
|
53 |
static char winMidiOutErrMsg[WIN_MAX_ERROR_LEN]; |
|
54 |
||
55 |
char* MIDI_OUT_GetErrorStr(INT32 err) { |
|
56 |
winMidiOutErrMsg[0] = 0; |
|
57 |
midiOutGetErrorText((MMRESULT) err, winMidiOutErrMsg, WIN_MAX_ERROR_LEN); |
|
58 |
return winMidiOutErrMsg; |
|
59 |
} |
|
60 |
||
61 |
INT32 MIDI_OUT_GetNumDevices() { |
|
62 |
// add one for the MIDI_MAPPER |
|
63 |
// we want to return it first so it'll be the default, so we |
|
64 |
// decrement each deviceID for these methods.... |
|
65 |
return (INT32) (midiOutGetNumDevs() + 1); |
|
66 |
} |
|
67 |
||
68 |
||
69 |
INT32 getMidiOutCaps(INT32 deviceID, MIDIOUTCAPS* caps, INT32* err) { |
|
70 |
if (deviceID == 0) { |
|
71 |
deviceID = MIDI_MAPPER; |
|
72 |
} else { |
|
73 |
deviceID--; |
|
74 |
} |
|
75 |
(*err) = (INT32) midiOutGetDevCaps(deviceID, caps, sizeof(MIDIOUTCAPS)); |
|
76 |
return ((*err) == MMSYSERR_NOERROR); |
|
77 |
} |
|
78 |
||
79 |
||
80 |
INT32 MIDI_OUT_GetDeviceName(INT32 deviceID, char *name, UINT32 nameLength) { |
|
81 |
MIDIOUTCAPS midiOutCaps; |
|
82 |
INT32 err; |
|
83 |
||
84 |
if (getMidiOutCaps(deviceID, &midiOutCaps, &err)) { |
|
85 |
strncpy(name, midiOutCaps.szPname, nameLength-1); |
|
86 |
name[nameLength-1] = 0; |
|
87 |
return MIDI_SUCCESS; |
|
88 |
} |
|
89 |
MIDIOUT_CHECK_ERROR; |
|
90 |
return err; |
|
91 |
} |
|
92 |
||
93 |
||
94 |
INT32 MIDI_OUT_GetDeviceVendor(INT32 deviceID, char *name, UINT32 nameLength) { |
|
95 |
return MIDI_NOT_SUPPORTED; |
|
96 |
} |
|
97 |
||
98 |
||
99 |
INT32 MIDI_OUT_GetDeviceDescription(INT32 deviceID, char *name, UINT32 nameLength) { |
|
100 |
MIDIOUTCAPS midiOutCaps; |
|
101 |
char *desc; |
|
102 |
INT32 err; |
|
103 |
||
104 |
if (getMidiOutCaps(deviceID, &midiOutCaps, &err)) { |
|
105 |
int tech = (int)midiOutCaps.wTechnology; |
|
106 |
switch(tech) { |
|
107 |
case MOD_MIDIPORT: |
|
108 |
desc = "External MIDI Port"; |
|
109 |
break; |
|
110 |
case MOD_SQSYNTH: |
|
111 |
desc = "Internal square wave synthesizer"; |
|
112 |
break; |
|
113 |
case MOD_FMSYNTH: |
|
114 |
desc = "Internal FM synthesizer"; |
|
115 |
break; |
|
116 |
case MOD_SYNTH: |
|
117 |
desc = "Internal synthesizer (generic)"; |
|
118 |
break; |
|
119 |
case MOD_MAPPER: |
|
120 |
desc = "Windows MIDI_MAPPER"; |
|
121 |
break; |
|
122 |
case 7 /* MOD_SWSYNTH*/: |
|
123 |
desc = "Internal software synthesizer"; |
|
124 |
break; |
|
125 |
default: |
|
126 |
return MIDI_NOT_SUPPORTED; |
|
127 |
} |
|
128 |
strncpy(name, desc, nameLength-1); |
|
129 |
name[nameLength-1] = 0; |
|
130 |
return MIDI_SUCCESS; |
|
131 |
} |
|
132 |
return err; |
|
133 |
} |
|
134 |
||
135 |
||
136 |
INT32 MIDI_OUT_GetDeviceVersion(INT32 deviceID, char *name, UINT32 nameLength) { |
|
137 |
MIDIOUTCAPS midiOutCaps; |
|
138 |
INT32 err; |
|
139 |
||
140 |
if (getMidiOutCaps(deviceID, &midiOutCaps, &err) && nameLength>7) { |
|
141 |
sprintf(name, "%d.%d", (midiOutCaps.vDriverVersion & 0xFF00) >> 8, midiOutCaps.vDriverVersion & 0xFF); |
|
142 |
return MIDI_SUCCESS; |
|
143 |
} |
|
144 |
MIDIOUT_CHECK_ERROR; |
|
145 |
return err; |
|
146 |
} |
|
147 |
||
148 |
||
149 |
/* *************************** MidiOutDevice implementation ***************************************** */ |
|
150 |
||
151 |
||
152 |
INT32 unprepareLongBuffers(MidiDeviceHandle* handle) { |
|
153 |
SysExQueue* sysex; |
|
154 |
MMRESULT err = MMSYSERR_NOERROR; |
|
155 |
int i; |
|
156 |
||
157 |
if (!handle || !handle->deviceHandle || !handle->longBuffers) { |
|
158 |
ERROR0("MIDI_OUT_unprepareLongBuffers: handle, deviceHandle, or longBuffers == NULL\n"); |
|
159 |
return MIDI_INVALID_HANDLE; |
|
160 |
} |
|
161 |
sysex = (SysExQueue*) handle->longBuffers; |
|
162 |
for (i = 0; i<sysex->count; i++) { |
|
163 |
MIDIHDR* hdr = &(sysex->header[i]); |
|
164 |
if (hdr->dwFlags) { |
|
165 |
err = midiOutUnprepareHeader((HMIDIOUT) handle->deviceHandle, hdr, sizeof(MIDIHDR)); |
|
166 |
} |
|
167 |
} |
|
168 |
MIDIOUT_CHECK_ERROR; |
|
169 |
return (INT32) err; |
|
170 |
} |
|
171 |
||
172 |
INT32 freeLongBuffer(MIDIHDR* hdr, HMIDIOUT deviceHandle, INT32 minToLeaveData) { |
|
173 |
MMRESULT err = MMSYSERR_NOERROR; |
|
174 |
||
175 |
if (!hdr) { |
|
176 |
ERROR0("MIDI_OUT_freeLongBuffer: hdr == NULL\n"); |
|
177 |
return MIDI_INVALID_HANDLE; |
|
178 |
} |
|
179 |
if (hdr->dwFlags && deviceHandle) { |
|
180 |
err = midiOutUnprepareHeader(deviceHandle, hdr, sizeof(MIDIHDR)); |
|
181 |
} |
|
182 |
if (hdr->lpData && (((INT32) hdr->dwBufferLength) < minToLeaveData || minToLeaveData < 0)) { |
|
183 |
free(hdr->lpData); |
|
184 |
hdr->lpData=NULL; |
|
185 |
hdr->dwBufferLength=0; |
|
186 |
} |
|
187 |
hdr->dwBytesRecorded=0; |
|
188 |
hdr->dwFlags=0; |
|
189 |
return (INT32) err; |
|
190 |
} |
|
191 |
||
192 |
INT32 freeLongBuffers(MidiDeviceHandle* handle) { |
|
193 |
SysExQueue* sysex; |
|
194 |
MMRESULT err = MMSYSERR_NOERROR; |
|
195 |
int i; |
|
196 |
||
197 |
if (!handle || !handle->longBuffers) { |
|
198 |
ERROR0("MIDI_OUT_freeLongBuffers: handle or longBuffers == NULL\n"); |
|
199 |
return MIDI_INVALID_HANDLE; |
|
200 |
} |
|
201 |
sysex = (SysExQueue*) handle->longBuffers; |
|
202 |
for (i = 0; i<sysex->count; i++) { |
|
203 |
err = freeLongBuffer(&(sysex->header[i]), (HMIDIOUT) handle->deviceHandle, -1); |
|
204 |
} |
|
205 |
MIDIOUT_CHECK_ERROR; |
|
206 |
return (INT32) err; |
|
207 |
} |
|
208 |
||
209 |
INT32 MIDI_OUT_OpenDevice(INT32 deviceID, MidiDeviceHandle** handle) { |
|
210 |
MMRESULT err; |
|
211 |
||
212 |
TRACE1(">> MIDI_OUT_OpenDevice: deviceID: %d\n", deviceID); |
|
213 |
||
214 |
if (deviceID == 0) { |
|
215 |
deviceID = MIDI_MAPPER; |
|
216 |
} else { |
|
217 |
deviceID--; |
|
218 |
} |
|
219 |
#ifdef USE_ERROR |
|
220 |
setvbuf(stdout, NULL, (int)_IONBF, 0); |
|
221 |
setvbuf(stderr, NULL, (int)_IONBF, 0); |
|
222 |
#endif |
|
223 |
||
224 |
(*handle) = (MidiDeviceHandle*) malloc(sizeof(MidiDeviceHandle)); |
|
225 |
if (!(*handle)) { |
|
226 |
ERROR0("ERROR: MIDI_OUT_OpenDevice: out of memory\n"); |
|
227 |
return MIDI_OUT_OF_MEMORY; |
|
228 |
} |
|
229 |
memset(*handle, 0, sizeof(MidiDeviceHandle)); |
|
230 |
||
231 |
// create long buffer queue |
|
232 |
if (!MIDI_WinCreateEmptyLongBufferQueue(*handle, MIDI_OUT_LONG_QUEUE_SIZE)) { |
|
233 |
ERROR0("ERROR: MIDI_OUT_OpenDevice: could not create long Buffers\n"); |
|
234 |
free(*handle); |
|
235 |
(*handle) = NULL; |
|
236 |
return MIDI_OUT_OF_MEMORY; |
|
237 |
} |
|
238 |
||
239 |
// create notification event |
|
240 |
(*handle)->platformData = (void*) CreateEvent(NULL, FALSE /*manual reset*/, FALSE /*signaled*/, NULL); |
|
241 |
if (!(*handle)->platformData) { |
|
242 |
ERROR0("ERROR: MIDI_OUT_StartDevice: could not create event\n"); |
|
243 |
MIDI_WinDestroyLongBufferQueue(*handle); |
|
244 |
free(*handle); |
|
245 |
(*handle) = NULL; |
|
246 |
return MIDI_OUT_OF_MEMORY; |
|
247 |
} |
|
248 |
||
249 |
// finally open the device |
|
250 |
err = midiOutOpen((HMIDIOUT*) &((*handle)->deviceHandle), deviceID, |
|
251 |
(UINT_PTR) (*handle)->platformData, (UINT_PTR) (*handle), CALLBACK_EVENT); |
|
252 |
||
253 |
if ((err != MMSYSERR_NOERROR) || (!(*handle)->deviceHandle)) { |
|
254 |
/* some devices return non zero, but no error! */ |
|
255 |
if (midiOutShortMsg((HMIDIOUT) ((*handle)->deviceHandle),0) == MMSYSERR_INVALHANDLE) { |
|
256 |
MIDIOUT_CHECK_ERROR; |
|
257 |
CloseHandle((HANDLE) (*handle)->platformData); |
|
258 |
MIDI_WinDestroyLongBufferQueue(*handle); |
|
259 |
free(*handle); |
|
260 |
(*handle) = NULL; |
|
261 |
return (INT32) err; |
|
262 |
} |
|
263 |
} |
|
264 |
//$$fb enable high resolution time |
|
265 |
timeBeginPeriod(1); |
|
266 |
MIDI_SetStartTime(*handle); |
|
267 |
TRACE0("<< MIDI_OUT_OpenDevice: succeeded\n"); |
|
268 |
return MIDI_SUCCESS; |
|
269 |
} |
|
270 |
||
271 |
INT32 MIDI_OUT_CloseDevice(MidiDeviceHandle* handle) { |
|
272 |
MMRESULT err = MMSYSERR_NOERROR; |
|
273 |
HANDLE event; |
|
274 |
||
275 |
TRACE0("> MIDI_OUT_CloseDevice\n"); |
|
276 |
if (!handle) { |
|
277 |
ERROR0("ERROR: MIDI_OUT_StopDevice: handle is NULL\n"); |
|
278 |
return MIDI_INVALID_HANDLE; // failure |
|
279 |
} |
|
280 |
// encourage MIDI_OUT_SendLongMessage to return soon |
|
281 |
event = handle->platformData; |
|
282 |
handle->platformData = NULL; |
|
283 |
if (event) { |
|
284 |
SetEvent(event); |
|
285 |
} else { |
|
286 |
ERROR0("ERROR: MIDI_OUT_StopDevice: event is NULL\n"); |
|
287 |
} |
|
288 |
||
289 |
if (handle->deviceHandle) { |
|
290 |
//$$fb disable high resolution time |
|
291 |
timeEndPeriod(1); |
|
292 |
err = midiOutReset((HMIDIOUT) handle->deviceHandle); |
|
293 |
} else { |
|
294 |
ERROR0("ERROR: MIDI_OUT_CloseDevice: deviceHandle is NULL\n"); |
|
295 |
} |
|
296 |
||
297 |
// issue a "SUSTAIN OFF" message to each MIDI channel, 0 to 15. |
|
298 |
// "CONTROL CHANGE" is 176, "SUSTAIN CONTROLLER" is 64, and the value is 0. |
|
299 |
// $$fb 2002-04-04: It is responsability of the application developer to |
|
300 |
// leave the device in a consistent state. So I put this in comments |
|
301 |
/* |
|
302 |
for (channel = 0; channel < 16; channel++) |
|
303 |
MIDI_OUT_SendShortMessage(deviceHandle, (unsigned char)(176 + channel), (unsigned char)64, (unsigned char)0, (UINT32)-1); |
|
304 |
*/ |
|
305 |
||
306 |
if (event) { |
|
307 |
// wait until MIDI_OUT_SendLongMessage has finished |
|
308 |
while (handle->isWaiting) Sleep(0); |
|
309 |
} |
|
310 |
||
311 |
unprepareLongBuffers(handle); |
|
312 |
||
313 |
if (handle->deviceHandle) { |
|
314 |
err = midiOutClose((HMIDIOUT) handle->deviceHandle); |
|
315 |
MIDIOUT_CHECK_ERROR; |
|
316 |
handle->deviceHandle = NULL; |
|
317 |
} |
|
318 |
freeLongBuffers(handle); |
|
319 |
||
320 |
if (event) { |
|
321 |
CloseHandle(event); |
|
322 |
} |
|
323 |
MIDI_WinDestroyLongBufferQueue(handle); |
|
324 |
free(handle); |
|
325 |
||
326 |
TRACE0("< MIDI_OUT_CloseDevice\n"); |
|
327 |
return (INT32) err; |
|
328 |
} |
|
329 |
||
330 |
||
331 |
/* return time stamp in microseconds */ |
|
332 |
INT64 MIDI_OUT_GetTimeStamp(MidiDeviceHandle* handle) { |
|
333 |
return MIDI_GetTimeStamp(handle); |
|
334 |
} |
|
335 |
||
336 |
||
337 |
INT32 MIDI_OUT_SendShortMessage(MidiDeviceHandle* handle, UINT32 packedMsg, UINT32 timestamp) { |
|
338 |
MMRESULT err = MMSYSERR_NOERROR; |
|
339 |
||
340 |
TRACE2("> MIDI_OUT_SendShortMessage %x, time: %d\n", packedMsg, timestamp); |
|
341 |
if (!handle) { |
|
342 |
ERROR0("ERROR: MIDI_OUT_SendShortMessage: handle is NULL\n"); |
|
343 |
return MIDI_INVALID_HANDLE; // failure |
|
344 |
} |
|
345 |
err = midiOutShortMsg((HMIDIOUT) handle->deviceHandle, packedMsg); |
|
346 |
MIDIOUT_CHECK_ERROR; |
|
347 |
TRACE0("< MIDI_OUT_SendShortMessage\n"); |
|
348 |
return (INT32) err; |
|
349 |
} |
|
350 |
||
351 |
INT32 MIDI_OUT_SendLongMessage(MidiDeviceHandle* handle, UBYTE* data, UINT32 size, UINT32 timestamp) { |
|
352 |
MMRESULT err; |
|
353 |
SysExQueue* sysex; |
|
354 |
MIDIHDR* hdr = NULL; |
|
355 |
INT32 remainingSize; |
|
356 |
int i; |
|
357 |
||
358 |
TRACE2("> MIDI_OUT_SendLongMessage size %d, time: %d\n", size, timestamp); |
|
359 |
if (!handle || !data || !handle->longBuffers) { |
|
360 |
ERROR0("< ERROR: MIDI_OUT_SendLongMessage: handle, data, or longBuffers is NULL\n"); |
|
361 |
return MIDI_INVALID_HANDLE; // failure |
|
362 |
} |
|
363 |
if (size == 0) { |
|
364 |
return MIDI_SUCCESS; |
|
365 |
} |
|
366 |
||
367 |
sysex = (SysExQueue*) handle->longBuffers; |
|
368 |
remainingSize = size; |
|
369 |
||
370 |
// send in chunks of 512 bytes |
|
371 |
size = 512; |
|
372 |
while (remainingSize > 0) { |
|
373 |
if (remainingSize < (INT32) size) { |
|
374 |
size = (UINT32) remainingSize; |
|
375 |
} |
|
376 |
||
377 |
while (!hdr && handle->platformData) { |
|
378 |
/* find a non-queued header */ |
|
379 |
for (i = 0; i < sysex->count; i++) { |
|
380 |
hdr = &(sysex->header[i]); |
|
381 |
if ((hdr->dwFlags & MHDR_DONE) || (hdr->dwFlags == 0)) { |
|
382 |
break; |
|
383 |
} |
|
384 |
hdr = NULL; |
|
385 |
} |
|
386 |
/* wait for a buffer to free up */ |
|
387 |
if (!hdr && handle->platformData) { |
|
388 |
DWORD res; |
|
389 |
TRACE0(" Need to wait for free buffer\n"); |
|
390 |
handle->isWaiting = TRUE; |
|
391 |
res = WaitForSingleObject((HANDLE) handle->platformData, 700); |
|
392 |
handle->isWaiting = FALSE; |
|
393 |
if (res == WAIT_TIMEOUT) { |
|
394 |
// break out back to Java if no buffer freed up after 700 milliseconds |
|
395 |
TRACE0("-> TIMEOUT. Need to go back to Java\n"); |
|
396 |
break; |
|
397 |
} |
|
398 |
} |
|
399 |
} |
|
400 |
if (!hdr) { |
|
401 |
// no free buffer |
|
402 |
return MIDI_NOT_SUPPORTED; |
|
403 |
} |
|
404 |
||
405 |
TRACE2("-> sending %d bytes with buffer index=%d\n", (int) size, (int) hdr->dwUser); |
|
406 |
freeLongBuffer(hdr, handle->deviceHandle, (INT32) size); |
|
407 |
if (hdr->lpData == NULL) { |
|
408 |
hdr->lpData = malloc(size); |
|
409 |
hdr->dwBufferLength = size; |
|
410 |
} |
|
411 |
hdr->dwBytesRecorded = size; |
|
412 |
memcpy(hdr->lpData, data, size); |
|
413 |
err = midiOutPrepareHeader((HMIDIOUT) handle->deviceHandle, hdr, sizeof(MIDIHDR)); |
|
414 |
if (err != MMSYSERR_NOERROR) { |
|
415 |
freeLongBuffer(hdr, handle->deviceHandle, -1); |
|
416 |
MIDIOUT_CHECK_ERROR; |
|
417 |
return (INT32) err; |
|
418 |
} |
|
419 |
err = midiOutLongMsg((HMIDIOUT) handle->deviceHandle, hdr, sizeof(MIDIHDR)); |
|
420 |
if (err != MMSYSERR_NOERROR) { |
|
421 |
freeLongBuffer(hdr, handle->deviceHandle, -1); |
|
422 |
ERROR0("ERROR: MIDI_OUT_SendLongMessage: midiOutLongMsg returned error:\n"); |
|
423 |
MIDIOUT_CHECK_ERROR; |
|
424 |
return (INT32) err; |
|
425 |
} |
|
426 |
remainingSize -= size; |
|
427 |
data += size; |
|
428 |
} |
|
429 |
TRACE0("< MIDI_OUT_SendLongMessage success\n"); |
|
430 |
return MIDI_SUCCESS; |
|
431 |
} |
|
432 |
||
433 |
#endif // USE_PLATFORM_MIDI_OUT |