1/* 2 * Copyright (c) 2003, 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/* 27** 28** Overview: 29** Implementation of the functions used for both MIDI in and MIDI out. 30** 31** Java package com.sun.media.sound defines the AbstractMidiDevice class 32** which encapsulates functionalities shared by both MidiInDevice and 33** MidiOutDevice classes in the same package. 34** 35** The Java layer classes MidiInDevice and MidiOutDevice in turn map to 36** the MIDIEndpointRef data type in the CoreMIDI framework, which 37** represents a source or destination for a standard 16-channel MIDI data 38** stream. 39*/ 40/*****************************************************************************/ 41 42//#define USE_ERROR 43//#define USE_TRACE 44 45/* Use THIS_FILE when it is available. */ 46#ifndef THIS_FILE 47 #define THIS_FILE __FILE__ 48#endif 49 50#if (USE_PLATFORM_MIDI_IN == TRUE) || (USE_PLATFORM_MIDI_OUT == TRUE) 51 52#include "PLATFORM_API_MacOSX_MidiUtils.h" 53#include <pthread.h> 54#include <assert.h> 55 56// Constant character string definitions of CoreMIDI's corresponding error codes. 57 58static const char* strMIDIInvalidClient = 59 "An invalid MIDIClientRef was passed."; 60static const char* strMIDIInvalidPort = 61 "An invalid MIDIPortRef was passed."; 62static const char* strMIDIWrongEndpointType = 63 "A source endpoint was passed to a function expecting a destination, or vice versa."; 64static const char* strMIDINoConnection = 65 "Attempt to close a non-existant connection."; 66static const char* strMIDIUnknownEndpoint = 67 "An invalid MIDIEndpointRef was passed."; 68static const char* strMIDIUnknownProperty = 69 "Attempt to query a property not set on the object."; 70static const char* strMIDIWrongPropertyType = 71 "Attempt to set a property with a value not of the correct type."; 72static const char* strMIDINoCurrentSetup = 73 "Internal error; there is no current MIDI setup object."; 74static const char* strMIDIMessageSendErr = 75 "Communication with MIDIServer failed."; 76static const char* strMIDIServerStartErr = 77 "Unable to start MIDIServer."; 78static const char* strMIDISetupFormatErr = 79 "Unable to read the saved state."; 80static const char* strMIDIWrongThread = 81 "A driver is calling a non-I/O function in the server from a thread other than" 82 "the server's main thread."; 83static const char* strMIDIObjectNotFound = 84 "The requested object does not exist."; 85static const char* strMIDIIDNotUnique = 86 "Attempt to set a non-unique kMIDIPropertyUniqueID on an object."; 87 88static const char* midi_strerror(int err) { 89/* 90 @enum Error Constants 91 @abstract The error constants unique to Core MIDI. 92 @discussion These are the error constants that are unique to Core MIDI. Note that Core MIDI 93 functions may return other codes that are not listed here. 94*/ 95 const char* strerr; 96 97 switch (err) { 98 case kMIDIInvalidClient: 99 strerr = strMIDIInvalidClient; 100 break; 101 case kMIDIInvalidPort: 102 strerr = strMIDIInvalidPort; 103 break; 104 case kMIDIWrongEndpointType: 105 strerr = strMIDIWrongEndpointType; 106 break; 107 case kMIDINoConnection: 108 strerr = strMIDINoConnection; 109 break; 110 case kMIDIUnknownEndpoint: 111 strerr = strMIDIUnknownEndpoint; 112 break; 113 case kMIDIUnknownProperty: 114 strerr = strMIDIUnknownProperty; 115 break; 116 case kMIDIWrongPropertyType: 117 strerr = strMIDIWrongPropertyType; 118 break; 119 case kMIDINoCurrentSetup: 120 strerr = strMIDINoCurrentSetup; 121 break; 122 case kMIDIMessageSendErr: 123 strerr = strMIDIMessageSendErr; 124 break; 125 case kMIDIServerStartErr: 126 strerr = strMIDIServerStartErr; 127 break; 128 case kMIDISetupFormatErr: 129 strerr = strMIDISetupFormatErr; 130 break; 131 case kMIDIWrongThread: 132 strerr = strMIDIWrongThread; 133 break; 134 case kMIDIObjectNotFound: 135 strerr = strMIDIObjectNotFound; 136 break; 137 case kMIDIIDNotUnique: 138 strerr = strMIDIIDNotUnique; 139 break; 140 default: 141 strerr = "Unknown error."; 142 break; 143 } 144 return strerr; 145} 146 147const char* MIDI_Utils_GetErrorMsg(int err) { 148 return midi_strerror(err); 149} 150 151 152void MIDI_Utils_PrintError(int err) { 153#ifdef USE_ERROR 154 const char* s = MIDI_Utils_GetErrorMsg(err); 155 if (s != NULL) { 156 fprintf(stderr, "%s\n", s); 157 } 158#endif 159} 160 161 162// Note direction is either MIDI_IN or MIDI_OUT. 163INT32 MIDI_Utils_GetNumDevices(int direction) { 164 int num_endpoints; 165 if (direction == MIDI_IN) { 166 num_endpoints = MIDIGetNumberOfSources(); 167 //fprintf(stdout, "MIDIGetNumberOfSources() returns %d\n", num_endpoints); 168 } else if (direction == MIDI_OUT) { 169 num_endpoints = MIDIGetNumberOfDestinations(); 170 //printf(stdout, "MIDIGetNumberOfDestinations() returns %d\n", num_endpoints); 171 } else { 172 assert((direction == MIDI_IN || direction == MIDI_OUT)); 173 num_endpoints = 0; 174 } 175 return (INT32) num_endpoints; 176} 177 178// Wraps calls to CFStringGetCStringPtr and CFStringGetCString to make sure 179// we extract the c characters into the buffer and null-terminate it. 180static void CFStringExtractCString(CFStringRef cfs, char* buffer, UINT32 bufferSize, CFStringEncoding encoding) { 181 const char* ptr = CFStringGetCStringPtr(cfs, encoding); 182 if (ptr) { 183 strlcpy(buffer, ptr, bufferSize); 184 } else { 185 if (! CFStringGetCString(cfs, buffer, bufferSize, encoding)) { 186 // There's an error in conversion, make sure we null-terminate the buffer. 187 buffer[bufferSize - 1] = '\0'; 188 } 189 } 190} 191 192// 193// @see com.sun.media.sound.AbstractMidiDeviceProvider.getDeviceInfo(). 194static int getEndpointProperty(int direction, INT32 deviceID, char *buffer, int bufferLength, CFStringRef propertyID) { 195 196 if (deviceID < 0) { 197 return MIDI_INVALID_DEVICEID; 198 } 199 200 MIDIEndpointRef endpoint; 201 202 if (direction == MIDI_IN) { 203 endpoint = MIDIGetSource(deviceID); 204 } else if (direction == MIDI_OUT) { 205 endpoint = MIDIGetDestination(deviceID); 206 } else { 207 return MIDI_INVALID_ARGUMENT; 208 } 209 210 if (!endpoint) { 211 return MIDI_INVALID_DEVICEID; 212 } 213 214 int status = MIDI_SUCCESS; 215 if (propertyID == kMIDIPropertyDriverVersion) { 216 SInt32 driverVersion; 217 status = MIDIObjectGetIntegerProperty(endpoint, kMIDIPropertyDriverVersion, &driverVersion); 218 if (status != MIDI_SUCCESS) return status; 219 snprintf(buffer, 220 bufferLength, 221 "%d", 222 (int) driverVersion); 223 } 224 else { 225 CFStringRef pname; 226 status = MIDIObjectGetStringProperty(endpoint, propertyID, &pname); 227 if (status != MIDI_SUCCESS) return status; 228 CFStringExtractCString(pname, buffer, bufferLength, 0); 229 } 230 return MIDI_ERROR_NONE; 231} 232 233// A simple utility which encapsulates CoreAudio's HostTime APIs. 234// It returns the current host time in nanoseconds which when subtracted from 235// a previous getCurrentTimeInNanos() result produces the delta in nanos. 236static UInt64 getCurrentTimeInNanos() { 237 UInt64 hostTime = AudioGetCurrentHostTime(); 238 UInt64 nanos = AudioConvertHostTimeToNanos(hostTime); 239 return nanos; 240} 241 242 243INT32 MIDI_Utils_GetDeviceName(int direction, INT32 deviceID, char *name, UINT32 bufferLength) { 244 return getEndpointProperty(direction, deviceID, name, bufferLength, kMIDIPropertyName); 245} 246 247 248INT32 MIDI_Utils_GetDeviceVendor(int direction, INT32 deviceID, char *name, UINT32 bufferLength) { 249 return getEndpointProperty(direction, deviceID, name, bufferLength, kMIDIPropertyManufacturer); 250} 251 252 253INT32 MIDI_Utils_GetDeviceDescription(int direction, INT32 deviceID, char *name, UINT32 bufferLength) { 254 return getEndpointProperty(direction, deviceID, name, bufferLength, kMIDIPropertyDisplayName); 255} 256 257 258INT32 MIDI_Utils_GetDeviceVersion(int direction, INT32 deviceID, char *name, UINT32 bufferLength) { 259 return getEndpointProperty(direction, deviceID, name, bufferLength, kMIDIPropertyDriverVersion); 260} 261 262 263static MIDIClientRef client = (MIDIClientRef) NULL; 264static MIDIPortRef inPort = (MIDIPortRef) NULL; 265static MIDIPortRef outPort = (MIDIPortRef) NULL; 266 267// Each MIDIPacket can contain more than one midi messages. 268// This function processes the packet and adds the messages to the specified message queue. 269// @see also src/share/native/com/sun/media/sound/PlatformMidi.h. 270static void processMessagesForPacket(const MIDIPacket* packet, MacMidiDeviceHandle* handle) { 271 const UInt8* data; 272 UInt16 length; 273 UInt8 byte; 274 UInt8 pendingMessageStatus; 275 UInt8 pendingData[2]; 276 UInt16 pendingDataIndex, pendingDataLength; 277 UINT32 packedMsg; 278 MIDITimeStamp ts = packet->timeStamp; 279 280 pendingMessageStatus = 0; 281 pendingDataIndex = pendingDataLength = 0; 282 283 data = packet->data; 284 length = packet->length; 285 while (length--) { 286 bool byteIsInvalid = FALSE; 287 288 byte = *data++; 289 packedMsg = byte; 290 291 if (byte >= 0xF8) { 292 // Each RealTime Category message (ie, Status of 0xF8 to 0xFF) consists of only 1 byte, the Status. 293 // Except that 0xFD is an invalid status code. 294 // 295 // 0xF8 -> Midi clock 296 // 0xF9 -> Midi tick 297 // 0xFA -> Midi start 298 // 0xFB -> Midi continue 299 // 0xFC -> Midi stop 300 // 0xFE -> Active sense 301 // 0xFF -> Reset 302 if (byte == 0xFD) { 303 byteIsInvalid = TRUE; 304 } else { 305 pendingDataLength = 0; 306 } 307 } else { 308 if (byte < 0x80) { 309 // Not a status byte -- check our history. 310 if (handle->readingSysExData) { 311 CFDataAppendBytes(handle->readingSysExData, &byte, 1); 312 313 } else if (pendingDataIndex < pendingDataLength) { 314 pendingData[pendingDataIndex] = byte; 315 pendingDataIndex++; 316 317 if (pendingDataIndex == pendingDataLength) { 318 // This message is now done -- do the final processing. 319 if (pendingDataLength == 2) { 320 packedMsg = pendingMessageStatus | pendingData[0] << 8 | pendingData[1] << 16; 321 } else if (pendingDataLength == 1) { 322 packedMsg = pendingMessageStatus | pendingData[0] << 8; 323 } else { 324 fprintf(stderr, "%s: %d->internal error: pendingMessageStatus=0x%X, pendingDataLength=%d\n", 325 THIS_FILE, __LINE__, pendingMessageStatus, pendingDataLength); 326 byteIsInvalid = TRUE; 327 } 328 pendingDataLength = 0; 329 } 330 } else { 331 // Skip this byte -- it is invalid. 332 byteIsInvalid = TRUE; 333 } 334 } else { 335 if (handle->readingSysExData /* && (byte == 0xF7) */) { 336 // We have reached the end of system exclusive message -- send it finally. 337 const UInt8* bytes = CFDataGetBytePtr(handle->readingSysExData); 338 CFIndex size = CFDataGetLength(handle->readingSysExData); 339 MIDI_QueueAddLong(handle->h.queue, 340 (UBYTE*) bytes, 341 (UINT32) size, 342 0, // Don't care, windowish porting only. 343 (INT64) (AudioConvertHostTimeToNanos(ts) + 500) / 1000, 344 TRUE); 345 CFRelease(handle->readingSysExData); 346 handle->readingSysExData = NULL; 347 } 348 349 pendingMessageStatus = byte; 350 pendingDataLength = 0; 351 pendingDataIndex = 0; 352 353 switch (byte & 0xF0) { 354 case 0x80: // Note off 355 case 0x90: // Note on 356 case 0xA0: // Aftertouch 357 case 0xB0: // Controller 358 case 0xE0: // Pitch wheel 359 pendingDataLength = 2; 360 break; 361 362 case 0xC0: // Program change 363 case 0xD0: // Channel pressure 364 pendingDataLength = 1; 365 break; 366 367 case 0xF0: { 368 // System common message 369 switch (byte) { 370 case 0xF0: 371 // System exclusive 372 // Allocates a CFMutableData reference to accumulate the SysEx data until EOX (0xF7) is reached. 373 handle->readingSysExData = CFDataCreateMutable(NULL, 0); 374 break; 375 376 case 0xF7: 377 // System exclusive ends--already handled above. 378 // But if this is showing up outside of sysex, it's invalid. 379 byteIsInvalid = TRUE; 380 break; 381 382 case 0xF1: // MTC quarter frame message 383 case 0xF3: // Song select 384 pendingDataLength = 1; 385 break; 386 387 case 0xF2: // Song position pointer 388 pendingDataLength = 2; 389 break; 390 391 case 0xF6: // Tune request 392 pendingDataLength = 0; 393 break; 394 395 default: 396 // Invalid message 397 byteIsInvalid = TRUE; 398 break; 399 } 400 break; 401 } 402 403 default: 404 // This can't happen, but handle it anyway. 405 byteIsInvalid = TRUE; 406 break; 407 } 408 } 409 } 410 if (byteIsInvalid) continue; 411 412 // If the byte is valid and pendingDataLength is 0, we are ready to send the message. 413 if (pendingDataLength == 0) { 414 MIDI_QueueAddShort(handle->h.queue, packedMsg, (INT64) (AudioConvertHostTimeToNanos(ts) + 500) / 1000, TRUE); 415 } 416 } 417} 418 419static void midiReadProc(const MIDIPacketList* packetList, void* refCon, void* connRefCon) { 420 unsigned int i; 421 const MIDIPacket* packet; 422 MacMidiDeviceHandle* handle = (MacMidiDeviceHandle*) connRefCon; 423 424 packet = packetList->packet; 425 for (i = 0; i < packetList->numPackets; ++i) { 426 processMessagesForPacket(packet, handle); 427 packet = MIDIPacketNext(packet); 428 } 429 430 // Notify the waiting thread that there's data available. 431 if (handle) { 432 MIDI_SignalConditionVariable(handle->h.platformData); 433 } 434} 435 436static void midiInit() { 437 if (client) { 438 return; 439 } 440 441 OSStatus err = noErr; 442 443 err = MIDIClientCreate(CFSTR("MIDI Client"), NULL, NULL, &client); 444 if (err != noErr) { goto Exit; } 445 446 // This just creates an input port through which the client may receive 447 // incoming MIDI messages from any MIDI source. 448 err = MIDIInputPortCreate(client, CFSTR("MIDI Input Port"), midiReadProc, NULL, &inPort); 449 if (err != noErr) { goto Exit; } 450 451 err = MIDIOutputPortCreate(client, CFSTR("MIDI Output Port"), &outPort); 452 if (err != noErr) { goto Exit; } 453 454Exit: 455 if (err != noErr) { 456 const char* s = MIDI_Utils_GetErrorMsg(err); 457 if (s != NULL) { 458 printf("%s\n", s); 459 } 460 } 461} 462 463 464INT32 MIDI_Utils_OpenDevice(int direction, INT32 deviceID, MacMidiDeviceHandle** handle, 465 int num_msgs, int num_long_msgs, 466 size_t lm_size) 467{ 468 midiInit(); 469 470 int err = MIDI_ERROR_NONE; 471 MIDIEndpointRef endpoint = (MIDIEndpointRef) NULL; 472 473 TRACE0("MIDI_Utils_OpenDevice\n"); 474 475 (*handle) = (MacMidiDeviceHandle*) malloc(sizeof(MacMidiDeviceHandle)); 476 if (!(*handle)) { 477 ERROR0("ERROR: MIDI_Utils_OpenDevice: out of memory\n"); 478 return MIDI_OUT_OF_MEMORY; 479 } 480 memset(*handle, 0, sizeof(MacMidiDeviceHandle)); 481 482 // Create the infrastructure for MIDI in/out, and after that, 483 // get the device's endpoint. 484 if (direction == MIDI_IN) { 485 // Create queue and the pthread condition variable. 486 (*handle)->h.queue = MIDI_CreateQueue(num_msgs); 487 (*handle)->h.platformData = MIDI_CreateConditionVariable(); 488 if (!(*handle)->h.queue || !(*handle)->h.platformData) { 489 ERROR0("< ERROR: MIDI_IN_OpenDevice: could not create queue or condition variable\n"); 490 free(*handle); 491 (*handle) = NULL; 492 return MIDI_OUT_OF_MEMORY; 493 } 494 endpoint = MIDIGetSource(deviceID); 495 (*handle)->port = inPort; 496 } else if (direction == MIDI_OUT) { 497 endpoint = MIDIGetDestination(deviceID); 498 (*handle)->port = outPort; 499 } 500 501 if (!endpoint) { 502 // An error occurred. 503 free(*handle); 504 return MIDI_INVALID_DEVICEID; 505 } 506 (*handle)->h.deviceHandle = (void*) (intptr_t) endpoint; 507 (*handle)->h.startTime = getCurrentTimeInNanos(); 508 (*handle)->direction = direction; 509 (*handle)->deviceID = deviceID; 510 511 TRACE0("MIDI_Utils_OpenDevice: succeeded\n"); 512 return err; 513} 514 515 516INT32 MIDI_Utils_CloseDevice(MacMidiDeviceHandle* handle) { 517 int err = MIDI_ERROR_NONE; 518 bool midiIn = (handle->direction == MIDI_IN); 519 520 TRACE0("> MIDI_Utils_CloseDevice\n"); 521 if (!handle) { 522 ERROR0("< ERROR: MIDI_Utils_CloseDevice: handle is NULL\n"); 523 return MIDI_INVALID_HANDLE; 524 } 525 if (!handle->h.deviceHandle) { 526 ERROR0("< ERROR: MIDI_Utils_CloseDevice: native handle is NULL\n"); 527 return MIDI_INVALID_HANDLE; 528 } 529 handle->isStarted = FALSE; 530 handle->h.deviceHandle = NULL; 531 532 if (midiIn) { 533 if (handle->h.queue != NULL) { 534 MidiMessageQueue* queue = handle->h.queue; 535 handle->h.queue = NULL; 536 MIDI_DestroyQueue(queue); 537 } 538 if (handle->h.platformData) { 539 MIDI_DestroyConditionVariable(handle->h.platformData); 540 } 541 } 542 free(handle); 543 544 TRACE0("< MIDI_Utils_CloseDevice: succeeded\n"); 545 return err; 546} 547 548 549INT32 MIDI_Utils_StartDevice(MacMidiDeviceHandle* handle) { 550 OSStatus err = noErr; 551 552 if (!handle || !handle->h.deviceHandle) { 553 ERROR0("ERROR: MIDI_Utils_StartDevice: handle or native is NULL\n"); 554 return MIDI_INVALID_HANDLE; 555 } 556 557 // Clears all the events from the queue. 558 MIDI_QueueClear(handle->h.queue); 559 560 if (!handle->isStarted) { 561 /* set the flag that we can now receive messages */ 562 handle->isStarted = TRUE; 563 564 if (handle->direction == MIDI_IN) { 565 // The handle->h.platformData field contains the (pthread_cond_t*) 566 // associated with the source of the MIDI input stream, and is 567 // used in the CoreMIDI's callback to signal the arrival of new 568 // data. 569 // 570 // Similarly, handle->h.queue is used in the CoreMDID's callback 571 // to dispatch the incoming messages to the appropriate queue. 572 // 573 err = MIDIPortConnectSource(inPort, (MIDIEndpointRef) (intptr_t) (handle->h.deviceHandle), (void*) handle); 574 } else if (handle->direction == MIDI_OUT) { 575 // Unschedules previous-sent packets. 576 err = MIDIFlushOutput((MIDIEndpointRef) (intptr_t) handle->h.deviceHandle); 577 } 578 579 MIDI_CHECK_ERROR; 580 } 581 return MIDI_SUCCESS; /* don't fail */ 582} 583 584 585INT32 MIDI_Utils_StopDevice(MacMidiDeviceHandle* handle) { 586 OSStatus err = noErr; 587 588 if (!handle || !handle->h.deviceHandle) { 589 ERROR0("ERROR: MIDI_Utils_StopDevice: handle or native handle is NULL\n"); 590 return MIDI_INVALID_HANDLE; 591 } 592 593 if (handle->isStarted) { 594 /* set the flag that we don't want to receive messages anymore */ 595 handle->isStarted = FALSE; 596 597 if (handle->direction == MIDI_IN) { 598 err = MIDIPortDisconnectSource(inPort, (MIDIEndpointRef) (intptr_t) (handle->h.deviceHandle)); 599 } else if (handle->direction == MIDI_OUT) { 600 // Unschedules previously-sent packets. 601 err = MIDIFlushOutput((MIDIEndpointRef) (intptr_t) handle->h.deviceHandle); 602 } 603 604 MIDI_CHECK_ERROR; 605 } 606 return MIDI_SUCCESS; 607} 608 609 610INT64 MIDI_Utils_GetTimeStamp(MacMidiDeviceHandle* handle) { 611 612 if (!handle || !handle->h.deviceHandle) { 613 ERROR0("ERROR: MIDI_Utils_GetTimeStamp: handle or native handle is NULL\n"); 614 return (INT64) -1; /* failure */ 615 } 616 617 UInt64 delta = getCurrentTimeInNanos() - handle->h.startTime; 618 return (INT64) ((delta + 500) / 1000); 619} 620 621 622/***************************************************************************/ 623/* Condition Variable Support for Mac OS X Port */ 624/* */ 625/* This works with the Native Locking Support defined below. We are using */ 626/* POSIX pthread_cond_t/pthread_mutex_t to do locking and synchronization. */ 627/* */ 628/* For MidiDeviceHandle* handle, the mutex reference is stored as handle-> */ 629/* queue->lock while the condition variabale reference is stored as handle */ 630/* ->platformData. */ 631/***************************************************************************/ 632 633// Called from Midi_Utils_Opendevice(...) to create a condition variable 634// used to synchronize between the receive thread created by the CoreMIDI 635// and the Java-initiated MidiInDevice run loop. 636void* MIDI_CreateConditionVariable() { 637 pthread_cond_t* cond = (pthread_cond_t*) malloc(sizeof(pthread_cond_t)); 638 pthread_cond_init(cond, NULL); 639 return (void*) cond; 640} 641 642void MIDI_DestroyConditionVariable(void* cond) { 643 while (pthread_cond_destroy((pthread_cond_t*) cond) == EBUSY) { 644 pthread_cond_broadcast((pthread_cond_t*) cond); 645 sched_yield(); 646 } 647 return; 648} 649 650// Called from MIDI_IN_GetMessage(...) to wait for MIDI messages to become 651// available via delivery from the CoreMIDI receive thread 652void MIDI_WaitOnConditionVariable(void* cond, void* lock) { 653 if (cond && lock) { 654 pthread_mutex_lock(lock); 655 pthread_cond_wait((pthread_cond_t*) cond, (pthread_mutex_t*) lock); 656 pthread_mutex_unlock(lock); 657 } 658 return; 659} 660 661// Called from midiReadProc(...) to notify the waiting thread to unblock on 662// the condition variable. 663void MIDI_SignalConditionVariable(void* cond) { 664 if (cond) { 665 pthread_cond_signal((pthread_cond_t*) cond); 666 } 667 return; 668} 669 670 671/**************************************************************************/ 672/* Native Locking Support */ 673/* */ 674/* @see src/share/natve/com/sun/media/sound/PlatformMidi.c which contains */ 675/* utility functions for platform midi support where the section of code */ 676/* for MessageQueue implementation calls out to these functions. */ 677/**************************************************************************/ 678 679void* MIDI_CreateLock() { 680 pthread_mutex_t* lock = (pthread_mutex_t*) malloc(sizeof(pthread_mutex_t)); 681 pthread_mutex_init(lock, NULL); 682 TRACE0("MIDI_CreateLock\n"); 683 return (void *)lock; 684} 685 686void MIDI_DestroyLock(void* lock) { 687 if (lock) { 688 pthread_mutex_destroy((pthread_mutex_t*) lock); 689 free(lock); 690 TRACE0("MIDI_DestroyLock\n"); 691 } 692} 693 694void MIDI_Lock(void* lock) { 695 if (lock) { 696 pthread_mutex_lock((pthread_mutex_t*) lock); 697 } 698} 699 700void MIDI_Unlock(void* lock) { 701 if (lock) { 702 pthread_mutex_unlock((pthread_mutex_t*) lock); 703 } 704} 705 706 707#endif // USE_PLATFORM_MIDI_IN || USE_PLATFORM_MIDI_OUT 708