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
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>
67 #undef HRESULT_FACILITY
73 #undef STDMETHODCALLTYPE
78 #define WIN32_NO_STATUS
86 #include "mmdeviceapi.h"
87 #include "audioclient.h"
88 #include "wine/debug.h"
89 #include "wine/unixlib.h"
91 #include "coreaudio.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(midi
);
98 /* graph and synth are only used for MIDI Synth */
102 MIDIEndpointRef dest
;
105 MIDIOPENDESC midiDesc
;
112 MIDIEndpointRef source
;
115 int state
; /* 0 is no recording started, 1 in recording, bit 2 set if in sys exclusive recording */
117 MIDIOPENDESC midiDesc
;
118 LPMIDIHDR lpQueueHdr
;
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
;
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
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
;
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
;
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
);
198 static void notify_post(struct notify_context
*notify
)
200 pthread_mutex_lock(¬ify_mutex
);
202 if (notify
) notify_buffer_add(notify
);
203 else notify_quit
= TRUE
;
204 pthread_cond_signal(¬ify_cond
);
206 pthread_mutex_unlock(¬ify_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
;
233 MIDIHDR
*hdr
= src
->lpQueueHdr
;
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
;
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(¬ify
, src
, src
->wDevID
, MIM_LONGDATA
, (UINT_PTR
)hdr
, current_time
);
249 notify_post(¬ify
);
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
)
266 switch (packet
->data
[pos
] & 0xf0)
269 data
= packet
->data
[pos
];
274 data
= (packet
->data
[pos
+ 1] << 8) | packet
->data
[pos
];
278 data
= (packet
->data
[pos
+ 2] << 16) | (packet
->data
[pos
+ 1] << 8) |
283 set_in_notify(¬ify
, src
, src
->wDevID
, MIM_DATA
, data
, current_time
);
284 notify_post(¬ify
);
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
;
295 if (dev_id
>= num_srcs
) return;
297 if (src
->state
< 1) /* input not started */
300 for (i
= 0; i
< pktlist
->numPackets
; ++i
)
302 if (packet
->data
[0] == 0xf0 || src
->state
& 2)
303 process_sysex_packet(src
, packet
);
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
;
318 pthread_mutex_lock(¬ify_mutex
);
320 notify_read
= notify_write
= notify_buffer
;
321 pthread_mutex_unlock(¬ify_mutex
);
323 sc
= MIDIClientCreate(name
, NULL
/* FIXME use notify proc */, NULL
, &midi_client
);
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
));
342 name
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("WineInputPort.%u"), getpid());
343 MIDIInputPortCreate(midi_client
, name
, midi_in_read_proc
, NULL
, &midi_in_port
);
347 if (num_dests
> MAX_MIDI_SYNTHS
)
349 name
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("WineOutputPort.%u"), getpid());
350 MIDIOutputPortCreate(midi_client
, name
, &midi_out_port
);
354 /* initialize sources */
355 for (i
= 0; i
< num_srcs
; i
++)
358 srcs
[i
].source
= MIDIGetSource(i
);
360 sc
= MIDIObjectGetStringProperty(srcs
[i
].source
, kMIDIPropertyName
, &name
);
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
);
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
);
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 */
430 if (midi_client
) MIDIClientDispose(midi_client
); /* MIDIClientDispose will close all ports */
435 return STATUS_SUCCESS
;
441 static BOOL
synth_unit_create_default(AUGraph
*graph
, AudioUnit
*synth
)
443 AudioComponentDescription desc
;
448 sc
= NewAUGraph(graph
);
451 ERR("NewAUGraph return %s\n", coreaudio_dbgstr_fourcc(sc
));
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
);
466 ERR("AUGraphAddNode cannot create synthNode : %s\n", coreaudio_dbgstr_fourcc(sc
));
470 /* create out node */
471 desc
.componentType
= kAudioUnitType_Output
;
472 desc
.componentSubType
= kAudioUnitSubType_DefaultOutput
;
474 sc
= AUGraphAddNode(*graph
, &desc
, &out_node
);
477 ERR("AUGraphAddNode cannot create outNode %s\n", coreaudio_dbgstr_fourcc(sc
));
481 sc
= AUGraphOpen(*graph
);
484 ERR("AUGraphOpen returns %s\n", coreaudio_dbgstr_fourcc(sc
));
488 /* connecting the nodes */
489 sc
= AUGraphConnectNodeInput(*graph
, synth_node
, 0, out_node
, 0);
492 ERR("AUGraphConnectNodeInput cannot connect synthNode to outNode : %s\n",
493 coreaudio_dbgstr_fourcc(sc
));
497 /* Get the synth unit */
498 sc
= AUGraphNodeInfo(*graph
, synth_node
, 0, synth
);
501 ERR("AUGraphNodeInfo return %s\n", coreaudio_dbgstr_fourcc(sc
));
508 static BOOL
synth_unit_init(AudioUnit synth
, AUGraph graph
)
512 sc
= AUGraphInitialize(graph
);
515 ERR("AUGraphInitialize(%p) returns %s\n", graph
, coreaudio_dbgstr_fourcc(sc
));
519 sc
= AUGraphStart(graph
);
522 ERR("AUGraphStart(%p) returns %s\n", graph
, coreaudio_dbgstr_fourcc(sc
));
529 static BOOL
synth_unit_close(AUGraph graph
)
533 sc
= AUGraphStop(graph
);
536 ERR("AUGraphStop(%p) returns %s\n", graph
, coreaudio_dbgstr_fourcc(sc
));
540 sc
= DisposeAUGraph(graph
);
543 ERR("DisposeAUGraph(%p) returns %s\n", graph
, coreaudio_dbgstr_fourcc(sc
));
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
;
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)
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
);
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
;
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;
665 bytes
[1] = (data
>> 8) & 0xff;
666 bytes
[2] = (data
>> 16) & 0xff;
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;
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);
689 ERR("MusicDeviceMIDIEvent returns %s\n", coreaudio_dbgstr_fourcc(sc
));
690 return MMSYSERR_ERROR
;
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
;
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
;
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
);
742 ERR("MusicDeviceSysEx returns %s\n", coreaudio_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
;
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
);
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)
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
;
824 WARN("Invalid Parameter\n");
825 return MMSYSERR_INVALPARAM
;
828 if (dests
[dev_id
].caps
.wTechnology
== MOD_SYNTH
)
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
)
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
)
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
);
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
;
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
;
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
;
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
)
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;
1001 next
= &srcs
[dev_id
].lpQueueHdr
;
1002 while (*next
) next
= &(*next
)->lpNext
;
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
;
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
);
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)
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
;
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
;
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
);
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
)
1137 *params
->err
= MMSYSERR_NOERROR
;
1140 *params
->err
= midi_out_open(params
->dev_id
, (MIDIOPENDESC
*)params
->param_1
, params
->param_2
, params
->notify
);
1143 *params
->err
= midi_out_close(params
->dev_id
, params
->notify
);
1146 *params
->err
= midi_out_data(params
->dev_id
, params
->param_1
);
1149 *params
->err
= midi_out_long_data(params
->dev_id
, (MIDIHDR
*)params
->param_1
, params
->param_2
, params
->notify
);
1152 *params
->err
= midi_out_prepare(params
->dev_id
, (MIDIHDR
*)params
->param_1
, params
->param_2
);
1154 case MODM_UNPREPARE
:
1155 *params
->err
= midi_out_unprepare(params
->dev_id
, (MIDIHDR
*)params
->param_1
, params
->param_2
);
1157 case MODM_GETDEVCAPS
:
1158 *params
->err
= midi_out_get_devcaps(params
->dev_id
, (MIDIOUTCAPSW
*)params
->param_1
, params
->param_2
);
1160 case MODM_GETNUMDEVS
:
1161 *params
->err
= midi_out_get_num_devs();
1163 case MODM_GETVOLUME
:
1164 *params
->err
= midi_out_get_volume(params
->dev_id
, (UINT
*)params
->param_1
);
1166 case MODM_SETVOLUME
:
1167 *params
->err
= midi_out_set_volume(params
->dev_id
, params
->param_1
);
1170 *params
->err
= midi_out_reset(params
->dev_id
);
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
)
1192 *params
->err
= MMSYSERR_NOERROR
;
1195 *params
->err
= midi_in_open(params
->dev_id
, (MIDIOPENDESC
*)params
->param_1
, params
->param_2
, params
->notify
);
1198 *params
->err
= midi_in_close(params
->dev_id
, params
->notify
);
1200 case MIDM_ADDBUFFER
:
1201 *params
->err
= midi_in_add_buffer(params
->dev_id
, (MIDIHDR
*)params
->param_1
, params
->param_2
);
1204 *params
->err
= midi_in_prepare(params
->dev_id
, (MIDIHDR
*)params
->param_1
, params
->param_2
);
1206 case MIDM_UNPREPARE
:
1207 *params
->err
= midi_in_unprepare(params
->dev_id
, (MIDIHDR
*)params
->param_1
, params
->param_2
);
1209 case MIDM_GETDEVCAPS
:
1210 *params
->err
= midi_in_get_devcaps(params
->dev_id
, (MIDIINCAPSW
*)params
->param_1
, params
->param_2
);
1212 case MIDM_GETNUMDEVS
:
1213 *params
->err
= midi_in_get_num_devs();
1216 *params
->err
= midi_in_start(params
->dev_id
);
1219 *params
->err
= midi_in_stop(params
->dev_id
);
1222 *params
->err
= midi_in_reset(params
->dev_id
, params
->notify
);
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(¬ify_mutex
);
1238 while (!notify_quit
&& notify_buffer_empty())
1239 pthread_cond_wait(¬ify_cond
, ¬ify_mutex
);
1241 *params
->quit
= notify_quit
;
1242 if (!notify_quit
) notify_buffer_remove(params
->notify
);
1244 pthread_mutex_unlock(¬ify_mutex
);
1246 return STATUS_SUCCESS
;
1253 NTSTATUS
unix_wow64_midi_init(void *args
)
1259 struct midi_init_params params
=
1261 .err
= ULongToPtr(params32
->err
)
1263 return unix_midi_init(¶ms
);
1266 struct notify_context32
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
1300 MIDIOPENSTRMID rgIds
;
1306 UINT dwBufferLength
;
1307 UINT dwBytesRecorded
;
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
;
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
)
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
;
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
),
1374 notify32
->send_notify
= FALSE
;
1376 switch (params32
->msg
)
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
;
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
);
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(¶ms
);
1419 switch (params32
->msg
)
1422 hdr32
= ULongToPtr(params32
->param_1
);
1424 hdr32
->dwFlags
= hdr
.dwFlags
;
1428 if (notify
.send_notify
)
1430 notify_to_notify32(notify32
, ¬ify
);
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
;
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
)
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
),
1498 notify32
->send_notify
= FALSE
;
1500 switch (params32
->msg
)
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
;
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
);
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(¶ms
);
1544 switch (params32
->msg
)
1546 case MIDM_ADDBUFFER
:
1547 hdr32
= ULongToPtr(params32
->param_1
);
1551 hdr32
->dwFlags
= hdr
->dwFlags
;
1552 hdr32
->dwBytesRecorded
= hdr
->dwBytesRecorded
;
1560 if (notify
.send_notify
)
1562 notify_to_notify32(notify32
, ¬ify
);
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
;
1574 return STATUS_SUCCESS
;
1577 NTSTATUS
unix_wow64_midi_notify_wait(void *args
)
1584 struct notify_context32
*notify32
= ULongToPtr(params32
->notify
);
1585 struct midi_hdr32
*hdr32
;
1586 struct notify_context notify
;
1588 struct midi_notify_wait_params params
=
1590 .quit
= ULongToPtr(params32
->quit
),
1593 notify32
->send_notify
= FALSE
;
1595 unix_midi_notify_wait(¶ms
);
1597 if (!*params
.quit
&& notify
.send_notify
)
1599 notify_to_notify32(notify32
, ¬ify
);
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
;
1611 return STATUS_SUCCESS
;