[MSADP32.ACM] Sync with Wine Staging 4.0. CORE-15682
[reactos.git] / dll / win32 / msadp32.acm / msadp32.c
index dbb6d20..78d99a2 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#define WIN32_NO_STATUS
-
 #include <assert.h>
 #include <stdarg.h>
-//#include <string.h>
-#include <windef.h>
-#include <winbase.h>
-#include <wingdi.h>
-#include <winuser.h>
-#include <winnls.h>
-//#include "mmsystem.h"
-//#include "mmreg.h"
-//#include "msacm.h"
-#include <msacmdrv.h>
-#include <wine/debug.h>
+#include <string.h>
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "mmsystem.h"
+#include "mmreg.h"
+#include "msacm.h"
+#include "msacmdrv.h"
+#include "wine/debug.h"
 
 /* see http://www.pcisys.net/~melanson/codecs/adpcm.txt for the details */
 
@@ -85,9 +83,6 @@ static const Format ADPCM_Formats[] =
     {1,  4, 22050}, {2,        4, 22050},  {1,  4, 44100}, {2,  4, 44100},
 };
 
-#define        NUM_PCM_FORMATS         (sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
-#define        NUM_ADPCM_FORMATS       (sizeof(ADPCM_Formats) / sizeof(ADPCM_Formats[0]))
-
 static int MS_Delta[] =
 {
     230, 230, 230, 230, 307, 409, 512, 614,
@@ -111,11 +106,11 @@ static    DWORD   ADPCM_GetFormatIndex(const WAVEFORMATEX* wfx)
     switch (wfx->wFormatTag)
     {
     case WAVE_FORMAT_PCM:
-       hi = NUM_PCM_FORMATS;
+       hi = ARRAY_SIZE(PCM_Formats);
        fmts = PCM_Formats;
        break;
     case WAVE_FORMAT_ADPCM:
-       hi = NUM_ADPCM_FORMATS;
+       hi = ARRAY_SIZE(ADPCM_Formats);
        fmts = ADPCM_Formats;
        break;
     default:
@@ -225,6 +220,11 @@ static inline void process_nibble(unsigned nibble, int* idelta,
     if (*idelta < 16) *idelta = 16;
 }
 
+static inline unsigned char C168(short s)
+{
+    return HIBYTE(s) ^ (unsigned char)0x80;
+}
+
 static void cvtSSms16K(const ACMDRVSTREAMINSTANCE *adsi,
                         const unsigned char* src, LPDWORD nsrc,
                         unsigned char* dst, LPDWORD ndst)
@@ -236,19 +236,27 @@ static    void cvtSSms16K(const ACMDRVSTREAMINSTANCE *adsi,
     int                 nsamp;
     int                        nsamp_blk = ((ADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
     DWORD              nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
-                                     *ndst / (nsamp_blk * 2 * 2));
+                                     *ndst / (nsamp_blk * adsi->pwfxDst->nBlockAlign));
 
     *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
-    *ndst = nblock * nsamp_blk * 2 * 2;
+    *ndst = nblock * nsamp_blk * adsi->pwfxDst->nBlockAlign;
 
     nsamp_blk -= 2; /* see below for samples from block head */
     for (; nblock > 0; nblock--)
     {
         const unsigned char*    in_src = src;
 
-        assert(*src <= 6);
+        /* Catch a problem from Tomb Raider III (bug 21000) where it passes
+         * invalid data after a valid sequence of blocks */
+        if (*src > 6 || *(src + 1) > 6)
+        {
+            /* Recalculate the amount of used output buffer. We are not changing
+             * nsrc, let's assume the bad data was parsed */
+            *ndst -= nblock * nsamp_blk * adsi->pwfxDst->nBlockAlign;
+            WARN("Invalid ADPCM data, stopping conversion\n");
+            break;
+        }
         coeffL = MSADPCM_CoeffSet[*src++];
-        assert(*src <= 6);
         coeffR = MSADPCM_CoeffSet[*src++];
 
         ideltaL  = R16(src);    src += 2;
@@ -258,18 +266,34 @@ static    void cvtSSms16K(const ACMDRVSTREAMINSTANCE *adsi,
         sample2L = R16(src);    src += 2;
         sample2R = R16(src);    src += 2;
 
-        /* store samples from block head */
-        W16(dst, sample2L);      dst += 2;
-        W16(dst, sample2R);      dst += 2;
-        W16(dst, sample1L);      dst += 2;
-        W16(dst, sample1R);      dst += 2;
-
-        for (nsamp = nsamp_blk; nsamp > 0; nsamp--)
-        {
-            process_nibble(*src >> 4, &ideltaL, &sample1L, &sample2L, &coeffL);
-            W16(dst, sample1L); dst += 2;
-            process_nibble(*src++ & 0x0F, &ideltaR, &sample1R, &sample2R, &coeffR);
-            W16(dst, sample1R); dst += 2;
+        if(adsi->pwfxDst->wBitsPerSample == 8){
+            /* store samples from block head */
+            *dst = C168(sample2L);      ++dst;
+            *dst = C168(sample2R);      ++dst;
+            *dst = C168(sample1L);      ++dst;
+            *dst = C168(sample1R);      ++dst;
+
+            for (nsamp = nsamp_blk; nsamp > 0; nsamp--)
+            {
+                process_nibble(*src >> 4, &ideltaL, &sample1L, &sample2L, &coeffL);
+                *dst = C168(sample1L); ++dst;
+                process_nibble(*src++ & 0x0F, &ideltaR, &sample1R, &sample2R, &coeffR);
+                *dst = C168(sample1R); ++dst;
+            }
+        }else if(adsi->pwfxDst->wBitsPerSample == 16){
+            /* store samples from block head */
+            W16(dst, sample2L);      dst += 2;
+            W16(dst, sample2R);      dst += 2;
+            W16(dst, sample1L);      dst += 2;
+            W16(dst, sample1R);      dst += 2;
+
+            for (nsamp = nsamp_blk; nsamp > 0; nsamp--)
+            {
+                process_nibble(*src >> 4, &ideltaL, &sample1L, &sample2L, &coeffL);
+                W16(dst, sample1L); dst += 2;
+                process_nibble(*src++ & 0x0F, &ideltaR, &sample1R, &sample2R, &coeffR);
+                W16(dst, sample1R); dst += 2;
+            }
         }
         src = in_src + adsi->pwfxSrc->nBlockAlign;
     }
@@ -285,10 +309,10 @@ static    void cvtMMms16K(const ACMDRVSTREAMINSTANCE *adsi,
     int                 nsamp;
     int                        nsamp_blk = ((ADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
     DWORD              nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
-                                     *ndst / (nsamp_blk * 2));
+                                     *ndst / (nsamp_blk * adsi->pwfxDst->nBlockAlign));
 
     *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
-    *ndst = nblock * nsamp_blk * 2;
+    *ndst = nblock * nsamp_blk * adsi->pwfxDst->nBlockAlign;
 
     nsamp_blk -= 2; /* see below for samples from block head */
     for (; nblock > 0; nblock--)
@@ -303,16 +327,30 @@ static    void cvtMMms16K(const ACMDRVSTREAMINSTANCE *adsi,
         sample2 = R16(src);     src += 2;
 
         /* store samples from block head */
-        W16(dst, sample2);      dst += 2;
-        W16(dst, sample1);      dst += 2;
-
-        for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
-        {
-            process_nibble(*src >> 4, &idelta, &sample1, &sample2, &coeff);
-            W16(dst, sample1); dst += 2;
-            process_nibble(*src++ & 0x0F, &idelta, &sample1, &sample2, &coeff);
-            W16(dst, sample1); dst += 2;
+        if(adsi->pwfxDst->wBitsPerSample == 8){
+            *dst = C168(sample2);    ++dst;
+            *dst = C168(sample1);    ++dst;
+
+            for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
+            {
+                process_nibble(*src >> 4, &idelta, &sample1, &sample2, &coeff);
+                *dst = C168(sample1); ++dst;
+                process_nibble(*src++ & 0x0F, &idelta, &sample1, &sample2, &coeff);
+                *dst = C168(sample1); ++dst;
+            }
+        }else if(adsi->pwfxDst->wBitsPerSample == 16){
+            W16(dst, sample2);      dst += 2;
+            W16(dst, sample1);      dst += 2;
+
+            for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
+            {
+                process_nibble(*src >> 4, &idelta, &sample1, &sample2, &coeff);
+                W16(dst, sample1); dst += 2;
+                process_nibble(*src++ & 0x0F, &idelta, &sample1, &sample2, &coeff);
+                W16(dst, sample1); dst += 2;
+            }
         }
+
         src = in_src + adsi->pwfxSrc->nBlockAlign;
     }
 }
@@ -339,8 +377,8 @@ static      LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
 {
     add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
     add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
-    add->wMid = 0xFF;
-    add->wPid = 0x00;
+    add->wMid = MM_MICROSOFT;
+    add->wPid = MM_MSFT_ACM_MSADPCM;
     add->vdwACM = 0x01000000;
     add->vdwDriver = 0x01000000;
     add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
@@ -348,13 +386,13 @@ static    LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
     add->cFilterTags = 0;
     add->hicon = NULL;
     MultiByteToWideChar( CP_ACP, 0, "MS-ADPCM", -1,
-                         add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
+                         add->szShortName, ARRAY_SIZE( add->szShortName ));
     MultiByteToWideChar( CP_ACP, 0, "Wine MS ADPCM converter", -1,
-                         add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
+                         add->szLongName, ARRAY_SIZE( add->szLongName ));
     MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
-                         add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
+                         add->szCopyright, ARRAY_SIZE( add->szCopyright ));
     MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
-                         add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
+                         add->szLicensing, ARRAY_SIZE( add->szLicensing ));
     add->szFeatures[0] = 0;
 
     return MMSYSERR_NOERROR;
@@ -380,7 +418,7 @@ static      LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
             aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_ADPCM is bigger than PCM */
            break;
        }
-       /* fall thru */
+       /* fall through */
     case ACM_FORMATTAGDETAILSF_FORMATTAG:
        switch (aftd->dwFormatTag)
         {
@@ -400,13 +438,13 @@ static    LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
     case 0:
        aftd->dwFormatTag = WAVE_FORMAT_PCM;
        aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
-       aftd->cStandardFormats = NUM_PCM_FORMATS;
+       aftd->cStandardFormats = ARRAY_SIZE(PCM_Formats);
         lstrcpyW(aftd->szFormatTag, szPcm);
         break;
     case 1:
        aftd->dwFormatTag = WAVE_FORMAT_ADPCM;
        aftd->cbFormatSize = sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET);
-       aftd->cStandardFormats = NUM_ADPCM_FORMATS;
+       aftd->cStandardFormats = ARRAY_SIZE(ADPCM_Formats);
         lstrcpyW(aftd->szFormatTag, szMsAdPcm);
        break;
     }
@@ -429,7 +467,7 @@ static      LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
        switch (afd->dwFormatTag)
         {
        case WAVE_FORMAT_PCM:
-           if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE;
+           if (afd->dwFormatIndex >= ARRAY_SIZE(PCM_Formats)) return ACMERR_NOTPOSSIBLE;
            afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
            afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
            afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
@@ -442,7 +480,7 @@ static      LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
                afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
            break;
        case WAVE_FORMAT_ADPCM:
-           if (afd->dwFormatIndex >= NUM_ADPCM_FORMATS) return ACMERR_NOTPOSSIBLE;
+           if (afd->dwFormatIndex >= ARRAY_SIZE(ADPCM_Formats)) return ACMERR_NOTPOSSIBLE;
             if (afd->cbwfx < sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET))
                 return ACMERR_NOTPOSSIBLE;
            afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels;
@@ -509,6 +547,8 @@ static      LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
         if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
         break;
     case WAVE_FORMAT_ADPCM:
+        if (adfs->cbwfxDst < sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET))
+            return ACMERR_NOTPOSSIBLE;
         init_wfx_adpcm((ADPCMWAVEFORMAT*)adfs->pwfxDst);
         /* check if result is ok */
         if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
@@ -555,12 +595,9 @@ static     LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
     else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM &&
              adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
     {
-       /* resampling or mono <=> stereo not available
-         * ADPCM algo only define 16 bit per sample output
-         */
+       /* resampling or mono <=> stereo not available */
        if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
-           adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
-            adsi->pwfxDst->wBitsPerSample != 16)
+           adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels)
            goto theEnd;
 
 #if 0
@@ -579,9 +616,9 @@ static      LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
 #endif
 
        /* adpcm decoding... */
-       if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2)
+       if (adsi->pwfxDst->nChannels == 2)
            aad->convert = cvtSSms16K;
-       if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1)
+       else if (adsi->pwfxDst->nChannels == 1)
            aad->convert = cvtMMms16K;
     }
     else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&