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
45JNIEXPORT jlong JNICALL
46Java_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
80JNIEXPORT void JNICALL
81Java_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
93JNIEXPORT void JNICALL
94Java_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
114JNIEXPORT void JNICALL
115Java_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
127JNIEXPORT jlong JNICALL
128Java_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
147JNIEXPORT void JNICALL
148Java_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}
261