Initial MIDI support on Mac OS X (1/8)

Emmanuel Maillard mahanuu at free.fr
Tue Apr 24 18:25:21 CDT 2007


Hi,

This is the first patch for initial MIDI out support on Mac OS X.

Thanks

Emmanuel

Changelog :
- initialize MIDI outputs
- implement modMessage (stub)

-------------- next part --------------
From cc66203987f307d5292ef07ad988a2d9745d5166 Mon Sep 17 00:00:00 2001
From: Emmanuel Maillard <mahanuu at free.fr>
Date: Wed, 25 Apr 2007 00:55:33 +0200
Subject: [PATCH] - initialize MIDI outputs
- implement modMessage (stub)
---
 configure.ac                                  |    2 +-
 dlls/winecoreaudio.drv/Makefile.in            |    4 +-
 dlls/winecoreaudio.drv/audiounit.c            |  113 +++++++++++++++
 dlls/winecoreaudio.drv/coreaudio.c            |    4 +
 dlls/winecoreaudio.drv/coreaudio.h            |    3 +-
 dlls/winecoreaudio.drv/coremidi.c             |   55 +++++++
 dlls/winecoreaudio.drv/coremidi.h             |   61 ++++++++
 dlls/winecoreaudio.drv/midi.c                 |  189 +++++++++++++++++++++++++
 dlls/winecoreaudio.drv/winecoreaudio.drv.spec |    1 +
 9 files changed, 429 insertions(+), 3 deletions(-)

diff --git a/configure.ac b/configure.ac
index 1ea3ad2..757e957 100644
--- a/configure.ac
+++ b/configure.ac
@@ -988,7 +988,7 @@ case $host_os in
     if test "$ac_cv_header_CoreAudio_CoreAudio_h" = "yes" -a "$ac_cv_header_AudioUnit_AudioUnit_h" = "yes"
     then
         dnl CoreServices needed by AudioUnit
-        AC_SUBST(COREAUDIO,"-framework CoreAudio -framework AudioUnit -framework CoreServices")
+        AC_SUBST(COREAUDIO,"-framework CoreAudio -framework AudioUnit -framework CoreServices -framework AudioToolbox -framework CoreMIDI")
     fi
     case $host_cpu in
       *powerpc*)
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 @@ EXTRALIBS = $(LIBUUID) @COREAUDIO@
 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..b2181c3 100644
--- a/dlls/winecoreaudio.drv/audiounit.c
+++ b/dlls/winecoreaudio.drv/audiounit.c
@@ -22,9 +22,11 @@
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(wave);
+WINE_DECLARE_DEBUG_CHANNEL(midi);
 
 #ifdef HAVE_AUDIOUNIT_AUDIOUNIT_H
 #include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/AudioToolbox.h>
 
 extern OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon, 
 				AudioUnitRenderActionFlags *ioActionFlags, 
@@ -312,4 +314,115 @@ error:
     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..5a42840 100644
--- a/dlls/winecoreaudio.drv/coreaudio.c
+++ b/dlls/winecoreaudio.drv/coreaudio.c
@@ -43,6 +43,8 @@ static LRESULT CoreAudio_drvLoad(void)
 {
     TRACE("()\n");
     CoreAudio_WaveInit();
+    CoreAudio_MIDIInit();
+    
     return 1;
 }
 
@@ -53,6 +55,8 @@ static LRESULT CoreAudio_drvFree(void)
 {
     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..ae44e7e
--- /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..137243b
--- /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..a72081a
--- /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};
+    OSStatus err = noErr;
+    
+    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
\ No newline at end of file
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
-- 
1.4.4



More information about the wine-patches mailing list