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 //#define USE_ERROR 27 //#define USE_TRACE 28 29 /* Use THIS_FILE when it is available. */ 30 #ifndef THIS_FILE 31 #define THIS_FILE __FILE__ 32 #endif 33 34 #if USE_PLATFORM_MIDI_OUT == TRUE 35 36 #include "PLATFORM_API_MacOSX_MidiUtils.h" 37 38 char* MIDI_OUT_GetErrorStr(INT32 err) { 39 return (char *) MIDI_Utils_GetErrorMsg((int) err); 40 } 41 42 43 INT32 MIDI_OUT_GetNumDevices() { 44 return MIDI_Utils_GetNumDevices(MIDI_OUT); 45 } 46 47 48 INT32 MIDI_OUT_GetDeviceName(INT32 deviceID, char *name, UINT32 nameLength) { 49 return MIDI_Utils_GetDeviceName(MIDI_OUT, deviceID, name, nameLength); 50 } 51 52 53 INT32 MIDI_OUT_GetDeviceVendor(INT32 deviceID, char *name, UINT32 nameLength) { 54 return MIDI_Utils_GetDeviceVendor(MIDI_OUT, deviceID, name, nameLength); 55 } 56 57 58 INT32 MIDI_OUT_GetDeviceDescription(INT32 deviceID, char *name, UINT32 nameLength) { 59 return MIDI_Utils_GetDeviceDescription(MIDI_OUT, deviceID, name, nameLength); 60 } 61 62 63 INT32 MIDI_OUT_GetDeviceVersion(INT32 deviceID, char *name, UINT32 nameLength) { 64 return MIDI_Utils_GetDeviceVersion(MIDI_OUT, deviceID, name, nameLength); 65 } 66 67 68 /* *************************** MidiOutDevice implementation ***************************************** */ 69 70 INT32 MIDI_OUT_OpenDevice(INT32 deviceID, MidiDeviceHandle** handle) { 71 TRACE1("MIDI_OUT_OpenDevice: deviceID: %d\n", (int) deviceID); 72 /* queue sizes are ignored for MIDI_OUT only (uses STREAMS) */ 73 return MIDI_Utils_OpenDevice(MIDI_OUT, deviceID, (MacMidiDeviceHandle**) handle, 0, 0, 0); 74 } 75 76 INT32 MIDI_OUT_CloseDevice(MidiDeviceHandle* handle) { 77 TRACE0("MIDI_OUT_CloseDevice\n"); 78 79 // issue a "SUSTAIN OFF" message to each MIDI channel, 0 to 15. 80 // "CONTROL CHANGE" is 176, "SUSTAIN CONTROLLER" is 64, and the value is 0. 81 // $$fb 2002-04-04: It is responsability of the application developer to 82 // leave the device in a consistent state. So I put this in comments 83 /* 84 for (channel = 0; channel < 16; channel++) 85 MIDI_OUT_SendShortMessage(deviceHandle, (unsigned char)(176 + channel), 86 (unsigned char)64, (unsigned char)0, (UINT32)-1); 87 */ 88 return MIDI_Utils_CloseDevice((MacMidiDeviceHandle*) handle); 89 } 90 91 92 INT64 MIDI_OUT_GetTimeStamp(MidiDeviceHandle* handle) { 93 return MIDI_Utils_GetTimeStamp((MacMidiDeviceHandle*) handle); 94 } 95 96 97 INT32 MIDI_OUT_SendShortMessage(MidiDeviceHandle* handle, UINT32 packedMsg, UINT32 timestamp) { 98 OSStatus err = noErr; 99 100 TRACE2("> MIDI_OUT_SendShortMessage %x, time: %d\n", (uint) packedMsg, (int) timestamp); 101 if (!handle) { 102 ERROR0("< ERROR: MIDI_OUT_SendShortMessage: handle is NULL\n"); 103 return MIDI_INVALID_HANDLE; 104 } 105 106 MacMidiDeviceHandle* macHandle = (MacMidiDeviceHandle*) handle; 107 UInt8 mBuffers[100]; 108 MIDIPacketList* packetList = (MIDIPacketList*) mBuffers; 109 MIDIPacket* packet; 110 UINT32 nData; 111 Byte data[3] = {packedMsg & 0xFF, (packedMsg >> 8) & 0xFF, (packedMsg >> 16) & 0xFF}; 112 bool byteIsInvalid = FALSE; 113 114 packet = MIDIPacketListInit(packetList); 115 switch (data[0] & 0xF0) { 116 case 0x80: // Note off 117 case 0x90: // Note on 118 case 0xA0: // Aftertouch 119 case 0xB0: // Controller 120 case 0xE0: // Pitch wheel 121 nData = 3; 122 break; 123 124 case 0xC0: // Program change 125 case 0xD0: // Channel pressure 126 nData = 2; 127 break; 128 129 case 0xF0: { 130 // System common message 131 switch (data[0]) { 132 case 0xF0: 133 case 0xF7: 134 // System exclusive 135 fprintf(stderr, "%s: %d->internal error: sysex message status=0x%X while sending short message\n", 136 THIS_FILE, __LINE__, data[0]); 137 byteIsInvalid = TRUE; 138 break; 139 140 case 0xF1: // MTC quarter frame message 141 //fprintf(stderr, ">>>MIDI_OUT_SendShortMessage: MTC quarter frame message....\n"); 142 nData = 2; 143 break; 144 case 0xF3: // Song select 145 //fprintf(stderr, ">>>MIDI_OUT_SendShortMessage: Song select....\n"); 146 nData = 2; 147 break; 148 149 case 0xF2: // Song position pointer 150 //fprintf(stderr, ">>>MIDI_OUT_SendShortMessage: Song position pointer....\n"); 151 nData = 3; 152 break; 153 154 case 0xF6: // Tune request 155 //fprintf(stderr, ">>>MIDI_OUT_SendShortMessage: Tune request....\n"); 156 nData = 1; 157 break; 158 159 default: 160 // Invalid message 161 fprintf(stderr, "%s: %d->Invalid message: message status=0x%X while sending short message\n", 162 THIS_FILE, __LINE__, data[0]); 163 byteIsInvalid = TRUE; 164 break; 165 } 166 break; 167 } 168 169 default: 170 // This can't happen, but handle it anyway. 171 fprintf(stderr, "%s: %d->Invalid message: message status=0x%X while sending short message\n", 172 THIS_FILE, __LINE__, data[0]); 173 byteIsInvalid = TRUE; 174 break; 175 } 176 177 if (byteIsInvalid) return -1; 178 179 MIDIPacketListAdd(packetList, sizeof(mBuffers), packet, 0, nData, data); 180 err = MIDISend(macHandle->port, (MIDIEndpointRef) (intptr_t) handle->deviceHandle, packetList); 181 182 MIDI_CHECK_ERROR; 183 TRACE0("< MIDI_OUT_SendShortMessage\n"); 184 return (err == noErr ? MIDI_SUCCESS : -1); 185 } 186 187 188 INT32 MIDI_OUT_SendLongMessage(MidiDeviceHandle* handle, UBYTE* data, UINT32 size, UINT32 timestamp) { 189 OSStatus err = noErr; 190 191 TRACE2("> MIDI_OUT_SendLongMessage size %d, time: %d\n", (int) size, (int) timestamp); 192 if (!handle || !data) { 193 ERROR0("< ERROR: MIDI_OUT_SendLongMessage: handle, or data is NULL\n"); 194 return MIDI_INVALID_HANDLE; 195 } 196 if (size == 0) { 197 return MIDI_SUCCESS; 198 } 199 200 MacMidiDeviceHandle* macHandle = (MacMidiDeviceHandle*) handle; 201 UInt8 mBuffers[8196]; 202 MIDIPacketList* packetList = (MIDIPacketList*) mBuffers; 203 MIDIPacket* packet = NULL; 204 UINT32 remaining = size; 205 UINT32 increment = 512; 206 UINT32 nData; 207 208 handle->isWaiting = TRUE; 209 210 while (remaining > 0) { 211 212 if (packet == NULL) { 213 packet = MIDIPacketListInit(packetList); 214 } 215 216 if (remaining > increment) { 217 nData = increment; 218 } else { 219 nData = remaining; 220 } 221 222 // Copies the bytes to our current packet. 223 if ((packet = MIDIPacketListAdd(packetList, sizeof(mBuffers), packet, 0, nData, (const Byte*) data)) == NULL) { 224 // Packet list is full, send it. 225 err = MIDISend(macHandle->port, (MIDIEndpointRef) (intptr_t) handle->deviceHandle, packetList); 226 if (err != noErr) { 227 break; 228 } 229 } else { 230 // Moves the data pointer to the next segment. 231 data += nData; 232 remaining -= nData; 233 packet = MIDIPacketNext(packet); 234 } 235 } 236 237 MIDI_CHECK_ERROR; 238 handle->isWaiting = FALSE; 239 TRACE0("< MIDI_OUT_SendLongMessage\n"); 240 return (err == noErr ? MIDI_SUCCESS : -1); 241 } 242 243 #endif /* USE_PLATFORM_MIDI_OUT */