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