Index: trunk/src/winmm/initwinmm.cpp
===================================================================
--- trunk/src/winmm/initwinmm.cpp	(revision 8470)
+++ trunk/src/winmm/initwinmm.cpp	(revision 8472)
@@ -1,3 +1,3 @@
-/* $Id: initwinmm.cpp,v 1.6 2001-12-23 09:43:12 sandervl Exp $
+/* $Id: initwinmm.cpp,v 1.7 2002-05-22 20:19:11 sandervl Exp $
  *
  * WINMM DLL entry point
@@ -49,4 +49,5 @@
 #include "initwinmm.h"
 #include <custombuild.h>
+#include "mixer.h"
 
 #define DBG_LOCALLOG    DBG_initterm
@@ -169,4 +170,5 @@
             RegCloseKey(hKey);
         }
+        mixerInit();
         return TRUE;
    }
@@ -181,4 +183,5 @@
         IRTMidiShutdown;  /* JT: Shutdown RT Midi subsystem, if running. */
 
+        mixerExit();
         if(MMPMLibraryHandle) DosFreeModule(MMPMLibraryHandle);
         return TRUE;
Index: trunk/src/winmm/mixer.cpp
===================================================================
--- trunk/src/winmm/mixer.cpp	(revision 8470)
+++ trunk/src/winmm/mixer.cpp	(revision 8472)
@@ -1,17 +1,9 @@
-/* $Id: mixer.cpp,v 1.11 2002-05-22 15:50:25 sandervl Exp $ */
+/* $Id: mixer.cpp,v 1.12 2002-05-22 20:19:11 sandervl Exp $ */
 
 /*
- * Mixer stubs
+ * Mixer functions
  *
- * Copyright 1998 Joel Troster
+ * Copyright 2002 Sander van Leeuwen (sandervl@xs4all.nl)
  * 
- * TODO: This is just a hack to fool apps into thinking a mixer exists
- *       Must be redesigned
- *
- * Based on Wine code (dlls\winmm\wineoss\mixer.c)
- * Copyright 	1997 Marcus Meissner
- * 		1999 Eric Pouech
- *
- *
  * Project Odin Software License can be found in LICENSE.TXT
  *
@@ -33,4 +25,7 @@
 #include "waveoutdart.h"
 #include "winmm.h"
+#include "initwinmm.h"
+#include "mixer.h"
+#include "mixeros2.h"
 
 #define DBG_LOCALLOG	DBG_mixer
@@ -38,82 +33,8 @@
 
 
-#define WINMM_MIXERSTRING_A	"OS/2 WINMM Mixer"
-#define WINMM_MIXERSTRING_W	(LPWSTR)L"OS/2 WINMM Mixer"
-
-#define WINMM_SHORTNAME_WAVEOUT_A	"Wave Out"
-#define WINMM_SHORTNAME_WAVEOUT_W	(LPWSTR)L"Wave Out"
-#define WINMM_SHORTNAME_LINEOUT_A	"Line Out"
-#define WINMM_SHORTNAME_LINEOUT_W	(LPWSTR)L"Line Out"
-
-#define SOUND_MIXER_LINEOUT	0
-#define SOUND_MIXER_WAVEOUT	1
-#define SOUND_MIXER_MAXID	2
-
-DWORD MIX_Volume[SOUND_MIXER_MAXID] = { 0x80008000, 0x80008000};
-DWORD MIX_Mute[SOUND_MIXER_MAXID]   = { 0, 0};
-
-//
-// All Stubs
-//
-
-/**************************************************************************
- * 				MIX_SplitControlID		[internal]
- */
-static BOOL MIX_SplitControlID(DWORD controlID, LPDWORD lineID, LPDWORD controlType)
-{
-    *lineID = controlID / 2;
-    *controlType = (controlID & 1) ? 
-	MIXERCONTROL_CONTROLTYPE_MUTE : MIXERCONTROL_CONTROLTYPE_VOLUME;
-
-    return *lineID < SOUND_MIXER_MAXID;
-}
-/**************************************************************************
- * 				MIX_MakeControlID		[internal]
- */
-static DWORD MIX_MakeControlID(DWORD lineID, DWORD controlType)
-{
-    switch (controlType) {
-    case MIXERCONTROL_CONTROLTYPE_VOLUME:
-	return 2 * lineID + 0;
-    case MIXERCONTROL_CONTROLTYPE_MUTE:
-	return 2 * lineID + 1;
-    }
-    dprintf(("MIX_MakeControlID: Internal error"));
-    return 0x00FADE00;
-}
-/**************************************************************************
- * 				MIX_DoGetLineControls		[internal]
- */
-static void MIX_DoGetLineControls(LPMIXERCONTROLA mc, DWORD lineID, DWORD dwType)
-{
-    mc->cbStruct = sizeof(MIXERCONTROLA);
-    
-    switch (dwType) {
-    case MIXERCONTROL_CONTROLTYPE_VOLUME:
-	mc->dwControlID = MIX_MakeControlID(lineID, dwType);
-	mc->dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
-	mc->fdwControl = 0;
-	mc->cMultipleItems = 0;
-	lstrcpynA(mc->szShortName, "Vol", MIXER_SHORT_NAME_CHARS);
-	lstrcpynA(mc->szName, "Volume", MIXER_LONG_NAME_CHARS);
-	memset(&mc->Bounds, 0, sizeof(mc->Bounds));
-	mc->Bounds.s1.dwMinimum = 0;
-	mc->Bounds.s1.dwMaximum = 65535;
-	memset(&mc->Metrics, 0, sizeof(mc->Metrics));
-	break;
-    case MIXERCONTROL_CONTROLTYPE_MUTE:
-	mc->dwControlID = MIX_MakeControlID(lineID, dwType);
-	mc->dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
-	mc->fdwControl = 0;
-	mc->cMultipleItems = 0;
-	lstrcpynA(mc->szShortName, "Mute", MIXER_SHORT_NAME_CHARS);
-	lstrcpynA(mc->szName, "Mute", MIXER_LONG_NAME_CHARS);
-	memset(&mc->Bounds, 0, sizeof(mc->Bounds));
-	memset(&mc->Metrics, 0, sizeof(mc->Metrics));
-	break;
-    default:
-	dprintf(("MIX_DoGetLineControls: Internal error: unknown type: %08lx\n", dwType));
-    }
-}
+MIXERLINEA    mixerDest[MAX_MIXER_DESTINATIONS] = {0};
+MIXERLINEA    mixerSource[MAX_MIXER_SOURCES]    = {0};
+MIXERCONTROLA mixerControls[MAX_MIXER_CONTROLS] = {0};
+
 /******************************************************************************/
 /******************************************************************************/
