Sync to Wine-20050419:
[reactos.git] / reactos / lib / winmm / wavemap / wavemap.c
index 2ff43cd..5a3a72d 100644 (file)
@@ -166,6 +166,7 @@ static      DWORD   wodOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
     if (dwFlags & WAVE_MAPPED) {\r
        if (lpDesc->uMappedDeviceID >= ndhi) {\r
             WARN("invalid parameter: dwFlags WAVE_MAPPED\n");\r
+            HeapFree(GetProcessHeap(), 0, wom);\r
             return MMSYSERR_INVALPARAM;\r
         }\r
        ndlo = lpDesc->uMappedDeviceID;\r
@@ -427,9 +428,10 @@ static     DWORD   wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2)
     if (lpTime->wType == TIME_MS)\r
         timepos.wType = TIME_BYTES;\r
 \r
+    /* This can change timepos.wType if the requested type is not supported */\r
     val = waveOutGetPosition(wom->u.out.hInnerWave, &timepos, dwParam2);\r
 \r
-    if (lpTime->wType == TIME_BYTES || lpTime->wType == TIME_MS)\r
+    if (timepos.wType == TIME_BYTES)\r
     {\r
         DWORD dwInnerSamplesPerOuter = wom->nSamplesPerSecInner / wom->nSamplesPerSecOuter;\r
         if (dwInnerSamplesPerOuter > 0)\r
@@ -463,10 +465,12 @@ static    DWORD   wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2)
 \r
         /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */\r
         if (lpTime->wType == TIME_MS)\r
-            lpTime->u.cb = MulDiv(lpTime->u.cb, 1000, wom->avgSpeedOuter);\r
+            lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wom->avgSpeedOuter);\r
+        else\r
+            lpTime->wType = TIME_BYTES;\r
     }\r
-    else if (lpTime->wType == TIME_SAMPLES)\r
-        lpTime->u.cb = MulDiv(timepos.u.cb, wom->nSamplesPerSecOuter, wom->nSamplesPerSecInner);\r
+    else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES)\r
+        lpTime->u.sample = MulDiv(timepos.u.sample, wom->nSamplesPerSecOuter, wom->nSamplesPerSecInner);\r
     else\r
         /* other time types don't require conversion */\r
         lpTime->u = timepos.u;\r
@@ -586,6 +590,13 @@ static  DWORD      wodMapperStatus(WAVEMAPDATA* wom, DWORD flags, LPVOID ptr)
     return ret;\r
 }\r
 \r
+static  DWORD   wodMapperReconfigure(WAVEMAPDATA* wom, DWORD dwParam1, DWORD dwParam2)\r
+{\r
+    FIXME("(%p %08lx %08lx) stub!\n", wom, dwParam1, dwParam2);\r
+\r
+    return MMSYSERR_NOERROR;\r
+}\r
+\r
 /**************************************************************************\r
  *                             wodMessage (MSACM.@)\r
  */\r
@@ -621,6 +632,7 @@ DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
     case WODM_RESTART:         return wodRestart       ((WAVEMAPDATA*)dwUser);\r
     case WODM_RESET:           return wodReset         ((WAVEMAPDATA*)dwUser);\r
     case WODM_MAPPER_STATUS:   return wodMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);\r
+    case DRVM_MAPPER_RECONFIGURE: return wodMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2);\r
     /* known but not supported */\r
     case DRV_QUERYDEVICEINTERFACESIZE:\r
     case DRV_QUERYDEVICEINTERFACE:\r
