Float-less TIME_SMPTE code

Francois Gouget fgouget at codeweavers.com
Fri Jul 23 12:27:06 CDT 2004


This patch is based on the code I posted to wine-devel in this email:
http://www.winehq.org/hypermail/wine-devel/2004/07/0288.html

I extended it to all the sound drivers. It does not move the code to 
winmm.c as I proposed another email because winmm.c does not have access 
to the sound device format (samples per seconds, etc) which makes the 
calculations impossible or less precise. However for each driver I 
created a bytes_to_mmtime() function which converts the position as 
given in bytes, to the requested MMTIME format. This makes has two 
advantages:
  * it lets us share that code between wodGetPosition() and widGetPosition()
  * the function can be copy/pasted between drivers with no modification 
despite the minor differences from driver to driver

The other advantages of the new code are that:
  * it does not use floating point arithmetic so there is no risk of 
getting wrong results because of rounding errors
  * some of the drivers still had potential integer overflows (e.g. val 
* 8...). The new code should never overflow.
  * it should also fix the FreeBSD compilation problem reported by 
Gerald Pfeifer as the code will no longer use round().


Changelog:

  * dlls/winmm/winealsa/audio.c
    dlls/winmm/winearts/audio.c
    dlls/winmm/wineaudioio/audio.c
    dlls/winmm/winejack/audio.c
    dlls/winmm/winenas/audio.c
    dlls/winmm/wineoss/audio.c

    Francois Gouget <fgouget at codeweavers.com>
    Added bytes_to_mmtime() to convert the stream position from bytes to 
the requested MMTIME format. This function should be identical in all 
drivers.
    Remove the corresponding code from wodGetPosition() and 
widGetPosition() and use bytes_to_mmtime() instead.
    bytes_to_mmtime() uses no floating-point arithmetic to compute 
TIME_SMPTE and no longer uses round(). It should have no integer 
overflows either.


-- 
Francois Gouget
fgouget at codeweavers.com

-------------- next part --------------
Index: dlls/winmm/winealsa/audio.c
===================================================================
RCS file: /var/cvs/wine/dlls/winmm/winealsa/audio.c,v
retrieving revision 1.47
diff -u -r1.47 audio.c
--- dlls/winmm/winealsa/audio.c	19 Jul 2004 21:20:59 -0000	1.47
+++ dlls/winmm/winealsa/audio.c	23 Jul 2004 00:58:23 -0000
@@ -258,6 +258,55 @@
 };
 #endif
 
+static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
+                             PCMWAVEFORMAT* format)
+{
+    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
+          lpTime->wType, format->wBitsPerSample, format->wf.nSamplesPerSec,
+          format->wf.nChannels, format->wf.nAvgBytesPerSec);
+    TRACE("Position in bytes=%lu\n", position);
+
+    switch (lpTime->wType) {
+    case TIME_SAMPLES:
+        lpTime->u.sample = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
+        TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
+        break;
+    case TIME_MS:
+        lpTime->u.ms = 1000.0 * position / (format->wBitsPerSample / 8 * format->wf.nChannels * format->wf.nSamplesPerSec);
+        TRACE("TIME_MS=%lu\n", lpTime->u.ms);
+        break;
+    case TIME_SMPTE:
+        position = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
+        lpTime->u.smpte.sec = position / format->wf.nSamplesPerSec;
+        position -= lpTime->u.smpte.sec * format->wf.nSamplesPerSec;
+        lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
+        lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
+        lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
+        lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
+        lpTime->u.smpte.fps = 30;
+        lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->wf.nSamplesPerSec;
+        position -= lpTime->u.smpte.frame * format->wf.nSamplesPerSec / lpTime->u.smpte.fps;
+        if (position != 0)
+        {
+            /* Round up */
+            lpTime->u.smpte.frame++;
+        }
+        TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
+              lpTime->u.smpte.hour, lpTime->u.smpte.min,
+              lpTime->u.smpte.sec, lpTime->u.smpte.frame);
+        break;
+    default:
+        FIXME("Format %d not supported ! use TIME_BYTES !\n", lpTime->wType);
+        lpTime->wType = TIME_BYTES;
+        /* fall through */
+    case TIME_BYTES:
+        lpTime->u.cb = position;
+        TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
+        break;
+    }
+    return MMSYSERR_NOERROR;
+}
+
 /*======================================================================*
  *                  Low level WAVE implementation			*
  *======================================================================*/
@@ -1835,8 +1897,6 @@
  */
 static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
 {
-    double		time;
-    DWORD		val;
     WINE_WAVEOUT*	wwo;
 
     TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize);
@@ -1850,46 +1910,8 @@
 
     wwo = &WOutDev[wDevID];
     ALSA_AddRingMessage(&wwo->msgRing, WINE_WM_UPDATE, 0, TRUE);
-    val = wwo->dwPlayedTotal;
 
