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 */