@@ -961,15 +973,62 @@ static    DWORD   widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwPara
 static DWORD   widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2)\r
 {\r
     DWORD       val;\r
-\r
+    MMTIME      timepos;\r
     TRACE("(%p %p %08lx)\n", wim, lpTime, dwParam2);\r
 \r
-    val = waveInGetPosition(wim->u.in.hInnerWave, lpTime, dwParam2);\r
-    if (lpTime->wType == TIME_BYTES)\r
-        lpTime->u.cb = MulDiv(lpTime->u.cb, wim->avgSpeedOuter, wim->avgSpeedInner);\r
-    if (lpTime->wType == TIME_SAMPLES)\r
-        lpTime->u.cb = MulDiv(lpTime->u.cb, wim->nSamplesPerSecOuter, wim->nSamplesPerSecInner);\r
-    /* other time types don't require conversion */\r
+    memcpy(&timepos, lpTime, sizeof(timepos));\r
+\r
+    /* For TIME_MS, we're going to recalculate using TIME_BYTES */\r
+    if (lpTime->wType == TIME_MS)\r
+        timepos.wType = TIME_BYTES;\r
+\r
+    /* This can change timepos.wType if the requested type is not supported */\r
+    val = waveInGetPosition(wim->u.in.hInnerWave, &timepos, dwParam2);\r
+\r
+    if (timepos.wType == TIME_BYTES)\r
+    {\r
+        DWORD dwInnerSamplesPerOuter = wim->nSamplesPerSecInner / wim->nSamplesPerSecOuter;\r
+        if (dwInnerSamplesPerOuter > 0)\r
+        {\r
+            DWORD dwInnerBytesPerSample = wim->avgSpeedInner / wim->nSamplesPerSecInner;\r
+            DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter;\r
+            DWORD remainder = 0;\r
+\r
+            /* If we are up sampling (going from lower sample rate to higher),\r
+            **   we need to make a special accomodation for times when we've\r
+            **   written a partial output sample.  This happens frequently\r
+            **   to us because we use msacm to do our up sampling, and it\r
+            **   will up sample on an unaligned basis.\r
+            ** For example, if you convert a 2 byte wide 8,000 'outer'\r
+            **   buffer to a 2 byte wide 48,000 inner device, you would\r
+            **   expect 2 bytes of input to produce 12 bytes of output.\r
+            **   Instead, msacm will produce 8 bytes of output.\r
+            **   But reporting our position as 1 byte of output is\r
+            **   nonsensical; the output buffer position needs to be\r
+            **   aligned on outer sample size, and aggressively rounded up.\r
+            */\r
+            remainder = timepos.u.cb % dwInnerBytesPerOuterSample;\r
+            if (remainder > 0)\r
+            {\r
+                timepos.u.cb -= remainder;\r
+                timepos.u.cb += dwInnerBytesPerOuterSample;\r
+            }\r
+        }\r
+\r
+        lpTime->u.cb = MulDiv(timepos.u.cb, wim->avgSpeedOuter, wim->avgSpeedInner);\r
+\r
+        /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */\r
+        if (lpTime->wType == TIME_MS)\r
+            lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wim->avgSpeedOuter);\r
+        else\r
+            lpTime->wType = TIME_BYTES;\r
+    }\r
+    else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES)\r
+        lpTime->u.sample = MulDiv(timepos.u.sample, wim->nSamplesPerSecOuter, wim->nSamplesPerSecInner);\r
+    else\r
+        /* other time types don't require conversion */\r
+        lpTime->u = timepos.u;\r
+\r
     return val;\r
 }\r
 \r
@@ -1058,6 +1117,13 @@ static  DWORD    widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr)
     return ret;\r
 }\r
 \r
+static  DWORD   widMapperReconfigure(WAVEMAPDATA* wim, DWORD dwParam1, DWORD dwParam2)\r
+{\r
+    FIXME("(%p %08lx %08lx) stub!\n", wim, dwParam1, dwParam2);\r
+\r
+    return MMSYSERR_NOERROR;\r
+}\r
+\r
 /**************************************************************************\r
  *                             widMessage (MSACM.@)\r
  */\r
@@ -1088,6 +1154,7 @@ DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
     case WIDM_START:           return widStart         ((WAVEMAPDATA*)dwUser);\r
     case WIDM_STOP:            return widStop          ((WAVEMAPDATA*)dwUser);\r
     case WIDM_MAPPER_STATUS:   return widMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);\r
+    case DRVM_MAPPER_RECONFIGURE: return widMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2);\r
     /* known but not supported */\r
     case DRV_QUERYDEVICEINTERFACESIZE:\r
     case DRV_QUERYDEVICEINTERFACE:\r