-    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
-	  lpTime->wType, wwo->format.wBitsPerSample,
-	  wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels,
-	  wwo->format.wf.nAvgBytesPerSec);
-    TRACE("dwPlayedTotal=%lu\n", val);
-
-    switch (lpTime->wType) {
-    case TIME_BYTES:
-	lpTime->u.cb = val;
-	TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
-	break;
-    case TIME_SAMPLES:
-	lpTime->u.sample = val * 8 / wwo->format.wBitsPerSample /wwo->format.wf.nChannels;
-	TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
-	break;
-    case TIME_SMPTE:
-	time = (double)val / (double)wwo->format.wf.nAvgBytesPerSec;
-	lpTime->u.smpte.hour = time / (60 * 60);
-	time -= lpTime->u.smpte.hour * (60 * 60);
-	lpTime->u.smpte.min = time / 60;
-	time -= lpTime->u.smpte.min * 60;
-	lpTime->u.smpte.sec = time;
-	time -= lpTime->u.smpte.sec;
-	lpTime->u.smpte.frame = round(time * 30);
-	lpTime->u.smpte.fps = 30;
-	TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
-	      lpTime->u.smpte.hour, lpTime->u.smpte.min,
-	      lpTime->u.smpte.sec, lpTime->u.smpte.frame);
-	break;
-    default:
-	FIXME("Format %d not supported ! use TIME_MS !\n", lpTime->wType);
-	lpTime->wType = TIME_MS;
-    case TIME_MS:
-	lpTime->u.ms = val * 1000.0 / wwo->format.wf.nAvgBytesPerSec;
-	TRACE("TIME_MS=%lu\n", lpTime->u.ms);
-	break;
-    }
-    return MMSYSERR_NOERROR;
+    return bytes_to_mmtime(lpTime, wwo->dwPlayedTotal, &wwo->format);
 }
 
 /**************************************************************************
@@ -3338,7 +3363,6 @@
  */
 static DWORD widGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
 {
-    double		time;
     WINE_WAVEIN*	wwi;
 
     FIXME("(%u, %p, %lu);\n", wDevID, lpTime, uSize);
@@ -3352,47 +3376,7 @@
     wwi = &WInDev[wDevID];
     ALSA_AddRingMessage(&wwi->msgRing, WINE_WM_UPDATE, 0, TRUE);
 
-    TRACE("wType=%04X !\n", lpTime->wType);
-    TRACE("wBitsPerSample=%u\n", wwi->format.wBitsPerSample);
-    TRACE("nSamplesPerSec=%lu\n", wwi->format.wf.nSamplesPerSec);
-    TRACE("nChannels=%u\n", wwi->format.wf.nChannels);
-    TRACE("nAvgBytesPerSec=%lu\n", wwi->format.wf.nAvgBytesPerSec);
-    FIXME("dwTotalRecorded=%lu\n",wwi->dwTotalRecorded);
-    switch (lpTime->wType) {
-    case TIME_BYTES:
-	lpTime->u.cb = wwi->dwTotalRecorded;
-	TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
-	break;
-    case TIME_SAMPLES:
-	lpTime->u.sample = wwi->dwTotalRecorded * 8 /
-	    wwi->format.wBitsPerSample / wwi->format.wf.nChannels;
-	TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
-	break;
-    case TIME_SMPTE:
-	time = (double)wwi->dwTotalRecorded /
-	    (double)wwi->format.wf.nAvgBytesPerSec;
-	lpTime->u.smpte.hour = time / (60 * 60);
-	time -= lpTime->u.smpte.hour * (60 * 60);
-	lpTime->u.smpte.min = time / 60;
-	time -= lpTime->u.smpte.min * 60;
-	lpTime->u.smpte.sec = time;
-	time -= lpTime->u.smpte.sec;
-	lpTime->u.smpte.frame = ceil(time * 30);
-	lpTime->u.smpte.fps = 30;
-	TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
-	      lpTime->u.smpte.hour, lpTime->u.smpte.min,
-	      lpTime->u.smpte.sec, lpTime->u.smpte.frame);
-	break;
-    default:
-	FIXME("format not supported (%u) ! use TIME_MS !\n", lpTime->wType);
-	lpTime->wType = TIME_MS;
-    case TIME_MS:
-	lpTime->u.ms = wwi->dwTotalRecorded * 1000.0 /
-	    wwi->format.wf.nAvgBytesPerSec;
-	TRACE("TIME_MS=%lu\n", lpTime->u.ms);
-	break;
-    }
-    return MMSYSERR_NOERROR;
+    return bytes_to_mmtime(lpTime, wwi->dwTotalRecorded, &wwi->format);
 }
 
 /**************************************************************************
Index: dlls/winmm/winearts/audio.c
===================================================================
RCS file: /var/cvs/wine/dlls/winmm/winearts/audio.c,v
retrieving revision 1.21
diff -u -r1.21 audio.c
--- dlls/winmm/winearts/audio.c	19 Jul 2004 20:08:06 -0000	1.21
+++ dlls/winmm/winearts/audio.c	23 Jul 2004 00:58:52 -0000
@@ -222,6 +222,55 @@
     "WINE_WM_STOPPING",
 };
 
+static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
+                             PCMWAVEFORMAT* format)
+{
+    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
+          lpTime->wType, format->wBitsPerSample, format->wf.nSamplesPerSec,
+          format->wf.nChannels, format->wf.nAvgBytesPerSec);
+    TRACE("Position in bytes=%lu\n", position);
+
+    switch (lpTime->wType) {
+    case TIME_SAMPLES:
+        lpTime->u.sample = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
+        TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
+        break;
+    case TIME_MS:
+        lpTime->u.ms = 1000.0 * position / (format->wBitsPerSample / 8 * format->wf.nChannels * format->wf.nSamplesPerSec);
+        TRACE("TIME_MS=%lu\n", lpTime->u.ms);
+        break;
+    case TIME_SMPTE:
+        position = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
+        lpTime->u.smpte.sec = position / format->wf.nSamplesPerSec;
+        position -= lpTime->u.smpte.sec * format->wf.nSamplesPerSec;
+        lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
+        lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
+        lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
+        lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
+        lpTime->u.smpte.fps = 30;
+        lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->wf.nSamplesPerSec;
+        position -= lpTime->u.smpte.frame * format->wf.nSamplesPerSec / lpTime->u.smpte.fps;
+        if (position != 0)
+        {
+            /* Round up */
+            lpTime->u.smpte.frame++;
+        }
+        TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
+              lpTime->u.smpte.hour, lpTime->u.smpte.min,
+              lpTime->u.smpte.sec, lpTime->u.smpte.frame);
+        break;
+    default:
+        FIXME("Format %d not supported ! use TIME_BYTES !\n", lpTime->wType);
+        lpTime->wType = TIME_BYTES;
+        /* fall through */
+    case TIME_BYTES:
+        lpTime->u.cb = position;
+        TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
+        break;
+    }
+    return MMSYSERR_NOERROR;
+}
+
 /*======================================================================*
  *                  Low level WAVE implementation			*
  *======================================================================*/
