midi mapper revisited

eric pouech eric.pouech at wanadoo.fr
Mon May 21 03:34:16 CDT 2001


this patch does two different things:
- it removes the midiIn mapper which doesn't exist under windows
- it adds the ability (for those who have several MIDI output channels
on their sound card(s))
  to drive how channels for the mapper will be directed to several midi
out devices

in order no to have error messages, you need to add this key to your
registry
[HKEY_LOCAL_USER\Software\Microsoft\Windows\CurrentVersion\Multimedia\MIDIMap]
989041554
"AutoScheme"=dword:00000000
"CurrentInstrument"="#0"
"UseScheme"=dword:00000000                                                                                                                                                        

this will tell the midi mapper to direct all channels to device #0

for more detailed use of the registry settings, read the MM
documentation

A+
-- 
---------------
Eric Pouech (http://perso.wanadoo.fr/eric.pouech/)
"The future will be better tomorrow", Vice President Dan Quayle
-------------- next part --------------
Name: midimap
ChangeLog: made midi mapper more robust
	added channel to device/channel mapping
	removed midiIn mapping (it doesn't exist on Windows)
GenDate: 2001/05/21 08:06:25 UTC
ModifiedFiles: dlls/winmm/midimap/midimap.c dlls/winmm/midimap/midimap.drv.spec winedefault.reg
AddedFiles: 
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/dlls/winmm/midimap/midimap.c,v
retrieving revision 1.7
diff -u -u -r1.7 midimap.c
--- dlls/winmm/midimap/midimap.c	2001/01/26 20:43:45	1.7
+++ dlls/winmm/midimap/midimap.c	2001/05/21 07:15:41
@@ -2,250 +2,435 @@
 /*				   
  * Wine Midi mapper driver
  *
- * Copyright 	1999 Eric Pouech
+ * Copyright 	1999, 2000, 2001 Eric Pouech
+ *
+ * TODO:
+ *	notification has to be implemented
+ *	IDF file loading
  */
 
 #include <string.h>
+#include <stdlib.h>
 #include "windef.h"
 #include "winbase.h"
 #include "wingdi.h"
 #include "winuser.h"
 #include "mmddk.h"
+#include "winreg.h"
 #include "debugtools.h"
 
+/*
+ * Here's how Windows stores the midiOut mapping information.
+ *
+ * Full form (in HKU) is:
+ *
+ * [Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap] 988836060
+ * "AutoScheme"=dword:00000000
+ * "ConfigureCount"=dword:00000004
+ * "CurrentInstrument"="Wine OSS midi"
+ * "CurrentScheme"="epp"
+ * "DriverList"=""
+ * "UseScheme"=dword:00000000
+ *
+ * AutoScheme: 		?
+ * CurrentInstrument: 	name of midiOut device to use when UseScheme is 0. Wine uses an extension
+ *			of the form #n to link to n'th midiOut device of the system
+ * CurrentScheme:	when UseScheme is non null, it's the scheme to use (see below)
+ * DriverList:		?
+ * UseScheme:		trigger for simple/complex mapping
+ *
+ * A scheme is defined (in HKLM) as:
+ *
+ * [System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Midi\\Schemes\\<nameScheme>]
+ * <nameScheme>:	one key for each defined scheme (system wide)
+ * under each one of these <nameScheme> keys, there's:
+ * [...\\<nameScheme>\\<idxDevice>]
+ * "Channels"="<bitMask>"
+ * (the default value of this key also refers to the name of the device).
+ *
+ * this defines, for each midiOut device (identified by its index in <idxDevice>), which 
+ * channels have to be mapped onto it. The <bitMask> defines the channels (from 0 to 15)
+ * will be mapped (mapping occurs for channel <ch> if bit <ch> is set in <bitMask>
+ *
+ * Further mapping information can also be defined in:
+ * [System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Midi\\Ports\\<nameDevice>\\Instruments\\<idx>]
+ * "Definition"="<.idf file>"
+ * "FriendlyName"="#for .idx file#"
+ * "Port"="<idxPort>"
+ *
+ * This last part isn't implemented (.idf file support).
+ */
+
 DEFAULT_DEBUG_CHANNEL(msacm);
 
-typedef	struct tagMIDIMAPDATA {
+typedef struct tagMIDIOUTPORT 
+{
+    char		name[MAXPNAMELEN];
+    int			loaded;
+    HMIDI		hMidi;
+    unsigned short	uDevID;
+    LPBYTE		lpbPatch;
+    unsigned int	aChn[16];
+} MIDIOUTPORT;
+
+typedef	struct tagMIDIMAPDATA 
+{
     struct tagMIDIMAPDATA*	self;
-    HMIDI	hMidi;
+    MIDIOUTPORT*	ChannelMap[16];
 } MIDIMAPDATA;
 
-static	BOOL	MIDIMAP_IsData(MIDIMAPDATA* mm)
+static	MIDIOUTPORT*	midiOutPorts;
+static  unsigned	numMidiOutPorts;
+
+static	BOOL	MIDIMAP_IsBadData(MIDIMAPDATA* mm)
 {
-    return (!IsBadReadPtr(mm, sizeof(MIDIMAPDATA)) && mm->self == mm);
+    if (!IsBadReadPtr(mm, sizeof(MIDIMAPDATA)) && mm->self == mm)
+	return FALSE;
+    TRACE("Bad midimap data (%p)\n", mm);
+    return TRUE;
 }
-
-/*======================================================================*
- *                  MIDI OUT part                                       *
- *======================================================================*/
 
-static	DWORD	modOpen(LPDWORD lpdwUser, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
+static BOOL	MIDIMAP_FindPort(const char* name, unsigned* dev)
 {
-    UINT 		nd = midiOutGetNumDevs();
-    UINT		i;
-    MIDIMAPDATA*	mom = HeapAlloc(GetProcessHeap(), 0, sizeof(MIDIMAPDATA));
-
-    TRACE("(%p %p %08lx\n", lpdwUser, lpDesc, dwFlags);
-
-    for (i = 0; i < nd; i++) {
-	if (midiOutOpen(&mom->hMidi, i, lpDesc->dwCallback, 
-			lpDesc->dwInstance, dwFlags) == MMSYSERR_NOERROR) {
-	    lpDesc->hMidi = mom->hMidi;
-	    *lpdwUser = (DWORD)mom;
-	    return MMSYSERR_NOERROR;
-	}
+    for (*dev = 0; *dev < numMidiOutPorts; (*dev)++) 
+    {
+	TRACE("%s\n", midiOutPorts[*dev].name);
+	if (strcmp(midiOutPorts[*dev].name, name) == 0)
+	    return TRUE;
     }
-    HeapFree(GetProcessHeap(), 0, mom);
-    return MMSYSERR_ALLOCATED;
+    /* try the form #nnn */
+    if (*name == '#' && isdigit(name[1])) 
+    {
+	*dev = atoi(name + 1);
+	if (*dev < numMidiOutPorts)
+	    return TRUE;
+    }
+    return FALSE;
 }
 
-static	DWORD	modClose(MIDIMAPDATA* mom)
+static BOOL	MIDIMAP_LoadSettingsDefault(MIDIMAPDATA* mom, const char* port)
 {
-    DWORD ret = midiOutClose(mom->hMidi);
-    if (ret == MMSYSERR_NOERROR)
-	HeapFree(GetProcessHeap(), 0, mom);
-    return ret;
-}
+    unsigned i, dev = 0;
 
-static	DWORD	modLongData(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2)
-{
-    return midiOutLongMsg(mom->hMidi, lpMidiHdr, dwParam2);
-}
+    if (port != NULL && !MIDIMAP_FindPort(port, &dev)) 
+    {
+	ERR("Registry glitch: couldn't find midi out (%s)\n", port);
+	dev = 0;
+    }
+    
+    /* sets default */
+    for (i = 0; i < 16; i++) mom->ChannelMap[i] = &midiOutPorts[dev];
 
-static	DWORD	modData(MIDIMAPDATA* mom, DWORD dwParam)
-{
-    return midiOutShortMsg(mom->hMidi, dwParam);
+    return TRUE;
 }
 
-static	DWORD	modPrepare(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2)
+static BOOL	MIDIMAP_LoadSettingsScheme(MIDIMAPDATA* mom, const char* scheme)
 {
-    return midiOutPrepareHeader(mom->hMidi, lpMidiHdr, dwParam2);
-}
+    HKEY	hSchemesKey, hKey, hPortKey;
+    unsigned	i, idx, dev;
+    char	buffer[256], port[256];
+    DWORD	type, size, mask;
 
-static	DWORD	modUnprepare(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2)
-{
-    return midiOutUnprepareHeader(mom->hMidi, lpMidiHdr, dwParam2);
-}
+    for (i = 0; i < 16; i++)	mom->ChannelMap[i] = NULL;
 
-static	DWORD	modGetDevCaps(UINT wDevID, MIDIMAPDATA* mom, LPMIDIOUTCAPSA lpMidiCaps, DWORD dwParam2)
-{
-    /* if opened low driver, forward message */
-    if (MIDIMAP_IsData(mom))
-	return midiOutGetDevCapsA(mom->hMidi, lpMidiCaps, dwParam2);
-    /* otherwise, return caps of mapper itself */
-    if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
-	lpMidiCaps->wMid = 0x00FF;
-	lpMidiCaps->wPid = 0x0001;
-	lpMidiCaps->vDriverVersion = 0x0100;
-	strcpy(lpMidiCaps->szPname, "Wine midi out mapper");
-	lpMidiCaps->wTechnology = MOD_MAPPER;
-	lpMidiCaps->wVoices = 0;
-	lpMidiCaps->wNotes = 0;
-	lpMidiCaps->wChannelMask = 0xFFFF;
-	lpMidiCaps->dwSupport = MIDICAPS_LRVOLUME | MIDICAPS_VOLUME;
+    if (RegOpenKeyA(HKEY_LOCAL_MACHINE, 
+		    "System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Midi\\Schemes", 
+		    &hSchemesKey)) 
+    {
+	return FALSE;
+    }
+    if (RegOpenKeyA(hSchemesKey, scheme, &hKey)) 
+    {
+	RegCloseKey(hSchemesKey);
+	return FALSE;
+    }
 
-	return MMSYSERR_NOERROR;
+    for (idx = 0; !RegEnumKeyA(hKey, idx, buffer, sizeof(buffer)); idx++) 
+    {
+	if (RegOpenKeyA(hKey, buffer, &hPortKey)) continue;
+
+	size = sizeof(port);
+	if (RegQueryValueExA(hPortKey, NULL, 0, &type, port, &size)) continue;
+
+	if (!MIDIMAP_FindPort(port, &dev)) continue;
+
+	size = sizeof(mask);
+	if (RegQueryValueExA(hPortKey, "Channels", 0, &type, (void*)&mask, &size))
+	    continue;
+
+	for (i = 0; i < 16; i++) 
+	{
+	    if (mask & (1 << i)) 
+	    {
+		if (mom->ChannelMap[i]) 
+		    ERR("Quirks in registry, channel %u is mapped twice\n", i);
+		mom->ChannelMap[i] = &midiOutPorts[dev];
+	    }
+	}
     }
-    ERR("This shouldn't happen\n");
-    return MMSYSERR_ERROR; 
-}
 
-static	DWORD	modGetVolume(UINT wDevID, MIDIMAPDATA* mom, LPDWORD lpVol)
-{
-    if (MIDIMAP_IsData(mom))
-	return midiOutGetVolume(mom->hMidi, lpVol);
-    return MMSYSERR_ERROR;
+    RegCloseKey(hSchemesKey);
+    RegCloseKey(hKey);
+    
+    return TRUE;
 }
 
-static	DWORD	modSetVolume(UINT wDevID, MIDIMAPDATA* mom, DWORD vol)
+static BOOL	MIDIMAP_LoadSettings(MIDIMAPDATA* mom)
 {
-    if (MIDIMAP_IsData(mom))
-	return midiOutSetVolume(mom->hMidi, vol);
-    return MMSYSERR_ERROR;
-}
+    HKEY 	hKey;
+    BOOL	ret;
 
-static	DWORD	modReset(MIDIMAPDATA* mom)
-{
-    return midiOutReset(mom->hMidi);
+    if (RegOpenKeyA(HKEY_CURRENT_USER, 
+		    "Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap", &hKey)) 
+    {
+	ret = MIDIMAP_LoadSettingsDefault(mom, NULL);
+    }
+    else 
+    {
+	DWORD	type, size, out;
+	char	buffer[256];
+    
+	ret = 2;
+	size = sizeof(out);
+	if (!RegQueryValueExA(hKey, "UseScheme", 0, &type, (void*)&out, &size) && out) 
+	{
+	    size = sizeof(buffer);
+	    if (!RegQueryValueExA(hKey, "CurrentScheme", 0, &type, buffer, &size)) 
+	    {
+		if (!(ret = MIDIMAP_LoadSettingsScheme(mom, buffer)))
+		    ret = MIDIMAP_LoadSettingsDefault(mom, NULL);
+	    }
+	    else 
+	    {
+		ERR("Wrong registry: UseScheme is active, but no CurrentScheme found\n");
+	    }
+	}
+	if (ret == 2) 
+	{
+	    size = sizeof(buffer);
+	    if (!RegQueryValueExA(hKey, "CurrentInstrument", 0, &type, buffer, &size) && *buffer) 
+	    {
+		ret = MIDIMAP_LoadSettingsDefault(mom, buffer);
+	    }
+	    else 
+	    {
+		ret = MIDIMAP_LoadSettingsDefault(mom, NULL);
+	    }
+	}
+    }
+    RegCloseKey(hKey);
+
+    if (TRACE_ON(msacm)) 
+    {
+	unsigned	i;
+
+	for (i = 0; i < 16; i++) 
+	{
+	    TRACE("chnMap[% 2d] => %d\n", 
+		  i, mom->ChannelMap[i] ? mom->ChannelMap[i]->uDevID : -1);
+	}
+    }
+    return ret;
 }
 
-/**************************************************************************
- * 				MIDIMAP_modMessage	[sample driver]
- */
-DWORD WINAPI MIDIMAP_modMessage(UINT wDevID, UINT wMsg, DWORD dwUser, 
-				DWORD dwParam1, DWORD dwParam2)
+static	DWORD	modOpen(LPDWORD lpdwUser, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
 {
-    TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
-	  wDevID, wMsg, dwUser, dwParam1, dwParam2);
-    
-    switch (wMsg) {
-    case DRVM_INIT:
-    case DRVM_EXIT:
-    case DRVM_ENABLE:
-    case DRVM_DISABLE:
-	/* FIXME: Pretend this is supported */
-	return 0;
+    MIDIMAPDATA*	mom = HeapAlloc(GetProcessHeap(), 0, sizeof(MIDIMAPDATA));
 
-    case MODM_OPEN:	 	return modOpen		((LPDWORD)dwUser,      (LPMIDIOPENDESC)dwParam1,dwParam2);
-    case MODM_CLOSE:	 	return modClose		((MIDIMAPDATA*)dwUser);
+    TRACE("(%p %p %08lx\n", lpdwUser, lpDesc, dwFlags);
 
-    case MODM_DATA:		return modData		((MIDIMAPDATA*)dwUser, dwParam1);
-    case MODM_LONGDATA:		return modLongData      ((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1,     dwParam2);
-    case MODM_PREPARE:	 	return modPrepare	((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, 	dwParam2);
-    case MODM_UNPREPARE: 	return modUnprepare	((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, 	dwParam2);
+    if (!mom) return MMSYSERR_NOMEM;
 
-    case MODM_GETDEVCAPS:	return modGetDevCaps	(wDevID, (MIDIMAPDATA*)dwUser, (LPMIDIOUTCAPSA)dwParam1,dwParam2);
-    case MODM_GETNUMDEVS:	return 1;
-    case MODM_GETVOLUME:	return modGetVolume	(wDevID, (MIDIMAPDATA*)dwUser, (LPDWORD)dwParam1);
-    case MODM_SETVOLUME:	return modSetVolume	(wDevID, (MIDIMAPDATA*)dwUser, dwParam1);
-    case MODM_RESET:		return modReset		((MIDIMAPDATA*)dwUser);
-    default:
-	FIXME("unknown message %d!\n", wMsg);
+    if (MIDIMAP_LoadSettings(mom)) 
+    {
+	*lpdwUser = (DWORD)mom;
+	mom->self = mom;
+
+	return MMSYSERR_NOERROR;
     }
-    return MMSYSERR_NOTSUPPORTED;
+    HeapFree(GetProcessHeap(), 0, mom);
+    return MIDIERR_INVALIDSETUP;
 }
-
-/*======================================================================*
- *                  MIDI IN part                                        *
- *======================================================================*/
 
-static	DWORD	midOpen(LPDWORD lpdwUser, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
+static	DWORD	modClose(MIDIMAPDATA* mom)
 {
-    UINT 		nd = midiInGetNumDevs();
-    UINT		i;
-    MIDIMAPDATA*	mim = HeapAlloc(GetProcessHeap(), 0, sizeof(MIDIMAPDATA));
+    UINT	i;
+    DWORD	ret = MMSYSERR_NOERROR;
 
-    TRACE("(%p %p %08lx\n", lpdwUser, lpDesc, dwFlags);
+    if (MIDIMAP_IsBadData(mom)) 	return MMSYSERR_ERROR;
 
-    for (i = 0; i < nd; i++) {
-	if (midiInOpen(&mim->hMidi, i, lpDesc->dwCallback, 
-			lpDesc->dwInstance, dwFlags) == MMSYSERR_NOERROR) {
-	    lpDesc->hMidi = mim->hMidi;
-	    *lpdwUser = (DWORD)mim;
-	    return MMSYSERR_NOERROR;
+    for (i = 0; i < 16; i++) 
+    {
+	DWORD	t;
+	if (mom->ChannelMap[i] && mom->ChannelMap[i]->loaded > 0) 
+	{
+	    t = midiOutClose(mom->ChannelMap[i]->hMidi);
+	    if (t == MMSYSERR_NOERROR) 
+	    {
+		mom->ChannelMap[i]->loaded = 0;
+		mom->ChannelMap[i]->hMidi = 0;
+	    }
+	    else if (ret == MMSYSERR_NOERROR)
+		ret = t;
 	}
     }
-    HeapFree(GetProcessHeap(), 0, mim);
-    return MMSYSERR_ALLOCATED;
-}
-
-static	DWORD	midClose(MIDIMAPDATA* mim)
-{
-    DWORD ret = midiInClose(mim->hMidi);
     if (ret == MMSYSERR_NOERROR)
-	HeapFree(GetProcessHeap(), 0, mim);
+	HeapFree(GetProcessHeap(), 0, mom);
     return ret;
 }
 
-static	DWORD	midAddBuffer(MIDIMAPDATA* mim, LPMIDIHDR lpMidiHdr, DWORD dwParam2)
+static	DWORD	modLongData(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2)
 {
-    return midiInAddBuffer(mim->hMidi, lpMidiHdr, dwParam2);
+    WORD	chn;
+    DWORD	ret = MMSYSERR_NOERROR;
+    MIDIHDR	mh;
+
+    if (MIDIMAP_IsBadData(mom))
+	return MMSYSERR_ERROR;
+
+    mh = *lpMidiHdr;
+    for (chn = 0; chn < 16; chn++) 
+    {
+	if (mom->ChannelMap[chn] && mom->ChannelMap[chn]->loaded > 0) 
+	{
+	    mh.dwFlags = 0;
+	    midiOutPrepareHeader(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh));
+	    ret = midiOutLongMsg(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh));
+	    midiOutUnprepareHeader(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh));
+	    if (ret != MMSYSERR_NOERROR) break;
+	}
+    }
+    return ret;
 }
 
-static	DWORD	midPrepare(MIDIMAPDATA* mim, LPMIDIHDR lpMidiHdr, DWORD dwParam2)
+static	DWORD	modData(MIDIMAPDATA* mom, DWORD dwParam)
 {
-    return midiInPrepareHeader(mim->hMidi, lpMidiHdr, dwParam2);
-}
+    BYTE	lb = LOBYTE(LOWORD(dwParam));
+    WORD	chn = lb & 0x0F;
+    DWORD	ret = MMSYSERR_NOERROR;
+
+    if (MIDIMAP_IsBadData(mom))
+	return MMSYSERR_ERROR;
+
+    if (!mom->ChannelMap[chn]) return MMSYSERR_NOERROR;
+
+    switch (lb & 0xF0) 
+    {
+    case 0x80:
+    case 0x90:
+    case 0xA0:
+    case 0xB0:
+    case 0xC0:
+    case 0xD0:
+    case 0xE0:
+	if (mom->ChannelMap[chn]->loaded == 0) 
+	{
+	    if (midiOutOpen(&mom->ChannelMap[chn]->hMidi, mom->ChannelMap[chn]->uDevID,
+			    0L, 0L, CALLBACK_NULL) == MMSYSERR_NOERROR)
+		mom->ChannelMap[chn]->loaded = 1;
+	    else
+		mom->ChannelMap[chn]->loaded = -1;
+	    /* FIXME: should load here the IDF midi data... and allow channel and
+	     * patch mappings 
+	     */
+	}
+	if (mom->ChannelMap[chn]->loaded > 0) 
+	{
+	    /* change channel */
+	    dwParam &= ~0x0F;
+	    dwParam |= mom->ChannelMap[chn]->aChn[chn];
+
+	    if ((LOBYTE(LOWORD(dwParam)) & 0xF0) == 0xC0 /* program change */ &&
+		mom->ChannelMap[chn]->lpbPatch) 
+	    {
+		BYTE patch = HIBYTE(LOWORD(dwParam));
+
+		/* change patch */
+		dwParam &= ~0x0000FF00;
+		dwParam |= mom->ChannelMap[chn]->lpbPatch[patch];
+	    }
+	    ret = midiOutShortMsg(mom->ChannelMap[chn]->hMidi, dwParam);
+	}
+	break;
+    case 0xF0:
+	for (chn = 0; chn < 16; chn++) 
+	{
+	    if (mom->ChannelMap[chn]->loaded > 0)
+		ret = midiOutShortMsg(mom->ChannelMap[chn]->hMidi, dwParam);
+	}
+	break;
+    default:
+	FIXME("ooch %lu\n", dwParam);
+    }
 
-static	DWORD	midUnprepare(MIDIMAPDATA* mim, LPMIDIHDR lpMidiHdr, DWORD dwParam2)
-{
-    return midiInUnprepareHeader(mim->hMidi, lpMidiHdr, dwParam2);
+    return ret;
 }
 
-static	DWORD	midGetDevCaps(UINT wDevID, MIDIMAPDATA* mim, LPMIDIINCAPSA lpMidiCaps, DWORD dwParam2)
+static	DWORD	modPrepare(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2)
 {
-    /* if opened low driver, forward message */
-    if (MIDIMAP_IsData(mim))
-	return midiInGetDevCapsA(mim->hMidi, lpMidiCaps, dwParam2);
-    /* otherwise, return caps of mapper itself */
-    if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
-	lpMidiCaps->wMid = 0x00FF;
-	lpMidiCaps->wPid = 0x0001;
-	lpMidiCaps->vDriverVersion = 0x0100;
-	strcpy(lpMidiCaps->szPname, "Wine midi int mapper");
-	lpMidiCaps->dwSupport = 0;
+    if (MIDIMAP_IsBadData(mom)) return MMSYSERR_ERROR;
+    if (lpMidiHdr->dwFlags & (MHDR_ISSTRM|MHDR_PREPARED))
+	return MMSYSERR_INVALPARAM;
 
-	return MMSYSERR_NOERROR;
-    }
-    ERR("This shouldn't happen\n");
-    return MMSYSERR_ERROR; 
+    lpMidiHdr->dwFlags |= MHDR_PREPARED;
+    return MMSYSERR_NOERROR;
 }
 
-static	DWORD	midStop(MIDIMAPDATA* mim)
+static	DWORD	modUnprepare(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2)
 {
-    return midiInStop(mim->hMidi);
-}
+    if (MIDIMAP_IsBadData(mom)) return MMSYSERR_ERROR;
+    if ((lpMidiHdr->dwFlags & MHDR_ISSTRM) || !(lpMidiHdr->dwFlags & MHDR_PREPARED))
+	return MMSYSERR_INVALPARAM;
+
+    lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
+    return MMSYSERR_NOERROR;
+}
+
+static	DWORD	modGetDevCaps(UINT wDevID, MIDIMAPDATA* mom, LPMIDIOUTCAPSA lpMidiCaps, DWORD size)
+{
+    lpMidiCaps->wMid = 0x00FF;
+    lpMidiCaps->wPid = 0x0001;
+    lpMidiCaps->vDriverVersion = 0x0100;
+    strcpy(lpMidiCaps->szPname, "Wine midi out mapper");
+    lpMidiCaps->wTechnology = MOD_MAPPER;
+    lpMidiCaps->wVoices = 0;
+    lpMidiCaps->wNotes = 0;
+    lpMidiCaps->wChannelMask = 0xFFFF;
+    lpMidiCaps->dwSupport = 0L;
 
-static	DWORD	midStart(MIDIMAPDATA* mim)
-{
-    return midiInStart(mim->hMidi);
+    return MMSYSERR_NOERROR;
 }
 
-static	DWORD	midReset(MIDIMAPDATA* mim)
+static	DWORD	modReset(MIDIMAPDATA* mom)
 {
-    return midiInReset(mim->hMidi);
+    WORD	chn;
+    DWORD	ret = MMSYSERR_NOERROR;
+
+    if (MIDIMAP_IsBadData(mom))
+	return MMSYSERR_ERROR;
+
+    for (chn = 0; chn < 16; chn++) 
+    {
+	if (mom->ChannelMap[chn] && mom->ChannelMap[chn]->loaded > 0) 
+	{
+	    ret = midiOutReset(mom->ChannelMap[chn]->hMidi);
+	    if (ret != MMSYSERR_NOERROR) break;
+	}
+    }
+    return ret;
 }
 
 /**************************************************************************
- * 				MIDIMAP_midMessage	[sample driver]
+ * 				MIDIMAP_modMessage	[sample driver]
  */
-DWORD WINAPI MIDIMAP_midMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
+DWORD WINAPI MIDIMAP_modMessage(UINT wDevID, UINT wMsg, DWORD dwUser, 
 				DWORD dwParam1, DWORD dwParam2)
 {
     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
 	  wDevID, wMsg, dwUser, dwParam1, dwParam2);
-
-    switch (wMsg) {
+    
+    switch (wMsg) 
+    {
     case DRVM_INIT:
     case DRVM_EXIT:
     case DRVM_ENABLE:
@@ -253,19 +438,21 @@
 	/* FIXME: Pretend this is supported */
 	return 0;
 
-    case MIDM_OPEN:		return midOpen          ((LPDWORD)dwUser,     (LPMIDIOPENDESC)dwParam1, dwParam2);
-    case MIDM_CLOSE:		return midClose         ((MIDIMAPDATA*)dwUser);
+    case MODM_OPEN:	 	return modOpen		((LPDWORD)dwUser,      (LPMIDIOPENDESC)dwParam1,dwParam2);
+    case MODM_CLOSE:	 	return modClose		((MIDIMAPDATA*)dwUser);
 
-    case MIDM_ADDBUFFER:	return midAddBuffer     ((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, dwParam2);
-    case MIDM_PREPARE:		return midPrepare       ((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, dwParam2);
-    case MIDM_UNPREPARE:	return midUnprepare     ((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, dwParam2);
-    case MIDM_GETDEVCAPS:	return midGetDevCaps    (wDevID, (MIDIMAPDATA*)dwUser, (LPMIDIINCAPSA)dwParam1, dwParam2);
-    case MIDM_GETNUMDEVS:	return 1;
-    case MIDM_RESET:		return midReset         ((MIDIMAPDATA*)dwUser);
-    case MIDM_START:		return midStart         ((MIDIMAPDATA*)dwUser);
-    case MIDM_STOP:		return midStop          ((MIDIMAPDATA*)dwUser);
+    case MODM_DATA:		return modData		((MIDIMAPDATA*)dwUser, dwParam1);
+    case MODM_LONGDATA:		return modLongData      ((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1,     dwParam2);
+    case MODM_PREPARE:	 	return modPrepare	((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, 	dwParam2);
+    case MODM_UNPREPARE: 	return modUnprepare	((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, 	dwParam2);
+    case MODM_RESET:		return modReset		((MIDIMAPDATA*)dwUser);
+
+    case MODM_GETDEVCAPS:	return modGetDevCaps	(wDevID, (MIDIMAPDATA*)dwUser, (LPMIDIOUTCAPSA)dwParam1,dwParam2);
+    case MODM_GETNUMDEVS:	return 1;
+    case MODM_GETVOLUME:	return MMSYSERR_NOTSUPPORTED;
+    case MODM_SETVOLUME:	return MMSYSERR_NOTSUPPORTED;
     default:
-	FIXME("unknown message %u!\n", wMsg);
+	FIXME("unknown message %d!\n", wMsg);
     }
     return MMSYSERR_NOTSUPPORTED;
 }
@@ -274,18 +461,38 @@
  *                  Driver part                                         *
  *======================================================================*/
 
-static	struct WINE_MIDIMAP* oss = NULL;
-
 /**************************************************************************
  * 				MIDIMAP_drvOpen			[internal]	
  */
 static	DWORD	MIDIMAP_drvOpen(LPSTR str)
 {
-    if (oss)
+    MIDIOUTCAPSA	moc;
+    unsigned		dev, i;
+
+    if (midiOutPorts)
 	return 0;
     
-    /* I know, this is ugly, but who cares... */
-    oss = (struct WINE_MIDIMAP*)1;
+    numMidiOutPorts = midiOutGetNumDevs();
+    midiOutPorts = HeapAlloc(GetProcessHeap(), 0, 
+			     numMidiOutPorts * sizeof(MIDIOUTPORT));
+    for (dev = 0; dev < numMidiOutPorts; dev++) 
+    {
+	if (midiOutGetDevCapsA((HMIDIOUT)dev, &moc, sizeof(moc)) == 0L) 
+	{
+	    strcpy(midiOutPorts[dev].name, moc.szPname);
+	    midiOutPorts[dev].loaded = 0;
+	    midiOutPorts[dev].hMidi = 0;
+	    midiOutPorts[dev].uDevID = 0;
+	    midiOutPorts[dev].lpbPatch = NULL;
+	    for (i = 0; i < 16; i++)
+		midiOutPorts[dev].aChn[i] = i;
+	}
+	else 
+	{
+	    midiOutPorts[dev].loaded = -1;
+	}
+    }
+
     return 1;
 }
 
@@ -294,8 +501,10 @@
  */
 static	DWORD	MIDIMAP_drvClose(DWORD dwDevID)
 {
-    if (oss) {
-	oss = NULL;
+    if (midiOutPorts) 
+    {
+	HeapFree(GetProcessHeap(), 0, midiOutPorts);
+	midiOutPorts = NULL;
 	return 1;
     }
     return 0;
@@ -310,7 +519,8 @@
 /* EPP     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",  */
 /* EPP 	  dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
     
-    switch(wMsg) {
+    switch (wMsg) 
+    {
     case DRV_LOAD:		return 1;
     case DRV_FREE:		return 1;
     case DRV_OPEN:		return MIDIMAP_drvOpen((LPSTR)dwParam1);
Index: dlls/winmm/midimap/midimap.drv.spec
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/dlls/winmm/midimap/midimap.drv.spec,v
retrieving revision 1.3
diff -u -u -r1.3 midimap.drv.spec
--- dlls/winmm/midimap/midimap.drv.spec	2000/11/05 04:53:18	1.3
+++ dlls/winmm/midimap/midimap.drv.spec	2000/11/14 07:20:59
@@ -4,11 +4,11 @@
 
 import winmm.dll
 import user32.dll
+import advapi32.dll
 import kernel32.dll
 import	ntdll.dll
 
 debug_channels (msacm)
 
 @ stdcall DriverProc(long long long long long) MIDIMAP_DriverProc
-@ stdcall midMessage(long long long long long) MIDIMAP_midMessage
 @ stdcall modMessage(long long long long long) MIDIMAP_modMessage
Index: winedefault.reg
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/winedefault.reg,v
retrieving revision 1.23
diff -u -u -r1.23 winedefault.reg
--- winedefault.reg	2001/05/10 03:10:06	1.23
+++ winedefault.reg	2001/05/21 08:03:08
@@ -155,6 +155,16 @@
 "ThreadingModel"="Both"
 
 #
+# Entries for Multimedia
+#
+
+# Midi Mapper
+[HKEY_LOCAL_USER\Software\Microsoft\Windows\CurrentVersion\Multimedia\MIDIMap] 989041554
+"AutoScheme"=dword:00000000
+"CurrentInstrument"="#0"
+"UseScheme"=dword:00000000
+
+#
 # Entries for IWebBrowser
 # Used by Internet Explorer HTML-rendering control
 #


More information about the wine-patches mailing list