@@ -127,54 +48,11 @@
     switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
     case MIXER_GETCONTROLDETAILSF_VALUE:
-	if(MIX_SplitControlID(lpmcd->dwControlID, &lineID, &controlType)) {
-	    switch (controlType) 
-	    {
-	    case MIXERCONTROL_CONTROLTYPE_VOLUME:
-		{
-		    LPMIXERCONTROLDETAILS_UNSIGNED	mcdu;
-		    int					val;
-
-		    /* return value is 00RL (4 bytes)... */
-		    val = MIX_Volume[lineID];
-	    
-		    switch (lpmcd->cChannels) {
-		    case 1:
-			/* mono... so R = L */
-			mcdu = (LPMIXERCONTROLDETAILS_UNSIGNED)lpmcd->paDetails;
-			mcdu->dwValue = LOWORD(val);
-			break;
-		    case 2:
-			/* stereo, left is paDetails[0] */
-			mcdu = (LPMIXERCONTROLDETAILS_UNSIGNED)((char*)lpmcd->paDetails + 0 * lpmcd->cbDetails);
-			mcdu->dwValue = LOWORD(val);
-			mcdu = (LPMIXERCONTROLDETAILS_UNSIGNED)((char*)lpmcd->paDetails + 1 * lpmcd->cbDetails);
-			mcdu->dwValue = HIWORD(val);
-			break;
-		    default:
-			dprintf(("Unknown cChannels (%ld)\n", lpmcd->cChannels));
-			return MMSYSERR_INVALPARAM;
-		    }
-		}
-		break;
-	    case MIXERCONTROL_CONTROLTYPE_MUTE:
-		{
-		    LPMIXERCONTROLDETAILS_BOOLEAN	mcdb;
-	    
-		    /* we mute both channels at the same time */
-		    mcdb = (LPMIXERCONTROLDETAILS_BOOLEAN)lpmcd->paDetails;
-		    mcdb->fValue = MIX_Mute[lineID];
-		}
-		break;
-	    }
-	    ret = MMSYSERR_NOERROR;
-	} else {
-	    ret = MMSYSERR_INVALPARAM;
-	}
-	break;
+        break;
     case MIXER_GETCONTROLDETAILSF_LISTTEXT:
-	dprintf(("mixerGetControlDetailsA: NIY\n"));
-	break;
+    	dprintf(("mixerGetControlDetailsA: NIY\n"));
+	    break;
     default:
-	dprintf(("Unknown flag (%08lx)\n", fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK));
+	    dprintf(("Unknown flag (%08lx)\n", fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK));
+        break;
     }
     return ret;
@@ -199,50 +77,11 @@
     switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
     case MIXER_GETCONTROLDETAILSF_VALUE:
-	if (MIX_SplitControlID(lpmcd->dwControlID, &lineID, &controlType)) {
-	    switch (controlType) {
-	    case MIXERCONTROL_CONTROLTYPE_VOLUME:
-		{
-		    LPMIXERCONTROLDETAILS_UNSIGNED	mcdu;
-		    
-		    /* val should contain 00RL */
-		    switch (lpmcd->cChannels) {
-		    case 1:
-			/* mono... so R = L */
-			mcdu = (LPMIXERCONTROLDETAILS_UNSIGNED)lpmcd->paDetails;
-			val = mcdu->dwValue;
-			break;
-		    case 2:
-			/* stereo, left is paDetails[0] */
-			mcdu = (LPMIXERCONTROLDETAILS_UNSIGNED)((char*)lpmcd->paDetails + 0 * lpmcd->cbDetails);
-			val = mcdu->dwValue;
-			mcdu = (LPMIXERCONTROLDETAILS_UNSIGNED)((char*)lpmcd->paDetails + 1 * lpmcd->cbDetails);
-			val += (mcdu->dwValue) << 16;
-			break;
-		    default:
-			dprintf(("Unknown cChannels (%ld)\n", lpmcd->cChannels));
-			return MMSYSERR_INVALPARAM;
-		    }
-		    
-  	 	    MIX_Volume[lineID] = val;
-		}
-		ret = MMSYSERR_NOERROR;
-		break;
-	    case MIXERCONTROL_CONTROLTYPE_MUTE:
-		{
-		    LPMIXERCONTROLDETAILS_BOOLEAN	mcdb;
-		    
-		    mcdb = (LPMIXERCONTROLDETAILS_BOOLEAN)lpmcd->paDetails;
-		    MIX_Mute[lineID] = mcdb->fValue;
-		}
-		ret = MMSYSERR_NOERROR;
-		break;
-	    }
-	}
-	break;
+    	break;
     case MIXER_GETCONTROLDETAILSF_LISTTEXT:
-	dprintf(("mixerSetControlDetails: NIY\n"));
-	break;
+    	dprintf(("mixerSetControlDetails: NIY\n"));
+    	break;
     default:
-	dprintf(("Unknown flag (%08lx)\n", fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK));
+	    dprintf(("Unknown flag (%08lx)\n", fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK));
+        break;
     }
     return MMSYSERR_NOTSUPPORTED;
@@ -267,21 +106,13 @@
     	} 
         else {
-	        MIX_DoGetLineControls(&lpMlc->pamxctrl[0], lpMlc->dwLineID, MIXERCONTROL_CONTROLTYPE_VOLUME);
-	        MIX_DoGetLineControls(&lpMlc->pamxctrl[1], lpMlc->dwLineID, MIXERCONTROL_CONTROLTYPE_MUTE);
 	    }
 	    break;
     case MIXER_GETLINECONTROLSF_ONEBYID:
-	    if (MIX_SplitControlID(lpMlc->u.dwControlID, &lineID, &controlType))
-	        MIX_DoGetLineControls(&lpMlc->pamxctrl[0], lineID, controlType);
-	    else 
-	        dwRet = MMSYSERR_INVALPARAM;
 	    break;
     case MIXER_GETLINECONTROLSF_ONEBYTYPE:
 	    switch (lpMlc->u.dwControlType & MIXERCONTROL_CT_CLASS_MASK) {
 	    case MIXERCONTROL_CT_CLASS_FADER:
-    	    MIX_DoGetLineControls(&lpMlc->pamxctrl[0], lpMlc->dwLineID, MIXERCONTROL_CONTROLTYPE_VOLUME);
 	        break;
 	    case MIXERCONTROL_CT_CLASS_SWITCH:
-    	    MIX_DoGetLineControls(&lpMlc->pamxctrl[0], lpMlc->dwLineID, MIXERCONTROL_CONTROLTYPE_MUTE);
 	        break;
 	    default:
@@ -302,56 +133,4 @@
     dprintf(("WINMM:mixerGetGetLineControlsW - stub\n" ));
     return MIXERR_INVALLINE;
-}
-/******************************************************************************/
-/******************************************************************************/
-MMRESULT WINAPI mixerGetDevCapsA(UINT uMxId, LPMIXERCAPSA pmxcaps, UINT cbmxcaps)
-{
-    if(DartWaveOut::getNumDevices() == 0) {
-        memset(pmxcaps, 0, sizeof(*pmxcaps));
-        return MMSYSERR_NODRIVER;
-    }
-
-    // we have to fill in this thing
-    pmxcaps->wMid = 0;                  /* manufacturer ID */
-    pmxcaps->wPid = 0;                  /* product ID */
-    pmxcaps->vDriverVersion = 0x0001;        /* version of the driver */
-    strcpy( pmxcaps->szPname, WINMM_MIXERSTRING_A); /* product name */
-
-    pmxcaps->fdwSupport = 0;
-    pmxcaps->cDestinations = 1;
-
-    return MMSYSERR_NOERROR;
-}
-/******************************************************************************/
-/******************************************************************************/
-MMRESULT WINAPI mixerGetDevCapsW(UINT uMxId, LPMIXERCAPSW pmxcaps, UINT cbmxcaps)
-{
-    if(DartWaveOut::getNumDevices() == 0) {
-        memset(pmxcaps, 0, sizeof(*pmxcaps));
-        return MMSYSERR_NODRIVER;
-    }
-
-    // we have to fill in this thing
-    pmxcaps->wMid = 0;                  /* manufacturer ID */
-    pmxcaps->wPid = 0;                  /* product ID */
-    pmxcaps->vDriverVersion = 0x0001;        /* version of the driver */
-    lstrcpyW( pmxcaps->szPname, WINMM_MIXERSTRING_W ); /* product name */
-
-    pmxcaps->fdwSupport = 0;
-    pmxcaps->cDestinations = 1;
-
-    return MMSYSERR_NOERROR;
-}
-/******************************************************************************/
-/******************************************************************************/
-MMRESULT WINAPI mixerGetID(HMIXEROBJ hmxobj, UINT * puMxId, DWORD fdwId)
-{
-    DEVICE_STRUCT *pMixInfo = (DEVICE_STRUCT *)hmxobj;
-
-    if(pMixInfo && puMxId) {
-        *puMxId = pMixInfo->uDeviceID;
-    }
-    else *puMxId = 0;
-    return MMSYSERR_NOERROR;
 }
 /******************************************************************************/