@@ -1386,8 +1438,6 @@
  */
 static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
 {
-    double		time;
-    DWORD		val;
     WINE_WAVEOUT*	wwo;
 
     TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize);
@@ -1403,46 +1453,8 @@
 
     wwo = &WOutDev[wDevID];
     ARTS_AddRingMessage(&wwo->msgRing, WINE_WM_UPDATE, 0, TRUE);
-    val = wwo->dwPlayedTotal;
 
-    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
-	  lpTime->wType, wwo->format.wBitsPerSample,
-	  wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels,
-	  wwo->format.wf.nAvgBytesPerSec);
-    TRACE("dwPlayedTotal=%lu\n", val);
-
-    switch (lpTime->wType) {
-    case TIME_BYTES:
-	lpTime->u.cb = val;
-	TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
-	break;
-    case TIME_SAMPLES:
-	lpTime->u.sample = val * 8 / wwo->format.wBitsPerSample /wwo->format.wf.nChannels;
-	TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
-	break;
-    case TIME_SMPTE:
-	time = (double)val / (double)wwo->format.wf.nAvgBytesPerSec;
-	lpTime->u.smpte.hour = time / (60 * 60);
-	time -= lpTime->u.smpte.hour * (60 * 60);
-	lpTime->u.smpte.min = time / 60;
-	time -= lpTime->u.smpte.min * 60;
-	lpTime->u.smpte.sec = time;
-	time -= lpTime->u.smpte.sec;
-	lpTime->u.smpte.frame = round(time * 30);
-	lpTime->u.smpte.fps = 30;
-	TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
-	      lpTime->u.smpte.hour, lpTime->u.smpte.min,
-	      lpTime->u.smpte.sec, lpTime->u.smpte.frame);
-	break;
-    default:
-	FIXME("Format %d not supported ! use TIME_MS !\n", lpTime->wType);
-	lpTime->wType = TIME_MS;
-    case TIME_MS:
-	lpTime->u.ms = val * 1000.0 / wwo->format.wf.nAvgBytesPerSec;
-	TRACE("TIME_MS=%lu\n", lpTime->u.ms);
-	break;
-    }
-    return MMSYSERR_NOERROR;
+    return bytes_to_mmtime(lpTime, wwo->dwPlayedTotal, &wwo->format);
 }
 
 /**************************************************************************
Index: dlls/winmm/wineaudioio/audio.c
===================================================================
RCS file: /var/cvs/wine/dlls/winmm/wineaudioio/audio.c,v
retrieving revision 1.13
diff -u -r1.13 audio.c
--- dlls/winmm/wineaudioio/audio.c	19 Jul 2004 20:08:06 -0000	1.13
+++ dlls/winmm/wineaudioio/audio.c	23 Jul 2004 00:51:06 -0000
@@ -185,6 +185,55 @@
 static DWORD wodDsGuid(UINT wDevID, LPGUID pGuid);
 static DWORD widDsGuid(UINT wDevID, LPGUID pGuid);
 
+static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
+                             PCMWAVEFORMAT* format)
+{
+    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
+          lpTime->wType, format->wBitsPerSample, format->wf.nSamplesPerSec,
+          format->wf.nChannels, format->wf.nAvgBytesPerSec);
+    TRACE("Position in bytes=%lu\n", position);
+
+    switch (lpTime->wType) {
+    case TIME_SAMPLES:
+        lpTime->u.sample = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
+        TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
+        break;
+    case TIME_MS:
+        lpTime->u.ms = 1000.0 * position / (format->wBitsPerSample / 8 * format->wf.nChannels * format->wf.nSamplesPerSec);
+        TRACE("TIME_MS=%lu\n", lpTime->u.ms);
+        break;
+    case TIME_SMPTE:
+        position = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
+        lpTime->u.smpte.sec = position / format->wf.nSamplesPerSec;
+        position -= lpTime->u.smpte.sec * format->wf.nSamplesPerSec;
+        lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
+        lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
+        lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
+        lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
+        lpTime->u.smpte.fps = 30;
+        lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->wf.nSamplesPerSec;
+        position -= lpTime->u.smpte.frame * format->wf.nSamplesPerSec / lpTime->u.smpte.fps;
+        if (position != 0)
+        {
+            /* Round up */
+            lpTime->u.smpte.frame++;
+        }
+        TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
+              lpTime->u.smpte.hour, lpTime->u.smpte.min,
+              lpTime->u.smpte.sec, lpTime->u.smpte.frame);
+        break;
+    default:
+        FIXME("Format %d not supported ! use TIME_BYTES !\n", lpTime->wType);
+        lpTime->wType = TIME_BYTES;
+        /* fall through */
+    case TIME_BYTES:
+        lpTime->u.cb = position;
+        TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
+        break;
+    }
+    return MMSYSERR_NOERROR;
+}
+
 /*======================================================================*
  *                  Low level WAVE implementation			*
  *======================================================================*/
