msadpcm.acm: Implement source & destination buffer size computation

Vincent Pelletier plr.vincent at gmail.com
Tue Jan 27 15:18:46 CST 2009


Also implements block boundary alignment, gets rid of "magic" constants, and 
add trace logs.

Tested to fix sound issues on Freespace.

Note that FreeSpace doesn't cover all cases, since it doesn't convert from a 
sampling rate to another, and only uses ACM_STREAMSIZEF_DESTINATION with 
WAVE_FORMAT_ADPCM source format.
But all 4 cases are quite symetric.

-- 
Vincent Pelletier
-------------- next part --------------
From 8488a22f2b65e62822e8ff46a23c04f28013cf63 Mon Sep 17 00:00:00 2001
From: Vincent Pelletier <plr.vincent at gmail.com>
Date: Tue, 27 Jan 2009 22:05:23 +0100
Subject: Implement source & destination buffer size computations more accurately.
 Add trace method to dump ACMDRVSTREAMINSTANCE, WAVEFORMATEX and ACMDRVSTREAMSIZE structures.

---
 dlls/msadp32.acm/msadp32.c |   66 ++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 58 insertions(+), 8 deletions(-)

diff --git a/dlls/msadp32.acm/msadp32.c b/dlls/msadp32.acm/msadp32.c
index 40b8260..91c2ae5 100644
--- a/dlls/msadp32.acm/msadp32.c
+++ b/dlls/msadp32.acm/msadp32.c
@@ -37,6 +37,40 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(adpcm);
 
+void _dump_WAVEFORMATEX(const WAVEFORMATEX *wfx) {
+    TRACE("wFormatTag      %04x\n", wfx->wFormatTag);
+    TRACE("nChannels       %04x\n", wfx->nChannels);
+    TRACE("nSamplesPerSec  %08x\n", wfx->nSamplesPerSec);
+    TRACE("nAvgBytesPerSec %08x\n", wfx->nAvgBytesPerSec);
+    TRACE("nBlockAlign     %04x\n", wfx->nBlockAlign);
+    TRACE("wBitsPerSample  %04x\n", wfx->wBitsPerSample);
+    TRACE("cbSize          %04x\n", wfx->cbSize);
+}
+
+void _dump_ACMDRVSTREAMINSTANCE(const ACMDRVSTREAMINSTANCE *adsi) {
+    TRACE("cbStruct   %08x (%s)\n", adsi->cbStruct, adsi->cbStruct == sizeof(ACMDRVSTREAMINSTANCE) ? "OK" : "ERROR");
+    TRACE("pwfxSrc    %p\n", adsi->pwfxSrc);
+    if (adsi->pwfxSrc)
+        _dump_WAVEFORMATEX(adsi->pwfxSrc);
+    TRACE("pwfxDst    %p\n", adsi->pwfxDst);
+    if (adsi->pwfxDst)
+        _dump_WAVEFORMATEX(adsi->pwfxDst);
+    TRACE("pwfltr     %p\n", adsi->pwfltr);
+    TRACE("dwCallback %08x\n", adsi->dwCallback);
+    TRACE("dwInstance %08x\n", adsi->dwInstance);
+    TRACE("fdwOpen    %08x\n", adsi->fdwOpen);
+    TRACE("fdwDriver  %08x\n", adsi->fdwDriver);
+    TRACE("dwDriver   %08x\n", adsi->dwDriver);
+    TRACE("has        %p\n", adsi->has);
+}
+
+void _dump_ACMDRVSTREAMSIZE(const ACMDRVSTREAMSIZE *adss) {
+    TRACE("cbStruct    %08x (%s)\n", adss->cbStruct, adss->cbStruct == sizeof(ACMDRVSTREAMSIZE) ? "OK" : "ERROR");
+    TRACE("fdwSize     %08x\n", adss->fdwSize);
+    TRACE("cbSrcLength %08x\n", adss->cbSrcLength);
+    TRACE("cbDstLength %08x\n", adss->cbDstLength);
+}
+
 /***********************************************************************
  *           ADPCM_drvOpen
  */
