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_MidiOut.c
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 "PLATFORM_API_WinOS_Util.h"
30
31
/* include to prevent charset problem */
32
#include "PLATFORM_API_WinOS_Charset_Util.h"
33
34
#if USE_PLATFORM_MIDI_OUT == TRUE
35
36
37
#ifdef USE_ERROR
38
#include <stdio.h>
39
40
#define MIDIOUT_CHECK_ERROR { \
41
if (err != MMSYSERR_NOERROR) \
42
ERROR3("MIDI OUT Error in %s:%d : %s\n", __FILE__, __LINE__, MIDI_OUT_GetErrorStr((INT32) err)); \
43
}
44
#else
45
#define MIDIOUT_CHECK_ERROR
46
#endif
47
48
/* *************************** MidiOutDeviceProvider implementation *********************************** */
49
50
/* not thread safe */
51
static char winMidiOutErrMsg[WIN_MAX_ERROR_LEN];
52
53
char* MIDI_OUT_GetErrorStr(INT32 err) {
54
winMidiOutErrMsg[0] = 0;
55
midiOutGetErrorText((MMRESULT) err, winMidiOutErrMsg, WIN_MAX_ERROR_LEN);
56
return winMidiOutErrMsg;
57
}
58
59
INT32 MIDI_OUT_GetNumDevices() {
60
// add one for the MIDI_MAPPER
61
// we want to return it first so it'll be the default, so we
62
// decrement each deviceID for these methods....
63
return (INT32) (midiOutGetNumDevs() + 1);
64
}
65
66
67
INT32 getMidiOutCaps(INT32 deviceID, MIDIOUTCAPSW* caps, INT32* err) {
68
UINT_PTR id;
69
if (deviceID == 0) {
70
id = MIDI_MAPPER;
71
} else {
72
id = (UINT_PTR)(deviceID-1);
73
}
74
(*err) = (INT32) midiOutGetDevCapsW(id, caps, sizeof(MIDIOUTCAPSW));
75
return ((*err) == MMSYSERR_NOERROR);
76
}
77
78
79
INT32 MIDI_OUT_GetDeviceName(INT32 deviceID, char *name, UINT32 nameLength) {
80
MIDIOUTCAPSW midiOutCaps;
81
INT32 err;
82
83
memset(&midiOutCaps, 0, sizeof(midiOutCaps));
84
if (getMidiOutCaps(deviceID, &midiOutCaps, &err)) {
85
UnicodeToUTF8AndCopy(name, midiOutCaps.szPname, nameLength);
86
return MIDI_SUCCESS;
87
}
88
MIDIOUT_CHECK_ERROR;
89
return err;
90
}
91
92
93
INT32 MIDI_OUT_GetDeviceVendor(INT32 deviceID, char *name, UINT32 nameLength) {
94
return MIDI_NOT_SUPPORTED;
95
}
96
97
98
INT32 MIDI_OUT_GetDeviceDescription(INT32 deviceID, char *name, UINT32 nameLength) {
99
MIDIOUTCAPSW midiOutCaps;
100
char *desc;
101
INT32 err;
102
103
memset(&midiOutCaps, 0, sizeof(midiOutCaps));
104
if (getMidiOutCaps(deviceID, &midiOutCaps, &err)) {
105
int tech = (int)midiOutCaps.wTechnology;
106
switch(tech) {
107
case MOD_MIDIPORT:
108
desc = "External MIDI Port";
109
break;
110
case MOD_SQSYNTH:
111
desc = "Internal square wave synthesizer";
112
break;
113
case MOD_FMSYNTH:
114
desc = "Internal FM synthesizer";
115
break;
116
case MOD_SYNTH:
117
desc = "Internal synthesizer (generic)";
118
break;
119
case MOD_MAPPER:
120
desc = "Windows MIDI_MAPPER";
121
break;
122
case 7 /* MOD_SWSYNTH*/:
123
desc = "Internal software synthesizer";
124
break;
125
default:
126
return MIDI_NOT_SUPPORTED;
127
}
128
strncpy(name, desc, nameLength-1);
129
name[nameLength-1] = 0;
130
return MIDI_SUCCESS;
131
}
132
return err;
133
}
134
135
136
INT32 MIDI_OUT_GetDeviceVersion(INT32 deviceID, char *name, UINT32 nameLength) {
137
MIDIOUTCAPSW midiOutCaps;
138
INT32 err;
139
140
memset(&midiOutCaps, 0, sizeof(midiOutCaps));
141
if (getMidiOutCaps(deviceID, &midiOutCaps, &err) && nameLength>7) {
142
sprintf(name, "%d.%d", (midiOutCaps.vDriverVersion & 0xFF00) >> 8, midiOutCaps.vDriverVersion & 0xFF);
143
return MIDI_SUCCESS;
144
}
145
MIDIOUT_CHECK_ERROR;
146
return err;
147
}
148
149
150
/* *************************** MidiOutDevice implementation ***************************************** */
151
152
153
INT32 unprepareLongBuffers(MidiDeviceHandle* handle) {
154
SysExQueue* sysex;
155
MMRESULT err = MMSYSERR_NOERROR;
156
int i;
157
158
if (!handle || !handle->deviceHandle || !handle->longBuffers) {
159
ERROR0("MIDI_OUT_unprepareLongBuffers: handle, deviceHandle, or longBuffers == NULL\n");
160
return MIDI_INVALID_HANDLE;
161
}
162
sysex = (SysExQueue*) handle->longBuffers;
163
for (i = 0; i<sysex->count; i++) {
164
MIDIHDR* hdr = &(sysex->header[i]);
165
if (hdr->dwFlags) {
166
err = midiOutUnprepareHeader((HMIDIOUT) handle->deviceHandle, hdr, sizeof(MIDIHDR));
167
}
168
}
169
MIDIOUT_CHECK_ERROR;
170
return (INT32) err;
171
}
172
173
INT32 freeLongBuffer(MIDIHDR* hdr, HMIDIOUT deviceHandle, INT32 minToLeaveData) {
174
MMRESULT err = MMSYSERR_NOERROR;
175
176
if (!hdr) {
177
ERROR0("MIDI_OUT_freeLongBuffer: hdr == NULL\n");
178
return MIDI_INVALID_HANDLE;
179
}
180
if (hdr->dwFlags && deviceHandle) {
181
err = midiOutUnprepareHeader(deviceHandle, hdr, sizeof(MIDIHDR));
182
}
183
if (hdr->lpData && (((INT32) hdr->dwBufferLength) < minToLeaveData || minToLeaveData < 0)) {
184
free(hdr->lpData);
185
hdr->lpData=NULL;
186
hdr->dwBufferLength=0;
187
}
188
hdr->dwBytesRecorded=0;
189
hdr->dwFlags=0;
190
return (INT32) err;
191
}
192
193
INT32 freeLongBuffers(MidiDeviceHandle* handle) {
194
SysExQueue* sysex;
195
MMRESULT err = MMSYSERR_NOERROR;
196
int i;
197
198
if (!handle || !handle->longBuffers) {
199
ERROR0("MIDI_OUT_freeLongBuffers: handle or longBuffers == NULL\n");
200
return MIDI_INVALID_HANDLE;
201
}
202
sysex = (SysExQueue*) handle->longBuffers;
203
for (i = 0; i<sysex->count; i++) {
204
err = freeLongBuffer(&(sysex->header[i]), (HMIDIOUT) handle->deviceHandle, -1);
205
}
206
MIDIOUT_CHECK_ERROR;
207
return (INT32) err;
208
}
209
210
INT32 MIDI_OUT_OpenDevice(INT32 deviceID, MidiDeviceHandle** handle) {
211
MMRESULT err;
212
213
TRACE1(">> MIDI_OUT_OpenDevice: deviceID: %d\n", deviceID);
214
215
if (deviceID == 0) {
216
deviceID = MIDI_MAPPER;
217
} else {
218
deviceID--;
219
}
220
#ifdef USE_ERROR
221
setvbuf(stdout, NULL, (int)_IONBF, 0);
222
setvbuf(stderr, NULL, (int)_IONBF, 0);
223
#endif
224
225
(*handle) = (MidiDeviceHandle*) malloc(sizeof(MidiDeviceHandle));
226
if (!(*handle)) {
227
ERROR0("ERROR: MIDI_OUT_OpenDevice: out of memory\n");
228
return MIDI_OUT_OF_MEMORY;
229
}
230
memset(*handle, 0, sizeof(MidiDeviceHandle));
231
232
// create long buffer queue
233
if (!MIDI_WinCreateEmptyLongBufferQueue(*handle, MIDI_OUT_LONG_QUEUE_SIZE)) {
234
ERROR0("ERROR: MIDI_OUT_OpenDevice: could not create long Buffers\n");
235
free(*handle);
236
(*handle) = NULL;
237
return MIDI_OUT_OF_MEMORY;
238
}
239
240
// create notification event
241
(*handle)->platformData = (void*) CreateEvent(NULL, FALSE /*manual reset*/, FALSE /*signaled*/, NULL);
242
if (!(*handle)->platformData) {
243
ERROR0("ERROR: MIDI_OUT_StartDevice: could not create event\n");
244
MIDI_WinDestroyLongBufferQueue(*handle);
245
free(*handle);
246
(*handle) = NULL;
247
return MIDI_OUT_OF_MEMORY;
248
}
249
250
// finally open the device
251
err = midiOutOpen((HMIDIOUT*) &((*handle)->deviceHandle), deviceID,
252
(UINT_PTR) (*handle)->platformData, (UINT_PTR) (*handle), CALLBACK_EVENT);
253
254
if ((err != MMSYSERR_NOERROR) || (!(*handle)->deviceHandle)) {
255
/* some devices return non zero, but no error! */
256
if (midiOutShortMsg((HMIDIOUT) ((*handle)->deviceHandle),0) == MMSYSERR_INVALHANDLE) {
257
MIDIOUT_CHECK_ERROR;
258
CloseHandle((HANDLE) (*handle)->platformData);
259
MIDI_WinDestroyLongBufferQueue(*handle);
260
free(*handle);
261
(*handle) = NULL;
262
return (INT32) err;
263
}
264
}
265
//$$fb enable high resolution time
266
timeBeginPeriod(1);
267
MIDI_SetStartTime(*handle);
268
TRACE0("<< MIDI_OUT_OpenDevice: succeeded\n");
269
return MIDI_SUCCESS;
270
}
271
272
INT32 MIDI_OUT_CloseDevice(MidiDeviceHandle* handle) {
273
MMRESULT err = MMSYSERR_NOERROR;
274
HANDLE event;
275
276
TRACE0("> MIDI_OUT_CloseDevice\n");
277
if (!handle) {
278
ERROR0("ERROR: MIDI_OUT_StopDevice: handle is NULL\n");
279
return MIDI_INVALID_HANDLE; // failure
280
}
281
// encourage MIDI_OUT_SendLongMessage to return soon
282
event = handle->platformData;
283
handle->platformData = NULL;
284
if (event) {
285
SetEvent(event);
286
} else {
287
ERROR0("ERROR: MIDI_OUT_StopDevice: event is NULL\n");
288
}
289
290
if (handle->deviceHandle) {
291
//$$fb disable high resolution time
292
timeEndPeriod(1);
293
err = midiOutReset((HMIDIOUT) handle->deviceHandle);
294
} else {
295
ERROR0("ERROR: MIDI_OUT_CloseDevice: deviceHandle is NULL\n");
296
}
297
298
// issue a "SUSTAIN OFF" message to each MIDI channel, 0 to 15.
299
// "CONTROL CHANGE" is 176, "SUSTAIN CONTROLLER" is 64, and the value is 0.
300
// $$fb 2002-04-04: It is responsability of the application developer to
301
// leave the device in a consistent state. So I put this in comments
302
/*
303
for (channel = 0; channel < 16; channel++)
304
MIDI_OUT_SendShortMessage(deviceHandle, (unsigned char)(176 + channel), (unsigned char)64, (unsigned char)0, (UINT32)-1);
305
*/
306
307
if (event) {
308
// wait until MIDI_OUT_SendLongMessage has finished
309
while (handle->isWaiting) Sleep(0);
310
}
311
312
unprepareLongBuffers(handle);
313
314
if (handle->deviceHandle) {
315
err = midiOutClose((HMIDIOUT) handle->deviceHandle);
316
MIDIOUT_CHECK_ERROR;
317
handle->deviceHandle = NULL;
318
}
319
freeLongBuffers(handle);
320
321
if (event) {
322
CloseHandle(event);
323
}
324
MIDI_WinDestroyLongBufferQueue(handle);
325
free(handle);
326
327
TRACE0("< MIDI_OUT_CloseDevice\n");
328
return (INT32) err;
329
}
330
331
332
/* return time stamp in microseconds */
333
INT64 MIDI_OUT_GetTimeStamp(MidiDeviceHandle* handle) {
334
return MIDI_GetTimeStamp(handle);
335
}
336
337
338
INT32 MIDI_OUT_SendShortMessage(MidiDeviceHandle* handle, UINT32 packedMsg, UINT32 timestamp) {
339
MMRESULT err = MMSYSERR_NOERROR;
340
341
TRACE2("> MIDI_OUT_SendShortMessage %x, time: %d\n", packedMsg, timestamp);
342
if (!handle) {
343
ERROR0("ERROR: MIDI_OUT_SendShortMessage: handle is NULL\n");
344
return MIDI_INVALID_HANDLE; // failure
345
}
346
err = midiOutShortMsg((HMIDIOUT) handle->deviceHandle, packedMsg);
347
MIDIOUT_CHECK_ERROR;
348
TRACE0("< MIDI_OUT_SendShortMessage\n");
349
return (INT32) err;
350
}
351
352
INT32 MIDI_OUT_SendLongMessage(MidiDeviceHandle* handle, UBYTE* data, UINT32 size, UINT32 timestamp) {
353
MMRESULT err;
354
SysExQueue* sysex;
355
MIDIHDR* hdr = NULL;
356
INT32 remainingSize;
357
int i;
358
359
TRACE2("> MIDI_OUT_SendLongMessage size %d, time: %d\n", size, timestamp);
360
if (!handle || !data || !handle->longBuffers) {
361
ERROR0("< ERROR: MIDI_OUT_SendLongMessage: handle, data, or longBuffers is NULL\n");
362
return MIDI_INVALID_HANDLE; // failure
363
}
364
if (size == 0) {
365
return MIDI_SUCCESS;
366
}
367
368
sysex = (SysExQueue*) handle->longBuffers;
369
remainingSize = size;
370
371
// send in chunks of 512 bytes
372
size = 512;
373
while (remainingSize > 0) {
374
if (remainingSize < (INT32) size) {
375
size = (UINT32) remainingSize;
376
}
377
378
while (!hdr && handle->platformData) {
379
/* find a non-queued header */
380
for (i = 0; i < sysex->count; i++) {
381
hdr = &(sysex->header[i]);
382
if ((hdr->dwFlags & MHDR_DONE) || (hdr->dwFlags == 0)) {
383
break;
384
}
385
hdr = NULL;
386
}
387
/* wait for a buffer to free up */
388
if (!hdr && handle->platformData) {
389
DWORD res;
390
TRACE0(" Need to wait for free buffer\n");
391
handle->isWaiting = TRUE;
392
res = WaitForSingleObject((HANDLE) handle->platformData, 700);
393
handle->isWaiting = FALSE;
394
if (res == WAIT_TIMEOUT) {
395
// break out back to Java if no buffer freed up after 700 milliseconds
396
TRACE0("-> TIMEOUT. Need to go back to Java\n");
397
break;
398
}
399
}
400
}
401
if (!hdr) {
402
// no free buffer
403
return MIDI_NOT_SUPPORTED;
404
}
405
406
TRACE2("-> sending %d bytes with buffer index=%d\n", (int) size, (int) hdr->dwUser);
407
freeLongBuffer(hdr, handle->deviceHandle, (INT32) size);
408
if (hdr->lpData == NULL) {
409
hdr->lpData = malloc(size);
410
hdr->dwBufferLength = size;
411
}
412
hdr->dwBytesRecorded = size;
413
memcpy(hdr->lpData, data, size);
414
err = midiOutPrepareHeader((HMIDIOUT) handle->deviceHandle, hdr, sizeof(MIDIHDR));
415
if (err != MMSYSERR_NOERROR) {
416
freeLongBuffer(hdr, handle->deviceHandle, -1);
417
MIDIOUT_CHECK_ERROR;
418
return (INT32) err;
419
}
420
err = midiOutLongMsg((HMIDIOUT) handle->deviceHandle, hdr, sizeof(MIDIHDR));
421
if (err != MMSYSERR_NOERROR) {
422
freeLongBuffer(hdr, handle->deviceHandle, -1);
423
ERROR0("ERROR: MIDI_OUT_SendLongMessage: midiOutLongMsg returned error:\n");
424
MIDIOUT_CHECK_ERROR;
425
return (INT32) err;
426
}
427
remainingSize -= size;
428
data += size;
429
}
430
TRACE0("< MIDI_OUT_SendLongMessage success\n");
431
return MIDI_SUCCESS;
432
}
433
434
#endif // USE_PLATFORM_MIDI_OUT
435
436