@@ -1082,8 +1131,6 @@
  */
 static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
 {
-    double		time;
-    DWORD		val;
     WINE_WAVEOUT*	wwo;
 
     TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize);
@@ -1096,46 +1143,8 @@
     if (lpTime == NULL)	return MMSYSERR_INVALPARAM;
 
     wwo = &WOutDev[wDevID];
-    val = wwo->dwPlayedTotal;
-
-    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
-	  lpTime->wType, wwo->format.wBitsPerSample,
-	  wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels,
-	  wwo->format.wf.nAvgBytesPerSec);
-    TRACE("dwTotalPlayed=%lu\n", val);
 
-    switch (lpTime->wType) {
-    case TIME_BYTES:
-	lpTime->u.cb = val;
-	TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
-	break;
-    case TIME_SAMPLES:
-	lpTime->u.sample = val * 8 / wwo->format.wBitsPerSample;
-	TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
-	break;
-    case TIME_SMPTE:
-	time = (double)val / (double)wwo->format.wf.nAvgBytesPerSec;
-	lpTime->u.smpte.hour = time / (60 * 60);
-	time -= lpTime->u.smpte.hour * (60 * 60);
-	lpTime->u.smpte.min = time / 60;
-	time -= lpTime->u.smpte.min * 60;
-	lpTime->u.smpte.sec = time;
-	time -= lpTime->u.smpte.sec;
-	lpTime->u.smpte.frame = round(time * 30);
-	lpTime->u.smpte.fps = 30;
-	TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
-	      lpTime->u.smpte.hour, lpTime->u.smpte.min,
-	      lpTime->u.smpte.sec, lpTime->u.smpte.frame);
-	break;
-    default:
-	FIXME("Format %d not supported ! use TIME_MS !\n", lpTime->wType);
-	lpTime->wType = TIME_MS;
-    case TIME_MS:
-	lpTime->u.ms = val * 1000.0 / wwo->format.wf.nAvgBytesPerSec;
-	TRACE("TIME_MS=%lu\n", lpTime->u.ms);
-	break;
-    }
-    return MMSYSERR_NOERROR;
+    return bytes_to_mmtime(lpTime, wwo->dwPlayedTotal, &wwo->format);
 }
 
 /**************************************************************************
@@ -2205,7 +2214,6 @@
  */
 static DWORD widGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
 {
-    double		time;
     WINE_WAVEIN*	wwi;
 
     TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize);
@@ -2218,46 +2226,7 @@
 
     wwi = &WInDev[wDevID];
 
