Correctly handle where waveOutGetPosition changes timepos.wType
authorRobert Reif <reif@earthlink.net>
Mon, 11 Apr 2005 12:49:04 +0000 (12:49 +0000)
committerAlexandre Julliard <julliard@winehq.org>
Mon, 11 Apr 2005 12:49:04 +0000 (12:49 +0000)
because the requested type is not supported.
Added Jeremy White's waveOutGetPosition fix to waveInGetPosition.

dlls/winmm/wavemap/wavemap.c

index 210d8716e38cd1f75b938e738f1cc066b2263c1e..0cf96763825fb76e2ebe295472c418572c6dc28c 100644 (file)
@@ -428,9 +428,10 @@ static     DWORD   wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2)
     if (lpTime->wType == TIME_MS)
         timepos.wType = TIME_BYTES;
 
+    /* This can change timepos.wType if the requested type is not supported */
     val = waveOutGetPosition(wom->u.out.hInnerWave, &timepos, dwParam2);
 
-    if (lpTime->wType == TIME_BYTES || lpTime->wType == TIME_MS)
+    if (timepos.wType == TIME_BYTES)
     {
         DWORD dwInnerSamplesPerOuter = wom->nSamplesPerSecInner / wom->nSamplesPerSecOuter;
         if (dwInnerSamplesPerOuter > 0)
@@ -464,10 +465,12 @@ static    DWORD   wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2)
 
         /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
         if (lpTime->wType == TIME_MS)
-            lpTime->u.cb = MulDiv(lpTime->u.cb, 1000, wom->avgSpeedOuter);
+            lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wom->avgSpeedOuter);
+        else
+            lpTime->wType = TIME_BYTES;
     }
-    else if (lpTime->wType == TIME_SAMPLES)
-        lpTime->u.cb = MulDiv(timepos.u.cb, wom->nSamplesPerSecOuter, wom->nSamplesPerSecInner);
+    else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES)
+        lpTime->u.sample = MulDiv(timepos.u.sample, wom->nSamplesPerSecOuter, wom->nSamplesPerSecInner);
     else
         /* other time types don't require conversion */
         lpTime->u = timepos.u;
@@ -962,15 +965,62 @@ static    DWORD   widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwPara
 static DWORD   widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2)
 {
     DWORD       val;
-
+    MMTIME      timepos;
     TRACE("(%p %p %08lx)\n", wim, lpTime, dwParam2);
 
-    val = waveInGetPosition(wim->u.in.hInnerWave, lpTime, dwParam2);
-    if (lpTime->wType == TIME_BYTES)
-        lpTime->u.cb = MulDiv(lpTime->u.cb, wim->avgSpeedOuter, wim->avgSpeedInner);
-    if (lpTime->wType == TIME_SAMPLES)
-        lpTime->u.cb = MulDiv(lpTime->u.cb, wim->nSamplesPerSecOuter, wim->nSamplesPerSecInner);
-    /* other time types don't require conversion */
+    memcpy(&timepos, lpTime, sizeof(timepos));
+
+    /* For TIME_MS, we're going to recalculate using TIME_BYTES */
+    if (lpTime->wType == TIME_MS)
+        timepos.wType = TIME_BYTES;
+
+    /* This can change timepos.wType if the requested type is not supported */
+    val = waveInGetPosition(wim->u.in.hInnerWave, &timepos, dwParam2);
+
+    if (timepos.wType == TIME_BYTES)
+    {
+        DWORD dwInnerSamplesPerOuter = wim->nSamplesPerSecInner / wim->nSamplesPerSecOuter;
+        if (dwInnerSamplesPerOuter > 0)
+        {
+            DWORD dwInnerBytesPerSample = wim->avgSpeedInner / wim->nSamplesPerSecInner;
+            DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter;
+            DWORD remainder = 0;
+
+            /* If we are up sampling (going from lower sample rate to higher),
+            **   we need to make a special accomodation for times when we've
+            **   written a partial output sample.  This happens frequently
+            **   to us because we use msacm to do our up sampling, and it
+            **   will up sample on an unaligned basis.
+            ** For example, if you convert a 2 byte wide 8,000 'outer'
+            **   buffer to a 2 byte wide 48,000 inner device, you would
+            **   expect 2 bytes of input to produce 12 bytes of output.
+            **   Instead, msacm will produce 8 bytes of output.
+            **   But reporting our position as 1 byte of output is
+            **   nonsensical; the output buffer position needs to be
+            **   aligned on outer sample size, and aggressively rounded up.
+            */
+            remainder = timepos.u.cb % dwInnerBytesPerOuterSample;
+            if (remainder > 0)
+            {
+                timepos.u.cb -= remainder;
+                timepos.u.cb += dwInnerBytesPerOuterSample;
+            }
+        }
+
+        lpTime->u.cb = MulDiv(timepos.u.cb, wim->avgSpeedOuter, wim->avgSpeedInner);
+
+        /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
+        if (lpTime->wType == TIME_MS)
+            lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wim->avgSpeedOuter);
+        else
+            lpTime->wType = TIME_BYTES;
+    }
+    else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES)
+        lpTime->u.sample = MulDiv(timepos.u.sample, wim->nSamplesPerSecOuter, wim->nSamplesPerSecInner);
+    else
+        /* other time types don't require conversion */
+        lpTime->u = timepos.u;
+
     return val;
 }