winecoreaudio: Initial MIDI support on Mac OS X.
[wine] / dlls / winecoreaudio.drv / midi.c
1 /*
2  * Sample MIDI Wine Driver for MacOSX (based on OSS midi driver)
3  *
4  * Copyright 1994       Martin Ayotte
5  * Copyright 1998       Luiz Otavio L. Zorzella (init procedures)
6  * Copyright 1998/1999  Eric POUECH :
7  *              98/7    changes for making this MIDI driver work on OSS
8  *                      current support is limited to MIDI ports of OSS systems
9  *              98/9    rewriting MCI code for MIDI
10  *              98/11   splitted in midi.c and mcimidi.c
11  * Copyright 2006       Emmanuel Maillard
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2.1 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this library; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26  */
27
28 #include "config.h"
29 #include "wine/port.h"
30
31 #include <string.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34
35 #include "windef.h"
36 #include "winbase.h"
37 #include "wingdi.h"
38 #include "winuser.h"
39 #include "winnls.h"
40 #include "mmddk.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(midi);
45
46 #if defined(HAVE_COREAUDIO_COREAUDIO_H)
47 #include <CoreAudio/CoreAudio.h>
48
49 #define WINE_DEFINITIONS
50 #include "coremidi.h"
51
52 static MIDIClientRef wineMIDIClient = NULL;
53
54 static DWORD MIDIOut_NumDevs = 0;
55
56 typedef struct tagMIDIDestination {
57     /* graph and synth are only used for MIDI Synth */
58     AUGraph graph;
59     AudioUnit synth;
60
61     MIDIPortRef port;
62     MIDIOUTCAPSW caps;
63     MIDIOPENDESC midiDesc;
64     WORD wFlags;
65 } MIDIDestination;
66
67 #define MAX_MIDI_SYNTHS 1
68
69 MIDIDestination *destinations;
70
71 extern int SynthUnit_CreateDefaultSynthUnit(AUGraph *graph, AudioUnit *synth);
72 extern int SynthUnit_Initialize(AudioUnit synth, AUGraph graph);
73 extern int SynthUnit_Close(AUGraph graph);
74
75
76 LONG CoreAudio_MIDIInit(void)
77 {
78     int i;
79     CHAR szPname[MAXPNAMELEN] = {0};
80
81     int numDest = MIDIGetNumberOfDestinations();
82     CFStringRef name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("wineMIDIClient.%d"), getpid());
83
84     wineMIDIClient = CoreMIDI_CreateClient( name );
85     if (wineMIDIClient == NULL)
86     {
87         CFRelease(name);
88         ERR("can't create wineMIDIClient\n");
89         return 0;
90     }
91     CFRelease(name);
92
93     MIDIOut_NumDevs = MAX_MIDI_SYNTHS;
94     MIDIOut_NumDevs += numDest;
95
96     TRACE("MIDIOut_NumDevs %d\n", MIDIOut_NumDevs);
97
98     destinations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MIDIOut_NumDevs * sizeof(MIDIDestination));
99
100     /* initialise MIDI synths */
101     for (i = 0; i < MAX_MIDI_SYNTHS; i++)
102     {
103         snprintf(szPname, sizeof(szPname), "CoreAudio MIDI Synth %d", i);
104         MultiByteToWideChar(CP_ACP, 0, szPname, -1, destinations[i].caps.szPname, sizeof(destinations[i].caps.szPname)/sizeof(WCHAR));
105
106         destinations[i].caps.wTechnology = MOD_SYNTH;
107         destinations[i].caps.wChannelMask = 0xFFFF;
108
109         destinations[i].caps.wMid = 0x00FF;     /* Manufac ID */
110         destinations[i].caps.wPid = 0x0001;     /* Product ID */
111         destinations[i].caps.vDriverVersion = 0x0001;
112         destinations[i].caps.dwSupport = MIDICAPS_VOLUME;
113         destinations[i].caps.wVoices = 16;
114         destinations[i].caps.wNotes = 16;
115     }
116     /* initialise available destinations */
117     for (i = MAX_MIDI_SYNTHS; i < numDest + MAX_MIDI_SYNTHS; i++)
118     {
119         MIDIEndpointRef endpoint = MIDIGetDestination(i - MAX_MIDI_SYNTHS);
120
121         CoreMIDI_GetObjectName(endpoint, szPname, sizeof(szPname));
122         MultiByteToWideChar(CP_ACP, 0, szPname, -1, destinations[i].caps.szPname, sizeof(destinations[i].caps.szPname)/sizeof(WCHAR));
123
124         name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("WineOutputPort.%d.%u"), i, getpid());
125         MIDIOutputPortCreate(wineMIDIClient, name, &destinations[i].port);
126         CFRelease(name);
127
128         destinations[i].caps.wTechnology = MOD_MIDIPORT;
129         destinations[i].caps.wChannelMask = 0xFFFF;
130
131         destinations[i].caps.wMid = 0x00FF;     /* Manufac ID */
132         destinations[i].caps.wPid = 0x0001;
133         destinations[i].caps.vDriverVersion = 0x0001;
134         destinations[i].caps.dwSupport = 0;
135         destinations[i].caps.wVoices = 16;
136         destinations[i].caps.wNotes = 16;
137     }
138     return 1;
139 }
140
141 LONG CoreAudio_MIDIRelease(void)
142 {
143     TRACE("\n");
144     if (wineMIDIClient) MIDIClientDispose(wineMIDIClient); /* MIDIClientDispose will close all ports */
145     HeapFree(GetProcessHeap(), 0, destinations);
146     return 1;
147 }
148
149 /**************************************************************************
150 *                               modMessage
151 */
152 DWORD WINAPI CoreAudio_modMessage(UINT wDevID, UINT wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
153 {
154     TRACE("%d %08x %08x %08x %08x\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
155
156     switch (wMsg) {
157         case DRVM_INIT:
158         case DRVM_EXIT:
159         case DRVM_ENABLE:
160         case DRVM_DISABLE:
161             return 0;
162         case MODM_OPEN:
163         case MODM_CLOSE:
164         case MODM_DATA:
165         case MODM_LONGDATA:
166         case MODM_PREPARE:
167         case MODM_UNPREPARE:
168         case MODM_GETDEVCAPS:
169         case MODM_GETNUMDEVS:
170         case MODM_GETVOLUME:
171         case MODM_SETVOLUME:
172         case MODM_RESET:
173         default:
174             TRACE("Unsupported message (08%x)\n", wMsg);
175     }
176     return MMSYSERR_NOTSUPPORTED;
177 }
178
179
180
181 #else
182
183 DWORD WINAPI CoreAudio_modMessage(UINT wDevID, UINT wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
184 {
185     TRACE("%08x, %08x, %08x, %08x, %08x\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
186     return MMSYSERR_NOTENABLED;
187 }
188
189 #endif