-    TRACE("wType=%04X !\n", lpTime->wType);
-    TRACE("wBitsPerSample=%u\n", wwi->format.wBitsPerSample);
-    TRACE("nSamplesPerSec=%lu\n", wwi->format.wf.nSamplesPerSec);
-    TRACE("nChannels=%u\n", wwi->format.wf.nChannels);
-    TRACE("nAvgBytesPerSec=%lu\n", wwi->format.wf.nAvgBytesPerSec);
-    switch (lpTime->wType) {
-    case TIME_BYTES:
-	lpTime->u.cb = wwi->dwTotalRecorded;
-	TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
-	break;
-    case TIME_SAMPLES:
-	lpTime->u.sample = wwi->dwTotalRecorded * 8 /
-	    wwi->format.wBitsPerSample;
-	TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
-	break;
-    case TIME_SMPTE:
-	time = (double)wwi->dwTotalRecorded /
-	    (double)wwi->format.wf.nAvgBytesPerSec;
-	lpTime->u.smpte.hour = time / (60 * 60);
-	time -= lpTime->u.smpte.hour *  (60 * 60);
-	lpTime->u.smpte.min = time / 60;
-	time -= lpTime->u.smpte.min * 60;
-	lpTime->u.smpte.sec = time;
-	time -= lpTime->u.smpte.sec;
-	lpTime->u.smpte.frame = celi(time * 30);
-	lpTime->u.smpte.fps = 30;
-	TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
-	      lpTime->u.smpte.hour, lpTime->u.smpte.min,
-	      lpTime->u.smpte.sec, lpTime->u.smpte.frame);
-	break;
-    case TIME_MS:
-	lpTime->u.ms = wwi->dwTotalRecorded * 1000.0 /
-	    wwi->format.wf.nAvgBytesPerSec;
-	TRACE("TIME_MS=%lu\n", lpTime->u.ms);
-	break;
-    default:
-	FIXME("format not supported (%u) ! use TIME_MS !\n", lpTime->wType);
-	lpTime->wType = TIME_MS;
-    }
-    return MMSYSERR_NOERROR;
+    return bytes_to_mmtime(lpTime, wwi->dwTotalRecorded, &wwi->format);
 }
 
 /**************************************************************************
Index: dlls/winmm/winejack/audio.c
===================================================================
RCS file: /var/cvs/wine/dlls/winmm/winejack/audio.c,v
retrieving revision 1.13
diff -u -r1.13 audio.c
--- dlls/winmm/winejack/audio.c	19 Jul 2004 20:08:06 -0000	1.13
+++ dlls/winmm/winejack/audio.c	23 Jul 2004 00:53:37 -0000
@@ -215,6 +215,55 @@
 static void	JACK_CloseWaveInDevice(WINE_WAVEIN* wwi);
 #endif
 
+static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
+                             PCMWAVEFORMAT* format)
+{
+    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
+          lpTime->wType, format->wBitsPerSample, format->wf.nSamplesPerSec,
+          format->wf.nChannels, format->wf.nAvgBytesPerSec);
+    TRACE("Position in bytes=%lu\n", position);
+
+    switch (lpTime->wType) {
+    case TIME_SAMPLES:
+        lpTime->u.sample = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
+        TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
+        break;
+    case TIME_MS:
+        lpTime->u.ms = 1000.0 * position / (format->wBitsPerSample / 8 * format->wf.nChannels * format->wf.nSamplesPerSec);
+        TRACE("TIME_MS=%lu\n", lpTime->u.ms);
+        break;
+    case TIME_SMPTE:
+        position = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
+        lpTime->u.smpte.sec = position / format->wf.nSamplesPerSec;
+        position -= lpTime->u.smpte.sec * format->wf.nSamplesPerSec;
+        lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
+        lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
+        lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
+        lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
+        lpTime->u.smpte.fps = 30;
+        lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->wf.nSamplesPerSec;
+        position -= lpTime->u.smpte.frame * format->wf.nSamplesPerSec / lpTime->u.smpte.fps;
+        if (position != 0)
+        {
+            /* Round up */
+            lpTime->u.smpte.frame++;
+        }
+        TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
+              lpTime->u.smpte.hour, lpTime->u.smpte.min,
+              lpTime->u.smpte.sec, lpTime->u.smpte.frame);
+        break;
+    default:
+        FIXME("Format %d not supported ! use TIME_BYTES !\n", lpTime->wType);
+        lpTime->wType = TIME_BYTES;
+        /* fall through */
+    case TIME_BYTES:
+        lpTime->u.cb = position;
+        TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
+        break;
+    }
+    return MMSYSERR_NOERROR;
+}
+
 
 /*======================================================================*
  *                  Low level WAVE implementation			*
@@ -1542,19 +1591,18 @@
  */
 static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
 {
-    double		time;
     DWORD		val;
     WINE_WAVEOUT*	wwo;
     DWORD elapsedMS;
 
     TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize);
-    
+
     if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
     {
       WARN("bad device ID !\n");
       return MMSYSERR_BADDEVICEID;
     }
-    
+
     /* if null pointer to time structure return error */
     if (lpTime == NULL)	return MMSYSERR_INVALPARAM;
 
