1 /* 2 * Copyright (c) 1999, 2007, 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 ** Native functions for interfacing Java with the native implementation 29 ** of PlatformMidi.h's functions. 30 */ 31 /*****************************************************************************/ 32 33 #define USE_ERROR 34 #define USE_TRACE 35 36 37 #include <jni.h> 38 /* for memcpy */ 39 #include <string.h> 40 #include "SoundDefs.h" 41 #include "PlatformMidi.h" 42 #include "com_sun_media_sound_MidiInDevice.h" 43 44 45 JNIEXPORT jlong JNICALL 46 Java_com_sun_media_sound_MidiInDevice_nOpen(JNIEnv* e, jobject thisObj, jint index) { 47 48 MidiDeviceHandle* deviceHandle = NULL; 49 INT32 err = MIDI_NOT_SUPPORTED; 50 51 TRACE1("> Java_com_sun_media_sound_MidiInDevice_nOpen: index: %d\n", index); 52 53 #if USE_PLATFORM_MIDI_IN == TRUE 54 err = MIDI_IN_OpenDevice((INT32) index, &deviceHandle); 55 #endif 56 57 /* $$mp 2003-08-28: 58 So far, the return value (err) hasn't been taken into account. 59 Now, it is also expected to be MIDI_SUCCESS (0). 60 This works for Linux, but has to be checked on other platforms. 61 62 It would be better to settle on one method of signaling error: 63 either returned error codes or a NULL handle. If the latter is used, 64 the return value should be removed from the signature of 65 MIDI_IN_OpenDevice. 66 */ 67 // if we didn't get a valid handle, throw a MidiUnavailableException 68 if (!deviceHandle || err != MIDI_SUCCESS) { 69 deviceHandle = NULL; 70 ERROR0("Java_com_sun_media_sound_MidiInDevice_nOpen: "); 71 ThrowJavaMessageException(e, JAVA_MIDI_PACKAGE_NAME"/MidiUnavailableException", 72 MIDI_IN_InternalGetErrorString(err)); 73 } else { 74 TRACE0("< Java_com_sun_media_sound_MidiInDevice_nOpen succeeded\n"); 75 } 76 return (jlong) (UINT_PTR) deviceHandle; 77 } 78 79 80 JNIEXPORT void JNICALL 81 Java_com_sun_media_sound_MidiInDevice_nClose(JNIEnv* e, jobject thisObj, jlong deviceHandle) { 82 83 TRACE0("> Java_com_sun_media_sound_MidiInDevice_nClose.\n"); 84 85 #if USE_PLATFORM_MIDI_IN == TRUE 86 MIDI_IN_CloseDevice((MidiDeviceHandle*) (UINT_PTR) deviceHandle); 87 #endif 88 89 TRACE0("< Java_com_sun_media_sound_MidiInDevice_nClose succeeded\n"); 90 } 91 92 93 JNIEXPORT void JNICALL 94 Java_com_sun_media_sound_MidiInDevice_nStart(JNIEnv* e, jobject thisObj, jlong deviceHandle) { 95 96 INT32 err = MIDI_NOT_SUPPORTED; 97 98 TRACE0("> Java_com_sun_media_sound_MidiInDevice_nStart.\n"); 99 100 #if USE_PLATFORM_MIDI_IN == TRUE 101 err = MIDI_IN_StartDevice((MidiDeviceHandle*) (UINT_PTR) deviceHandle); 102 #endif 103 104 if (err != MIDI_SUCCESS) { 105 ERROR0("Java_com_sun_media_sound_MidiInDevice_nStart: "); 106 ThrowJavaMessageException(e, JAVA_MIDI_PACKAGE_NAME"/MidiUnavailableException", 107 MIDI_IN_InternalGetErrorString(err)); 108 } else { 109 TRACE0("< Java_com_sun_media_sound_MidiInDevice_nStart succeeded\n"); 110 } 111 } 112 113 114 JNIEXPORT void JNICALL 115 Java_com_sun_media_sound_MidiInDevice_nStop(JNIEnv* e, jobject thisObj, jlong deviceHandle) { 116 117 TRACE0("> Java_com_sun_media_sound_MidiInDevice_nStop.\n"); 118 119 #if USE_PLATFORM_MIDI_IN == TRUE 120 // stop the device and remove all queued events for this device handle 121 MIDI_IN_StopDevice((MidiDeviceHandle*) (UINT_PTR) deviceHandle); 122 #endif 123 124 TRACE0("< Java_com_sun_media_sound_MidiInDevice_nStop succeeded\n"); 125 } 126 127 JNIEXPORT jlong JNICALL 128 Java_com_sun_media_sound_MidiInDevice_nGetTimeStamp(JNIEnv* e, jobject thisObj, jlong deviceHandle) { 129 130 jlong ret = -1; 131 132 TRACE0("Java_com_sun_media_sound_MidiInDevice_nGetTimeStamp.\n"); 133 134 #if USE_PLATFORM_MIDI_IN == TRUE 135 ret = (jlong) MIDI_IN_GetTimeStamp((MidiDeviceHandle*) (UINT_PTR) deviceHandle); 136 #endif 137 138 /* Handle error codes. */ 139 if (ret < -1) { 140 ERROR1("Java_com_sun_media_sound_MidiInDevice_nGetTimeStamp: MIDI_IN_GetTimeStamp returned %lld\n", ret); 141 ret = -1; 142 } 143 return ret; 144 } 145 146 147 JNIEXPORT void JNICALL 148 Java_com_sun_media_sound_MidiInDevice_nGetMessages(JNIEnv* e, jobject thisObj, jlong deviceHandle) { 149 150 #if USE_PLATFORM_MIDI_IN == TRUE 151 MidiMessage* pMessage; 152 jclass javaClass = NULL; 153 jmethodID callbackShortMessageMethodID = NULL; 154 jmethodID callbackLongMessageMethodID = NULL; 155 #endif 156 157 TRACE0("> Java_com_sun_media_sound_MidiInDevice_nGetMessages\n"); 158 159 #if USE_PLATFORM_MIDI_IN == TRUE 160 while ((pMessage = MIDI_IN_GetMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle))) { 161 if ((javaClass == NULL) || (callbackShortMessageMethodID == NULL)) { 162 if (!thisObj) { 163 ERROR0("MidiInDevice: Java_com_sun_media_sound_MidiInDevice_nGetMessages: thisObj is NULL\n"); 164 return; 165 } 166 167 if (javaClass == NULL) { 168 javaClass = (*e)->GetObjectClass(e, thisObj); 169 if (javaClass == NULL) { 170 ERROR0("MidiInDevice: Java_com_sun_media_sound_MidiInDevice_nGetMessages: javaClass is NULL\n"); 171 return; 172 } 173 } 174 175 if (callbackShortMessageMethodID == NULL) { 176 // save the callbackShortMessage callback method id. 177 // this is valid as long as the class is not unloaded. 178 callbackShortMessageMethodID = (*e)->GetMethodID(e, javaClass, "callbackShortMessage", "(IJ)V"); 179 if (callbackShortMessageMethodID == 0) { 180 ERROR0("MidiInDevice: Java_com_sun_media_sound_MidiInDevice_nGetMessages: callbackShortMessageMethodID is 0\n"); 181 return; 182 } 183 } 184 if (callbackLongMessageMethodID == NULL) { 185 // save the callbackLongMessage callback method id. 186 // this is valid as long as the class is not unloaded. 187 callbackLongMessageMethodID = (*e)->GetMethodID(e, javaClass, "callbackLongMessage", "([BJ)V"); 188 if (callbackLongMessageMethodID == 0) { 189 ERROR0("MidiInDevice: Java_com_sun_media_sound_MidiInDevice_nGetMessages: callbackLongMessageMethodID is 0\n"); 190 return; 191 } 192 } 193 } 194 195 switch ((int)pMessage->type) { 196 case SHORT_MESSAGE: { 197 jint msg = (jint)pMessage->data.s.packedMsg; 198 jlong ts = (jlong)pMessage->timestamp; 199 TRACE0("Java_com_sun_media_sound_MidiInDevice_nGetMessages: got SHORT_MESSAGE\n"); 200 // now we can put this message object back in the queue 201 MIDI_IN_ReleaseMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle, pMessage); 202 // and notify Java space 203 (*e)->CallVoidMethod(e, thisObj, callbackShortMessageMethodID, msg, ts); 204 break; 205 } 206 207 case LONG_MESSAGE: { 208 jlong ts = (jlong)pMessage->timestamp; 209 jbyteArray jData; 210 UBYTE* data; 211 int isSXCont = 0; 212 TRACE0("Java_com_sun_media_sound_MidiInDevice_nGetMessages: got LONG_MESSAGE\n"); 213 if ((*(pMessage->data.l.data) != 0xF0) 214 && (*(pMessage->data.l.data) != 0xF7)) { 215 // this is a continued sys ex message 216 // need to prepend 0xF7 217 isSXCont = 1; 218 } 219 jData = (*e)->NewByteArray(e, pMessage->data.l.size + isSXCont); 220 if (!jData) { 221 ERROR0("Java_com_sun_media_sound_MidiInDevice_nGetMessages: cannot create long byte array.\n"); 222 break; 223 } 224 data = (UBYTE*) ((*e)->GetByteArrayElements(e, jData, NULL)); 225 if (!data) { 226 ERROR0("MidiInDevice: Java_com_sun_media_sound_MidiInDevice_nGetMessages: array data is NULL\n"); 227 break; 228 } 229 // finally copy the long message 230 memcpy(data + isSXCont, pMessage->data.l.data, pMessage->data.l.size); 231 232 // now we can put this message object back in the queue 233 MIDI_IN_ReleaseMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle, pMessage); 234 235 // if this is a patched continued sys ex message, prepend 0xF7 236 if (isSXCont) { 237 *data = 0xF7; 238 } 239 240 // commit the byte array 241 (*e)->ReleaseByteArrayElements(e, jData, (jbyte*) data, (jint) 0); 242 243 (*e)->CallVoidMethod(e, thisObj, callbackLongMessageMethodID, jData, ts); 244 // release local reference to array: not needed anymore. 245 (*e)->DeleteLocalRef(e, jData); 246 break; 247 } 248 249 default: 250 // put this message object back in the queue 251 MIDI_IN_ReleaseMessage((MidiDeviceHandle*) (UINT_PTR) deviceHandle, pMessage); 252 ERROR1("Java_com_sun_media_sound_MidiInDevice_nGetMessages: got unsupported message, type %d\n", pMessage->type); 253 break; 254 } // switch 255 } 256 257 #endif // USE_PLATFORM_MIDI_IN 258 259 TRACE0("< Java_com_sun_media_sound_MidiInDevice_nGetMessages returning\n"); 260 }