Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/windows/native/libjsound/PLATFORM_API_WinOS_MidiIn.cpp
41149 views
1
/*
2
* Copyright (c) 1999, 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
/* include Java Sound specific headers as C code */
30
extern "C" {
31
#include "PLATFORM_API_WinOS_Util.h"
32
}
33
34
/* include to prevent charset problem */
35
#include "PLATFORM_API_WinOS_Charset_Util.h"
36
37
#if USE_PLATFORM_MIDI_IN == TRUE
38
39
#ifdef USE_ERROR
40
#include <stdio.h>
41
42
#define MIDIIN_CHECK_ERROR { \
43
if (err != MMSYSERR_NOERROR) \
44
ERROR3("MIDI IN Error in %s:%d : %s\n", __FILE__, __LINE__, MIDI_IN_GetErrorStr((INT32) err)); \
45
}
46
#else
47
#define MIDIIN_CHECK_ERROR
48
#endif
49
50
/*
51
* Callback from the MIDI device for all messages.
52
*/
53
//$$fb dwParam1 holds a pointer for long messages. How can that be a DWORD then ???
54
void CALLBACK MIDI_IN_PutMessage( HMIDIIN hMidiIn, UINT wMsg, UINT_PTR dwInstance, UINT_PTR dwParam1, UINT_PTR dwParam2 ) {
55
56
MidiDeviceHandle* handle = (MidiDeviceHandle*) dwInstance;
57
58
TRACE3("> MIDI_IN_PutMessage, hMidiIn: %x, wMsg: %x, dwInstance: %x\n", hMidiIn, wMsg, dwInstance);
59
TRACE2(" dwParam1: %x, dwParam2: %x\n", dwParam1, dwParam2);
60
61
switch(wMsg) {
62
63
case MIM_OPEN:
64
TRACE0("< MIDI_IN_PutMessage: MIM_OPEN\n");
65
break;
66
67
case MIM_CLOSE:
68
TRACE0("< MIDI_IN_PutMessage: MIM_CLOSE\n");
69
break;
70
71
case MIM_MOREDATA:
72
case MIM_DATA:
73
TRACE3(" MIDI_IN_PutMessage: MIM_MOREDATA or MIM_DATA. status=%x data1=%x data2=%x\n",
74
dwParam1 & 0xFF, (dwParam1 & 0xFF00)>>8, (dwParam1 & 0xFF0000)>>16);
75
if (handle!=NULL && handle->queue!=NULL && handle->platformData) {
76
MIDI_QueueAddShort(handle->queue,
77
// queue stores packedMsg in big endian
78
//(dwParam1 << 24) | ((dwParam1 << 8) & 0xFF0000) | ((dwParam1 >> 8) & 0xFF00),
79
(UINT32) dwParam1,
80
// queue uses microseconds
81
((INT64) dwParam2)*1000,
82
// overwrite if queue is full
83
TRUE);
84
SetEvent((HANDLE) handle->platformData);
85
}
86
TRACE0("< MIDI_IN_PutMessage\n");
87
break;
88
89
case MIM_LONGDATA:
90
TRACE1(" MIDI_IN_PutMessage: MIM_LONGDATA (%d bytes recorded)\n", (int) (((MIDIHDR*) dwParam1)->dwBytesRecorded));
91
if (handle!=NULL && handle->queue!=NULL && handle->platformData) {
92
MIDIHDR* hdr = (MIDIHDR*) dwParam1;
93
TRACE2(" MIDI_IN_PutMessage: Adding to queue: index %d, %d bytes\n", (INT32) hdr->dwUser, hdr->dwBytesRecorded);
94
MIDI_QueueAddLong(handle->queue,
95
(UBYTE*) hdr->lpData,
96
(UINT32) hdr->dwBytesRecorded,
97
// sysex buffer index
98
(INT32) hdr->dwUser,
99
// queue uses microseconds
100
((INT64) dwParam2)*1000,
101
// overwrite if queue is full
102
TRUE);
103
SetEvent((HANDLE) handle->platformData);
104
}
105
TRACE0("< MIDI_IN_PutMessage\n");
106
break;
107
108
case MIM_ERROR:
109
ERROR0("< MIDI_IN_PutMessage: MIM_ERROR!\n");
110
break;
111
112
case MIM_LONGERROR:
113
if (dwParam1 != 0) {
114
MIDIHDR* hdr = (MIDIHDR*) dwParam1;
115
#ifdef USE_TRACE
116
if (hdr->dwBytesRecorded > 0) {
117
TRACE2(" MIDI_IN_PutMessage: MIM_LONGERROR! recorded: %d bytes with status 0x%2x\n",
118
hdr->dwBytesRecorded, (int) (*((UBYTE*) hdr->lpData)));
119
}
120
#endif
121
// re-add hdr to device query
122
hdr->dwBytesRecorded = 0;
123
midiInAddBuffer((HMIDIIN)handle->deviceHandle, hdr, sizeof(MIDIHDR));
124
}
125
ERROR0("< MIDI_IN_PutMessage: MIM_LONGERROR!\n");
126
break;
127
128
default:
129
ERROR1("< MIDI_IN_PutMessage: ERROR unknown message %d!\n", wMsg);
130
break;
131
132
} // switch (wMsg)
133
}
134
135
136
/*
137
** data/routines for opening MIDI input (MidiIn) device by separate thread
138
** (joint into MidiIn_OpenHelper class)
139
** see 6415669 - MidiIn device stops work and crushes JVM after exiting
140
** from thread that has open the device (it looks like WinMM bug).
141
*/
142
class MidiIn_OpenHelper {
143
public:
144
/* opens MidiIn device */
145
static MMRESULT midiInOpen(INT32 deviceID, MidiDeviceHandle* handle);
146
/* checks for initialization success */
147
static inline BOOL isInitialized() { return data.threadHandle != NULL; }
148
protected:
149
MidiIn_OpenHelper() {} // no need to create an instance
150
151
/* data class */
152
class Data {
153
public:
154
Data();
155
~Data();
156
// public data to access from parent class
157
CRITICAL_SECTION crit_sect;
158
volatile HANDLE threadHandle;
159
volatile HANDLE doEvent; // event to resume thread
160
volatile HANDLE doneEvent; // processing has been completed
161
volatile MMRESULT err; // processing result
162
// data to process; (handle == null) is command to thread terminating
163
volatile INT32 deviceID;
164
volatile MidiDeviceHandle* handle;
165
} static data;
166
167
/* StartThread function */
168
static DWORD WINAPI __stdcall ThreadProc(void *param);
169
};
170
171
/* MidiIn_OpenHelper class implementation
172
*/
173
MidiIn_OpenHelper::Data MidiIn_OpenHelper::data;
174
175
MidiIn_OpenHelper::Data::Data() {
176
threadHandle = NULL;
177
::InitializeCriticalSection(&crit_sect);
178
doEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
179
doneEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
180
if (doEvent != NULL && doneEvent != NULL)
181
threadHandle = ::CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
182
}
183
184
MidiIn_OpenHelper::Data::~Data() {
185
::EnterCriticalSection(&crit_sect);
186
if (threadHandle != NULL) {
187
// terminate thread
188
handle = NULL;
189
::SetEvent(doEvent);
190
::CloseHandle(threadHandle);
191
threadHandle = NULL;
192
}
193
::LeaveCriticalSection(&crit_sect);
194
// won't delete doEvent/doneEvent/crit_sect
195
// - Windows will do during process shutdown
196
}
197
198
DWORD WINAPI __stdcall MidiIn_OpenHelper::ThreadProc(void *param) {
199
while (1) {
200
// wait for something to do
201
::WaitForSingleObject(data.doEvent, INFINITE);
202
if (data.handle == NULL) {
203
// (data.handle == NULL) is a signal to terminate thread
204
break;
205
}
206
207
data.err = ::midiInOpen((HMIDIIN*)&(data.handle->deviceHandle),
208
data.deviceID, (UINT_PTR)&(MIDI_IN_PutMessage),
209
(UINT_PTR)data.handle,
210
CALLBACK_FUNCTION|MIDI_IO_STATUS);
211
212
::SetEvent(data.doneEvent);
213
}
214
return 0;
215
}
216
217
MMRESULT MidiIn_OpenHelper::midiInOpen(INT32 deviceID, MidiDeviceHandle* handle) {
218
MMRESULT err;
219
::EnterCriticalSection(&data.crit_sect);
220
if (!isInitialized()) {
221
::LeaveCriticalSection(&data.crit_sect);
222
return MMSYSERR_ERROR;
223
}
224
data.deviceID = deviceID;
225
data.handle = handle;
226
::SetEvent(data.doEvent);
227
::WaitForSingleObject(data.doneEvent, INFINITE);
228
err = data.err;
229
::LeaveCriticalSection(&data.crit_sect);
230
return err;
231
}
232
233
234
// PLATFORM_MIDI_IN method implementations
235
236
/* not thread safe */
237
static char winMidiInErrMsg[WIN_MAX_ERROR_LEN];
238
239
char* MIDI_IN_GetErrorStr(INT32 err) {
240
winMidiInErrMsg[0] = 0;
241
midiInGetErrorText((MMRESULT) err, winMidiInErrMsg, WIN_MAX_ERROR_LEN);
242
return winMidiInErrMsg;
243
}
244
245
INT32 MIDI_IN_GetNumDevices() {
246
return (INT32) midiInGetNumDevs();
247
}
248
249
INT32 getMidiInCaps(INT32 deviceID, MIDIINCAPSW* caps, INT32* err) {
250
(*err) = midiInGetDevCapsW(deviceID, caps, sizeof(MIDIINCAPSW));
251
return ((*err) == MMSYSERR_NOERROR);
252
}
253
254
INT32 MIDI_IN_GetDeviceName(INT32 deviceID, char *name, UINT32 nameLength) {
255
MIDIINCAPSW midiInCaps;
256
INT32 err;
257
258
memset(&midiInCaps, 0, sizeof(midiInCaps));
259
if (getMidiInCaps(deviceID, &midiInCaps, &err)) {
260
UnicodeToUTF8AndCopy(name, midiInCaps.szPname, nameLength);
261
return MIDI_SUCCESS;
262
}
263
MIDIIN_CHECK_ERROR;
264
return err;
265
}
266
267
268
INT32 MIDI_IN_GetDeviceVendor(INT32 deviceID, char *name, UINT32 nameLength) {
269
return MIDI_NOT_SUPPORTED;
270
}
271
272
273
INT32 MIDI_IN_GetDeviceDescription(INT32 deviceID, char *name, UINT32 nameLength) {
274
return MIDI_NOT_SUPPORTED;
275
}
276
277
278
279
INT32 MIDI_IN_GetDeviceVersion(INT32 deviceID, char *name, UINT32 nameLength) {
280
MIDIINCAPSW midiInCaps;
281
INT32 err = MIDI_NOT_SUPPORTED;
282
283
memset(&midiInCaps, 0, sizeof(midiInCaps));
284
if (getMidiInCaps(deviceID, &midiInCaps, &err) && (nameLength>7)) {
285
sprintf(name, "%d.%d", (midiInCaps.vDriverVersion & 0xFF00) >> 8, midiInCaps.vDriverVersion & 0xFF);
286
return MIDI_SUCCESS;
287
}
288
MIDIIN_CHECK_ERROR;
289
return err;
290
}
291
292
293
INT32 prepareBuffers(MidiDeviceHandle* handle) {
294
SysExQueue* sysex;
295
MMRESULT err = MMSYSERR_NOERROR;
296
int i;
297
298
if (!handle || !handle->longBuffers || !handle->deviceHandle) {
299
ERROR0("MIDI_IN_prepareBuffers: handle, or longBuffers, or deviceHandle==NULL\n");
300
return MIDI_INVALID_HANDLE;
301
}
302
sysex = (SysExQueue*) handle->longBuffers;
303
for (i = 0; i<sysex->count; i++) {
304
MIDIHDR* hdr = &(sysex->header[i]);
305
midiInPrepareHeader((HMIDIIN) handle->deviceHandle, hdr, sizeof(MIDIHDR));
306
err = midiInAddBuffer((HMIDIIN) handle->deviceHandle, hdr, sizeof(MIDIHDR));
307
}
308
MIDIIN_CHECK_ERROR;
309
return (INT32) err;
310
}
311
312
INT32 unprepareBuffers(MidiDeviceHandle* handle) {
313
SysExQueue* sysex;
314
MMRESULT err = MMSYSERR_NOERROR;
315
int i;
316
317
if (!handle || !handle->longBuffers || !handle->deviceHandle) {
318
ERROR0("MIDI_IN_unprepareBuffers: handle, or longBuffers, or deviceHandle==NULL\n");
319
return MIDI_INVALID_HANDLE;
320
}
321
sysex = (SysExQueue*) handle->longBuffers;
322
for (i = 0; i<sysex->count; i++) {
323
err = midiInUnprepareHeader((HMIDIIN) handle->deviceHandle, &(sysex->header[i]), sizeof(MIDIHDR));
324
}
325
MIDIIN_CHECK_ERROR;
326
return (INT32) err;
327
}
328
329
INT32 MIDI_IN_OpenDevice(INT32 deviceID, MidiDeviceHandle** handle) {
330
MMRESULT err;
331
332
TRACE0("> MIDI_IN_OpenDevice\n");
333
#ifdef USE_ERROR
334
setvbuf(stdout, NULL, (int)_IONBF, 0);
335
setvbuf(stderr, NULL, (int)_IONBF, 0);
336
#endif
337
338
(*handle) = (MidiDeviceHandle*) malloc(sizeof(MidiDeviceHandle));
339
if (!(*handle)) {
340
ERROR0("< ERROR: MIDI_IN_OpenDevice: out of memory\n");
341
return MIDI_OUT_OF_MEMORY;
342
}
343
memset(*handle, 0, sizeof(MidiDeviceHandle));
344
345
// create queue
346
(*handle)->queue = MIDI_CreateQueue(MIDI_IN_MESSAGE_QUEUE_SIZE);
347
if (!(*handle)->queue) {
348
ERROR0("< ERROR: MIDI_IN_OpenDevice: could not create queue\n");
349
free(*handle);
350
(*handle) = NULL;
351
return MIDI_OUT_OF_MEMORY;
352
}
353
354
// create long buffer queue
355
if (!MIDI_WinCreateLongBufferQueue(*handle, MIDI_IN_LONG_QUEUE_SIZE, MIDI_IN_LONG_MESSAGE_SIZE, NULL)) {
356
ERROR0("< ERROR: MIDI_IN_OpenDevice: could not create long Buffers\n");
357
MIDI_DestroyQueue((*handle)->queue);
358
free(*handle);
359
(*handle) = NULL;
360
return MIDI_OUT_OF_MEMORY;
361
}
362
363
// finally open the device
364
err = MidiIn_OpenHelper::midiInOpen(deviceID, *handle);
365
366
if ((err != MMSYSERR_NOERROR) || (!(*handle)->deviceHandle)) {
367
MIDIIN_CHECK_ERROR;
368
MIDI_WinDestroyLongBufferQueue(*handle);
369
MIDI_DestroyQueue((*handle)->queue);
370
free(*handle);
371
(*handle) = NULL;
372
return (INT32) err;
373
}
374
375
prepareBuffers(*handle);
376
MIDI_SetStartTime(*handle);
377
TRACE0("< MIDI_IN_OpenDevice: midiInOpen succeeded\n");
378
return MIDI_SUCCESS;
379
}
380
381
382
INT32 MIDI_IN_CloseDevice(MidiDeviceHandle* handle) {
383
MMRESULT err;
384
385
TRACE0("> MIDI_IN_CloseDevice: midiInClose\n");
386
if (!handle) {
387
ERROR0("ERROR: MIDI_IN_CloseDevice: handle is NULL\n");
388
return MIDI_INVALID_HANDLE;
389
}
390
midiInReset((HMIDIIN) handle->deviceHandle);
391
unprepareBuffers(handle);
392
err = midiInClose((HMIDIIN) handle->deviceHandle);
393
handle->deviceHandle=NULL;
394
MIDIIN_CHECK_ERROR;
395
MIDI_WinDestroyLongBufferQueue(handle);
396
397
if (handle->queue!=NULL) {
398
MidiMessageQueue* queue = handle->queue;
399
handle->queue = NULL;
400
MIDI_DestroyQueue(queue);
401
}
402
free(handle);
403
404
TRACE0("< MIDI_IN_CloseDevice: midiInClose succeeded\n");
405
return (INT32) err;
406
}
407
408
409
INT32 MIDI_IN_StartDevice(MidiDeviceHandle* handle) {
410
MMRESULT err;
411
412
if (!handle || !handle->deviceHandle || !handle->queue) {
413
ERROR0("ERROR: MIDI_IN_StartDevice: handle or queue is NULL\n");
414
return MIDI_INVALID_HANDLE;
415
}
416
417
// clear all the events from the queue
418
MIDI_QueueClear(handle->queue);
419
420
handle->platformData = (void*) CreateEvent(NULL, FALSE /*manual reset*/, FALSE /*signaled*/, NULL);
421
if (!handle->platformData) {
422
ERROR0("ERROR: MIDI_IN_StartDevice: could not create event\n");
423
return MIDI_OUT_OF_MEMORY;
424
}
425
426
err = midiInStart((HMIDIIN) handle->deviceHandle);
427
/* $$mp 200308-11: This method is already called in ...open(). It is
428
unclear why it is called again. The specification says that
429
MidiDevice.getMicrosecondPosition() returns the time since the
430
device was opened (the spec doesn't know about start/stop).
431
So I guess this call is obsolete. */
432
MIDI_SetStartTime(handle);
433
434
MIDIIN_CHECK_ERROR;
435
TRACE0("MIDI_IN_StartDevice: midiInStart finished\n");
436
return (INT32) err;
437
}
438
439
440
INT32 MIDI_IN_StopDevice(MidiDeviceHandle* handle) {
441
MMRESULT err;
442
HANDLE event;
443
444
TRACE0("> MIDI_IN_StopDevice: midiInStop \n");
445
if (!handle || !handle->platformData) {
446
ERROR0("ERROR: MIDI_IN_StopDevice: handle or event is NULL\n");
447
return MIDI_INVALID_HANDLE;
448
}
449
// encourage MIDI_IN_GetMessage to return soon
450
event = handle->platformData;
451
handle->platformData = NULL;
452
SetEvent(event);
453
454
err = midiInStop((HMIDIIN) handle->deviceHandle);
455
456
// wait until the Java thread has exited
457
while (handle->isWaiting) Sleep(0);
458
CloseHandle(event);
459
460
MIDIIN_CHECK_ERROR;
461
TRACE0("< MIDI_IN_StopDevice: midiInStop finished\n");
462
return (INT32) err;
463
}
464
465
466
/* return time stamp in microseconds */
467
INT64 MIDI_IN_GetTimeStamp(MidiDeviceHandle* handle) {
468
return MIDI_GetTimeStamp(handle);
469
}
470
471
472
// read the next message from the queue
473
MidiMessage* MIDI_IN_GetMessage(MidiDeviceHandle* handle) {
474
if (handle == NULL) {
475
return NULL;
476
}
477
while (handle->queue!=NULL && handle->platformData!=NULL) {
478
MidiMessage* msg = MIDI_QueueRead(handle->queue);
479
DWORD res;
480
if (msg != NULL) {
481
//fprintf(stdout, "GetMessage returns index %d\n", msg->data.l.index); fflush(stdout);
482
return msg;
483
}
484
TRACE0("MIDI_IN_GetMessage: before waiting\n");
485
handle->isWaiting = TRUE;
486
res = WaitForSingleObject((HANDLE) handle->platformData, 2000);
487
handle->isWaiting = FALSE;
488
if (res == WAIT_TIMEOUT) {
489
// break out back to Java from time to time - just to be sure
490
TRACE0("MIDI_IN_GetMessage: waiting finished with timeout\n");
491
break;
492
}
493
TRACE0("MIDI_IN_GetMessage: waiting finished\n");
494
}
495
return NULL;
496
}
497
498
void MIDI_IN_ReleaseMessage(MidiDeviceHandle* handle, MidiMessage* msg) {
499
SysExQueue* sysex;
500
if (handle == NULL || handle->queue == NULL) {
501
return;
502
}
503
sysex = (SysExQueue*) handle->longBuffers;
504
if (msg->type == LONG_MESSAGE && sysex) {
505
MIDIHDR* hdr = &(sysex->header[msg->data.l.index]);
506
//fprintf(stdout, "ReleaseMessage index %d\n", msg->data.l.index); fflush(stdout);
507
hdr->dwBytesRecorded = 0;
508
midiInAddBuffer((HMIDIIN) handle->deviceHandle, hdr, sizeof(MIDIHDR));
509
}
510
MIDI_QueueRemove(handle->queue, TRUE /*onlyLocked*/);
511
}
512
513
#endif // USE_PLATFORM_MIDI_IN
514
515