@@ -1568,44 +1616,7 @@
     /* account for the bytes played since the last JACK_Callback() */
     val+=((elapsedMS * wwo->format.wf.nAvgBytesPerSec) / 1000);
 
-    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n", 
-      lpTime->wType, wwo->format.wBitsPerSample,
-      wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels,
-      wwo->format.wf.nAvgBytesPerSec);
-    TRACE("dwPlayedTotal=%lu\n", val);
-    
-    switch (lpTime->wType) {
-    case TIME_BYTES:
-      lpTime->u.cb = val;
-      TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
-      break;
-    case TIME_SAMPLES:
-      lpTime->u.sample = val * 8 / wwo->format.wBitsPerSample /wwo->format.wf.nChannels;
-      TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
-      break;
-    case TIME_SMPTE:
-      time = (double)val / (double)wwo->format.wf.nAvgBytesPerSec;
-      lpTime->u.smpte.hour = time / (60 * 60);
-      time -= lpTime->u.smpte.hour * (60 * 60);
-      lpTime->u.smpte.min = time / 60;
-      time -= lpTime->u.smpte.min * 60;
-      lpTime->u.smpte.sec = time;
-      time -= lpTime->u.smpte.sec;
-      lpTime->u.smpte.frame = round(time * 30);
-      lpTime->u.smpte.fps = 30;
-      TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
-        lpTime->u.smpte.hour, lpTime->u.smpte.min,
-        lpTime->u.smpte.sec, lpTime->u.smpte.frame);
-      break;
-    default:
-      FIXME("Format %d not supported ! use TIME_MS !\n", lpTime->wType);
-      lpTime->wType = TIME_MS;
-    case TIME_MS:
-      lpTime->u.ms = val * 1000.0 / wwo->format.wf.nAvgBytesPerSec;
-      TRACE("TIME_MS=%lu\n", lpTime->u.ms);
-      break;
-    }
-    return MMSYSERR_NOERROR;
+    return bytes_to_mmtime(lpTime, val, &wwo->format);
 }
 
 /**************************************************************************
Index: dlls/winmm/winenas/audio.c
===================================================================
RCS file: /var/cvs/wine/dlls/winmm/winenas/audio.c,v
retrieving revision 1.15
diff -u -r1.15 audio.c
--- dlls/winmm/winenas/audio.c	19 Jul 2004 20:08:06 -0000	1.15
+++ dlls/winmm/winenas/audio.c	23 Jul 2004 00:56:04 -0000
@@ -279,6 +279,55 @@
         return nas_states[state];
 }
 
+static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
+                             PCMWAVEFORMAT* format)
+{
+    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
+          lpTime->wType, format->wBitsPerSample, format->wf.nSamplesPerSec,
+          format->wf.nChannels, format->wf.nAvgBytesPerSec);
+    TRACE("Position in bytes=%lu\n", position);
+
+    switch (lpTime->wType) {
+    case TIME_SAMPLES:
+        lpTime->u.sample = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
+        TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
+        break;
+    case TIME_MS:
+        lpTime->u.ms = 1000.0 * position / (format->wBitsPerSample / 8 * format->wf.nChannels * format->wf.nSamplesPerSec);
+        TRACE("TIME_MS=%lu\n", lpTime->u.ms);
+        break;
+    case TIME_SMPTE:
+        position = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
+        lpTime->u.smpte.sec = position / format->wf.nSamplesPerSec;
+        position -= lpTime->u.smpte.sec * format->wf.nSamplesPerSec;
+        lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
+        lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
+        lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
+        lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
+        lpTime->u.smpte.fps = 30;
+        lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->wf.nSamplesPerSec;
+        position -= lpTime->u.smpte.frame * format->wf.nSamplesPerSec / lpTime->u.smpte.fps;
+        if (position != 0)
+        {
+            /* Round up */
+            lpTime->u.smpte.frame++;
+        }
+        TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
+              lpTime->u.smpte.hour, lpTime->u.smpte.min,
+              lpTime->u.smpte.sec, lpTime->u.smpte.frame);
+        break;
+    default:
+        FIXME("Format %d not supported ! use TIME_BYTES !\n", lpTime->wType);
+        lpTime->wType = TIME_BYTES;
+        /* fall through */
+    case TIME_BYTES:
+        lpTime->u.cb = position;
+        TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
+        break;
+    }
+    return MMSYSERR_NOERROR;
+}
+
 /*======================================================================*
  *                  Low level WAVE implementation			*
  *======================================================================*/
