winecoreaudio: Initial MIDI support on Mac OS X.
diff --git a/dlls/winecoreaudio.drv/Makefile.in b/dlls/winecoreaudio.drv/Makefile.in
index a54c476..c31933d 100644
--- a/dlls/winecoreaudio.drv/Makefile.in
+++ b/dlls/winecoreaudio.drv/Makefile.in
@@ -9,7 +9,9 @@
C_SRCS = \
audio.c \
audiounit.c \
- coreaudio.c
+ coreaudio.c \
+ coremidi.c \
+ midi.c
@MAKE_DLL_RULES@
diff --git a/dlls/winecoreaudio.drv/audiounit.c b/dlls/winecoreaudio.drv/audiounit.c
index b6da953..08fd5ec 100644
--- a/dlls/winecoreaudio.drv/audiounit.c
+++ b/dlls/winecoreaudio.drv/audiounit.c
@@ -25,6 +25,9 @@
#ifdef HAVE_AUDIOUNIT_AUDIOUNIT_H
#include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/AudioToolbox.h>
+
+WINE_DECLARE_DEBUG_CHANNEL(midi);
extern OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
@@ -312,4 +315,115 @@
return 0;
}
+/*
+ * MIDI Synth Unit
+ */
+int SynthUnit_CreateDefaultSynthUnit(AUGraph *graph, AudioUnit *synth)
+{
+ OSStatus err;
+ ComponentDescription desc;
+ AUNode synthNode;
+ AUNode outNode;
+
+ err = NewAUGraph(graph);
+ if (err != noErr)
+ {
+ ERR_(midi)("NewAUGraph return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
+ return 0;
+ }
+
+ desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+ desc.componentFlags = 0;
+ desc.componentFlagsMask = 0;
+
+ /* create synth node */
+ desc.componentType = kAudioUnitType_MusicDevice;
+ desc.componentSubType = kAudioUnitSubType_DLSSynth;
+
+ err = AUGraphNewNode(*graph, &desc, 0, NULL, &synthNode);
+ if (err != noErr)
+ {
+ ERR_(midi)("AUGraphNewNode cannot create synthNode : %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
+ return 0;
+ }
+
+ /* create out node */
+ desc.componentType = kAudioUnitType_Output;
+ desc.componentSubType = kAudioUnitSubType_DefaultOutput;
+
+ err = AUGraphNewNode(*graph, &desc, 0, NULL, &outNode);
+ if (err != noErr)
+ {
+ ERR_(midi)("AUGraphNewNode cannot create outNode %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
+ return 0;
+ }
+
+ err = AUGraphOpen(*graph);
+ if (err != noErr)
+ {
+ ERR_(midi)("AUGraphOpen return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
+ return 0;
+ }
+
+ /* connecting the nodes */
+ err = AUGraphConnectNodeInput(*graph, synthNode, 0, outNode, 0);
+ if (err != noErr)
+ {
+ ERR_(midi)("AUGraphConnectNodeInput cannot connect synthNode to outNode : %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
+ return 0;
+ }
+
+ /* Get the synth unit */
+ err = AUGraphGetNodeInfo(*graph, synthNode, 0, 0, 0, synth);
+ if (err != noErr)
+ {
+ ERR_(midi)("AUGraphGetNodeInfo return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
+ return 0;
+ }
+
+ return 1;
+}
+
+int SynthUnit_Initialize(AudioUnit synth, AUGraph graph)
+{
+ OSStatus err = noErr;
+
+ err = AUGraphInitialize(graph);
+ if (err != noErr)
+ {
+ ERR_(midi)("AUGraphInitialize(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
+ return 0;
+ }
+
+ err = AUGraphStart(graph);
+ if (err != noErr)
+ {
+ ERR_(midi)("AUGraphStart(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
+ return 0;
+ }
+
+ return 1;
+}
+
+int SynthUnit_Close(AUGraph graph)
+{
+ OSStatus err = noErr;
+
+ err = AUGraphStop(graph);
+ if (err != noErr)
+ {
+ ERR_(midi)("AUGraphStop(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
+ return 0;
+ }
+
+ err = DisposeAUGraph(graph);
+ if (err != noErr)
+ {
+ ERR_(midi)("DisposeAUGraph(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
+ return 0;
+ }
+
+ return 1;
+}
+
#endif
diff --git a/dlls/winecoreaudio.drv/coreaudio.c b/dlls/winecoreaudio.drv/coreaudio.c
index 6fd21d7..7cff0ac 100644
--- a/dlls/winecoreaudio.drv/coreaudio.c
+++ b/dlls/winecoreaudio.drv/coreaudio.c
@@ -43,6 +43,8 @@
{
TRACE("()\n");
CoreAudio_WaveInit();
+ CoreAudio_MIDIInit();
+
return 1;
}
@@ -53,6 +55,8 @@
{
TRACE("()\n");
CoreAudio_WaveRelease();
+ CoreAudio_MIDIRelease();
+
return 1;
}
diff --git a/dlls/winecoreaudio.drv/coreaudio.h b/dlls/winecoreaudio.drv/coreaudio.h
index 312ba0e..92c78d0 100644
--- a/dlls/winecoreaudio.drv/coreaudio.h
+++ b/dlls/winecoreaudio.drv/coreaudio.h
@@ -23,6 +23,7 @@
extern LONG CoreAudio_WaveInit(void);
extern void CoreAudio_WaveRelease(void);
-/* extern BOOL CoreAudio_MidiInit(void); */
+extern LONG CoreAudio_MIDIInit(void);
+extern void CoreAudio_MIDIRelease(void);
#endif /* __WINE_COREAUDIO_H */
diff --git a/dlls/winecoreaudio.drv/coremidi.c b/dlls/winecoreaudio.drv/coremidi.c
new file mode 100644
index 0000000..59101ee
--- /dev/null
+++ b/dlls/winecoreaudio.drv/coremidi.c
@@ -0,0 +1,55 @@
+/*
+ * Wine Midi driver for MacOSX
+ *
+ * Copyright 2006 Emmanuel Maillard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+
+#include "config.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(midi);
+
+#ifdef HAVE_COREAUDIO_COREAUDIO_H
+#include <CoreMIDI/CoreMIDI.h>
+
+#include "coremidi.h"
+
+MIDIClientRef CoreMIDI_CreateClient(CFStringRef name)
+{
+ MIDIClientRef client = NULL;
+
+ if (MIDIClientCreate(name, NULL /* FIXME use notify proc */, NULL, &client) != noErr)
+ return NULL;
+
+ return client;
+}
+
+void CoreMIDI_GetObjectName(MIDIObjectRef obj, char *name, int size)
+{
+ OSStatus err = noErr;
+ CFStringRef cfname;
+
+ err = MIDIObjectGetStringProperty(obj, kMIDIPropertyName, &cfname);
+ if (err == noErr)
+ {
+ CFStringGetCString(cfname, name, size, kCFStringEncodingASCII);
+ CFRelease(cfname);
+ }
+}
+
+#endif /* HAVE_COREAUDIO_COREAUDIO_H */
diff --git a/dlls/winecoreaudio.drv/coremidi.h b/dlls/winecoreaudio.drv/coremidi.h
new file mode 100644
index 0000000..38f1507
--- /dev/null
+++ b/dlls/winecoreaudio.drv/coremidi.h
@@ -0,0 +1,61 @@
+/*
+ * Wine Midi driver for MacOSX
+ *
+ * Copyright 2006 Emmanuel Maillard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef WINE_COREMIDI_H
+#define WINE_COREMIDI_H
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#ifdef WINE_DEFINITIONS
+/*
+ * Due to CoreMIDI headers conflict redefine some types for Wine
+ */
+typedef void *MIDIClientRef;
+typedef void *MIDIEndpointRef;
+typedef void *MIDIPortRef;
+typedef void *MIDIObjectRef;
+
+typedef struct MIDIPacketList MIDIPacketList;
+
+/*
+ * functions
+ */
+extern OSStatus MIDIClientDispose(MIDIClientRef client);
+extern unsigned MIDIGetNumberOfDestinations(void);
+extern MIDIEndpointRef MIDIGetDestination(unsigned i);
+extern unsigned MIDIGetNumberOfSources(void);
+extern MIDIEndpointRef MIDIGetSource(unsigned i);
+extern OSStatus MIDIOutputPortCreate(MIDIClientRef client, CFStringRef portName, MIDIPortRef *outPort);
+
+extern OSStatus MIDIObjectGetProperties(MIDIObjectRef obj, CFPropertyListRef *outProperties, Boolean deep);
+
+/*
+ * Due to AudioUnit headers conflict redefine some types.
+ */
+typedef void *AudioUnit;
+typedef void *AUGraph;
+
+#endif
+
+/* coremidi.c */
+extern MIDIClientRef CoreMIDI_CreateClient(CFStringRef name);
+extern void CoreMIDI_GetObjectName(MIDIObjectRef obj, char *name, int size);
+
+#endif
diff --git a/dlls/winecoreaudio.drv/midi.c b/dlls/winecoreaudio.drv/midi.c
new file mode 100644
index 0000000..314dbe3
--- /dev/null
+++ b/dlls/winecoreaudio.drv/midi.c
@@ -0,0 +1,189 @@
+/*
+ * Sample MIDI Wine Driver for MacOSX (based on OSS midi driver)
+ *
+ * Copyright 1994 Martin Ayotte
+ * Copyright 1998 Luiz Otavio L. Zorzella (init procedures)
+ * Copyright 1998/1999 Eric POUECH :
+ * 98/7 changes for making this MIDI driver work on OSS
+ * current support is limited to MIDI ports of OSS systems
+ * 98/9 rewriting MCI code for MIDI
+ * 98/11 splitted in midi.c and mcimidi.c
+ * Copyright 2006 Emmanuel Maillard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "mmddk.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(midi);
+
+#if defined(HAVE_COREAUDIO_COREAUDIO_H)
+#include <CoreAudio/CoreAudio.h>
+
+#define WINE_DEFINITIONS
+#include "coremidi.h"
+
+static MIDIClientRef wineMIDIClient = NULL;
+
+static DWORD MIDIOut_NumDevs = 0;
+
+typedef struct tagMIDIDestination {
+ /* graph and synth are only used for MIDI Synth */
+ AUGraph graph;
+ AudioUnit synth;
+
+ MIDIPortRef port;
+ MIDIOUTCAPSW caps;
+ MIDIOPENDESC midiDesc;
+ WORD wFlags;
+} MIDIDestination;
+
+#define MAX_MIDI_SYNTHS 1
+
+MIDIDestination *destinations;
+
+extern int SynthUnit_CreateDefaultSynthUnit(AUGraph *graph, AudioUnit *synth);
+extern int SynthUnit_Initialize(AudioUnit synth, AUGraph graph);
+extern int SynthUnit_Close(AUGraph graph);
+
+
+LONG CoreAudio_MIDIInit(void)
+{
+ int i;
+ CHAR szPname[MAXPNAMELEN] = {0};
+
+ int numDest = MIDIGetNumberOfDestinations();
+ CFStringRef name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("wineMIDIClient.%d"), getpid());
+
+ wineMIDIClient = CoreMIDI_CreateClient( name );
+ if (wineMIDIClient == NULL)
+ {
+ CFRelease(name);
+ ERR("can't create wineMIDIClient\n");
+ return 0;
+ }
+ CFRelease(name);
+
+ MIDIOut_NumDevs = MAX_MIDI_SYNTHS;
+ MIDIOut_NumDevs += numDest;
+
+ TRACE("MIDIOut_NumDevs %d\n", MIDIOut_NumDevs);
+
+ destinations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MIDIOut_NumDevs * sizeof(MIDIDestination));
+
+ /* initialise MIDI synths */
+ for (i = 0; i < MAX_MIDI_SYNTHS; i++)
+ {
+ snprintf(szPname, sizeof(szPname), "CoreAudio MIDI Synth %d", i);
+ MultiByteToWideChar(CP_ACP, 0, szPname, -1, destinations[i].caps.szPname, sizeof(destinations[i].caps.szPname)/sizeof(WCHAR));
+
+ destinations[i].caps.wTechnology = MOD_SYNTH;
+ destinations[i].caps.wChannelMask = 0xFFFF;
+
+ destinations[i].caps.wMid = 0x00FF; /* Manufac ID */
+ destinations[i].caps.wPid = 0x0001; /* Product ID */
+ destinations[i].caps.vDriverVersion = 0x0001;
+ destinations[i].caps.dwSupport = MIDICAPS_VOLUME;
+ destinations[i].caps.wVoices = 16;
+ destinations[i].caps.wNotes = 16;
+ }
+ /* initialise available destinations */
+ for (i = MAX_MIDI_SYNTHS; i < numDest + MAX_MIDI_SYNTHS; i++)
+ {
+ MIDIEndpointRef endpoint = MIDIGetDestination(i - MAX_MIDI_SYNTHS);
+
+ CoreMIDI_GetObjectName(endpoint, szPname, sizeof(szPname));
+ MultiByteToWideChar(CP_ACP, 0, szPname, -1, destinations[i].caps.szPname, sizeof(destinations[i].caps.szPname)/sizeof(WCHAR));
+
+ name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("WineOutputPort.%d.%u"), i, getpid());
+ MIDIOutputPortCreate(wineMIDIClient, name, &destinations[i].port);
+ CFRelease(name);
+
+ destinations[i].caps.wTechnology = MOD_MIDIPORT;
+ destinations[i].caps.wChannelMask = 0xFFFF;
+
+ destinations[i].caps.wMid = 0x00FF; /* Manufac ID */
+ destinations[i].caps.wPid = 0x0001;
+ destinations[i].caps.vDriverVersion = 0x0001;
+ destinations[i].caps.dwSupport = 0;
+ destinations[i].caps.wVoices = 16;
+ destinations[i].caps.wNotes = 16;
+ }
+ return 1;
+}
+
+LONG CoreAudio_MIDIRelease(void)
+{
+ TRACE("\n");
+ if (wineMIDIClient) MIDIClientDispose(wineMIDIClient); /* MIDIClientDispose will close all ports */
+ HeapFree(GetProcessHeap(), 0, destinations);
+ return 1;
+}
+
+/**************************************************************************
+* modMessage
+*/
+DWORD WINAPI CoreAudio_modMessage(UINT wDevID, UINT wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
+{
+ TRACE("%d %08x %08x %08x %08x\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
+
+ switch (wMsg) {
+ case DRVM_INIT:
+ case DRVM_EXIT:
+ case DRVM_ENABLE:
+ case DRVM_DISABLE:
+ return 0;
+ case MODM_OPEN:
+ case MODM_CLOSE:
+ case MODM_DATA:
+ case MODM_LONGDATA:
+ case MODM_PREPARE:
+ case MODM_UNPREPARE:
+ case MODM_GETDEVCAPS:
+ case MODM_GETNUMDEVS:
+ case MODM_GETVOLUME:
+ case MODM_SETVOLUME:
+ case MODM_RESET:
+ default:
+ TRACE("Unsupported message (08%x)\n", wMsg);
+ }
+ return MMSYSERR_NOTSUPPORTED;
+}
+
+
+
+#else
+
+DWORD WINAPI CoreAudio_modMessage(UINT wDevID, UINT wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
+{
+ TRACE("%08x, %08x, %08x, %08x, %08x\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
+ return MMSYSERR_NOTENABLED;
+}
+
+#endif
diff --git a/dlls/winecoreaudio.drv/winecoreaudio.drv.spec b/dlls/winecoreaudio.drv/winecoreaudio.drv.spec
index 49fbfb2..dced551 100644
--- a/dlls/winecoreaudio.drv/winecoreaudio.drv.spec
+++ b/dlls/winecoreaudio.drv/winecoreaudio.drv.spec
@@ -1,3 +1,4 @@
@ stdcall -private DriverProc(long long long long long) CoreAudio_DriverProc
@ stdcall -private widMessage(long long long long long) CoreAudio_widMessage
@ stdcall -private wodMessage(long long long long long) CoreAudio_wodMessage
+@ stdcall -private modMessage(long long long long long) CoreAudio_modMessage