@@ -618,6 +652,8 @@ static	LRESULT	ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
  */
 static	LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss)
 {
+    _dump_ACMDRVSTREAMINSTANCE(adsi);
+    _dump_ACMDRVSTREAMSIZE(adss);
     switch (adss->fdwSize)
     {
     case ACM_STREAMSIZEF_DESTINATION:
@@ -625,38 +661,52 @@ static	LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMS
 	if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
 	    adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM)
         {
-	    /* don't take block overhead into account, doesn't matter too much */
-	    adss->cbSrcLength = adss->cbDstLength * 4;
+	    /* Reduce cbDstLength by its header size, and scale pwfxDst to pwfxSrc format. */
+	    adss->cbSrcLength = ((adss->cbDstLength - adsi->pwfxDst->nChannels * (sizeof(int) * 3 + sizeof(char))) *
+                                  adsi->pwfxSrc->wBitsPerSample * adsi->pwfxSrc->nSamplesPerSec) /
+                                 (adsi->pwfxDst->wBitsPerSample * adsi->pwfxDst->nSamplesPerSec);
 	}
         else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM &&
                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
         {
-	    FIXME("misses the block header overhead\n");
-	    adss->cbSrcLength = 256 + adss->cbDstLength / 4;
+	    /* Scale pwfxDst to pwfxSrc format and augment cbSrcLength by its header size. */
+	    adss->cbSrcLength = (adsi->pwfxSrc->nChannels * (sizeof(int) * 3 + sizeof(char))) +
+				((adss->cbDstLength * adsi->pwfxSrc->wBitsPerSample * adsi->pwfxSrc->nSamplesPerSec) /
+                                 (adsi->pwfxDst->wBitsPerSample * adsi->pwfxDst->nSamplesPerSec));
 	}
         else
         {
 	    return MMSYSERR_NOTSUPPORTED;
 	}
+	/* Pad cbSrcLength to nearest greater block boundary. */
+	adss->cbSrcLength += adsi->pwfxSrc->nBlockAlign - (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign);
+	TRACE("Computed cbSrcLength = %08x\n", adss->cbSrcLength);
 	break;
     case ACM_STREAMSIZEF_SOURCE:
 	/* cbSrcLength => cbDstLength */
 	if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
 	    adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM)
         {
-	    FIXME("misses the block header overhead\n");
-	    adss->cbDstLength = 256 + adss->cbSrcLength / 4;
+	    /* Scale pwfxSrc to pwfxDst format and augment cbDstLength by its header size. */
+	    adss->cbDstLength = (adsi->pwfxDst->nChannels * (sizeof(int) * 3 + sizeof(char))) +
+				((adss->cbSrcLength * adsi->pwfxDst->wBitsPerSample * adsi->pwfxDst->nSamplesPerSec) /
+				 (adsi->pwfxSrc->wBitsPerSample * adsi->pwfxSrc->nSamplesPerSec));
 	}
         else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM &&
                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
         {
-	    /* don't take block overhead into account, doesn't matter too much */
-	    adss->cbDstLength = adss->cbSrcLength * 4;
+	    /* Reduce cbSrcLength by its header size, and scale pwfxSrc to pwfxDst format. */
+	    adss->cbDstLength = ((adss->cbSrcLength - adsi->pwfxSrc->nChannels * (sizeof(int) * 3 + sizeof(char))) *
+				 adsi->pwfxDst->wBitsPerSample * adsi->pwfxDst->nSamplesPerSec) /
+				(adsi->pwfxSrc->wBitsPerSample * adsi->pwfxSrc->nSamplesPerSec);
 	}
         else
         {
 	    return MMSYSERR_NOTSUPPORTED;
 	}
+	/* Pad cbDstLength to nearest greater block boundary. */
+	adss->cbDstLength += adsi->pwfxDst->nBlockAlign - (adss->cbDstLength % adsi->pwfxDst->nBlockAlign);
+	TRACE("Computed cbDstLength = %08x\n", adss->cbDstLength);
 	break;
     default:
 	WARN("Unsupported query %08x\n", adss->fdwSize);
-- 
1.5.6.5



More information about the wine-patches mailing list