ntdll/tests: Adjust test_virtual_unwind() for Win11 results.
[wine.git] / dlls / winecoreaudio.drv / coremidi.c
blobc9b377f68b0eed64f5eec2c877e90563128edf66
1 /*
2 * MIDI driver for macOS (unixlib)
4 * Copyright 1994 Martin Ayotte
5 * Copyright 1998 Luiz Otavio L. Zorzella
6 * Copyright 1998, 1999 Eric POUECH
7 * Copyright 2005, 2006 Emmanuel Maillard
8 * Copyright 2021 Huw Davies
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #if 0
25 #pragma makedep unix
26 #endif
28 #include "config.h"
30 #define ULONG __carbon_ULONG
31 #define E_INVALIDARG __carbon_E_INVALIDARG
32 #define E_OUTOFMEMORY __carbon_E_OUTOFMEMORY
33 #define E_HANDLE __carbon_E_HANDLE
34 #define E_ACCESSDENIED __carbon_E_ACCESSDENIED
35 #define E_UNEXPECTED __carbon_E_UNEXPECTED
36 #define E_FAIL __carbon_E_FAIL
37 #define E_ABORT __carbon_E_ABORT
38 #define E_POINTER __carbon_E_POINTER
39 #define E_NOINTERFACE __carbon_E_NOINTERFACE
40 #define E_NOTIMPL __carbon_E_NOTIMPL
41 #define S_FALSE __carbon_S_FALSE
42 #define S_OK __carbon_S_OK
43 #define HRESULT_FACILITY __carbon_HRESULT_FACILITY
44 #define IS_ERROR __carbon_IS_ERROR
45 #define FAILED __carbon_FAILED
46 #define SUCCEEDED __carbon_SUCCEEDED
47 #define MAKE_HRESULT __carbon_MAKE_HRESULT
48 #define HRESULT __carbon_HRESULT
49 #define STDMETHODCALLTYPE __carbon_STDMETHODCALLT
50 #include <mach/mach_time.h>
51 #include <CoreMIDI/CoreMIDI.h>
52 #include <AudioUnit/AudioUnit.h>
53 #include <AudioToolbox/AudioToolbox.h>
54 #undef ULONG
55 #undef E_INVALIDARG
56 #undef E_OUTOFMEMORY
57 #undef E_HANDLE
58 #undef E_ACCESSDENIED
59 #undef E_UNEXPECTED
60 #undef E_FAIL
61 #undef E_ABORT
62 #undef E_POINTER
63 #undef E_NOINTERFACE
64 #undef E_NOTIMPL
65 #undef S_FALSE
66 #undef S_OK
67 #undef HRESULT_FACILITY
68 #undef IS_ERROR
69 #undef FAILED
70 #undef SUCCEEDED
71 #undef MAKE_HRESULT
72 #undef HRESULT
73 #undef STDMETHODCALLTYPE
75 #include <pthread.h>
77 #include "ntstatus.h"
78 #define WIN32_NO_STATUS
79 #include "windef.h"
80 #include "winbase.h"
81 #include "winnls.h"
82 #include "winreg.h"
83 #include "winternl.h"
84 #include "mmsystem.h"
85 #include "mmddk.h"
86 #include "mmdeviceapi.h"
87 #include "audioclient.h"
88 #include "wine/debug.h"
89 #include "wine/unixlib.h"
91 #include "coreaudio.h"
92 #include "unixlib.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(midi);
96 struct midi_dest
98 /* graph and synth are only used for MIDI Synth */
99 AUGraph graph;
100 AudioUnit synth;
102 MIDIEndpointRef dest;
104 MIDIOUTCAPSW caps;
105 MIDIOPENDESC midiDesc;
106 BYTE runningStatus;
107 WORD wFlags;
110 struct midi_src
112 MIDIEndpointRef source;
114 WORD wDevID;
115 int state; /* 0 is no recording started, 1 in recording, bit 2 set if in sys exclusive recording */
116 MIDIINCAPSW caps;
117 MIDIOPENDESC midiDesc;
118 LPMIDIHDR lpQueueHdr;
119 WORD wFlags;
120 UINT startTime;
123 static MIDIClientRef midi_client;
124 static MIDIPortRef midi_out_port, midi_in_port;
125 static UINT num_dests, num_srcs;
126 static struct midi_dest *dests;
127 static struct midi_src *srcs;
129 static pthread_mutex_t midi_in_mutex = PTHREAD_MUTEX_INITIALIZER;
131 #define NOTIFY_BUFFER_SIZE 64 + 1 /* + 1 for the sentinel */
132 static pthread_mutex_t notify_mutex = PTHREAD_MUTEX_INITIALIZER;
133 static pthread_cond_t notify_cond = PTHREAD_COND_INITIALIZER;
134 static BOOL notify_quit;
135 static struct notify_context notify_buffer[NOTIFY_BUFFER_SIZE];
136 static struct notify_context *notify_read, *notify_write;
138 #define MAX_MIDI_SYNTHS 1
140 static void midi_in_lock(BOOL lock)
142 if (lock) pthread_mutex_lock(&midi_in_mutex);
143 else pthread_mutex_unlock(&midi_in_mutex);
146 static void set_in_notify(struct notify_context *notify, struct midi_src *src, WORD dev_id, WORD msg,
147 UINT_PTR param_1, UINT_PTR param_2)
149 notify->send_notify = TRUE;
150 notify->dev_id = dev_id;
151 notify->msg = msg;
152 notify->param_1 = param_1;
153 notify->param_2 = param_2;
154 notify->callback = src->midiDesc.dwCallback;
155 notify->flags = src->wFlags;
156 notify->device = src->midiDesc.hMidi;
157 notify->instance = src->midiDesc.dwInstance;
161 * notify buffer: The notification ring buffer is implemented so that
162 * there is always at least one unused sentinel before the current
163 * read position in order to allow detection of the full vs empty
164 * state.
166 static struct notify_context *notify_buffer_next(struct notify_context *notify)
168 if (++notify >= notify_buffer + ARRAY_SIZE(notify_buffer))
169 notify = notify_buffer;
171 return notify;
174 static void notify_buffer_add(struct notify_context *notify)
176 struct notify_context *next = notify_buffer_next(notify_write);
178 if (next == notify_read) /* buffer is full - we can't issue a WARN() in a non-Win32 thread */
179 notify_read = notify_buffer_next(notify_read); /* drop the oldest notification */
180 *notify_write = *notify;
181 notify_write = next;
184 static BOOL notify_buffer_empty(void)
186 return notify_read == notify_write;
189 static BOOL notify_buffer_remove(struct notify_context *notify)
191 if (notify_buffer_empty()) return FALSE;
193 *notify = *notify_read;
194 notify_read = notify_buffer_next(notify_read);
195 return TRUE;
198 static void notify_post(struct notify_context *notify)
200 pthread_mutex_lock(&notify_mutex);
202 if (notify) notify_buffer_add(notify);
203 else notify_quit = TRUE;
204 pthread_cond_signal(&notify_cond);
206 pthread_mutex_unlock(&notify_mutex);
210 * CoreMIDI IO threaded callback,
211 * we can't call Wine debug channels, critical section or anything using NtCurrentTeb here.
213 static uint64_t get_time_ms(void)
215 static mach_timebase_info_data_t timebase;
217 if (!timebase.denom) mach_timebase_info(&timebase);
218 return mach_absolute_time() / 1000000 * timebase.numer / timebase.denom;
221 static void process_sysex_packet(struct midi_src *src, MIDIPacket *packet)
223 unsigned int pos = 0, len = packet->length, copy_len;
224 UINT current_time = get_time_ms() - src->startTime;
225 struct notify_context notify;
227 src->state |= 2;
229 midi_in_lock(TRUE);
231 while (len)
233 MIDIHDR *hdr = src->lpQueueHdr;
234 if (!hdr) break;
236 copy_len = min(len, hdr->dwBufferLength - hdr->dwBytesRecorded);
237 memcpy(hdr->lpData + hdr->dwBytesRecorded, packet->data + pos, copy_len);
238 hdr->dwBytesRecorded += copy_len;
239 len -= copy_len;
240 pos += copy_len;
242 if ((hdr->dwBytesRecorded == hdr->dwBufferLength) ||
243 (*(BYTE*)(hdr->lpData + hdr->dwBytesRecorded - 1) == 0xf7))
244 { /* buffer full or end of sysex message */
245 src->lpQueueHdr = hdr->lpNext;
246 hdr->dwFlags &= ~MHDR_INQUEUE;
247 hdr->dwFlags |= MHDR_DONE;
248 set_in_notify(&notify, src, src->wDevID, MIM_LONGDATA, (UINT_PTR)hdr, current_time);
249 notify_post(&notify);
250 src->state &= ~2;
254 midi_in_lock(FALSE);
257 static void process_small_packet(struct midi_src *src, MIDIPacket *packet)
259 UINT current_time = get_time_ms() - src->startTime, data;
260 struct notify_context notify;
261 unsigned int pos = 0;
263 while (pos < packet->length)
265 data = 0;
266 switch (packet->data[pos] & 0xf0)
268 case 0xf0:
269 data = packet->data[pos];
270 pos++;
271 break;
272 case 0xc0:
273 case 0xd0:
274 data = (packet->data[pos + 1] << 8) | packet->data[pos];
275 pos += 2;
276 break;
277 default:
278 data = (packet->data[pos + 2] << 16) | (packet->data[pos + 1] << 8) |
279 packet->data[pos];
280 pos += 3;
281 break;
283 set_in_notify(&notify, src, src->wDevID, MIM_DATA, data, current_time);
284 notify_post(&notify);
288 static void midi_in_read_proc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon)
290 MIDIPacket *packet = (MIDIPacket *)pktlist->packet;
291 WORD dev_id = *(WORD *)connRefCon;
292 struct midi_src *src;
293 unsigned int i;
295 if (dev_id >= num_srcs) return;
296 src = srcs + dev_id;
297 if (src->state < 1) /* input not started */
298 return;
300 for (i = 0; i < pktlist->numPackets; ++i)
302 if (packet->data[0] == 0xf0 || src->state & 2)
303 process_sysex_packet(src, packet);
304 else
305 process_small_packet(src, packet);
307 packet = MIDIPacketNext(packet);
311 NTSTATUS unix_midi_init(void *args)
313 CFStringRef name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("wineMIDIClient.%d"), getpid());
314 struct midi_init_params *params = args;
315 OSStatus sc;
316 UINT i;
318 pthread_mutex_lock(&notify_mutex);
319 notify_quit = FALSE;
320 notify_read = notify_write = notify_buffer;
321 pthread_mutex_unlock(&notify_mutex);
323 sc = MIDIClientCreate(name, NULL /* FIXME use notify proc */, NULL, &midi_client);
324 CFRelease(name);
325 if (sc)
327 ERR("can't create MIDI Client\n");
328 *params->err = DRV_FAILURE;
329 return STATUS_SUCCESS;
332 num_dests = MAX_MIDI_SYNTHS + MIDIGetNumberOfDestinations();
333 num_srcs = MIDIGetNumberOfSources();
335 TRACE("num_dests %d num_srcs %d\n", num_dests, num_srcs);
337 dests = calloc(num_dests, sizeof(*dests));
338 srcs = calloc(num_srcs, sizeof(*srcs));
340 if (num_srcs > 0)
342 name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("WineInputPort.%u"), getpid());
343 MIDIInputPortCreate(midi_client, name, midi_in_read_proc, NULL, &midi_in_port);
344 CFRelease(name);
347 if (num_dests > MAX_MIDI_SYNTHS)
349 name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("WineOutputPort.%u"), getpid());
350 MIDIOutputPortCreate(midi_client, name, &midi_out_port);
351 CFRelease(name);
354 /* initialize sources */
355 for (i = 0; i < num_srcs; i++)
357 srcs[i].wDevID = i;
358 srcs[i].source = MIDIGetSource(i);
360 sc = MIDIObjectGetStringProperty(srcs[i].source, kMIDIPropertyName, &name);
361 if (!sc)
363 int len = min(CFStringGetLength(name), ARRAY_SIZE(srcs[i].caps.szPname) - 1);
364 CFStringGetCharacters(name, CFRangeMake(0, len), srcs[i].caps.szPname);
365 srcs[i].caps.szPname[len] = '\0';
367 MIDIPortConnectSource(midi_in_port, srcs[i].source, &srcs[i].wDevID);
369 srcs[i].state = 0;
370 /* FIXME */
371 srcs[i].caps.wMid = 0x00FF; /* Manufac ID */
372 srcs[i].caps.wPid = 0x0001; /* Product ID */
373 srcs[i].caps.vDriverVersion = 0x0001;
374 srcs[i].caps.dwSupport = 0;
377 /* initialise MIDI synths */
378 for (i = 0; i < MAX_MIDI_SYNTHS; i++)
380 static const WCHAR synth_name[] = {'C','o','r','e','A','u','d','i','o',' ','M','I','D','I',' ','S','y','n','t','h',' '};
382 C_ASSERT(MAX_MIDI_SYNTHS < 10);
383 memcpy(dests[i].caps.szPname, synth_name, sizeof(synth_name));
384 dests[i].caps.szPname[ARRAY_SIZE(synth_name)] = '1' + i;
385 dests[i].caps.szPname[ARRAY_SIZE(synth_name) + 1] = '\0';
387 dests[i].caps.wTechnology = MOD_SYNTH;
388 dests[i].caps.wChannelMask = 0xFFFF;
390 dests[i].caps.wMid = 0x00FF; /* Manufac ID */
391 dests[i].caps.wPid = 0x0001; /* Product ID */
392 dests[i].caps.vDriverVersion = 0x0001;
393 dests[i].caps.dwSupport = MIDICAPS_VOLUME;
394 dests[i].caps.wVoices = 16;
395 dests[i].caps.wNotes = 16;
397 /* initialise available destinations */
398 for (i = MAX_MIDI_SYNTHS; i < num_dests; i++)
400 dests[i].dest = MIDIGetDestination(i - MAX_MIDI_SYNTHS);
402 sc = MIDIObjectGetStringProperty(dests[i].dest, kMIDIPropertyName, &name);
403 if (!sc)
405 int len = min(CFStringGetLength(name), ARRAY_SIZE(dests[i].caps.szPname) - 1);
406 CFStringGetCharacters(name, CFRangeMake(0, len), dests[i].caps.szPname);
407 dests[i].caps.szPname[len] = '\0';
410 dests[i].caps.wTechnology = MOD_MIDIPORT;
411 dests[i].caps.wChannelMask = 0xFFFF;
413 dests[i].caps.wMid = 0x00FF; /* Manufac ID */
414 dests[i].caps.wPid = 0x0001;
415 dests[i].caps.vDriverVersion = 0x0001;
416 dests[i].caps.dwSupport = 0;
417 dests[i].caps.wVoices = 0;
418 dests[i].caps.wNotes = 0;
421 *params->err = DRV_SUCCESS;
422 return STATUS_SUCCESS;
425 NTSTATUS unix_midi_release(void *args)
427 /* stop the notify_wait thread */
428 notify_post(NULL);
430 if (midi_client) MIDIClientDispose(midi_client); /* MIDIClientDispose will close all ports */
432 free(srcs);
433 free(dests);
435 return STATUS_SUCCESS;
439 * MIDI Synth Unit
441 static BOOL synth_unit_create_default(AUGraph *graph, AudioUnit *synth)
443 AudioComponentDescription desc;
444 AUNode synth_node;
445 AUNode out_node;
446 OSStatus sc;
448 sc = NewAUGraph(graph);
449 if (sc != noErr)
451 ERR("NewAUGraph return %s\n", wine_dbgstr_fourcc(sc));
452 return FALSE;
455 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
456 desc.componentFlags = 0;
457 desc.componentFlagsMask = 0;
459 /* create synth node */
460 desc.componentType = kAudioUnitType_MusicDevice;
461 desc.componentSubType = kAudioUnitSubType_DLSSynth;
463 sc = AUGraphAddNode(*graph, &desc, &synth_node);
464 if (sc != noErr)
466 ERR("AUGraphAddNode cannot create synthNode : %s\n", wine_dbgstr_fourcc(sc));
467 return FALSE;
470 /* create out node */
471 desc.componentType = kAudioUnitType_Output;
472 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
474 sc = AUGraphAddNode(*graph, &desc, &out_node);
475 if (sc != noErr)
477 ERR("AUGraphAddNode cannot create outNode %s\n", wine_dbgstr_fourcc(sc));
478 return FALSE;
481 sc = AUGraphOpen(*graph);
482 if (sc != noErr)
484 ERR("AUGraphOpen returns %s\n", wine_dbgstr_fourcc(sc));
485 return FALSE;
488 /* connecting the nodes */
489 sc = AUGraphConnectNodeInput(*graph, synth_node, 0, out_node, 0);
490 if (sc != noErr)
492 ERR("AUGraphConnectNodeInput cannot connect synthNode to outNode : %s\n",
493 wine_dbgstr_fourcc(sc));
494 return FALSE;
497 /* Get the synth unit */
498 sc = AUGraphNodeInfo(*graph, synth_node, 0, synth);
499 if (sc != noErr)
501 ERR("AUGraphNodeInfo return %s\n", wine_dbgstr_fourcc(sc));
502 return FALSE;
505 return TRUE;
508 static BOOL synth_unit_init(AudioUnit synth, AUGraph graph)
510 OSStatus sc;
512 sc = AUGraphInitialize(graph);
513 if (sc != noErr)
515 ERR("AUGraphInitialize(%p) returns %s\n", graph, wine_dbgstr_fourcc(sc));
516 return FALSE;
519 sc = AUGraphStart(graph);
520 if (sc != noErr)
522 ERR("AUGraphStart(%p) returns %s\n", graph, wine_dbgstr_fourcc(sc));
523 return FALSE;
526 return TRUE;
529 static BOOL synth_unit_close(AUGraph graph)
531 OSStatus sc;
533 sc = AUGraphStop(graph);
534 if (sc != noErr)
536 ERR("AUGraphStop(%p) returns %s\n", graph, wine_dbgstr_fourcc(sc));
537 return FALSE;
540 sc = DisposeAUGraph(graph);
541 if (sc != noErr)
543 ERR("DisposeAUGraph(%p) returns %s\n", graph, wine_dbgstr_fourcc(sc));
544 return FALSE;
547 return TRUE;
550 static void set_out_notify(struct notify_context *notify, struct midi_dest *dest, WORD dev_id, WORD msg,
551 UINT_PTR param_1, UINT_PTR param_2)
553 notify->send_notify = TRUE;
554 notify->dev_id = dev_id;
555 notify->msg = msg;
556 notify->param_1 = param_1;
557 notify->param_2 = param_2;
558 notify->callback = dest->midiDesc.dwCallback;
559 notify->flags = dest->wFlags;
560 notify->device = dest->midiDesc.hMidi;
561 notify->instance = dest->midiDesc.dwInstance;
564 static UINT midi_out_open(WORD dev_id, MIDIOPENDESC *midi_desc, UINT flags, struct notify_context *notify)
566 struct midi_dest *dest;
568 TRACE("dev_id = %d desc = %p flags = %08x\n", dev_id, midi_desc, flags);
570 if (!midi_desc) return MMSYSERR_INVALPARAM;
572 if (dev_id >= num_dests)
574 WARN("bad device ID : %d\n", dev_id);
575 return MMSYSERR_BADDEVICEID;
577 if (dests[dev_id].midiDesc.hMidi != 0)
579 WARN("device already open!\n");
580 return MMSYSERR_ALLOCATED;
582 if ((flags & ~CALLBACK_TYPEMASK) != 0)
584 WARN("bad flags\n");
585 return MMSYSERR_INVALFLAG;
588 dest = dests + dev_id;
589 if (dest->caps.wTechnology == MOD_SYNTH)
591 if (!synth_unit_create_default(&dest->graph, &dest->synth))
593 ERR("SynthUnit_CreateDefaultSynthUnit dest=%p failed\n", dest);
594 return MMSYSERR_ERROR;
596 if (!synth_unit_init(dest->synth, dest->graph))
598 ERR("SynthUnit_Initialise dest=%p failed\n", dest);
599 return MMSYSERR_ERROR;
602 dest->runningStatus = 0;
603 dest->wFlags = HIWORD(flags & CALLBACK_TYPEMASK);
604 dest->midiDesc = *midi_desc;
606 set_out_notify(notify, dest, dev_id, MOM_OPEN, 0, 0);
608 return MMSYSERR_NOERROR;
611 static UINT midi_out_close(WORD dev_id, struct notify_context *notify)
613 struct midi_dest *dest;
615 TRACE("dev_id = %d\n", dev_id);
617 if (dev_id >= num_dests)
619 WARN("bad device ID : %d\n", dev_id);
620 return MMSYSERR_BADDEVICEID;
623 dest = dests + dev_id;
625 if (dest->caps.wTechnology == MOD_SYNTH)
626 synth_unit_close(dest->graph);
627 dest->graph = 0;
628 dest->synth = 0;
630 set_out_notify(notify, dest, dev_id, MOM_CLOSE, 0, 0);
632 dest->midiDesc.hMidi = 0;
634 return MMSYSERR_NOERROR;
637 static void midi_send(MIDIPortRef port, MIDIEndpointRef dest, UInt8 *buffer, unsigned len)
639 Byte packet_buf[512];
640 MIDIPacketList *packet_list = (MIDIPacketList *)packet_buf;
641 MIDIPacket *packet = MIDIPacketListInit(packet_list);
643 packet = MIDIPacketListAdd(packet_list, sizeof(packet_buf), packet, mach_absolute_time(), len, buffer);
644 if (packet) MIDISend(port, dest, packet_list);
647 static UINT midi_out_data(WORD dev_id, UINT data)
649 struct midi_dest *dest;
650 UInt8 bytes[3];
651 OSStatus sc;
653 TRACE("dev_id = %d data = %08x\n", dev_id, data);
655 if (dev_id >= num_dests)
657 WARN("bad device ID : %d\n", dev_id);
658 return MMSYSERR_BADDEVICEID;
660 dest = dests + dev_id;
662 bytes[0] = data & 0xff;
663 if (bytes[0] & 0x80)
665 bytes[1] = (data >> 8) & 0xff;
666 bytes[2] = (data >> 16) & 0xff;
667 if (bytes[0] < 0xF0)
668 dest->runningStatus = bytes[0];
669 else if (bytes[0] <= 0xF7)
670 dest->runningStatus = 0;
672 else if (dest->runningStatus)
674 bytes[0] = dest->runningStatus;
675 bytes[1] = data & 0xff;
676 bytes[2] = (data >> 8) & 0xff;
678 else
680 FIXME("ooch %x\n", data);
681 return MMSYSERR_NOERROR;
684 if (dest->caps.wTechnology == MOD_SYNTH)
686 sc = MusicDeviceMIDIEvent(dest->synth, bytes[0], bytes[1], bytes[2], 0);
687 if (sc != noErr)
689 ERR("MusicDeviceMIDIEvent returns %s\n", wine_dbgstr_fourcc(sc));
690 return MMSYSERR_ERROR;
693 else
695 midi_send(midi_out_port, dest->dest, bytes, sizeof(bytes));
698 return MMSYSERR_NOERROR;
701 static UINT midi_out_long_data(WORD dev_id, MIDIHDR *hdr, UINT hdr_size, struct notify_context *notify)
703 struct midi_dest *dest;
704 OSStatus sc;
706 TRACE("dev_id = %d midi_hdr = %p hdr_size = %d\n", dev_id, hdr, hdr_size);
708 if (dev_id >= num_dests)
710 WARN("bad device ID : %d\n", dev_id);
711 return MMSYSERR_BADDEVICEID;
713 if (!hdr)
715 WARN("Invalid Parameter\n");
716 return MMSYSERR_INVALPARAM;
718 if (!hdr->lpData || !(hdr->dwFlags & MHDR_PREPARED))
719 return MIDIERR_UNPREPARED;
721 if (hdr->dwFlags & MHDR_INQUEUE)
722 return MIDIERR_STILLPLAYING;
724 hdr->dwFlags &= ~MHDR_DONE;
725 hdr->dwFlags |= MHDR_INQUEUE;
727 if ((UInt8)hdr->lpData[0] != 0xf0)
728 /* System Exclusive */
729 ERR("Add missing 0xf0 marker at the beginning of system exclusive byte stream\n");
731 if ((UInt8)hdr->lpData[hdr->dwBufferLength - 1] != 0xF7)
732 /* Send end of System Exclusive */
733 ERR("Add missing 0xf7 marker at the end of system exclusive byte stream\n");
735 dest = dests + dev_id;
737 if (dest->caps.wTechnology == MOD_SYNTH) /* FIXME */
739 sc = MusicDeviceSysEx(dest->synth, (const UInt8 *)hdr->lpData, hdr->dwBufferLength);
740 if (sc != noErr)
742 ERR("MusicDeviceSysEx returns %s\n", wine_dbgstr_fourcc(sc));
743 return MMSYSERR_ERROR;
746 else if (dest->caps.wTechnology == MOD_MIDIPORT)
747 midi_send(midi_out_port, dest->dest, (UInt8 *)hdr->lpData, hdr->dwBufferLength);
749 dest->runningStatus = 0;
750 hdr->dwFlags &= ~MHDR_INQUEUE;
751 hdr->dwFlags |= MHDR_DONE;
753 set_out_notify(notify, dest, dev_id, MOM_DONE, (UINT_PTR)hdr, 0);
755 return MMSYSERR_NOERROR;
758 static UINT midi_out_prepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size)
760 TRACE("dev_id = %d midi_hdr = %p hdr_size = %d\n", dev_id, hdr, hdr_size);
762 if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData)
763 return MMSYSERR_INVALPARAM;
764 if (hdr->dwFlags & MHDR_PREPARED)
765 return MMSYSERR_NOERROR;
767 hdr->lpNext = 0;
768 hdr->dwFlags |= MHDR_PREPARED;
769 hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE);
770 return MMSYSERR_NOERROR;
773 static UINT midi_out_unprepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size)
775 TRACE("dev_id = %d midi_hdr = %p hdr_size = %d\n", dev_id, hdr, hdr_size);
777 if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData)
778 return MMSYSERR_INVALPARAM;
779 if (!(hdr->dwFlags & MHDR_PREPARED))
780 return MMSYSERR_NOERROR;
781 if (hdr->dwFlags & MHDR_INQUEUE)
782 return MIDIERR_STILLPLAYING;
784 hdr->dwFlags &= ~MHDR_PREPARED;
785 return MMSYSERR_NOERROR;
788 static UINT midi_out_get_devcaps(WORD dev_id, MIDIOUTCAPSW *caps, UINT size)
790 TRACE("dev_id = %d caps = %p size = %d\n", dev_id, caps, size);
792 if (!caps)
794 WARN("Invalid Parameter\n");
795 return MMSYSERR_INVALPARAM;
798 if (dev_id >= num_dests)
800 WARN("bad device ID : %d\n", dev_id);
801 return MMSYSERR_BADDEVICEID;
803 memcpy(caps, &dests[dev_id].caps, min(size, sizeof(*caps)));
804 return MMSYSERR_NOERROR;
807 static UINT midi_out_get_num_devs(void)
809 TRACE("\n");
810 return num_dests;
813 static UINT midi_out_get_volume(WORD dev_id, UINT *volume)
815 TRACE("%d\n", dev_id);
817 if (dev_id >= num_dests)
819 WARN("bad device ID : %d\n", dev_id);
820 return MMSYSERR_BADDEVICEID;
822 if (!volume)
824 WARN("Invalid Parameter\n");
825 return MMSYSERR_INVALPARAM;
828 if (dests[dev_id].caps.wTechnology == MOD_SYNTH)
830 static int once;
831 float left;
833 if (!once++) FIXME("independent left/right volume not implemented\n");
834 AudioUnitGetParameter(dests[dev_id].synth, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, &left);
835 *volume = (WORD)(left * 0xffff) + ((WORD)(left * 0xffff) << 16);
836 return MMSYSERR_NOERROR;
839 return MMSYSERR_NOTSUPPORTED;
842 static UINT midi_out_set_volume(WORD dev_id, UINT volume)
844 TRACE("dev_id = %d vol = %08x\n", dev_id, volume);
846 if (dev_id >= num_dests)
848 WARN("bad device ID : %d\n", dev_id);
849 return MMSYSERR_BADDEVICEID;
851 if (dests[dev_id].caps.wTechnology == MOD_SYNTH)
853 float left, right;
854 static int once;
856 if (!once++) FIXME("independent left/right volume not implemented\n");
857 left = LOWORD(volume) / 65535.0f;
858 right = HIWORD(volume) / 65535.0f;
860 AudioUnitSetParameter(dests[dev_id].synth, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left, 0);
861 return MMSYSERR_NOERROR;
864 return MMSYSERR_NOTSUPPORTED;
867 static UINT midi_out_reset(WORD dev_id)
869 unsigned chn;
871 TRACE("%d\n", dev_id);
873 if (dev_id >= num_dests)
875 WARN("bad device ID : %d\n", dev_id);
876 return MMSYSERR_BADDEVICEID;
878 if (dests[dev_id].caps.wTechnology == MOD_SYNTH)
880 for (chn = 0; chn < 16; chn++)
882 /* turn off every note */
883 MusicDeviceMIDIEvent(dests[dev_id].synth, 0xB0 | chn, 0x7B, 0, 0);
884 /* remove sustain on channel */
885 MusicDeviceMIDIEvent(dests[dev_id].synth, 0xB0 | chn, 0x40, 0, 0);
888 else FIXME("MOD_MIDIPORT\n");
890 dests[dev_id].runningStatus = 0;
892 /* FIXME: the LongData buffers must also be returned to the app */
893 return MMSYSERR_NOERROR;
896 static UINT midi_in_open(WORD dev_id, MIDIOPENDESC *midi_desc, UINT flags, struct notify_context *notify)
898 struct midi_src *src;
900 TRACE("dev_id = %d desc = %p flags = %08x\n", dev_id, midi_desc, flags);
902 if (!midi_desc)
904 WARN("Invalid Parameter\n");
905 return MMSYSERR_INVALPARAM;
907 if (dev_id >= num_srcs)
909 WARN("bad device ID : %d\n", dev_id);
910 return MMSYSERR_BADDEVICEID;
912 src = srcs + dev_id;
914 if (src->midiDesc.hMidi)
916 WARN("device already open !\n");
917 return MMSYSERR_ALLOCATED;
919 if (flags & MIDI_IO_STATUS)
921 FIXME("No support for MIDI_IO_STATUS in flags yet, ignoring it\n");
922 flags &= ~MIDI_IO_STATUS;
924 if (flags & ~CALLBACK_TYPEMASK)
926 FIXME("Bad flags\n");
927 return MMSYSERR_INVALFLAG;
930 src->wFlags = HIWORD(flags & CALLBACK_TYPEMASK);
931 src->lpQueueHdr = NULL;
932 src->midiDesc = *midi_desc;
933 src->startTime = 0;
934 src->state = 0;
936 set_in_notify(notify, src, dev_id, MIM_OPEN, 0, 0);
938 return MMSYSERR_NOERROR;
941 static UINT midi_in_close(WORD dev_id, struct notify_context *notify)
943 struct midi_src *src;
945 TRACE("dev_id = %d\n", dev_id);
947 if (dev_id >= num_srcs)
949 WARN("bad device ID : %d\n", dev_id);
950 return MMSYSERR_BADDEVICEID;
952 src = srcs + dev_id;
954 if (!src->midiDesc.hMidi)
956 WARN("device not opened !\n");
957 return MMSYSERR_ERROR;
959 if (src->lpQueueHdr) return MIDIERR_STILLPLAYING;
961 set_in_notify(notify, src, dev_id, MIM_CLOSE, 0, 0);
962 src->midiDesc.hMidi = 0;
964 return MMSYSERR_NOERROR;
967 static UINT midi_in_add_buffer(WORD dev_id, MIDIHDR *hdr, UINT hdr_size)
969 MIDIHDR **next;
971 TRACE("dev_id = %d hdr = %p hdr_size = %d\n", dev_id, hdr, hdr_size);
973 if (dev_id >= num_srcs)
975 WARN("bad device ID : %d\n", dev_id);
976 return MMSYSERR_BADDEVICEID;
978 if (!hdr || hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr->dwBufferLength)
980 WARN("Invalid Parameter\n");
981 return MMSYSERR_INVALPARAM;
983 if (hdr->dwFlags & MHDR_INQUEUE)
985 WARN("Still playing\n");
986 return MIDIERR_STILLPLAYING;
988 if (!(hdr->dwFlags & MHDR_PREPARED))
990 WARN("Unprepared\n");
991 return MIDIERR_UNPREPARED;
994 hdr->dwFlags &= ~WHDR_DONE;
995 hdr->dwFlags |= MHDR_INQUEUE;
996 hdr->dwBytesRecorded = 0;
997 hdr->lpNext = NULL;
999 midi_in_lock(TRUE);
1001 next = &srcs[dev_id].lpQueueHdr;
1002 while (*next) next = &(*next)->lpNext;
1003 *next = hdr;
1005 midi_in_lock(FALSE);
1007 return MMSYSERR_NOERROR;
1010 static UINT midi_in_prepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size)
1012 TRACE("dev_id = %d hdr = %p hdr_size = %d\n", dev_id, hdr, hdr_size);
1014 if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData)
1015 return MMSYSERR_INVALPARAM;
1016 if (hdr->dwFlags & MHDR_PREPARED)
1017 return MMSYSERR_NOERROR;
1019 hdr->lpNext = NULL;
1020 hdr->dwFlags |= MHDR_PREPARED;
1021 hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE);
1022 return MMSYSERR_NOERROR;
1025 static UINT midi_in_unprepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size)
1027 TRACE("dev_id = %d hdr = %p hdr_size = %d\n", dev_id, hdr, hdr_size);
1029 if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData)
1030 return MMSYSERR_INVALPARAM;
1031 if (!(hdr->dwFlags & MHDR_PREPARED))
1032 return MMSYSERR_NOERROR;
1033 if (hdr->dwFlags & MHDR_INQUEUE)
1034 return MIDIERR_STILLPLAYING;
1036 hdr->dwFlags &= ~MHDR_PREPARED;
1037 return MMSYSERR_NOERROR;
1040 static UINT midi_in_get_devcaps(WORD dev_id, MIDIINCAPSW *caps, UINT size)
1042 TRACE("dev_id = %d caps = %p size = %d\n", dev_id, caps, size);
1044 if (!caps)
1046 WARN("Invalid Parameter\n");
1047 return MMSYSERR_INVALPARAM;
1049 if (dev_id >= num_srcs)
1051 WARN("bad device ID : %d\n", dev_id);
1052 return MMSYSERR_BADDEVICEID;
1055 memcpy(caps, &srcs[dev_id].caps, min(size, sizeof(*caps)));
1056 return MMSYSERR_NOERROR;
1059 static UINT midi_in_get_num_devs(void)
1061 TRACE("\n");
1062 return num_srcs;
1065 static UINT midi_in_start(WORD dev_id)
1067 TRACE("%d\n", dev_id);
1069 if (dev_id >= num_srcs)
1071 WARN("bad device ID : %d\n", dev_id);
1072 return MMSYSERR_BADDEVICEID;
1074 srcs[dev_id].state = 1;
1075 srcs[dev_id].startTime = get_time_ms();
1076 return MMSYSERR_NOERROR;
1079 static UINT midi_in_stop(WORD dev_id)
1081 TRACE("%d\n", dev_id);
1083 if (dev_id >= num_srcs)
1085 WARN("bad device ID : %d\n", dev_id);
1086 return MMSYSERR_BADDEVICEID;
1088 srcs[dev_id].state = 0;
1089 return MMSYSERR_NOERROR;
1092 static UINT midi_in_reset(WORD dev_id, struct notify_context *notify)
1094 UINT cur_time = get_time_ms();
1095 UINT err = MMSYSERR_NOERROR;
1096 struct midi_src *src;
1097 MIDIHDR *hdr;
1099 TRACE("%d\n", dev_id);
1101 if (dev_id >= num_srcs)
1103 WARN("bad device ID : %d\n", dev_id);
1104 return MMSYSERR_BADDEVICEID;
1106 src = srcs + dev_id;
1108 midi_in_lock(TRUE);
1110 if (src->lpQueueHdr)
1112 hdr = src->lpQueueHdr;
1113 src->lpQueueHdr = hdr->lpNext;
1114 hdr->dwFlags &= ~MHDR_INQUEUE;
1115 hdr->dwFlags |= MHDR_DONE;
1116 set_in_notify(notify, src, dev_id, MIM_LONGDATA, (UINT_PTR)hdr, cur_time - src->startTime);
1117 if (src->lpQueueHdr) err = ERROR_RETRY; /* ask the client to call again */
1120 midi_in_lock(FALSE);
1122 return err;
1125 NTSTATUS unix_midi_out_message(void *args)
1127 struct midi_out_message_params *params = args;
1129 params->notify->send_notify = FALSE;
1131 switch (params->msg)
1133 case DRVM_INIT:
1134 case DRVM_EXIT:
1135 case DRVM_ENABLE:
1136 case DRVM_DISABLE:
1137 *params->err = MMSYSERR_NOERROR;
1138 break;
1139 case MODM_OPEN:
1140 *params->err = midi_out_open(params->dev_id, (MIDIOPENDESC *)params->param_1, params->param_2, params->notify);
1141 break;
1142 case MODM_CLOSE:
1143 *params->err = midi_out_close(params->dev_id, params->notify);
1144 break;
1145 case MODM_DATA:
1146 *params->err = midi_out_data(params->dev_id, params->param_1);
1147 break;
1148 case MODM_LONGDATA:
1149 *params->err = midi_out_long_data(params->dev_id, (MIDIHDR *)params->param_1, params->param_2, params->notify);
1150 break;
1151 case MODM_PREPARE:
1152 *params->err = midi_out_prepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2);
1153 break;
1154 case MODM_UNPREPARE:
1155 *params->err = midi_out_unprepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2);
1156 break;
1157 case MODM_GETDEVCAPS:
1158 *params->err = midi_out_get_devcaps(params->dev_id, (MIDIOUTCAPSW *)params->param_1, params->param_2);
1159 break;
1160 case MODM_GETNUMDEVS:
1161 *params->err = midi_out_get_num_devs();
1162 break;
1163 case MODM_GETVOLUME:
1164 *params->err = midi_out_get_volume(params->dev_id, (UINT *)params->param_1);
1165 break;
1166 case MODM_SETVOLUME:
1167 *params->err = midi_out_set_volume(params->dev_id, params->param_1);
1168 break;
1169 case MODM_RESET:
1170 *params->err = midi_out_reset(params->dev_id);
1171 break;
1172 default:
1173 TRACE("Unsupported message\n");
1174 *params->err = MMSYSERR_NOTSUPPORTED;
1177 return STATUS_SUCCESS;
1180 NTSTATUS unix_midi_in_message(void *args)
1182 struct midi_in_message_params *params = args;
1184 params->notify->send_notify = FALSE;
1186 switch (params->msg)
1188 case DRVM_INIT:
1189 case DRVM_EXIT:
1190 case DRVM_ENABLE:
1191 case DRVM_DISABLE:
1192 *params->err = MMSYSERR_NOERROR;
1193 break;
1194 case MIDM_OPEN:
1195 *params->err = midi_in_open(params->dev_id, (MIDIOPENDESC *)params->param_1, params->param_2, params->notify);
1196 break;
1197 case MIDM_CLOSE:
1198 *params->err = midi_in_close(params->dev_id, params->notify);
1199 break;
1200 case MIDM_ADDBUFFER:
1201 *params->err = midi_in_add_buffer(params->dev_id, (MIDIHDR *)params->param_1, params->param_2);
1202 break;
1203 case MIDM_PREPARE:
1204 *params->err = midi_in_prepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2);
1205 break;
1206 case MIDM_UNPREPARE:
1207 *params->err = midi_in_unprepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2);
1208 break;
1209 case MIDM_GETDEVCAPS:
1210 *params->err = midi_in_get_devcaps(params->dev_id, (MIDIINCAPSW *)params->param_1, params->param_2);
1211 break;
1212 case MIDM_GETNUMDEVS:
1213 *params->err = midi_in_get_num_devs();
1214 break;
1215 case MIDM_START:
1216 *params->err = midi_in_start(params->dev_id);
1217 break;
1218 case MIDM_STOP:
1219 *params->err = midi_in_stop(params->dev_id);
1220 break;
1221 case MIDM_RESET:
1222 *params->err = midi_in_reset(params->dev_id, params->notify);
1223 break;
1224 default:
1225 TRACE("Unsupported message\n");
1226 *params->err = MMSYSERR_NOTSUPPORTED;
1229 return STATUS_SUCCESS;
1232 NTSTATUS unix_midi_notify_wait(void *args)
1234 struct midi_notify_wait_params *params = args;
1236 pthread_mutex_lock(&notify_mutex);
1238 while (!notify_quit && notify_buffer_empty())
1239 pthread_cond_wait(&notify_cond, &notify_mutex);
1241 *params->quit = notify_quit;
1242 if (!notify_quit) notify_buffer_remove(params->notify);
1244 pthread_mutex_unlock(&notify_mutex);
1246 return STATUS_SUCCESS;
1249 #ifdef _WIN64
1251 typedef UINT PTR32;
1253 NTSTATUS unix_wow64_midi_init(void *args)
1255 struct
1257 PTR32 err;
1258 } *params32 = args;
1259 struct midi_init_params params =
1261 .err = ULongToPtr(params32->err)
1263 return unix_midi_init(&params);
1266 struct notify_context32
1268 BOOL send_notify;
1269 WORD dev_id;
1270 WORD msg;
1271 UINT param_1;
1272 UINT param_2;
1273 UINT callback;
1274 UINT flags;
1275 PTR32 device;
1276 UINT instance;
1279 static void notify_to_notify32(struct notify_context32 *notify32,
1280 const struct notify_context *notify)
1282 notify32->send_notify = notify->send_notify;
1283 notify32->dev_id = notify->dev_id;
1284 notify32->msg = notify->msg;
1285 notify32->param_1 = notify->param_1;
1286 notify32->param_2 = notify->param_2;
1287 notify32->callback = notify->callback;
1288 notify32->flags = notify->flags;
1289 notify32->device = PtrToUlong(notify->device);
1290 notify32->instance = notify->instance;
1293 struct midi_open_desc32
1295 PTR32 hMidi;
1296 UINT dwCallback;
1297 UINT dwInstance;
1298 UINT dnDevNode;
1299 UINT cIds;
1300 MIDIOPENSTRMID rgIds;
1303 struct midi_hdr32
1305 PTR32 lpData;
1306 UINT dwBufferLength;
1307 UINT dwBytesRecorded;
1308 UINT dwUser;
1309 UINT dwFlags;
1310 PTR32 lpNext;
1311 UINT reserved;
1312 UINT dwOffset;
1313 UINT dwReserved[8];
1316 static UINT wow64_midi_out_prepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size)
1318 TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
1320 if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData)
1321 return MMSYSERR_INVALPARAM;
1322 if (hdr->dwFlags & MHDR_PREPARED)
1323 return MMSYSERR_NOERROR;
1325 hdr->lpNext = 0;
1326 hdr->dwFlags |= MHDR_PREPARED;
1327 hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE);
1328 return MMSYSERR_NOERROR;
1331 static UINT wow64_midi_out_unprepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size)
1333 TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
1335 if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData)
1336 return MMSYSERR_INVALPARAM;
1337 if (!(hdr->dwFlags & MHDR_PREPARED))
1338 return MMSYSERR_NOERROR;
1339 if (hdr->dwFlags & MHDR_INQUEUE)
1340 return MIDIERR_STILLPLAYING;
1342 hdr->dwFlags &= ~MHDR_PREPARED;
1343 return MMSYSERR_NOERROR;
1346 NTSTATUS unix_wow64_midi_out_message(void *args)
1348 struct
1350 UINT dev_id;
1351 UINT msg;
1352 UINT user;
1353 UINT param_1;
1354 UINT param_2;
1355 PTR32 err;
1356 PTR32 notify;
1357 } *params32 = args;
1358 struct notify_context32 *notify32 = ULongToPtr(params32->notify);
1359 struct midi_open_desc32 *desc32;
1360 struct midi_hdr32 *hdr32;
1361 struct notify_context notify;
1362 MIDIOPENDESC open_desc;
1363 MIDIHDR hdr;
1364 struct midi_out_message_params params =
1366 .dev_id = params32->dev_id,
1367 .msg = params32->msg,
1368 .user = params32->user,
1369 .param_1 = params32->param_1,
1370 .param_2 = params32->param_2,
1371 .err = ULongToPtr(params32->err),
1372 .notify = &notify
1374 notify32->send_notify = FALSE;
1376 switch (params32->msg)
1378 case MODM_OPEN:
1379 desc32 = ULongToPtr(params32->param_1);
1381 open_desc.hMidi = ULongToPtr(desc32->hMidi);
1382 open_desc.dwCallback = desc32->dwCallback;
1383 open_desc.dwInstance = desc32->dwInstance;
1384 open_desc.dnDevNode = desc32->dnDevNode;
1385 open_desc.cIds = desc32->cIds;
1386 open_desc.rgIds.dwStreamID = desc32->rgIds.dwStreamID;
1387 open_desc.rgIds.wDeviceID = desc32->rgIds.wDeviceID;
1389 params.param_1 = (UINT_PTR)&open_desc;
1390 break;
1392 case MODM_LONGDATA:
1393 hdr32 = ULongToPtr(params32->param_1);
1395 memset(&hdr, 0, sizeof(hdr));
1396 hdr.lpData = ULongToPtr(hdr32->lpData);
1397 hdr.dwBufferLength = hdr32->dwBufferLength;
1398 hdr.dwFlags = hdr32->dwFlags;
1400 params.param_1 = (UINT_PTR)&hdr;
1401 params.param_2 = sizeof(hdr);
1402 break;
1404 case MODM_PREPARE: /* prepare and unprepare are easier to handle explicitly */
1405 hdr32 = ULongToPtr(params32->param_1);
1407 *params.err = wow64_midi_out_prepare(params32->dev_id, hdr32, params32->param_2);
1408 return STATUS_SUCCESS;
1410 case MODM_UNPREPARE:
1411 hdr32 = ULongToPtr(params32->param_1);
1413 *params.err = wow64_midi_out_unprepare(params32->dev_id, hdr32, params32->param_2);
1414 return STATUS_SUCCESS;
1417 unix_midi_out_message(&params);
1419 switch (params32->msg)
1421 case MODM_LONGDATA:
1422 hdr32 = ULongToPtr(params32->param_1);
1424 hdr32->dwFlags = hdr.dwFlags;
1425 break;
1428 if (notify.send_notify)
1430 notify_to_notify32(notify32, &notify);
1432 if (notify.msg == MOM_DONE)
1433 notify32->param_1 = params32->param_1; /* restore the 32-bit hdr */
1435 return STATUS_SUCCESS;
1438 static UINT wow64_midi_in_prepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size)
1440 TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
1442 if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData)
1443 return MMSYSERR_INVALPARAM;
1444 if (hdr->dwFlags & MHDR_PREPARED)
1445 return MMSYSERR_NOERROR;
1447 hdr->lpNext = 0;
1448 hdr->dwFlags |= MHDR_PREPARED;
1449 hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE);
1451 return MMSYSERR_NOERROR;
1454 static UINT wow64_midi_in_unprepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size)
1456 TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
1458 if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData)
1459 return MMSYSERR_INVALPARAM;
1460 if (!(hdr->dwFlags & MHDR_PREPARED))
1461 return MMSYSERR_NOERROR;
1462 if (hdr->dwFlags & MHDR_INQUEUE)
1463 return MIDIERR_STILLPLAYING;
1465 hdr->dwFlags &= ~MHDR_PREPARED;
1467 return MMSYSERR_NOERROR;
1470 NTSTATUS unix_wow64_midi_in_message(void *args)
1472 struct
1474 UINT dev_id;
1475 UINT msg;
1476 UINT user;
1477 UINT param_1;
1478 UINT param_2;
1479 PTR32 err;
1480 PTR32 notify;
1481 } *params32 = args;
1482 struct notify_context32 *notify32 = ULongToPtr(params32->notify);
1483 struct midi_open_desc32 *desc32;
1484 struct midi_hdr32 *hdr32;
1485 struct notify_context notify;
1486 MIDIOPENDESC open_desc;
1487 MIDIHDR *hdr = NULL;
1488 struct midi_in_message_params params =
1490 .dev_id = params32->dev_id,
1491 .msg = params32->msg,
1492 .user = params32->user,
1493 .param_1 = params32->param_1,
1494 .param_2 = params32->param_2,
1495 .err = ULongToPtr(params32->err),
1496 .notify = &notify
1498 notify32->send_notify = FALSE;
1500 switch (params32->msg)
1502 case MIDM_OPEN:
1503 desc32 = ULongToPtr(params32->param_1);
1505 open_desc.hMidi = ULongToPtr(desc32->hMidi);
1506 open_desc.dwCallback = desc32->dwCallback;
1507 open_desc.dwInstance = desc32->dwInstance;
1508 open_desc.dnDevNode = desc32->dnDevNode;
1509 open_desc.cIds = desc32->cIds;
1510 open_desc.rgIds.dwStreamID = desc32->rgIds.dwStreamID;
1511 open_desc.rgIds.wDeviceID = desc32->rgIds.wDeviceID;
1513 params.param_1 = (UINT_PTR)&open_desc;
1514 break;
1516 case MIDM_ADDBUFFER:
1517 hdr32 = ULongToPtr(params32->param_1);
1519 hdr = calloc(1, sizeof(*hdr));
1520 hdr->lpData = ULongToPtr(hdr32->lpData);
1521 hdr->dwBufferLength = hdr32->dwBufferLength;
1522 hdr->dwFlags = hdr32->dwFlags;
1523 hdr->dwReserved[7] = params32->param_1; /* keep hdr32 for MIM_LONGDATA notification */
1525 params.param_1 = (UINT_PTR)hdr;
1526 params.param_2 = sizeof(*hdr);
1527 break;
1529 case MIDM_PREPARE: /* prepare and unprepare are easier to handle explicitly */
1530 hdr32 = ULongToPtr(params32->param_1);
1532 *params.err = wow64_midi_in_prepare(params32->dev_id, hdr32, params32->param_2);
1533 return STATUS_SUCCESS;
1535 case MIDM_UNPREPARE:
1536 hdr32 = ULongToPtr(params32->param_1);
1538 *params.err = wow64_midi_in_unprepare(params32->dev_id, hdr32, params32->param_2);
1539 return STATUS_SUCCESS;
1542 unix_midi_in_message(&params);
1544 switch (params32->msg)
1546 case MIDM_ADDBUFFER:
1547 hdr32 = ULongToPtr(params32->param_1);
1549 if (!*params.err)
1551 hdr32->dwFlags = hdr->dwFlags;
1552 hdr32->dwBytesRecorded = hdr->dwBytesRecorded;
1553 hdr32->lpNext = 0;
1555 else
1556 free(hdr);
1557 break;
1560 if (notify.send_notify)
1562 notify_to_notify32(notify32, &notify);
1564 if (notify.msg == MIM_LONGDATA)
1566 hdr = (MIDIHDR *)notify.param_1;
1567 notify32->param_1 = hdr->dwReserved[7];
1568 hdr32 = ULongToPtr(notify32->param_1);
1569 hdr32->dwBytesRecorded = hdr->dwBytesRecorded;
1570 hdr32->dwFlags = hdr->dwFlags;
1571 free(hdr);
1574 return STATUS_SUCCESS;
1577 NTSTATUS unix_wow64_midi_notify_wait(void *args)
1579 struct
1581 PTR32 quit;
1582 PTR32 notify;
1583 } *params32 = args;
1584 struct notify_context32 *notify32 = ULongToPtr(params32->notify);
1585 struct midi_hdr32 *hdr32;
1586 struct notify_context notify;
1587 MIDIHDR *hdr;
1588 struct midi_notify_wait_params params =
1590 .quit = ULongToPtr(params32->quit),
1591 .notify = &notify
1593 notify32->send_notify = FALSE;
1595 unix_midi_notify_wait(&params);
1597 if (!*params.quit && notify.send_notify)
1599 notify_to_notify32(notify32, &notify);
1601 if (notify.msg == MIM_LONGDATA)
1603 hdr = (MIDIHDR *)notify.param_1;
1604 notify32->param_1 = hdr->dwReserved[7];
1605 hdr32 = ULongToPtr(notify32->param_1);
1606 hdr32->dwBytesRecorded = hdr->dwBytesRecorded;
1607 hdr32->dwFlags = hdr->dwFlags;
1608 free(hdr);
1611 return STATUS_SUCCESS;
1614 #endif /* _WIN64 */