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