@@ -373,92 +152,34 @@
     {
     case MIXER_GETLINEINFOF_DESTINATION:
-	/* FIXME: Linux doesn't seem to support multiple outputs? 
-	 * So we have only one output type: Speaker.
-	 */
-	lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
-	lpMl->dwSource = 0xFFFFFFFF;
-	lpMl->dwLineID = SOUND_MIXER_LINEOUT;
-	lstrcpynA(lpMl->szShortName, WINMM_SHORTNAME_LINEOUT_A, MIXER_SHORT_NAME_CHARS);
-	lstrcpynA(lpMl->szName, WINMM_SHORTNAME_LINEOUT_A, MIXER_LONG_NAME_CHARS);
-	
-	/* we have all connections found in the MIX_DevMask */
-	lpMl->cConnections = 1; //waveout
-       	lpMl->cControls    = 1;
-        lpMl->cChannels    = 2;
-	break;
+    	break;
 
     case MIXER_GETLINEINFOF_LINEID:
-	if(lpMl->dwLineID >= SOUND_MIXER_MAXID)
-	    return MIXERR_INVALLINE;
-
-        lpMl->cChannels     = 2;
-        lpMl->dwDestination = 0; /* index for speakers */
-	if(lpMl->dwLineID == SOUND_MIXER_WAVEOUT) {
-        	lpMl->dwLineID      = SOUND_MIXER_WAVEOUT;
-		lstrcpynA(lpMl->szShortName, WINMM_SHORTNAME_WAVEOUT_A, MIXER_SHORT_NAME_CHARS);
-		lstrcpynA(lpMl->szName, WINMM_SHORTNAME_WAVEOUT_A, MIXER_LONG_NAME_CHARS);
-        	lpMl->cConnections  = 0;
-        	lpMl->cControls     = 1;
-		lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
-		lpMl->fdwLine	     |= MIXERLINE_LINEF_SOURCE;
-	}
-	else {
-		lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
-		lpMl->dwSource = 0xFFFFFFFF;
-        	lpMl->dwLineID = SOUND_MIXER_LINEOUT;
-		lstrcpynA(lpMl->szShortName, WINMM_SHORTNAME_LINEOUT_A, MIXER_SHORT_NAME_CHARS);
-		lstrcpynA(lpMl->szName, WINMM_SHORTNAME_LINEOUT_A, MIXER_LONG_NAME_CHARS);
-        	lpMl->cConnections  = 1;
-        	lpMl->cControls     = 1;
-	}
-	break;
+    	break;
 
     case MIXER_GETLINEINFOF_SOURCE:
-	if(lpMl->dwSource != SOUND_MIXER_WAVEOUT)
-	    return MIXERR_INVALLINE;
-
-       	lpMl->dwLineID      = SOUND_MIXER_WAVEOUT;
-	lstrcpynA(lpMl->szShortName, WINMM_SHORTNAME_WAVEOUT_A, MIXER_SHORT_NAME_CHARS);
-	lstrcpynA(lpMl->szName, WINMM_SHORTNAME_WAVEOUT_A, MIXER_LONG_NAME_CHARS);
-       	lpMl->cConnections  = 0;
-       	lpMl->cControls     = 1;
-	lpMl->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
-	lpMl->fdwLine	     |= MIXERLINE_LINEF_SOURCE;
-        lpMl->cChannels     = 2;
-        lpMl->dwLineID      = SOUND_MIXER_WAVEOUT;
-        lpMl->dwDestination = 0; /* index for speakers */
-	break;
+    	break;
 
     case MIXER_GETLINEINFOF_COMPONENTTYPE:
-	switch (lpMl->dwComponentType) 
-	{
-	case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS:
-	    	lpMl->dwDestination = 0;
-		lpMl->dwSource = 0xFFFFFFFF;
-        	lpMl->dwLineID = SOUND_MIXER_LINEOUT;
-   	    	lstrcpynA(lpMl->szShortName, WINMM_SHORTNAME_LINEOUT_A, MIXER_SHORT_NAME_CHARS);
-	    	lstrcpynA(lpMl->szName, WINMM_SHORTNAME_LINEOUT_A, MIXER_LONG_NAME_CHARS);
+	    switch (lpMl->dwComponentType) 
+	    {
+	    case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS:
 	    	break;
-	case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT:
-       	 	lpMl->dwLineID = SOUND_MIXER_WAVEOUT;
-	    	lpMl->fdwLine |= MIXERLINE_LINEF_SOURCE;
-	    	lstrcpynA(lpMl->szShortName, WINMM_SHORTNAME_WAVEOUT_A, MIXER_SHORT_NAME_CHARS);
-            	lstrcpynA(lpMl->szName, WINMM_SHORTNAME_WAVEOUT_A, MIXER_LONG_NAME_CHARS);
-	    	break;
-	default:
+    	case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT:
+        	break;
+    	default:
 	    	dprintf(("Unhandled component type (%08lx)\n", lpMl->dwComponentType));
 	    	return MMSYSERR_INVALPARAM;
-	}
+	    }
        	lpMl->cConnections  = 0;
        	lpMl->cControls     = 1;
         lpMl->cChannels     = 2;
-	break;
+	    break;
 
     case MIXER_GETLINEINFOF_TARGETTYPE:
-	dprintf(("_TARGETTYPE not implemented yet.\n"));
-	break;
+	    dprintf(("_TARGETTYPE not implemented yet.\n"));
+	    break;
     default:
-	dprintf(("Unknown flag (%08lx)\n", fdwInfo & MIXER_GETLINEINFOF_QUERYMASK));
-	break;
+	    dprintf(("Unknown flag (%08lx)\n", fdwInfo & MIXER_GETLINEINFOF_QUERYMASK));
+	    break;
     }
     