@@ -1122,8 +1171,6 @@
  */
 static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
 {
-    double		time;
-    DWORD		val;
     WINE_WAVEOUT*	wwo;
 
     TRACE("%u, %p, %lu);\n", wDevID, lpTime, uSize);
@@ -1140,46 +1187,8 @@
 #if 0
     NAS_AddRingMessage(&wwo->msgRing, WINE_WM_UPDATE, 0, TRUE);
 #endif
-    val = wwo->WrittenTotal;
 
-    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
-	  lpTime->wType, wwo->format.wBitsPerSample,
-	  wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels,
-	  wwo->format.wf.nAvgBytesPerSec);
-    TRACE("PlayedTotal=%lu\n", val);
-
-    switch (lpTime->wType) {
-    case TIME_BYTES:
-	lpTime->u.cb = val;
-	TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
-	break;
-    case TIME_SAMPLES:
-	lpTime->u.sample = val * 8 / wwo->format.wBitsPerSample / wwo->format.wf.nChannels;
-	TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
-	break;
-    case TIME_SMPTE:
-	time = (double)val / (double)wwo->format.wf.nAvgBytesPerSec;
-	lpTime->u.smpte.hour = time / (60 * 60);
-	time -= lpTime->u.smpte.hour * (60 * 60);
-	lpTime->u.smpte.min = time / 60;
-	time -= lpTime->u.smpte.min * 60;
-	lpTime->u.smpte.sec = time;
-	time -= lpTime->u.smpte.sec;
-	lpTime->u.smpte.frame = round(time * 30);
-	lpTime->u.smpte.fps = 30;
-	TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
-	      lpTime->u.smpte.hour, lpTime->u.smpte.min,
-	      lpTime->u.smpte.sec, lpTime->u.smpte.frame);
-	break;
-    default:
-	FIXME("Format %d not supported ! use TIME_MS !\n", lpTime->wType);
-	lpTime->wType = TIME_MS;
-    case TIME_MS:
-	lpTime->u.ms = val * 1000.0 / wwo->format.wf.nAvgBytesPerSec;
-	TRACE("TIME_MS=%lu\n", lpTime->u.ms);
-	break;
-    }
-    return MMSYSERR_NOERROR;
+    return bytes_to_mmtime(lpTime, wwo->WrittenTotal, &wwo->format);
 }
 
 /**************************************************************************
Index: dlls/winmm/wineoss/audio.c
===================================================================
RCS file: /var/cvs/wine/dlls/winmm/wineoss/audio.c,v
retrieving revision 1.135
diff -u -r1.135 audio.c
--- dlls/winmm/wineoss/audio.c	19 Jul 2004 20:08:06 -0000	1.135
+++ dlls/winmm/wineoss/audio.c	22 Jul 2004 14:49:26 -0000
@@ -323,6 +323,55 @@
     return MMSYSERR_INVALPARAM;
 }
 
+static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
+                             PCMWAVEFORMAT* format)
+{
+    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
+          lpTime->wType, format->wBitsPerSample, format->wf.nSamplesPerSec,
+          format->wf.nChannels, format->wf.nAvgBytesPerSec);
+    TRACE("Position in bytes=%lu\n", position);
+
+    switch (lpTime->wType) {
+    case TIME_SAMPLES:
+        lpTime->u.sample = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
+        TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
+        break;
+    case TIME_MS:
+        lpTime->u.ms = 1000.0 * position / (format->wBitsPerSample / 8 * format->wf.nChannels * format->wf.nSamplesPerSec);
+        TRACE("TIME_MS=%lu\n", lpTime->u.ms);
+        break;
+    case TIME_SMPTE:
+        position = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
+        lpTime->u.smpte.sec = position / format->wf.nSamplesPerSec;
+        position -= lpTime->u.smpte.sec * format->wf.nSamplesPerSec;
+        lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
+        lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
+        lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
+        lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
+        lpTime->u.smpte.fps = 30;
+        lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->wf.nSamplesPerSec;
+        position -= lpTime->u.smpte.frame * format->wf.nSamplesPerSec / lpTime->u.smpte.fps;
+        if (position != 0)
+        {
+            /* Round up */
+            lpTime->u.smpte.frame++;
+        }
+        TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
+              lpTime->u.smpte.hour, lpTime->u.smpte.min,
+              lpTime->u.smpte.sec, lpTime->u.smpte.frame);
+        break;
+    default:
+        FIXME("Format %d not supported ! use TIME_BYTES !\n", lpTime->wType);
+        lpTime->wType = TIME_BYTES;
+        /* fall through */
+    case TIME_BYTES:
+        lpTime->u.cb = position;
+        TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
+        break;
+    }
+    return MMSYSERR_NOERROR;
+}
+
 /*======================================================================*
  *                  Low level WAVE implementation			*
  *======================================================================*/
@@ -2077,8 +2126,6 @@
  */
 static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
 {
-    double		time;
-    DWORD		val;
     WINE_WAVEOUT*	wwo;
 
     TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize);
@@ -2098,46 +2145,8 @@
     if (wwo->ossdev->out_caps.dwSupport & WAVECAPS_SAMPLEACCURATE)
 	OSS_AddRingMessage(&wwo->msgRing, WINE_WM_UPDATE, 0, TRUE);
 #endif
-    val = wwo->dwPlayedTotal;
 
