2
|
1 |
/*
|
|
2 |
* Copyright 2003-2007 Sun Microsystems, Inc. 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. Sun designates this
|
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
|
9 |
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
22 |
* CA 95054 USA or visit www.sun.com if you need additional information or
|
|
23 |
* have any questions.
|
|
24 |
*/
|
|
25 |
|
|
26 |
#define USE_ERROR
|
|
27 |
#define USE_TRACE
|
|
28 |
|
|
29 |
#if USE_PLATFORM_MIDI_IN == TRUE
|
|
30 |
|
|
31 |
|
|
32 |
#include <alsa/asoundlib.h>
|
|
33 |
#include "PlatformMidi.h"
|
|
34 |
#include "PLATFORM_API_LinuxOS_ALSA_MidiUtils.h"
|
|
35 |
|
|
36 |
/*
|
|
37 |
* Helper methods
|
|
38 |
*/
|
|
39 |
|
|
40 |
static inline UINT32 packMessage(int status, int data1, int data2) {
|
|
41 |
return ((status & 0xFF) | ((data1 & 0xFF) << 8) | ((data2 & 0xFF) << 16));
|
|
42 |
}
|
|
43 |
|
|
44 |
|
|
45 |
static void setShortMessage(MidiMessage* message,
|
|
46 |
int status, int data1, int data2) {
|
|
47 |
message->type = SHORT_MESSAGE;
|
|
48 |
message->data.s.packedMsg = packMessage(status, data1, data2);
|
|
49 |
}
|
|
50 |
|
|
51 |
|
|
52 |
static void setRealtimeMessage(MidiMessage* message, int status) {
|
|
53 |
setShortMessage(message, status, 0, 0);
|
|
54 |
}
|
|
55 |
|
|
56 |
|
|
57 |
static void set14bitMessage(MidiMessage* message, int status, int value) {
|
|
58 |
TRACE3("14bit value: %d, lsb: %d, msb: %d\n", value, value & 0x7F, (value >> 7) & 0x7F);
|
|
59 |
value &= 0x3FFF;
|
|
60 |
TRACE3("14bit value (2): %d, lsb: %d, msb: %d\n", value, value & 0x7F, (value >> 7) & 0x7F);
|
|
61 |
setShortMessage(message, status,
|
|
62 |
value & 0x7F,
|
|
63 |
(value >> 7) & 0x7F);
|
|
64 |
}
|
|
65 |
|
|
66 |
|
|
67 |
/*
|
|
68 |
* implementation of the platform-dependent
|
|
69 |
* MIDI in functions declared in PlatformMidi.h
|
|
70 |
*/
|
|
71 |
|
|
72 |
char* MIDI_IN_GetErrorStr(INT32 err) {
|
|
73 |
return (char*) getErrorStr(err);
|
|
74 |
}
|
|
75 |
|
|
76 |
|
|
77 |
INT32 MIDI_IN_GetNumDevices() {
|
|
78 |
TRACE0("MIDI_IN_GetNumDevices()\n");
|
|
79 |
return getMidiDeviceCount(SND_RAWMIDI_STREAM_INPUT);
|
|
80 |
}
|
|
81 |
|
|
82 |
|
|
83 |
INT32 MIDI_IN_GetDeviceName(INT32 deviceIndex, char *name, UINT32 nameLength) {
|
|
84 |
int ret = getMidiDeviceName(SND_RAWMIDI_STREAM_INPUT, deviceIndex,
|
|
85 |
name, nameLength);
|
|
86 |
return ret;
|
|
87 |
}
|
|
88 |
|
|
89 |
|
|
90 |
INT32 MIDI_IN_GetDeviceVendor(INT32 deviceIndex, char *name, UINT32 nameLength) {
|
|
91 |
int ret = getMidiDeviceVendor(deviceIndex, name, nameLength);
|
|
92 |
return ret;
|
|
93 |
}
|
|
94 |
|
|
95 |
|
|
96 |
INT32 MIDI_IN_GetDeviceDescription(INT32 deviceIndex, char *name, UINT32 nameLength) {
|
|
97 |
int ret = getMidiDeviceDescription(SND_RAWMIDI_STREAM_INPUT, deviceIndex,
|
|
98 |
name, nameLength);
|
|
99 |
return ret;
|
|
100 |
}
|
|
101 |
|
|
102 |
|
|
103 |
INT32 MIDI_IN_GetDeviceVersion(INT32 deviceIndex, char *name, UINT32 nameLength) {
|
|
104 |
int ret = getMidiDeviceVersion(deviceIndex, name, nameLength);
|
|
105 |
return ret;
|
|
106 |
}
|
|
107 |
|
|
108 |
/*************************************************************************/
|
|
109 |
|
|
110 |
INT32 MIDI_IN_OpenDevice(INT32 deviceIndex, MidiDeviceHandle** handle) {
|
|
111 |
INT32 ret;
|
|
112 |
TRACE0("> MIDI_IN_OpenDevice\n");
|
|
113 |
ret = openMidiDevice(SND_RAWMIDI_STREAM_INPUT, deviceIndex, handle);
|
|
114 |
TRACE1("< MIDI_IN_OpenDevice: returning %d\n", (int) ret);
|
|
115 |
return ret;
|
|
116 |
}
|
|
117 |
|
|
118 |
|
|
119 |
INT32 MIDI_IN_CloseDevice(MidiDeviceHandle* handle) {
|
|
120 |
INT32 ret;
|
|
121 |
TRACE0("> MIDI_IN_CloseDevice\n");
|
|
122 |
ret = closeMidiDevice(handle);
|
|
123 |
TRACE1("< MIDI_IN_CloseDevice: returning %d\n", (int) ret);
|
|
124 |
return ret;
|
|
125 |
}
|
|
126 |
|
|
127 |
|
|
128 |
INT32 MIDI_IN_StartDevice(MidiDeviceHandle* handle) {
|
|
129 |
TRACE0("MIDI_IN_StartDevice\n");
|
|
130 |
return MIDI_SUCCESS;
|
|
131 |
}
|
|
132 |
|
|
133 |
|
|
134 |
INT32 MIDI_IN_StopDevice(MidiDeviceHandle* handle) {
|
|
135 |
TRACE0("MIDI_IN_StopDevice\n");
|
|
136 |
return MIDI_SUCCESS;
|
|
137 |
}
|
|
138 |
|
|
139 |
|
|
140 |
INT64 MIDI_IN_GetTimeStamp(MidiDeviceHandle* handle) {
|
|
141 |
return getMidiTimestamp(handle);
|
|
142 |
}
|
|
143 |
|
|
144 |
|
|
145 |
/* read the next message from the queue */
|
|
146 |
MidiMessage* MIDI_IN_GetMessage(MidiDeviceHandle* handle) {
|
|
147 |
snd_seq_event_t alsa_message;
|
|
148 |
MidiMessage* jdk_message;
|
|
149 |
int err;
|
|
150 |
char buffer[1];
|
|
151 |
int status;
|
|
152 |
|
|
153 |
TRACE0("> MIDI_IN_GetMessage\n");
|
|
154 |
if (!handle) {
|
|
155 |
ERROR0("< ERROR: MIDI_IN_GetMessage(): handle is NULL\n");
|
|
156 |
return NULL;
|
|
157 |
}
|
|
158 |
if (!handle->deviceHandle) {
|
|
159 |
ERROR0("< ERROR: MIDI_IN_GetMessage(): native handle is NULL\n");
|
|
160 |
return NULL;
|
|
161 |
}
|
|
162 |
if (!handle->platformData) {
|
|
163 |
ERROR0("< ERROR: MIDI_IN_GetMessage(): platformData is NULL\n");
|
|
164 |
return NULL;
|
|
165 |
}
|
|
166 |
|
|
167 |
/* For MIDI In, the device is left in non blocking mode. So if there is
|
|
168 |
no data from the device, snd_rawmidi_read() returns with -11 (EAGAIN).
|
|
169 |
This results in jumping back to the Java layer. */
|
|
170 |
while (TRUE) {
|
|
171 |
TRACE0("before snd_rawmidi_read()\n");
|
|
172 |
err = snd_rawmidi_read((snd_rawmidi_t*) handle->deviceHandle, buffer, 1);
|
|
173 |
TRACE0("after snd_rawmidi_read()\n");
|
|
174 |
if (err != 1) {
|
|
175 |
ERROR2("< ERROR: MIDI_IN_GetMessage(): snd_rawmidi_read() returned %d : %s\n", err, snd_strerror(err));
|
|
176 |
return NULL;
|
|
177 |
}
|
|
178 |
// printf("received byte: %d\n", buffer[0]);
|
|
179 |
err = snd_midi_event_encode_byte((snd_midi_event_t*) handle->platformData,
|
|
180 |
(int) buffer[0],
|
|
181 |
&alsa_message);
|
|
182 |
if (err == 1) {
|
|
183 |
break;
|
|
184 |
} else if (err < 0) {
|
|
185 |
ERROR1("< ERROR: MIDI_IN_GetMessage(): snd_midi_event_encode_byte() returned %d\n", err);
|
|
186 |
return NULL;
|
|
187 |
}
|
|
188 |
}
|
|
189 |
jdk_message = (MidiMessage*) calloc(sizeof(MidiMessage), 1);
|
|
190 |
if (!jdk_message) {
|
|
191 |
ERROR0("< ERROR: MIDI_IN_GetMessage(): out of memory\n");
|
|
192 |
return NULL;
|
|
193 |
}
|
|
194 |
// TODO: tra
|
|
195 |
switch (alsa_message.type) {
|
|
196 |
case SND_SEQ_EVENT_NOTEON:
|
|
197 |
case SND_SEQ_EVENT_NOTEOFF:
|
|
198 |
case SND_SEQ_EVENT_KEYPRESS:
|
|
199 |
status = (alsa_message.type == SND_SEQ_EVENT_KEYPRESS) ? 0xA0 :
|
|
200 |
(alsa_message.type == SND_SEQ_EVENT_NOTEON) ? 0x90 : 0x80;
|
|
201 |
status |= alsa_message.data.note.channel;
|
|
202 |
setShortMessage(jdk_message, status,
|
|
203 |
alsa_message.data.note.note,
|
|
204 |
alsa_message.data.note.velocity);
|
|
205 |
break;
|
|
206 |
|
|
207 |
case SND_SEQ_EVENT_CONTROLLER:
|
|
208 |
status = 0xB0 | alsa_message.data.control.channel;
|
|
209 |
setShortMessage(jdk_message, status,
|
|
210 |
alsa_message.data.control.param,
|
|
211 |
alsa_message.data.control.value);
|
|
212 |
break;
|
|
213 |
|
|
214 |
case SND_SEQ_EVENT_PGMCHANGE:
|
|
215 |
case SND_SEQ_EVENT_CHANPRESS:
|
|
216 |
status = (alsa_message.type == SND_SEQ_EVENT_PGMCHANGE) ? 0xC0 : 0xD0;
|
|
217 |
status |= alsa_message.data.control.channel;
|
|
218 |
setShortMessage(jdk_message, status,
|
|
219 |
alsa_message.data.control.value, 0);
|
|
220 |
break;
|
|
221 |
|
|
222 |
case SND_SEQ_EVENT_PITCHBEND:
|
|
223 |
status = 0xE0 | alsa_message.data.control.channel;
|
|
224 |
// $$mp 2003-09-23:
|
|
225 |
// possible hack to work around a bug in ALSA. Necessary for
|
|
226 |
// ALSA 0.9.2. May be fixed in newer versions of ALSA.
|
|
227 |
// alsa_message.data.control.value ^= 0x2000;
|
|
228 |
// TRACE1("pitchbend value: %d\n", alsa_message.data.control.value);
|
|
229 |
set14bitMessage(jdk_message, status,
|
|
230 |
alsa_message.data.control.value);
|
|
231 |
break;
|
|
232 |
|
|
233 |
/* System exclusive messages */
|
|
234 |
|
|
235 |
case SND_SEQ_EVENT_SYSEX:
|
|
236 |
jdk_message->type = LONG_MESSAGE;
|
|
237 |
jdk_message->data.l.size = alsa_message.data.ext.len;
|
|
238 |
jdk_message->data.l.data = malloc(alsa_message.data.ext.len);
|
|
239 |
if (jdk_message->data.l.data == NULL) {
|
|
240 |
ERROR0("< ERROR: MIDI_IN_GetMessage(): out of memory\n");
|
|
241 |
free(jdk_message);
|
|
242 |
jdk_message = NULL;
|
|
243 |
} else {
|
|
244 |
memcpy(jdk_message->data.l.data, alsa_message.data.ext.ptr, alsa_message.data.ext.len);
|
|
245 |
}
|
|
246 |
break;
|
|
247 |
|
|
248 |
/* System common messages */
|
|
249 |
|
|
250 |
case SND_SEQ_EVENT_QFRAME:
|
|
251 |
setShortMessage(jdk_message, 0xF1,
|
|
252 |
alsa_message.data.control.value & 0x7F, 0);
|
|
253 |
break;
|
|
254 |
|
|
255 |
case SND_SEQ_EVENT_SONGPOS:
|
|
256 |
set14bitMessage(jdk_message, 0xF2,
|
|
257 |
alsa_message.data.control.value);
|
|
258 |
break;
|
|
259 |
|
|
260 |
case SND_SEQ_EVENT_SONGSEL:
|
|
261 |
setShortMessage(jdk_message, 0xF3,
|
|
262 |
alsa_message.data.control.value & 0x7F, 0);
|
|
263 |
break;
|
|
264 |
|
|
265 |
case SND_SEQ_EVENT_TUNE_REQUEST:
|
|
266 |
setRealtimeMessage(jdk_message, 0xF6);
|
|
267 |
break;
|
|
268 |
|
|
269 |
/* System realtime messages */
|
|
270 |
|
|
271 |
case SND_SEQ_EVENT_CLOCK:
|
|
272 |
setRealtimeMessage(jdk_message, 0xF8);
|
|
273 |
break;
|
|
274 |
|
|
275 |
case SND_SEQ_EVENT_START:
|
|
276 |
setRealtimeMessage(jdk_message, 0xFA);
|
|
277 |
break;
|
|
278 |
|
|
279 |
case SND_SEQ_EVENT_CONTINUE:
|
|
280 |
setRealtimeMessage(jdk_message, 0xFB);
|
|
281 |
break;
|
|
282 |
|
|
283 |
case SND_SEQ_EVENT_STOP:
|
|
284 |
setRealtimeMessage(jdk_message, 0xFC);
|
|
285 |
break;
|
|
286 |
|
|
287 |
case SND_SEQ_EVENT_SENSING:
|
|
288 |
setRealtimeMessage(jdk_message, 0xFE);
|
|
289 |
break;
|
|
290 |
|
|
291 |
case SND_SEQ_EVENT_RESET:
|
|
292 |
setRealtimeMessage(jdk_message, 0xFF);
|
|
293 |
break;
|
|
294 |
|
|
295 |
default:
|
|
296 |
ERROR0("< ERROR: MIDI_IN_GetMessage(): unhandled ALSA MIDI message type\n");
|
|
297 |
free(jdk_message);
|
|
298 |
jdk_message = NULL;
|
|
299 |
|
|
300 |
}
|
|
301 |
|
|
302 |
// set timestamp
|
|
303 |
if (jdk_message != NULL) {
|
|
304 |
jdk_message->timestamp = getMidiTimestamp(handle);
|
|
305 |
}
|
|
306 |
TRACE1("< MIDI_IN_GetMessage: returning %p\n", jdk_message);
|
|
307 |
return jdk_message;
|
|
308 |
}
|
|
309 |
|
|
310 |
|
|
311 |
void MIDI_IN_ReleaseMessage(MidiDeviceHandle* handle, MidiMessage* msg) {
|
|
312 |
if (!msg) {
|
|
313 |
ERROR0("< ERROR: MIDI_IN_ReleaseMessage(): message is NULL\n");
|
|
314 |
return;
|
|
315 |
}
|
|
316 |
if (msg->type == LONG_MESSAGE && msg->data.l.data) {
|
|
317 |
free(msg->data.l.data);
|
|
318 |
}
|
|
319 |
free(msg);
|
|
320 |
}
|
|
321 |
|
|
322 |
#endif /* USE_PLATFORM_MIDI_IN */
|