@@ -490,8 +211,76 @@
 UINT WINAPI mixerGetNumDevs()
 {
-  if(DartWaveOut::getNumDevices() == 0) {
+    if(fMMPMAvailable == FALSE || DartWaveOut::getNumDevices() == 0) {
         return 0;
-  }
-  return 1;
+    }
+    return 1;
+}
+/******************************************************************************/
+/******************************************************************************/
+MMRESULT WINAPI mixerGetDevCapsA(UINT uMxId, LPMIXERCAPSA pmxcaps, UINT cbmxcaps)
+{
+    if(fMMPMAvailable == FALSE || DartWaveOut::getNumDevices() == 0) {
+        return MMSYSERR_BADDEVICEID;
+    }
+
+    if(uMxId > 0) {
+        return MMSYSERR_BADDEVICEID;
+    }
+
+    //According to MSDN, nothing is copied when cbmxcaps is zero
+    if(cbmxcaps >= sizeof(MIXERCAPSA)) {
+        // we have to fill in this thing
+        pmxcaps->wMid = 0;                  /* manufacturer ID */
+        pmxcaps->wPid = 0;                  /* product ID */
+        pmxcaps->vDriverVersion = 0x0001;        /* version of the driver */
+        strcpy( pmxcaps->szPname, WINMM_MIXERSTRING_A); /* product name */
+
+        pmxcaps->fdwSupport    = 0;    //no mixer flags exist
+        pmxcaps->cDestinations = 1;
+    }
+
+    return MMSYSERR_NOERROR;
+}
+/******************************************************************************/
+/******************************************************************************/
+MMRESULT WINAPI mixerGetDevCapsW(UINT uMxId, LPMIXERCAPSW pmxcaps, UINT cbmxcaps)
+{
+    if(fMMPMAvailable == FALSE || DartWaveOut::getNumDevices() == 0) {
+        return MMSYSERR_BADDEVICEID;
+    }
+
+    if(uMxId > 0) {
+        return MMSYSERR_BADDEVICEID;
+    }
+
+    //According to MSDN, nothing is copied when cbmxcaps is zero
+    if(cbmxcaps >= sizeof(MIXERCAPSW)) {
+        // we have to fill in this thing
+        pmxcaps->wMid = 0;                  /* manufacturer ID */
+        pmxcaps->wPid = 0;                  /* product ID */
+        pmxcaps->vDriverVersion = 0x0001;        /* version of the driver */
+        lstrcpyW( pmxcaps->szPname, WINMM_MIXERSTRING_W ); /* product name */
+
+        pmxcaps->fdwSupport    = 0;    //no mixer flags exist
+        pmxcaps->cDestinations = 1;
+    }
+
+    return MMSYSERR_NOERROR;
+}
+/******************************************************************************/
+/******************************************************************************/
+MMRESULT WINAPI mixerGetID(HMIXEROBJ hmxobj, UINT * puMxId, DWORD fdwId)
+{
+    DEVICE_STRUCT *pMixInfo = (DEVICE_STRUCT *)hmxobj;
+
+    if(!pMixInfo) {
+        return MMSYSERR_INVALHANDLE;
+    }
+
+    if(puMxId) {
+        *puMxId = pMixInfo->uDeviceID;
+    }
+    else *puMxId = 0;
+    return MMSYSERR_NOERROR;
 }
 /******************************************************************************/