-    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
-	  lpTime->wType, wwo->format.wBitsPerSample,
-	  wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels,
-	  wwo->format.wf.nAvgBytesPerSec);
-    TRACE("dwPlayedTotal=%lu\n", val);
-
-    switch (lpTime->wType) {
-    case TIME_BYTES:
-	lpTime->u.cb = val;
-	TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
-	break;
-    case TIME_SAMPLES:
-	lpTime->u.sample = val * 8 / wwo->format.wBitsPerSample /wwo->format.wf.nChannels;
-	TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
-	break;
-    case TIME_SMPTE:
-	time = (double)val / (double)wwo->format.wf.nAvgBytesPerSec;
-	lpTime->u.smpte.hour = time / (60 * 60);
-	time -= lpTime->u.smpte.hour * (60 * 60);
-	lpTime->u.smpte.min = time / 60;
-	time -= lpTime->u.smpte.min * 60;
-	lpTime->u.smpte.sec = time;
-	time -= lpTime->u.smpte.sec;
-	lpTime->u.smpte.frame = round(time * 30);
-	lpTime->u.smpte.fps = 30;
-	TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
-	      lpTime->u.smpte.hour, lpTime->u.smpte.min,
-	      lpTime->u.smpte.sec, lpTime->u.smpte.frame);
-	break;
-    default:
-	FIXME("Format %d not supported ! use TIME_MS !\n", lpTime->wType);
-	lpTime->wType = TIME_MS;
-    case TIME_MS:
-	lpTime->u.ms = val * 1000.0 / wwo->format.wf.nAvgBytesPerSec;
-	TRACE("TIME_MS=%lu\n", lpTime->u.ms);
-	break;
-    }
-    return MMSYSERR_NOERROR;
+    return bytes_to_mmtime(lpTime, wwo->dwPlayedTotal, &wwo->format);
 }
 
 /**************************************************************************
@@ -3867,7 +3881,6 @@
  */
 static DWORD widGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
 {
-    double		time;
     WINE_WAVEIN*	wwi;
 
     TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize);
@@ -3885,50 +3898,10 @@
     wwi = &WInDev[wDevID];
 #ifdef EXACT_WIDPOSITION
     if (wwi->ossdev->in_caps_support & WAVECAPS_SAMPLEACCURATE)
-	OSS_AddRingMessage(&(wwi->msgRing), WINE_WM_UPDATE, 0, TRUE);
+        OSS_AddRingMessage(&(wwi->msgRing), WINE_WM_UPDATE, 0, TRUE);
 #endif
 
-    TRACE("wType=%04X !\n", lpTime->wType);
-    TRACE("wBitsPerSample=%u\n", wwi->format.wBitsPerSample);
-    TRACE("nSamplesPerSec=%lu\n", wwi->format.wf.nSamplesPerSec);
-    TRACE("nChannels=%u\n", wwi->format.wf.nChannels);
-    TRACE("nAvgBytesPerSec=%lu\n", wwi->format.wf.nAvgBytesPerSec);
-    TRACE("dwTotalRecorded=%lu\n",wwi->dwTotalRecorded);
-    switch (lpTime->wType) {
-    case TIME_BYTES:
-	lpTime->u.cb = wwi->dwTotalRecorded;
-	TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
-	break;
-    case TIME_SAMPLES:
-	lpTime->u.sample = wwi->dwTotalRecorded * 8 /
-	    wwi->format.wBitsPerSample / wwi->format.wf.nChannels;
-	TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
-	break;
-    case TIME_SMPTE:
-	time = (double)wwi->dwTotalRecorded /
-	    (double)wwi->format.wf.nAvgBytesPerSec;
-	lpTime->u.smpte.hour = time / (60 * 60);
-	time -= lpTime->u.smpte.hour * (60 * 60);
-	lpTime->u.smpte.min = time / 60;
-	time -= lpTime->u.smpte.min * 60;
-	lpTime->u.smpte.sec = time;
-	time -= lpTime->u.smpte.sec;
-	lpTime->u.smpte.frame = ceil(time * 30);
-	lpTime->u.smpte.fps = 30;
-	TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
-	      lpTime->u.smpte.hour, lpTime->u.smpte.min,
-	      lpTime->u.smpte.sec, lpTime->u.smpte.frame);
-	break;
-    default:
-	FIXME("format not supported (%u) ! use TIME_MS !\n", lpTime->wType);
-	lpTime->wType = TIME_MS;
-    case TIME_MS:
-	lpTime->u.ms = wwi->dwTotalRecorded * 1000.0 /
-	    wwi->format.wf.nAvgBytesPerSec;
-	TRACE("TIME_MS=%lu\n", lpTime->u.ms);
-	break;
-    }
-    return MMSYSERR_NOERROR;
+    return bytes_to_mmtime(lpTime, wwi->dwTotalRecorded, &wwi->format);
 }
 
 /**************************************************************************


More information about the wine-patches mailing list