1 /* 2 * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. 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 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 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 * 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. 24 */ 25 26 #define USE_ERROR 27 #define USE_TRACE 28 29 #include "PLATFORM_API_WinOS_Util.h" 30 31 /* include to prevent charset problem */ 32 #include "PLATFORM_API_WinOS_Charset_Util.h" 33 34 #if USE_PLATFORM_MIDI_OUT == TRUE 35 36 37 #ifdef USE_ERROR 38 #include <stdio.h> 39 40 #define MIDIOUT_CHECK_ERROR { \ 41 if (err != MMSYSERR_NOERROR) \ 42 ERROR3("MIDI OUT Error in %s:%d : %s\n", __FILE__, __LINE__, MIDI_OUT_GetErrorStr((INT32) err)); \ 43 } 44 #else 45 #define MIDIOUT_CHECK_ERROR 46 #endif 47 48 /* *************************** MidiOutDeviceProvider implementation *********************************** */ 49 50 /* not thread safe */ 51 static char winMidiOutErrMsg[WIN_MAX_ERROR_LEN]; 52 53 char* MIDI_OUT_GetErrorStr(INT32 err) { 54 winMidiOutErrMsg[0] = 0; 55 midiOutGetErrorText((MMRESULT) err, winMidiOutErrMsg, WIN_MAX_ERROR_LEN); 56 return winMidiOutErrMsg; 57 } 58 59 INT32 MIDI_OUT_GetNumDevices() { 60 // add one for the MIDI_MAPPER 61 // we want to return it first so it'll be the default, so we 62 // decrement each deviceID for these methods.... 63 return (INT32) (midiOutGetNumDevs() + 1); 64 } 65 66 67 INT32 getMidiOutCaps(INT32 deviceID, MIDIOUTCAPSW* caps, INT32* err) { 68 UINT_PTR id; 69 if (deviceID == 0) { 70 id = MIDI_MAPPER; 71 } else { 72 id = (UINT_PTR)(deviceID-1); 73 } 74 (*err) = (INT32) midiOutGetDevCapsW(id, caps, sizeof(MIDIOUTCAPSW)); 75 return ((*err) == MMSYSERR_NOERROR); 76 } 77 78 79 INT32 MIDI_OUT_GetDeviceName(INT32 deviceID, char *name, UINT32 nameLength) { 80 MIDIOUTCAPSW midiOutCaps; 81 INT32 err; 82 83 memset(&midiOutCaps, 0, sizeof(midiOutCaps)); 84 if (getMidiOutCaps(deviceID, &midiOutCaps, &err)) { 85 UnicodeToUTF8AndCopy(name, midiOutCaps.szPname, nameLength); 86 return MIDI_SUCCESS; 87 } 88 MIDIOUT_CHECK_ERROR; 89 return err; 90 } 91 92 93 INT32 MIDI_OUT_GetDeviceVendor(INT32 deviceID, char *name, UINT32 nameLength) { 94 return MIDI_NOT_SUPPORTED; 95 } 96 97 98 INT32 MIDI_OUT_GetDeviceDescription(INT32 deviceID, char *name, UINT32 nameLength) { 99 MIDIOUTCAPSW midiOutCaps; 100 char *desc; 101 INT32 err; 102 103 memset(&midiOutCaps, 0, sizeof(midiOutCaps)); 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 MIDIOUTCAPSW midiOutCaps; 138 INT32 err; 139 140 memset(&midiOutCaps, 0, sizeof(midiOutCaps)); 141 if (getMidiOutCaps(deviceID, &midiOutCaps, &err) && nameLength>7) { 142 sprintf(name, "%d.%d", (midiOutCaps.vDriverVersion & 0xFF00) >> 8, midiOutCaps.vDriverVersion & 0xFF); 143 return MIDI_SUCCESS; 144 } 145 MIDIOUT_CHECK_ERROR; 146 return err; 147 } 148 149 150 /* *************************** MidiOutDevice implementation ***************************************** */ 151 152 153 INT32 unprepareLongBuffers(MidiDeviceHandle* handle) { 154 SysExQueue* sysex; 155 MMRESULT err = MMSYSERR_NOERROR; 156 int i; 157 158 if (!handle || !handle->deviceHandle || !handle->longBuffers) { 159 ERROR0("MIDI_OUT_unprepareLongBuffers: handle, deviceHandle, or longBuffers == NULL\n"); 160 return MIDI_INVALID_HANDLE; 161 } 162 sysex = (SysExQueue*) handle->longBuffers; 163 for (i = 0; i<sysex->count; i++) { 164 MIDIHDR* hdr = &(sysex->header[i]); 165 if (hdr->dwFlags) { 166 err = midiOutUnprepareHeader((HMIDIOUT) handle->deviceHandle, hdr, sizeof(MIDIHDR)); 167 } 168 } 169 MIDIOUT_CHECK_ERROR; 170 return (INT32) err; 171 } 172 173 INT32 freeLongBuffer(MIDIHDR* hdr, HMIDIOUT deviceHandle, INT32 minToLeaveData) { 174 MMRESULT err = MMSYSERR_NOERROR; 175 176 if (!hdr) { 177 ERROR0("MIDI_OUT_freeLongBuffer: hdr == NULL\n"); 178 return MIDI_INVALID_HANDLE; 179 } 180 if (hdr->dwFlags && deviceHandle) { 181 err = midiOutUnprepareHeader(deviceHandle, hdr, sizeof(MIDIHDR)); 182 } 183 if (hdr->lpData && (((INT32) hdr->dwBufferLength) < minToLeaveData || minToLeaveData < 0)) { 184 free(hdr->lpData); 185 hdr->lpData=NULL; 186 hdr->dwBufferLength=0; 187 } 188 hdr->dwBytesRecorded=0; 189 hdr->dwFlags=0; 190 return (INT32) err; 191 } 192 193 INT32 freeLongBuffers(MidiDeviceHandle* handle) { 194 SysExQueue* sysex; 195 MMRESULT err = MMSYSERR_NOERROR; 196 int i; 197 198 if (!handle || !handle->longBuffers) { 199 ERROR0("MIDI_OUT_freeLongBuffers: handle or longBuffers == NULL\n"); 200 return MIDI_INVALID_HANDLE; 201 } 202 sysex = (SysExQueue*) handle->longBuffers; 203 for (i = 0; i<sysex->count; i++) { 204 err = freeLongBuffer(&(sysex->header[i]), (HMIDIOUT) handle->deviceHandle, -1); 205 } 206 MIDIOUT_CHECK_ERROR; 207 return (INT32) err; 208 } 209 210 INT32 MIDI_OUT_OpenDevice(INT32 deviceID, MidiDeviceHandle** handle) { 211 MMRESULT err; 212 213 TRACE1(">> MIDI_OUT_OpenDevice: deviceID: %d\n", deviceID); 214 215 if (deviceID == 0) { 216 deviceID = MIDI_MAPPER; 217 } else { 218 deviceID--; 219 } 220 #ifdef USE_ERROR 221 setvbuf(stdout, NULL, (int)_IONBF, 0); 222 setvbuf(stderr, NULL, (int)_IONBF, 0); 223 #endif 224 225 (*handle) = (MidiDeviceHandle*) malloc(sizeof(MidiDeviceHandle)); 226 if (!(*handle)) { 227 ERROR0("ERROR: MIDI_OUT_OpenDevice: out of memory\n"); 228 return MIDI_OUT_OF_MEMORY; 229 } 230 memset(*handle, 0, sizeof(MidiDeviceHandle)); 231 232 // create long buffer queue 233 if (!MIDI_WinCreateEmptyLongBufferQueue(*handle, MIDI_OUT_LONG_QUEUE_SIZE)) { 234 ERROR0("ERROR: MIDI_OUT_OpenDevice: could not create long Buffers\n"); 235 free(*handle); 236 (*handle) = NULL; 237 return MIDI_OUT_OF_MEMORY; 238 } 239 240 // create notification event 241 (*handle)->platformData = (void*) CreateEvent(NULL, FALSE /*manual reset*/, FALSE /*signaled*/, NULL); 242 if (!(*handle)->platformData) { 243 ERROR0("ERROR: MIDI_OUT_StartDevice: could not create event\n"); 244 MIDI_WinDestroyLongBufferQueue(*handle); 245 free(*handle); 246 (*handle) = NULL; 247 return MIDI_OUT_OF_MEMORY; 248 } 249 250 // finally open the device 251 err = midiOutOpen((HMIDIOUT*) &((*handle)->deviceHandle), deviceID, 252 (UINT_PTR) (*handle)->platformData, (UINT_PTR) (*handle), CALLBACK_EVENT); 253 254 if ((err != MMSYSERR_NOERROR) || (!(*handle)->deviceHandle)) { 255 /* some devices return non zero, but no error! */ 256 if (midiOutShortMsg((HMIDIOUT) ((*handle)->deviceHandle),0) == MMSYSERR_INVALHANDLE) { 257 MIDIOUT_CHECK_ERROR; 258 CloseHandle((HANDLE) (*handle)->platformData); 259 MIDI_WinDestroyLongBufferQueue(*handle); 260 free(*handle); 261 (*handle) = NULL; 262 return (INT32) err; 263 } 264 } 265 //$$fb enable high resolution time 266 timeBeginPeriod(1); 267 MIDI_SetStartTime(*handle); 268 TRACE0("<< MIDI_OUT_OpenDevice: succeeded\n"); 269 return MIDI_SUCCESS; 270 } 271 272 INT32 MIDI_OUT_CloseDevice(MidiDeviceHandle* handle) { 273 MMRESULT err = MMSYSERR_NOERROR; 274 HANDLE event; 275 276 TRACE0("> MIDI_OUT_CloseDevice\n"); 277 if (!handle) { 278 ERROR0("ERROR: MIDI_OUT_StopDevice: handle is NULL\n"); 279 return MIDI_INVALID_HANDLE; // failure 280 } 281 // encourage MIDI_OUT_SendLongMessage to return soon 282 event = handle->platformData; 283 handle->platformData = NULL; 284 if (event) { 285 SetEvent(event); 286 } else { 287 ERROR0("ERROR: MIDI_OUT_StopDevice: event is NULL\n"); 288 } 289 290 if (handle->deviceHandle) { 291 //$$fb disable high resolution time 292 timeEndPeriod(1); 293 err = midiOutReset((HMIDIOUT) handle->deviceHandle); 294 } else { 295 ERROR0("ERROR: MIDI_OUT_CloseDevice: deviceHandle is NULL\n"); 296 } 297 298 // issue a "SUSTAIN OFF" message to each MIDI channel, 0 to 15. 299 // "CONTROL CHANGE" is 176, "SUSTAIN CONTROLLER" is 64, and the value is 0. 300 // $$fb 2002-04-04: It is responsability of the application developer to 301 // leave the device in a consistent state. So I put this in comments 302 /* 303 for (channel = 0; channel < 16; channel++) 304 MIDI_OUT_SendShortMessage(deviceHandle, (unsigned char)(176 + channel), (unsigned char)64, (unsigned char)0, (UINT32)-1); 305 */ 306 307 if (event) { 308 // wait until MIDI_OUT_SendLongMessage has finished 309 while (handle->isWaiting) Sleep(0); 310 } 311 312 unprepareLongBuffers(handle); 313 314 if (handle->deviceHandle) { 315 err = midiOutClose((HMIDIOUT) handle->deviceHandle); 316 MIDIOUT_CHECK_ERROR; 317 handle->deviceHandle = NULL; 318 } 319 freeLongBuffers(handle); 320 321 if (event) { 322 CloseHandle(event); 323 } 324 MIDI_WinDestroyLongBufferQueue(handle); 325 free(handle); 326 327 TRACE0("< MIDI_OUT_CloseDevice\n"); 328 return (INT32) err; 329 } 330 331 332 /* return time stamp in microseconds */ 333 INT64 MIDI_OUT_GetTimeStamp(MidiDeviceHandle* handle) { 334 return MIDI_GetTimeStamp(handle); 335 } 336 337 338 INT32 MIDI_OUT_SendShortMessage(MidiDeviceHandle* handle, UINT32 packedMsg, UINT32 timestamp) { 339 MMRESULT err = MMSYSERR_NOERROR; 340 341 TRACE2("> MIDI_OUT_SendShortMessage %x, time: %d\n", packedMsg, timestamp); 342 if (!handle) { 343 ERROR0("ERROR: MIDI_OUT_SendShortMessage: handle is NULL\n"); 344 return MIDI_INVALID_HANDLE; // failure 345 } 346 err = midiOutShortMsg((HMIDIOUT) handle->deviceHandle, packedMsg); 347 MIDIOUT_CHECK_ERROR; 348 TRACE0("< MIDI_OUT_SendShortMessage\n"); 349 return (INT32) err; 350 } 351 352 INT32 MIDI_OUT_SendLongMessage(MidiDeviceHandle* handle, UBYTE* data, UINT32 size, UINT32 timestamp) { 353 MMRESULT err; 354 SysExQueue* sysex; 355 MIDIHDR* hdr = NULL; 356 INT32 remainingSize; 357 int i; 358 359 TRACE2("> MIDI_OUT_SendLongMessage size %d, time: %d\n", size, timestamp); 360 if (!handle || !data || !handle->longBuffers) { 361 ERROR0("< ERROR: MIDI_OUT_SendLongMessage: handle, data, or longBuffers is NULL\n"); 362 return MIDI_INVALID_HANDLE; // failure 363 } 364 if (size == 0) { 365 return MIDI_SUCCESS; 366 } 367 368 sysex = (SysExQueue*) handle->longBuffers; 369 remainingSize = size; 370 371 // send in chunks of 512 bytes 372 size = 512; 373 while (remainingSize > 0) { 374 if (remainingSize < (INT32) size) { 375 size = (UINT32) remainingSize; 376 } 377 378 while (!hdr && handle->platformData) { 379 /* find a non-queued header */ 380 for (i = 0; i < sysex->count; i++) { 381 hdr = &(sysex->header[i]); 382 if ((hdr->dwFlags & MHDR_DONE) || (hdr->dwFlags == 0)) { 383 break; 384 } 385 hdr = NULL; 386 } 387 /* wait for a buffer to free up */ 388 if (!hdr && handle->platformData) { 389 DWORD res; 390 TRACE0(" Need to wait for free buffer\n"); 391 handle->isWaiting = TRUE; 392 res = WaitForSingleObject((HANDLE) handle->platformData, 700); 393 handle->isWaiting = FALSE; 394 if (res == WAIT_TIMEOUT) { 395 // break out back to Java if no buffer freed up after 700 milliseconds 396 TRACE0("-> TIMEOUT. Need to go back to Java\n"); 397 break; 398 } 399 } 400 } 401 if (!hdr) { 402 // no free buffer 403 return MIDI_NOT_SUPPORTED; 404 } 405 406 TRACE2("-> sending %d bytes with buffer index=%d\n", (int) size, (int) hdr->dwUser); 407 freeLongBuffer(hdr, handle->deviceHandle, (INT32) size); 408 if (hdr->lpData == NULL) { 409 hdr->lpData = malloc(size); 410 hdr->dwBufferLength = size; 411 } 412 hdr->dwBytesRecorded = size; 413 memcpy(hdr->lpData, data, size); 414 err = midiOutPrepareHeader((HMIDIOUT) handle->deviceHandle, hdr, sizeof(MIDIHDR)); 415 if (err != MMSYSERR_NOERROR) { 416 freeLongBuffer(hdr, handle->deviceHandle, -1); 417 MIDIOUT_CHECK_ERROR; 418 return (INT32) err; 419 } 420 err = midiOutLongMsg((HMIDIOUT) handle->deviceHandle, hdr, sizeof(MIDIHDR)); 421 if (err != MMSYSERR_NOERROR) { 422 freeLongBuffer(hdr, handle->deviceHandle, -1); 423 ERROR0("ERROR: MIDI_OUT_SendLongMessage: midiOutLongMsg returned error:\n"); 424 MIDIOUT_CHECK_ERROR; 425 return (INT32) err; 426 } 427 remainingSize -= size; 428 data += size; 429 } 430 TRACE0("< MIDI_OUT_SendLongMessage success\n"); 431 return MIDI_SUCCESS; 432 } 433 434 #endif // USE_PLATFORM_MIDI_OUT