@@ -503,8 +292,8 @@
 
     if(DartWaveOut::getNumDevices() == 0) {
-            if(phmx) *phmx = 0;
-            return MMSYSERR_NODRIVER;
-    }
-      pMixInfo = (DEVICE_STRUCT *)malloc(sizeof(DEVICE_STRUCT));
+        if(phmx) *phmx = 0;
+        return MMSYSERR_NODRIVER;
+    }
+    pMixInfo = (DEVICE_STRUCT *)malloc(sizeof(DEVICE_STRUCT));
     if(pMixInfo == NULL) {
         return MMSYSERR_NODRIVER;
@@ -530,4 +319,20 @@
 /******************************************************************************/
 /******************************************************************************/
-
-
+BOOL mixerInit() 
+{
+    if(!fMMPMAvailable) return TRUE;
+
+    if(OSLibMixerOpen() == FALSE) {
+        return FALSE;
+    }
+    return TRUE;
+}
+/******************************************************************************/
+/******************************************************************************/
+void mixerExit()
+{
+    OSLibMixerClose();
+}
+/******************************************************************************/
+/******************************************************************************/
+
Index: trunk/src/winmm/mixer.h
===================================================================
--- trunk/src/winmm/mixer.h	(revision 8472)
+++ trunk/src/winmm/mixer.h	(revision 8472)
@@ -0,0 +1,41 @@
+/* $Id: mixer.h,v 1.1 2002-05-22 20:19:19 sandervl Exp $ */
+
+/*
+ * Mixer multimedia
+ *
+ * Copyright 2002 Sander van Leeuwen (sandervl@xs4all.nl)
+ *
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+#ifndef __WINMM_MIXER_H__
+#define __WINMM_MIXER_H__
+
+#define WINMM_MIXERSTRING_A    		"OS/2 WINMM Mixer"
+#define WINMM_MIXERSTRING_W		(LPWSTR)L"OS/2 WINMM Mixer"
+
+#define WINMM_SHORTNAME_WAVEOUT_A	"Wave Out"
+#define WINMM_SHORTNAME_WAVEOUT_W	(LPWSTR)L"Wave Out"
+#define WINMM_SHORTNAME_LINEOUT_A	"Line Out"
+#define WINMM_SHORTNAME_LINEOUT_W	(LPWSTR)L"Line Out"
+
+#define MAX_MIXER_DESTINATIONS      8
+#define MAX_MIXER_SOURCES           16
+#define MAX_MIXER_CONTROLS          64
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+BOOL mixerInit();
+void mixerExit();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__WINMM_MIXER_H__
+
Index: trunk/src/winmm/mixeros2.cpp
===================================================================
--- trunk/src/winmm/mixeros2.cpp	(revision 8472)
+++ trunk/src/winmm/mixeros2.cpp	(revision 8472)
@@ -0,0 +1,383 @@
+/* $Id: mixeros2.cpp,v 1.1 2002-05-22 20:19:11 sandervl Exp $ */
+
+/*
+ * OS/2 Mixer multimedia
+ *
+ * Copyright 2002 Sander van Leeuwen (sandervl@xs4all.nl)
+ *
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+#define INCL_BASE
+#define INCL_DOSERRORS
+#define INCL_DOSDEVIOCTL
+#define INCL_DOSFILEMGR
+#define INCL_OS2MM
+#include <os2wrap.h>
+#include <os2mewrap.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dbglog.h>
+#include <ioctl90.h>
+
+#include "initwinmm.h"
+#include "mixeros2.h"
+
+static BOOL  GetAudioPDDName (char *pszPDDName);
+static HFILE DevOpen (char *ddName);
+static BOOL  mixerapiIOCTL90 (HFILE hPdd, ULONG ulFunc, PVOID pData, ULONG cbDataSize);
+
+static HFILE hPDDMix = 0;
+static char  mixerApiMap[256] = {0};
+
+/******************************************************************************/
+/******************************************************************************/
+BOOL OSLibMixerOpen()
+{
+    char szPDDName[128] = "\\DEV\\";
+
+    if(GetAudioPDDName(&szPDDName[5]) == FALSE) {
+        return FALSE;
+    }
+
+    dprintf(("OSLibMixerOpen: PDD name %s", szPDDName));
+
+    hPDDMix = DevOpen(szPDDName);
+    if(hPDDMix == 0) {
+        dprintf(("Unable to open PDD %s", szPDDName));
+        return FALSE;
+    }
+    if(mixerapiIOCTL90(hPDDMix, GETAPIMAP, mixerApiMap, sizeof(mixerApiMap)) == FALSE) {
+        dprintf(("GETAPIMAP failed!!"));
+        DosClose(hPDDMix);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+/******************************************************************************/
+/******************************************************************************/
+void OSLibMixerClose()
+{
+    if(hPDDMix) {
+        DosClose(hPDDMix);
+    }
+}
+/******************************************************************************/
+/******************************************************************************/
+static DWORD OSLibMixGetIndex(DWORD dwControl) 
+{
+    DWORD idx;
+
+    switch(dwControl) {
+    case MIXER_CTRL_MONOIN:
+        idx = MONOINSET;
+        break;
+    case MIXER_CTRL_PHONE:
+        idx = PHONESET;
+        break;
+    case MIXER_CTRL_MIC:
+        idx = MICSET;
+        break;
+    case MIXER_CTRL_LINE:
+        idx = LINESET;
+        break;
+    case MIXER_CTRL_CD:
+        idx = CDSET;
+        break;
+    case MIXER_CTRL_VIDEO:
+        idx = VIDEOSET;
+        break;
+    case MIXER_CTRL_AUX:
+        idx = AUXSET;
+        break;
+    case MIXER_CTRL_BASS:
+        idx = BASSTREBLESET;
+        break;
+    case MIXER_CTRL_TREBLE:
+        idx = BASSTREBLESET;
+        break;
+    case MIXER_CTRL_3D:
+        idx = THREEDSET;
+        break;
+    case MIXER_CTRL_STREAMVOL:
+        idx = STREAMVOLSET;
+        break;
+    case MIXER_CTRL_RECORDSRC:
+        idx = RECORDSRCSET;
+        break;
+    case MIXER_CTRL_RECORDGAIN:
+        idx = RECORDGAINSET;
+        break;
+    default:
+        DebugInt3();
+        return -1;
+    }
+    return idx & 0xF;
+}
+/******************************************************************************/
+/******************************************************************************/
+BOOL OSLibMixIsControlPresent(DWORD dwControl)
+{
+    DWORD idx;
+
+    idx = OSLibMixGetIndex(dwControl);
+    if(idx == -1) {
+        return FALSE;
+    }
+    idx += MONOINSET;
+    return mixerApiMap[idx] != 0;
+}
+/******************************************************************************/
+/******************************************************************************/
+BOOL OSLibMixSetVolume(DWORD dwControl, BOOL fMute, DWORD dwVolLeft, DWORD dwVolRight)
+{
+    DWORD     dwFunc;
+    MIXSTRUCT mixstruct;
+
+    dwFunc = OSLibMixGetIndex(dwControl);
+    if(dwFunc == -1) {
+        return FALSE;
+    }
+    dwFunc += MONOINSET;
+
+    if(dwVolLeft > MIXER_MAX_VOLUME || dwVolRight > MIXER_MAX_VOLUME) {
+        dprintf(("OSLibMixSetVolume: Volume (%d,%d) out of RANGE!!", dwVolLeft, dwVolRight));
+        return FALSE;
+    }
+    mixstruct.Mute    = fMute;
+    mixstruct.VolumeL = dwVolLeft;
+    mixstruct.VolumeR = dwVolRight;
+
+    if(mixerapiIOCTL90(hPDDMix, dwFunc, &mixstruct, sizeof(mixstruct)) == TRUE) {
+        return TRUE;
+    }
+    dprintf(("OSLibMixSetVolume: mixerapiIOCTL90 %d failed!!", dwFunc));
+    return FALSE;
+}
+/******************************************************************************/
+/******************************************************************************/
+BOOL OSLibMixGetVolume(DWORD dwControl, BOOL *pfMute, DWORD *pdwVolLeft, DWORD *pdwVolRight)
+{
+    DWORD     dwFunc;
+    MIXSTRUCT mixstruct;
+
+    dwFunc = OSLibMixGetIndex(dwControl);
+    if(dwFunc == -1) {
+        return FALSE;
+    }
+    dwFunc += MONOINQUERY;
+
+    if(mixerapiIOCTL90(hPDDMix, dwFunc, &mixstruct, sizeof(mixstruct)) == TRUE) {
+        return TRUE;
+    }
+    if(pfMute)      *pfMute      = mixstruct.Mute;
+    if(pdwVolLeft)  *pdwVolLeft  = mixstruct.VolumeL;
+    if(pdwVolRight) *pdwVolRight = mixstruct.VolumeR;
+
+    if(mixstruct.VolumeL > MIXER_MAX_VOLUME || mixstruct.VolumeR > MIXER_MAX_VOLUME) {
+        dprintf(("OSLibMixGetVolume: Volume (%d,%d) out of RANGE!!", mixstruct.VolumeL, mixstruct.VolumeR));
+        return FALSE;
+    }
+
+    dprintf(("OSLibMixGetVolume: mixerapiIOCTL90 %d failed!!", dwFunc));
+    return FALSE;
+}
+/******************************************************************************/
+/******************************************************************************/
+BOOL OSLibMixSetRecSource(DWORD dwRecSrc)
+{
+    DWORD idx;
+    MIXSTRUCT mixstruct;
+
+    switch(dwRecSrc) {
+    case MIXER_RECSRC_MIC:
+        idx = I90SRC_MIC;
+        break;
+    case MIXER_RECSRC_CD:
+        idx = I90SRC_CD;
+        break;
+    case MIXER_RECSRC_VIDEO:
+        idx = I90SRC_VIDEO;
+        break;
+    case MIXER_RECSRC_AUX:
+        idx = I90SRC_AUX;
+        break;
+    case MIXER_RECSRC_LINE:
+        idx = I90SRC_LINE;
+        break;
+    case MIXER_RECSRC_RES5:
+        idx = I90SRC_RES5;
+        break;
+    case MIXER_RECSRC_RES6:
+        idx = I90SRC_RES6;
+        break;
+    case MIXER_RECSRC_PHONE:
+        idx = I90SRC_PHONE;
+        break;
+    default:
+        DebugInt3();
+        return FALSE;
+    }
+    mixstruct.Mute    = 0;
+    mixstruct.VolumeL = idx;
+
+    if(mixerapiIOCTL90(hPDDMix, RECORDSRCSET, &mixstruct, sizeof(mixstruct)) == TRUE) {
+        return TRUE;
+    }
+    dprintf(("OSLibMixSetRecSource: mixerapiIOCTL90 RECORDSRCSET failed!!"));
+    return FALSE;
+}
+/******************************************************************************/
+/******************************************************************************/
+BOOL OSLibMixGetRecSource(DWORD *pdwRecSrc)
+{
+    DWORD idx;
+    MIXSTRUCT mixstruct;
+
+    if(mixerapiIOCTL90(hPDDMix, RECORDSRCQUERY, &mixstruct, sizeof(mixstruct)) == FALSE) {
+        dprintf(("OSLibMixSetRecSource: mixerapiIOCTL90 RECORDSRCGET failed!!"));
+        return FALSE;
+    }
+    switch(mixstruct.VolumeL) {
+    case I90SRC_MIC:
+        idx = MIXER_RECSRC_MIC;
+        break;
+    case I90SRC_CD:
+        idx = MIXER_RECSRC_CD;
+        break;
+    case I90SRC_VIDEO:
+        idx = MIXER_RECSRC_VIDEO;
+        break;
+    case I90SRC_AUX:
+        idx = MIXER_RECSRC_AUX;
+        break;
+    case I90SRC_LINE:
+        idx = MIXER_RECSRC_LINE;
+        break;
+    case I90SRC_RES5:
+        idx = MIXER_RECSRC_RES5;
+        break;
+    case I90SRC_RES6:
+        idx = MIXER_RECSRC_RES6;
+        break;
+    case I90SRC_PHONE:
+        idx = MIXER_RECSRC_PHONE;
+        break;
+    default:
+        DebugInt3();
+        return FALSE;
+    }
+    if(pdwRecSrc) {
+        *pdwRecSrc = idx;
+    }
+    return TRUE;
+}
+/******************************************************************************/
+// OS/2 32-bit program to query the Physical Device Driver name
+// for the default MMPM/2 WaveAudio device.  Joe Nord 10-Mar-1999
+/******************************************************************************/
+static HFILE DevOpen (char *ddName)
+{
+   ULONG ulRC;
+   ULONG OpenFlags;
+   ULONG OpenMode;
+   ULONG ulFileSize      = 0;
+   ULONG ulFileAttribute = 0;
+   ULONG ulActionTaken   = 0;
+   HFILE hPdd            = NULL;
+
+   OpenFlags = OPEN_ACTION_OPEN_IF_EXISTS;   // Do not create file
+
+   OpenMode  = OPEN_ACCESS_READWRITE +       // Read/Write file
+               OPEN_SHARE_DENYNONE +         // Non-exclusive access
+               OPEN_FLAGS_FAIL_ON_ERROR;     // No system popups on errors
+
+   ulRC = DosOpen (ddName,          // in
+                   &hPdd,           //    out (handle)
+                   &ulActionTaken,  //    out
+                   ulFileSize,      // in
+                   ulFileAttribute, // in
+                   OpenFlags,       // in
+                   OpenMode,        // in
+                   NULL);           // in
+
+   if (ulRC != 0)
+      hPdd = NULL;
+
+   return (hPdd);
+} 
+/******************************************************************************/
+/******************************************************************************/
+static BOOL mixerapiIOCTL90 (HFILE hPdd, ULONG ulFunc, PVOID pData, ULONG cbDataSize)
+{
+   ULONG     ulRC;
+
+   ulRC = DosDevIOCtl
+      (hPdd,               // Device Handle
+       0x90,               // Category (user defined >= 0x80)
+       ulFunc,             // Function Use defines in .H file
+       NULL,               // in      Address of parm data (not used)
+       0,                  // in      Max size of parm data structure
+       NULL,               // in out  Actual size of parm data structure
+       pData,              // in      Address of command data
+       cbDataSize,         // in      Maximum size of command data
+       &cbDataSize);       // in out  Size of command data
+
+   return ulRC == NO_ERROR;
+}
+/******************************************************************************/
+// OS/2 32-bit program to query the Physical Device Driver name
+// for the default MMPM/2 WaveAudio device.  Joe Nord 10-Mar-1999
+/******************************************************************************/
+static BOOL GetAudioPDDName (char *pszPDDName)
+{
+   ULONG                   ulRC;
+   char                    szAmpMix[9] = "AMPMIX01";
+
+   MCI_SYSINFO_PARMS       SysInfo;
+   MCI_SYSINFO_LOGDEVICE   SysInfoParm;
+   MCI_SYSINFO_QUERY_NAME  QueryNameParm;
+
+   memset (&SysInfo, '\0', sizeof(SysInfo));
+   memset (&SysInfoParm, '\0', sizeof(SysInfoParm));
+   memset (&QueryNameParm, '\0', sizeof(QueryNameParm));
+
+   SysInfo.ulItem       = MCI_SYSINFO_QUERY_NAMES;
+   SysInfo.usDeviceType  = MCI_DEVTYPE_WAVEFORM_AUDIO;
+   SysInfo.pSysInfoParm = &QueryNameParm;
+
+   strcpy (QueryNameParm.szLogicalName, szAmpMix);
+
+   ulRC = mymciSendCommand (0,
+                          MCI_SYSINFO,
+                          MCI_SYSINFO_ITEM | MCI_WAIT,
+                          (PVOID) &SysInfo,
+                          0);
+   if (ulRC != 0) return FALSE;
+
+   // Get PDD associated with our AmpMixer
+   // Device name is in pSysInfoParm->szPDDName
+
+   SysInfo.ulItem       = MCI_SYSINFO_QUERY_DRIVER;
+   SysInfo.usDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
+   SysInfo.pSysInfoParm = &SysInfoParm;
+
+   strcpy (SysInfoParm.szInstallName, QueryNameParm.szInstallName);
+
+   ulRC = mymciSendCommand (0,
+                          MCI_SYSINFO,
+                          MCI_SYSINFO_ITEM | MCI_WAIT,
+                          (PVOID) &SysInfo,
+                          0);
+   if (ulRC != 0) return FALSE;
+
+   strcpy (pszPDDName, SysInfoParm.szPDDName);
+
+   return TRUE;
+}
+/******************************************************************************/
+/******************************************************************************/
+
Index: trunk/src/winmm/mixeros2.h
===================================================================
--- trunk/src/winmm/mixeros2.h	(revision 8472)
+++ trunk/src/winmm/mixeros2.h	(revision 8472)
@@ -0,0 +1,58 @@
+/* $Id: mixeros2.h,v 1.1 2002-05-22 20:19:11 sandervl Exp $ */
+
+/*
+ * Mixer multimedia
+ *
+ * Copyright 2002 Sander van Leeuwen (sandervl@xs4all.nl)
+ *
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+#ifndef __WINMM_OS2MIXER_H__
+#define __WINMM_OS2MIXER_H__
+
+#define MIXER_MAX_VOLUME        100
+
+#define MIXER_CTRL_MONOIN       0
+#define MIXER_CTRL_PHONE        1
+#define MIXER_CTRL_MIC          2
+#define MIXER_CTRL_LINE         3
+#define MIXER_CTRL_CD           4
+#define MIXER_CTRL_VIDEO        5
+#define MIXER_CTRL_AUX          6
+#define MIXER_CTRL_3D           7
+#define MIXER_CTRL_STREAMVOL    8
+#define MIXER_CTRL_RECORDSRC    9
+#define MIXER_CTRL_RECORDGAIN   10
+#define MIXER_CTRL_TREBLE       11
+#define MIXER_CTRL_BASS         12
+
+#define MIXER_RECSRC_MIC        0
+#define MIXER_RECSRC_CD         1
+#define MIXER_RECSRC_VIDEO      2
+#define MIXER_RECSRC_AUX        3
+#define MIXER_RECSRC_LINE       4
+#define MIXER_RECSRC_RES5       5
+#define MIXER_RECSRC_RES6       6
+#define MIXER_RECSRC_PHONE      7
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+BOOL OSLibMixerOpen();
+void OSLibMixerClose();
+
+BOOL OSLibMixIsControlPresent(DWORD dwControl);
+BOOL OSLibMixSetVolume(DWORD dwControl, BOOL fMute, DWORD dwVolLeft, DWORD dwVolRight);
+BOOL OSLibMixGetVolume(DWORD dwControl, BOOL *pfMute, DWORD *pdwVolLeft, DWORD *pdwVolRight);
+BOOL OSLibMixSetRecSource(DWORD dwRecSrc);
+BOOL OSLibMixGetRecSource(DWORD *pdwRecSrc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__WINMM_OS2MIXER_H__
Index: trunk/src/winmm/winmm.mak
===================================================================
--- trunk/src/winmm/winmm.mak	(revision 8470)
+++ trunk/src/winmm/winmm.mak	(revision 8472)
@@ -1,3 +1,3 @@
-# $Id: winmm.mak,v 1.9 2002-05-22 15:50:26 sandervl Exp $
+# $Id: winmm.mak,v 1.10 2002-05-22 20:19:11 sandervl Exp $
 
 #
@@ -42,4 +42,5 @@
 $(OBJDIR)\auxos2.obj \
 $(OBJDIR)\mixer.obj \
+$(OBJDIR)\mixeros2.obj \
 $(OBJDIR)\midi.obj \
 $(OBJDIR)\irtmidi.obj \
