winecoreaudio: Move midi_out_get_devcaps to the unixlib.
[wine.git] / dlls / winecoreaudio.drv / midi.c
blob675950f45d17904aa705c5be3a1cee65b1eced94
1 /*
2 * MIDI driver for macOS (PE-side)
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
25 #include "config.h"
26 #include "wine/port.h"
28 #include <string.h>
29 #include <stdarg.h>
30 #include <stdio.h>
32 #include "windef.h"
33 #include "winbase.h"
34 #include "wingdi.h"
35 #include "winuser.h"
36 #include "winnls.h"
37 #include "mmddk.h"
38 #include "mmdeviceapi.h"
39 #include "audioclient.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42 #include "wine/unixlib.h"
43 #include "coreaudio.h"
44 #include "unixlib.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(midi);
48 #include <CoreAudio/CoreAudio.h>
50 #define WINE_DEFINITIONS
51 #include "coremidi.h"
53 static DWORD MIDIOut_NumDevs = 0;
54 static DWORD MIDIIn_NumDevs = 0;
56 static CRITICAL_SECTION midiInLock; /* Critical section for MIDI In */
57 static CFStringRef MIDIInThreadPortName;
59 static DWORD WINAPI MIDIIn_MessageThread(LPVOID p);
61 static MIDIPortRef MIDIInPort = NULL;
62 static MIDIPortRef MIDIOutPort = NULL;
64 MIDIDestination *destinations;
65 MIDISource *sources;
67 static void notify_client(struct notify_context *notify)
69 TRACE("dev_id=%d msg=%d param1=%04lX param2=%04lX\n", notify->dev_id, notify->msg, notify->param_1, notify->param_2);
71 DriverCallback(notify->callback, notify->flags, notify->device, notify->msg,
72 notify->instance, notify->param_1, notify->param_2);
75 static LONG CoreAudio_MIDIInit(void)
77 struct midi_init_params params;
78 DWORD err;
80 params.err = &err;
82 UNIX_CALL(midi_init, &params);
83 if (err != DRV_SUCCESS)
85 ERR("can't create midi client\n");
86 return err;
89 MIDIOut_NumDevs = params.num_dests;
90 MIDIIn_NumDevs = params.num_srcs;
91 destinations = params.dests;
92 sources = params.srcs;
93 MIDIOutPort = params.midi_out_port;
94 MIDIInPort = params.midi_in_port;
96 if (MIDIIn_NumDevs > 0)
98 InitializeCriticalSection(&midiInLock);
99 midiInLock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": midiInLock");
101 MIDIInThreadPortName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("MIDIInThreadPortName.%u"), getpid());
102 CloseHandle( CreateThread(NULL, 0, MIDIIn_MessageThread, NULL, 0, NULL));
104 return err;
107 static LONG CoreAudio_MIDIRelease(void)
109 TRACE("\n");
111 UNIX_CALL(midi_release, NULL);
112 sources = NULL;
113 destinations = NULL;
115 if (MIDIIn_NumDevs > 0)
117 midiInLock.DebugInfo->Spare[0] = 0;
118 DeleteCriticalSection(&midiInLock);
121 return DRV_SUCCESS;
125 /**************************************************************************
126 * MIDI_NotifyClient [internal]
128 static void MIDI_NotifyClient(UINT wDevID, WORD wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
130 DWORD_PTR dwCallBack;
131 UINT uFlags;
132 HANDLE hDev;
133 DWORD_PTR dwInstance;
135 TRACE("wDevID=%d wMsg=%d dwParm1=%04lX dwParam2=%04lX\n", wDevID, wMsg, dwParam1, dwParam2);
137 switch (wMsg) {
138 case MIM_OPEN:
139 case MIM_CLOSE:
140 case MIM_DATA:
141 case MIM_LONGDATA:
142 case MIM_ERROR:
143 case MIM_LONGERROR:
144 case MIM_MOREDATA:
145 dwCallBack = sources[wDevID].midiDesc.dwCallback;
146 uFlags = sources[wDevID].wFlags;
147 hDev = sources[wDevID].midiDesc.hMidi;
148 dwInstance = sources[wDevID].midiDesc.dwInstance;
149 break;
150 default:
151 ERR("Unsupported MSW-MIDI message %u\n", wMsg);
152 return;
155 DriverCallback(dwCallBack, uFlags, hDev, wMsg, dwInstance, dwParam1, dwParam2);
158 static DWORD MIDIOut_GetNumDevs(void)
160 TRACE("\n");
161 return MIDIOut_NumDevs;
164 static DWORD MIDIOut_GetVolume(WORD wDevID, DWORD *lpdwVolume)
166 TRACE("%d\n", wDevID);
168 if (wDevID >= MIDIOut_NumDevs) {
169 WARN("bad device ID : %d\n", wDevID);
170 return MMSYSERR_BADDEVICEID;
172 if (lpdwVolume == NULL) {
173 WARN("Invalid Parameter\n");
174 return MMSYSERR_INVALPARAM;
177 if (destinations[wDevID].caps.wTechnology == MOD_SYNTH)
179 float left;
180 float right;
181 AudioUnit_GetVolume(destinations[wDevID].synth, &left, &right);
183 *lpdwVolume = (WORD) (left * 0xFFFF) + ((WORD) (right * 0xFFFF) << 16);
185 return MMSYSERR_NOERROR;
188 return MMSYSERR_NOTSUPPORTED;
191 static DWORD MIDIOut_SetVolume(WORD wDevID, DWORD dwVolume)
193 TRACE("%d\n", wDevID);
195 if (wDevID >= MIDIOut_NumDevs) {
196 WARN("bad device ID : %d\n", wDevID);
197 return MMSYSERR_BADDEVICEID;
199 if (destinations[wDevID].caps.wTechnology == MOD_SYNTH)
201 float left;
202 float right;
204 left = LOWORD(dwVolume) / 65535.0f;
205 right = HIWORD(dwVolume) / 65535.0f;
206 AudioUnit_SetVolume(destinations[wDevID].synth, left, right);
208 return MMSYSERR_NOERROR;
211 return MMSYSERR_NOTSUPPORTED;
214 static DWORD MIDIOut_Reset(WORD wDevID)
216 unsigned chn;
218 TRACE("%d\n", wDevID);
220 if (wDevID >= MIDIOut_NumDevs) {
221 WARN("bad device ID : %d\n", wDevID);
222 return MMSYSERR_BADDEVICEID;
224 if (destinations[wDevID].caps.wTechnology == MOD_SYNTH)
226 for (chn = 0; chn < 16; chn++) {
227 /* turn off every note */
228 MusicDeviceMIDIEvent(destinations[wDevID].synth, 0xB0 | chn, 0x7B, 0, 0);
229 /* remove sustain on channel */
230 MusicDeviceMIDIEvent(destinations[wDevID].synth, 0xB0 | chn, 0x40, 0, 0);
233 else FIXME("MOD_MIDIPORT\n");
235 /* FIXME: the LongData buffers must also be returned to the app */
236 return MMSYSERR_NOERROR;
239 static DWORD MIDIIn_Open(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
241 TRACE("wDevID=%d lpDesc=%p dwFlags=%08x\n", wDevID, lpDesc, dwFlags);
243 if (lpDesc == NULL) {
244 WARN("Invalid Parameter\n");
245 return MMSYSERR_INVALPARAM;
247 if (wDevID >= MIDIIn_NumDevs) {
248 WARN("bad device ID : %d\n", wDevID);
249 return MMSYSERR_BADDEVICEID;
251 if (sources[wDevID].midiDesc.hMidi != 0) {
252 WARN("device already open !\n");
253 return MMSYSERR_ALLOCATED;
255 if ((dwFlags & MIDI_IO_STATUS) != 0) {
256 WARN("No support for MIDI_IO_STATUS in dwFlags yet, ignoring it\n");
257 dwFlags &= ~MIDI_IO_STATUS;
259 if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) {
260 FIXME("Bad dwFlags\n");
261 return MMSYSERR_INVALFLAG;
264 sources[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
265 sources[wDevID].lpQueueHdr = NULL;
266 sources[wDevID].midiDesc = *lpDesc;
267 sources[wDevID].startTime = 0;
268 sources[wDevID].state = 0;
270 MIDI_NotifyClient(wDevID, MIM_OPEN, 0L, 0L);
271 return MMSYSERR_NOERROR;
274 static DWORD MIDIIn_Close(WORD wDevID)
276 DWORD ret = MMSYSERR_NOERROR;
278 TRACE("wDevID=%d\n", wDevID);
280 if (wDevID >= MIDIIn_NumDevs) {
281 WARN("bad device ID : %d\n", wDevID);
282 return MMSYSERR_BADDEVICEID;
285 if (sources[wDevID].midiDesc.hMidi == 0) {
286 WARN("device not opened !\n");
287 return MMSYSERR_ERROR;
289 if (sources[wDevID].lpQueueHdr != 0) {
290 return MIDIERR_STILLPLAYING;
293 MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L);
294 sources[wDevID].midiDesc.hMidi = 0;
295 return ret;
298 static DWORD MIDIIn_AddBuffer(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
300 TRACE("wDevID=%d lpMidiHdr=%p dwSize=%d\n", wDevID, lpMidiHdr, dwSize);
302 if (wDevID >= MIDIIn_NumDevs) {
303 WARN("bad device ID : %d\n", wDevID);
304 return MMSYSERR_BADDEVICEID;
306 if (lpMidiHdr == NULL) {
307 WARN("Invalid Parameter\n");
308 return MMSYSERR_INVALPARAM;
310 if (dwSize < offsetof(MIDIHDR,dwOffset)) {
311 WARN("Invalid Parameter\n");
312 return MMSYSERR_INVALPARAM;
314 if (lpMidiHdr->dwBufferLength == 0) {
315 WARN("Invalid Parameter\n");
316 return MMSYSERR_INVALPARAM;
318 if (lpMidiHdr->dwFlags & MHDR_INQUEUE) {
319 WARN("Still playing\n");
320 return MIDIERR_STILLPLAYING;
322 if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) {
323 WARN("Unprepared\n");
324 return MIDIERR_UNPREPARED;
327 EnterCriticalSection(&midiInLock);
328 lpMidiHdr->dwFlags &= ~WHDR_DONE;
329 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
330 lpMidiHdr->dwBytesRecorded = 0;
331 lpMidiHdr->lpNext = 0;
332 if (sources[wDevID].lpQueueHdr == 0) {
333 sources[wDevID].lpQueueHdr = lpMidiHdr;
334 } else {
335 LPMIDIHDR ptr;
336 for (ptr = sources[wDevID].lpQueueHdr;
337 ptr->lpNext != 0;
338 ptr = ptr->lpNext);
339 ptr->lpNext = lpMidiHdr;
341 LeaveCriticalSection(&midiInLock);
343 return MMSYSERR_NOERROR;
346 static DWORD MIDIIn_Prepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
348 TRACE("wDevID=%d lpMidiHdr=%p dwSize=%d\n", wDevID, lpMidiHdr, dwSize);
350 if (dwSize < offsetof(MIDIHDR,dwOffset) || lpMidiHdr == 0 || lpMidiHdr->lpData == 0)
351 return MMSYSERR_INVALPARAM;
352 if (lpMidiHdr->dwFlags & MHDR_PREPARED)
353 return MMSYSERR_NOERROR;
355 lpMidiHdr->lpNext = 0;
356 lpMidiHdr->dwFlags |= MHDR_PREPARED;
357 lpMidiHdr->dwFlags &= ~(MHDR_DONE|MHDR_INQUEUE); /* flags cleared since w2k */
358 return MMSYSERR_NOERROR;
361 static DWORD MIDIIn_Unprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
363 TRACE("wDevID=%d lpMidiHdr=%p dwSize=%d\n", wDevID, lpMidiHdr, dwSize);
365 if (dwSize < offsetof(MIDIHDR,dwOffset) || lpMidiHdr == 0 || lpMidiHdr->lpData == 0)
366 return MMSYSERR_INVALPARAM;
367 if (!(lpMidiHdr->dwFlags & MHDR_PREPARED))
368 return MMSYSERR_NOERROR;
369 if (lpMidiHdr->dwFlags & MHDR_INQUEUE)
370 return MIDIERR_STILLPLAYING;
372 lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
373 return MMSYSERR_NOERROR;
376 static DWORD MIDIIn_GetDevCaps(WORD wDevID, LPMIDIINCAPSW lpCaps, DWORD dwSize)
378 TRACE("wDevID=%d lpCaps=%p dwSize=%d\n", wDevID, lpCaps, dwSize);
380 if (lpCaps == NULL) {
381 WARN("Invalid Parameter\n");
382 return MMSYSERR_INVALPARAM;
385 if (wDevID >= MIDIIn_NumDevs) {
386 WARN("bad device ID : %d\n", wDevID);
387 return MMSYSERR_BADDEVICEID;
389 memcpy(lpCaps, &sources[wDevID].caps, min(dwSize, sizeof(*lpCaps)));
390 return MMSYSERR_NOERROR;
393 static DWORD MIDIIn_GetNumDevs(void)
395 TRACE("\n");
396 return MIDIIn_NumDevs;
399 static DWORD MIDIIn_Start(WORD wDevID)
401 TRACE("%d\n", wDevID);
403 if (wDevID >= MIDIIn_NumDevs) {
404 WARN("bad device ID : %d\n", wDevID);
405 return MMSYSERR_BADDEVICEID;
407 sources[wDevID].state = 1;
408 sources[wDevID].startTime = GetTickCount();
409 return MMSYSERR_NOERROR;
412 static DWORD MIDIIn_Stop(WORD wDevID)
414 TRACE("%d\n", wDevID);
415 if (wDevID >= MIDIIn_NumDevs) {
416 WARN("bad device ID : %d\n", wDevID);
417 return MMSYSERR_BADDEVICEID;
419 sources[wDevID].state = 0;
420 return MMSYSERR_NOERROR;
423 static DWORD MIDIIn_Reset(WORD wDevID)
425 DWORD dwTime = GetTickCount();
427 TRACE("%d\n", wDevID);
428 if (wDevID >= MIDIIn_NumDevs) {
429 WARN("bad device ID : %d\n", wDevID);
430 return MMSYSERR_BADDEVICEID;
433 EnterCriticalSection(&midiInLock);
434 while (sources[wDevID].lpQueueHdr) {
435 LPMIDIHDR lpMidiHdr = sources[wDevID].lpQueueHdr;
436 sources[wDevID].lpQueueHdr = lpMidiHdr->lpNext;
437 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
438 lpMidiHdr->dwFlags |= MHDR_DONE;
439 /* FIXME: when called from 16 bit, lpQueueHdr needs to be a segmented ptr */
440 MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD_PTR)lpMidiHdr, dwTime);
442 LeaveCriticalSection(&midiInLock);
444 return MMSYSERR_NOERROR;
448 * MIDI In Mach message handling
450 static CFDataRef MIDIIn_MessageHandler(CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info)
452 MIDIMessage *msg = NULL;
453 int i = 0;
454 MIDISource *src = NULL;
455 DWORD sendData = 0;
456 int pos = 0;
457 DWORD currentTime;
458 BOOL sysexStart;
460 switch (msgid)
462 case 0:
463 msg = (MIDIMessage *) CFDataGetBytePtr(data);
464 TRACE("devID=%d\n", msg->devID);
465 for (i = 0; i < msg->length; ++i) {
466 TRACE("%02X ", msg->data[i]);
468 TRACE("\n");
469 src = &sources[msg->devID];
470 if (src->state < 1)
472 TRACE("input not started, thrown away\n");
473 return NULL;
476 sysexStart = (msg->data[0] == 0xF0);
478 if (sysexStart || src->state & 2) {
479 int pos = 0;
480 int len = msg->length;
482 if (sysexStart) {
483 TRACE("Receiving sysex message\n");
484 src->state |= 2;
487 EnterCriticalSection(&midiInLock);
488 currentTime = GetTickCount() - src->startTime;
490 while (len) {
491 LPMIDIHDR lpMidiHdr = src->lpQueueHdr;
493 if (lpMidiHdr != NULL) {
494 int copylen = min(len, lpMidiHdr->dwBufferLength - lpMidiHdr->dwBytesRecorded);
495 memcpy(lpMidiHdr->lpData + lpMidiHdr->dwBytesRecorded, msg->data + pos, copylen);
496 lpMidiHdr->dwBytesRecorded += copylen;
497 len -= copylen;
498 pos += copylen;
500 TRACE("Copied %d bytes of sysex message\n", copylen);
502 if ((lpMidiHdr->dwBytesRecorded == lpMidiHdr->dwBufferLength) ||
503 (*(BYTE*)(lpMidiHdr->lpData + lpMidiHdr->dwBytesRecorded - 1) == 0xF7)) {
504 TRACE("Sysex message complete (or buffer limit reached), dispatching %d bytes\n", lpMidiHdr->dwBytesRecorded);
505 src->lpQueueHdr = lpMidiHdr->lpNext;
506 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
507 lpMidiHdr->dwFlags |= MHDR_DONE;
508 MIDI_NotifyClient(msg->devID, MIM_LONGDATA, (DWORD_PTR)lpMidiHdr, currentTime);
509 src->state &= ~2;
512 else {
513 FIXME("Sysex data received but no buffer to store it!\n");
514 break;
518 LeaveCriticalSection(&midiInLock);
519 return NULL;
522 EnterCriticalSection(&midiInLock);
523 currentTime = GetTickCount() - src->startTime;
525 while (pos < msg->length)
527 sendData = 0;
528 switch (msg->data[pos] & 0xF0)
530 case 0xF0:
531 sendData = (msg->data[pos] << 0);
532 pos++;
533 break;
535 case 0xC0:
536 case 0xD0:
537 sendData = (msg->data[pos + 1] << 8) | (msg->data[pos] << 0);
538 pos += 2;
539 break;
540 default:
541 sendData = (msg->data[pos + 2] << 16) |
542 (msg->data[pos + 1] << 8) |
543 (msg->data[pos] << 0);
544 pos += 3;
545 break;
547 MIDI_NotifyClient(msg->devID, MIM_DATA, sendData, currentTime);
549 LeaveCriticalSection(&midiInLock);
550 break;
551 default:
552 CFRunLoopStop(CFRunLoopGetCurrent());
553 break;
555 return NULL;
558 static DWORD WINAPI MIDIIn_MessageThread(LPVOID p)
560 CFMessagePortRef local;
561 CFRunLoopSourceRef source;
562 Boolean info;
564 local = CFMessagePortCreateLocal(kCFAllocatorDefault, MIDIInThreadPortName, &MIDIIn_MessageHandler, NULL, &info);
566 source = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, local, 0);
567 CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
569 CFRunLoopRun();
571 CFRunLoopSourceInvalidate(source);
572 CFRelease(source);
573 CFRelease(local);
574 CFRelease(MIDIInThreadPortName);
575 MIDIInThreadPortName = NULL;
577 return 0;
580 /**************************************************************************
581 * modMessage
583 DWORD WINAPI CoreAudio_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
585 struct midi_out_message_params params;
586 struct notify_context notify;
587 DWORD err;
589 TRACE("%d %08x %08lx %08lx %08lx\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
591 switch (wMsg) {
592 case MODM_GETNUMDEVS:
593 return MIDIOut_GetNumDevs();
594 case MODM_GETVOLUME:
595 return MIDIOut_GetVolume(wDevID, (DWORD*)dwParam1);
596 case MODM_SETVOLUME:
597 return MIDIOut_SetVolume(wDevID, dwParam1);
598 case MODM_RESET:
599 return MIDIOut_Reset(wDevID);
602 params.dev_id = wDevID;
603 params.msg = wMsg;
604 params.user = dwUser;
605 params.param_1 = dwParam1;
606 params.param_2 = dwParam2;
607 params.err = &err;
608 params.notify = &notify;
610 UNIX_CALL(midi_out_message, &params);
612 if (!err && notify.send_notify) notify_client(&notify);
614 return err;
617 /**************************************************************************
618 * midMessage
620 DWORD WINAPI CoreAudio_midMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
622 TRACE("%d %08x %08lx %08lx %08lx\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
623 switch (wMsg) {
624 case DRVM_INIT:
625 case DRVM_EXIT:
626 case DRVM_ENABLE:
627 case DRVM_DISABLE:
628 return 0;
629 case MIDM_OPEN:
630 return MIDIIn_Open(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2);
631 case MIDM_CLOSE:
632 return MIDIIn_Close(wDevID);
633 case MIDM_ADDBUFFER:
634 return MIDIIn_AddBuffer(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
635 case MIDM_PREPARE:
636 return MIDIIn_Prepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
637 case MIDM_UNPREPARE:
638 return MIDIIn_Unprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
639 case MIDM_GETDEVCAPS:
640 return MIDIIn_GetDevCaps(wDevID, (LPMIDIINCAPSW) dwParam1, dwParam2);
641 case MIDM_GETNUMDEVS:
642 return MIDIIn_GetNumDevs();
643 case MIDM_START:
644 return MIDIIn_Start(wDevID);
645 case MIDM_STOP:
646 return MIDIIn_Stop(wDevID);
647 case MIDM_RESET:
648 return MIDIIn_Reset(wDevID);
649 default:
650 TRACE("Unsupported message\n");
652 return MMSYSERR_NOTSUPPORTED;
655 /**************************************************************************
656 * CoreAudio_drvLoad [internal]
658 static LRESULT CoreAudio_drvLoad(void)
660 TRACE("()\n");
662 if (CoreAudio_MIDIInit() != DRV_SUCCESS)
663 return DRV_FAILURE;
665 return DRV_SUCCESS;
668 /**************************************************************************
669 * CoreAudio_drvFree [internal]
671 static LRESULT CoreAudio_drvFree(void)
673 TRACE("()\n");
674 CoreAudio_MIDIRelease();
675 return DRV_SUCCESS;
678 /**************************************************************************
679 * CoreAudio_drvOpen [internal]
681 static LRESULT CoreAudio_drvOpen(LPSTR str)
683 TRACE("(%s)\n", str);
684 return 1;
687 /**************************************************************************
688 * CoreAudio_drvClose [internal]
690 static DWORD CoreAudio_drvClose(DWORD dwDevID)
692 TRACE("(%08x)\n", dwDevID);
693 return 1;
696 /**************************************************************************
697 * DriverProc (WINECOREAUDIO.1)
699 LRESULT CALLBACK CoreAudio_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
700 LPARAM dwParam1, LPARAM dwParam2)
702 TRACE("(%08lX, %p, %s (%08X), %08lX, %08lX)\n",
703 dwDevID, hDriv, wMsg == DRV_LOAD ? "DRV_LOAD" :
704 wMsg == DRV_FREE ? "DRV_FREE" :
705 wMsg == DRV_OPEN ? "DRV_OPEN" :
706 wMsg == DRV_CLOSE ? "DRV_CLOSE" :
707 wMsg == DRV_ENABLE ? "DRV_ENABLE" :
708 wMsg == DRV_DISABLE ? "DRV_DISABLE" :
709 wMsg == DRV_QUERYCONFIGURE ? "DRV_QUERYCONFIGURE" :
710 wMsg == DRV_CONFIGURE ? "DRV_CONFIGURE" :
711 wMsg == DRV_INSTALL ? "DRV_INSTALL" :
712 wMsg == DRV_REMOVE ? "DRV_REMOVE" : "UNKNOWN",
713 wMsg, dwParam1, dwParam2);
715 switch(wMsg) {
716 case DRV_LOAD: return CoreAudio_drvLoad();
717 case DRV_FREE: return CoreAudio_drvFree();
718 case DRV_OPEN: return CoreAudio_drvOpen((LPSTR)dwParam1);
719 case DRV_CLOSE: return CoreAudio_drvClose(dwDevID);
720 case DRV_ENABLE: return 1;
721 case DRV_DISABLE: return 1;
722 case DRV_QUERYCONFIGURE: return 1;
723 case DRV_CONFIGURE: MessageBoxA(0, "CoreAudio driver!", "CoreAudio driver", MB_OK); return 1;
724 case DRV_INSTALL: return DRVCNF_RESTART;
725 case DRV_REMOVE: return DRVCNF_RESTART;
726 default:
727 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);