ReactOS Fundraising Campaign 2012
 
€ 3,873 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

msadp32.c
Go to the documentation of this file.
00001 /*
00002  * MS ADPCM handling
00003  *
00004  *      Copyright (C) 2002      Eric Pouech
00005  *
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00020  */
00021 
00022 #include <assert.h>
00023 #include <stdarg.h>
00024 #include <string.h>
00025 #include "windef.h"
00026 #include "winbase.h"
00027 #include "wingdi.h"
00028 #include "winuser.h"
00029 #include "winnls.h"
00030 #include "mmsystem.h"
00031 #include "mmreg.h"
00032 #include "msacm.h"
00033 #include "msacmdrv.h"
00034 #include "wine/debug.h"
00035 
00036 /* see http://www.pcisys.net/~melanson/codecs/adpcm.txt for the details */
00037 
00038 WINE_DEFAULT_DEBUG_CHANNEL(adpcm);
00039 
00040 /***********************************************************************
00041  *           ADPCM_drvOpen
00042  */
00043 static  DWORD   ADPCM_drvOpen(LPCSTR str)
00044 {
00045     return 1;
00046 }
00047 
00048 /***********************************************************************
00049  *           ADPCM_drvClose
00050  */
00051 static  DWORD   ADPCM_drvClose(DWORD dwDevID)
00052 {
00053     return 1;
00054 }
00055 
00056 typedef struct tagAcmAdpcmData
00057 {
00058     void (*convert)(PACMDRVSTREAMINSTANCE adsi,
00059             const unsigned char*, LPDWORD, unsigned char*, LPDWORD);
00060 } AcmAdpcmData;
00061 
00062 /* table to list all supported formats... those are the basic ones. this
00063  * also helps given a unique index to each of the supported formats
00064  */
00065 typedef struct
00066 {
00067     int     nChannels;
00068     int     nBits;
00069     int     rate;
00070 } Format;
00071 
00072 static Format PCM_Formats[] =
00073 {
00074     {1,  8,  8000}, {2,  8,  8000}, {1, 16,  8000}, {2, 16,  8000},
00075     {1,  8, 11025}, {2,  8, 11025}, {1, 16, 11025}, {2, 16, 11025},
00076     {1,  8, 22050}, {2,  8, 22050}, {1, 16, 22050}, {2, 16, 22050},
00077     {1,  8, 44100}, {2,  8, 44100}, {1, 16, 44100}, {2, 16, 44100},
00078 };
00079 
00080 static Format ADPCM_Formats[] =
00081 {
00082     {1,  4,  8000}, {2, 4,  8000},  {1,  4, 11025}, {2,  4, 11025},
00083     {1,  4, 22050}, {2, 4, 22050},  {1,  4, 44100}, {2,  4, 44100},
00084 };
00085 
00086 #define NUM_PCM_FORMATS     (sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
00087 #define NUM_ADPCM_FORMATS   (sizeof(ADPCM_Formats) / sizeof(ADPCM_Formats[0]))
00088 
00089 static int MS_Delta[] =
00090 {
00091     230, 230, 230, 230, 307, 409, 512, 614,
00092     768, 614, 512, 409, 307, 230, 230, 230
00093 };
00094 
00095 
00096 static ADPCMCOEFSET MSADPCM_CoeffSet[] =
00097 {
00098     {256, 0}, {512, -256}, {0, 0}, {192, 64}, {240, 0}, {460, -208}, {392, -232}
00099 };
00100 
00101 /***********************************************************************
00102  *           ADPCM_GetFormatIndex
00103  */
00104 static  DWORD   ADPCM_GetFormatIndex(WAVEFORMATEX* wfx)
00105 {
00106     int     i, hi;
00107     Format* fmts;
00108 
00109     switch (wfx->wFormatTag)
00110     {
00111     case WAVE_FORMAT_PCM:
00112     hi = NUM_PCM_FORMATS;
00113     fmts = PCM_Formats;
00114     break;
00115     case WAVE_FORMAT_ADPCM:
00116     hi = NUM_ADPCM_FORMATS;
00117     fmts = ADPCM_Formats;
00118     break;
00119     default:
00120     return 0xFFFFFFFF;
00121     }
00122 
00123     for (i = 0; i < hi; i++)
00124     {
00125     if (wfx->nChannels == fmts[i].nChannels &&
00126         wfx->nSamplesPerSec == fmts[i].rate &&
00127         wfx->wBitsPerSample == fmts[i].nBits)
00128         return i;
00129     }
00130 
00131     return 0xFFFFFFFF;
00132 }
00133 
00134 static void     init_wfx_adpcm(ADPCMWAVEFORMAT* awfx)
00135 {
00136     register WAVEFORMATEX*      pwfx = &awfx->wfx;
00137 
00138     /* we assume wFormatTag, nChannels, nSamplesPerSec and wBitsPerSample
00139      * have been initialized... */
00140 
00141     if (pwfx->wFormatTag != WAVE_FORMAT_ADPCM) {FIXME("wrong FT\n"); return;}
00142     if (ADPCM_GetFormatIndex(pwfx) == 0xFFFFFFFF) {FIXME("wrong fmt\n"); return;}
00143 
00144     switch (pwfx->nSamplesPerSec)
00145     {
00146     case  8000: pwfx->nBlockAlign = 256;   break;
00147     case 11025: pwfx->nBlockAlign = 256;   break;
00148     case 22050: pwfx->nBlockAlign = 512;   break;
00149     default:
00150     case 44100: pwfx->nBlockAlign = 1024;  break;
00151     }
00152     pwfx->cbSize = 2 * sizeof(WORD) + 7 * sizeof(ADPCMCOEFSET);
00153     /* 7 is the size of the block head (which contains two samples) */
00154 
00155     awfx->wSamplesPerBlock = (pwfx->nBlockAlign - (7 * pwfx->nChannels)) * (2 / pwfx->nChannels) + 2;
00156     pwfx->nAvgBytesPerSec = (pwfx->nSamplesPerSec * pwfx->nBlockAlign) / awfx->wSamplesPerBlock;
00157     awfx->wNumCoef = 7;
00158     memcpy(awfx->aCoef, MSADPCM_CoeffSet, 7 * sizeof(ADPCMCOEFSET));
00159 }
00160 
00161 /***********************************************************************
00162  *           R16
00163  *
00164  * Read a 16 bit sample (correctly handles endianess)
00165  */
00166 static inline short  R16(const unsigned char* src)
00167 {
00168     return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8));
00169 }
00170 
00171 /***********************************************************************
00172  *           W16
00173  *
00174  * Write a 16 bit sample (correctly handles endianess)
00175  */
00176 static inline void  W16(unsigned char* dst, short s)
00177 {
00178     dst[0] = LOBYTE(s);
00179     dst[1] = HIBYTE(s);
00180 }
00181 
00182 static inline void clamp_sample(int* sample)
00183 {
00184     if (*sample < -32768) *sample = -32768;
00185     if (*sample >  32767) *sample =  32767;
00186 }
00187 
00188 static inline void process_nibble(unsigned nibble, int* idelta,
00189                                   int* sample1, int* sample2,
00190                                   const ADPCMCOEFSET* coeff)
00191 {
00192     int sample;
00193     int snibble;
00194 
00195     /* nibble is in fact a signed 4 bit integer => propagate sign if needed */
00196     snibble = (nibble & 0x08) ? (nibble - 16) : nibble;
00197     sample = ((*sample1 * coeff->iCoef1) + (*sample2 * coeff->iCoef2)) / 256 +
00198         snibble * *idelta;
00199     clamp_sample(&sample);
00200 
00201     *sample2 = *sample1;
00202     *sample1 = sample;
00203     *idelta = ((MS_Delta[nibble] * *idelta) / 256);
00204     if (*idelta < 16) *idelta = 16;
00205 }
00206 
00207 static  void cvtSSms16K(PACMDRVSTREAMINSTANCE adsi,
00208                         const unsigned char* src, LPDWORD nsrc,
00209                         unsigned char* dst, LPDWORD ndst)
00210 {
00211     int                 ideltaL, ideltaR;
00212     int                 sample1L, sample2L;
00213     int                 sample1R, sample2R;
00214     ADPCMCOEFSET        coeffL, coeffR;
00215     int                 nsamp;
00216     int             nsamp_blk = ((ADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
00217     DWORD           nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
00218                                      *ndst / (nsamp_blk * 2 * 2));
00219 
00220     *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
00221     *ndst = nblock * nsamp_blk * 2 * 2;
00222 
00223     nsamp_blk -= 2; /* see below for samples from block head */
00224     for (; nblock > 0; nblock--)
00225     {
00226         const unsigned char*    in_src = src;
00227 
00228         assert(*src <= 6);
00229         coeffL = MSADPCM_CoeffSet[*src++];
00230         assert(*src <= 6);
00231         coeffR = MSADPCM_CoeffSet[*src++];
00232 
00233         ideltaL  = R16(src);    src += 2;
00234         ideltaR  = R16(src);    src += 2;
00235         sample1L = R16(src);    src += 2;
00236         sample1R = R16(src);    src += 2;
00237         sample2L = R16(src);    src += 2;
00238         sample2R = R16(src);    src += 2;
00239 
00240         /* store samples from block head */
00241         W16(dst, sample2L);      dst += 2;
00242         W16(dst, sample2R);      dst += 2;
00243         W16(dst, sample1L);      dst += 2;
00244         W16(dst, sample1R);      dst += 2;
00245 
00246         for (nsamp = nsamp_blk; nsamp > 0; nsamp--)
00247         {
00248             process_nibble(*src >> 4, &ideltaL, &sample1L, &sample2L, &coeffL);
00249             W16(dst, sample1L); dst += 2;
00250             process_nibble(*src++ & 0x0F, &ideltaR, &sample1R, &sample2R, &coeffR);
00251             W16(dst, sample1R); dst += 2;
00252         }
00253         src = in_src + adsi->pwfxSrc->nBlockAlign;
00254     }
00255 }
00256 
00257 static  void cvtMMms16K(PACMDRVSTREAMINSTANCE adsi,
00258                         const unsigned char* src, LPDWORD nsrc,
00259                         unsigned char* dst, LPDWORD ndst)
00260 {
00261     int                 idelta;
00262     int                 sample1, sample2;
00263     ADPCMCOEFSET        coeff;
00264     int                 nsamp;
00265     int             nsamp_blk = ((ADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
00266     DWORD           nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
00267                                      *ndst / (nsamp_blk * 2));
00268 
00269     *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
00270     *ndst = nblock * nsamp_blk * 2;
00271 
00272     nsamp_blk -= 2; /* see below for samples from block head */
00273     for (; nblock > 0; nblock--)
00274     {
00275         const unsigned char*    in_src = src;
00276 
00277         assert(*src <= 6);
00278         coeff = MSADPCM_CoeffSet[*src++];
00279 
00280         idelta =  R16(src);     src += 2;
00281         sample1 = R16(src);     src += 2;
00282         sample2 = R16(src);     src += 2;
00283 
00284         /* store samples from block head */
00285         W16(dst, sample2);      dst += 2;
00286         W16(dst, sample1);      dst += 2;
00287 
00288         for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
00289         {
00290             process_nibble(*src >> 4, &idelta, &sample1, &sample2, &coeff);
00291             W16(dst, sample1); dst += 2;
00292             process_nibble(*src++ & 0x0F, &idelta, &sample1, &sample2, &coeff);
00293             W16(dst, sample1); dst += 2;
00294         }
00295         src = in_src + adsi->pwfxSrc->nBlockAlign;
00296     }
00297 }
00298 
00299 #if 0
00300 static  void cvtSS16msK(PACMDRVSTREAMINSTANCE adsi,
00301                         const unsigned char* src, LPDWORD nsrc,
00302                         unsigned char* dst, LPDWORD ndst)
00303 {
00304 }
00305 
00306 static  void cvtMM16msK(PACMDRVSTREAMINSTANCE adsi,
00307                         const unsigned char* src, LPDWORD nsrc,
00308                         unsigned char* dst, LPDWORD ndst)
00309 {
00310 }
00311 #endif
00312 
00313 /***********************************************************************
00314  *           ADPCM_DriverDetails
00315  *
00316  */
00317 static  LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
00318 {
00319     add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
00320     add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
00321     add->wMid = 0xFF;
00322     add->wPid = 0x00;
00323     add->vdwACM = 0x01000000;
00324     add->vdwDriver = 0x01000000;
00325     add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
00326     add->cFormatTags = 2; /* PCM, MS ADPCM */
00327     add->cFilterTags = 0;
00328     add->hicon = NULL;
00329     MultiByteToWideChar( CP_ACP, 0, "WINE-MS ADPCM", -1,
00330                          add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
00331     MultiByteToWideChar( CP_ACP, 0, "Wine MS ADPCM converter", -1,
00332                          add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
00333     MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
00334                          add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
00335     MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
00336                          add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
00337     add->szFeatures[0] = 0;
00338 
00339     return MMSYSERR_NOERROR;
00340 }
00341 
00342 /***********************************************************************
00343  *           ADPCM_FormatTagDetails
00344  *
00345  */
00346 static  LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
00347 {
00348     static WCHAR szPcm[]={'P','C','M',0};
00349     static WCHAR szMsAdPcm[]={'M','S',' ','A','d','P','C','M',0};
00350 
00351     switch (dwQuery)
00352     {
00353     case ACM_FORMATTAGDETAILSF_INDEX:
00354     if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
00355     break;
00356     case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
00357     if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
00358         {
00359             aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_ADPCM is bigger than PCM */
00360         break;
00361     }
00362     /* fall thru */
00363     case ACM_FORMATTAGDETAILSF_FORMATTAG:
00364     switch (aftd->dwFormatTag)
00365         {
00366     case WAVE_FORMAT_PCM:   aftd->dwFormatTagIndex = 0; break;
00367     case WAVE_FORMAT_ADPCM: aftd->dwFormatTagIndex = 1; break;
00368     default:        return ACMERR_NOTPOSSIBLE;
00369     }
00370     break;
00371     default:
00372     WARN("Unsupported query %08lx\n", dwQuery);
00373     return MMSYSERR_NOTSUPPORTED;
00374     }
00375 
00376     aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
00377     switch (aftd->dwFormatTagIndex)
00378     {
00379     case 0:
00380     aftd->dwFormatTag = WAVE_FORMAT_PCM;
00381     aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
00382     aftd->cStandardFormats = NUM_PCM_FORMATS;
00383         lstrcpyW(aftd->szFormatTag, szPcm);
00384         break;
00385     case 1:
00386     aftd->dwFormatTag = WAVE_FORMAT_ADPCM;
00387     aftd->cbFormatSize = sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET);
00388     aftd->cStandardFormats = NUM_ADPCM_FORMATS;
00389         lstrcpyW(aftd->szFormatTag, szMsAdPcm);
00390     break;
00391     }
00392     return MMSYSERR_NOERROR;
00393 }
00394 
00395 /***********************************************************************
00396  *           ADPCM_FormatDetails
00397  *
00398  */
00399 static  LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
00400 {
00401     switch (dwQuery)
00402     {
00403     case ACM_FORMATDETAILSF_FORMAT:
00404     if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
00405     break;
00406     case ACM_FORMATDETAILSF_INDEX:
00407     afd->pwfx->wFormatTag = afd->dwFormatTag;
00408     switch (afd->dwFormatTag)
00409         {
00410     case WAVE_FORMAT_PCM:
00411         if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE;
00412         afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
00413         afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
00414         afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
00415         /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
00416          * afd->pwfx->cbSize = 0;
00417          */
00418         afd->pwfx->nBlockAlign =
00419         (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
00420         afd->pwfx->nAvgBytesPerSec =
00421         afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
00422         break;
00423     case WAVE_FORMAT_ADPCM:
00424         if (afd->dwFormatIndex >= NUM_ADPCM_FORMATS) return ACMERR_NOTPOSSIBLE;
00425             if (afd->cbwfx < sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET))
00426                 return ACMERR_NOTPOSSIBLE;
00427         afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels;
00428         afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate;
00429         afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits;
00430             init_wfx_adpcm((ADPCMWAVEFORMAT*)afd->pwfx);
00431         break;
00432     default:
00433         WARN("Unsupported tag %08lx\n", afd->dwFormatTag);
00434         return MMSYSERR_INVALPARAM;
00435     }
00436     break;
00437     default:
00438     WARN("Unsupported query %08lx\n", dwQuery);
00439     return MMSYSERR_NOTSUPPORTED;
00440     }
00441     afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
00442     afd->szFormat[0] = 0; /* let MSACM format this for us... */
00443 
00444     return MMSYSERR_NOERROR;
00445 }
00446 
00447 /***********************************************************************
00448  *           ADPCM_FormatSuggest
00449  *
00450  */
00451 static  LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
00452 {
00453     /* some tests ... */
00454     if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
00455     adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
00456     ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
00457     /* FIXME: should do those tests against the real size (according to format tag */
00458 
00459     /* If no suggestion for destination, then copy source value */
00460     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
00461     adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
00462     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
00463         adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
00464 
00465     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
00466     {
00467     if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
00468             adfs->pwfxDst->wBitsPerSample = 4;
00469         else
00470             adfs->pwfxDst->wBitsPerSample = 16;
00471     }
00472     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
00473     {
00474     if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
00475             adfs->pwfxDst->wFormatTag = WAVE_FORMAT_ADPCM;
00476         else
00477             adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
00478     }
00479 
00480     /* check if result is ok */
00481     if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
00482 
00483     /* recompute other values */
00484     switch (adfs->pwfxDst->wFormatTag)
00485     {
00486     case WAVE_FORMAT_PCM:
00487         adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
00488         adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
00489         break;
00490     case WAVE_FORMAT_ADPCM:
00491         init_wfx_adpcm((ADPCMWAVEFORMAT*)adfs->pwfxDst);
00492         break;
00493     default:
00494         FIXME("\n");
00495         break;
00496     }
00497 
00498     return MMSYSERR_NOERROR;
00499 }
00500 
00501 /***********************************************************************
00502  *           ADPCM_Reset
00503  *
00504  */
00505 static  void    ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad)
00506 {
00507 }
00508 
00509 /***********************************************************************
00510  *           ADPCM_StreamOpen
00511  *
00512  */
00513 static  LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
00514 {
00515     AcmAdpcmData*   aad;
00516 
00517     assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
00518 
00519     if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
00520     ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
00521     return ACMERR_NOTPOSSIBLE;
00522 
00523     aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData));
00524     if (aad == 0) return MMSYSERR_NOMEM;
00525 
00526     adsi->dwDriver = (DWORD)aad;
00527 
00528     if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
00529     adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
00530     {
00531     goto theEnd;
00532     }
00533     else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM &&
00534              adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
00535     {
00536     /* resampling or mono <=> stereo not available
00537          * ADPCM algo only define 16 bit per sample output
00538          */
00539     if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
00540         adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
00541             adsi->pwfxDst->wBitsPerSample != 16)
00542         goto theEnd;
00543 
00544 #if 0
00545         {
00546             unsigned int nspb = ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
00547             FIXME("spb=%u\n", nspb);
00548 
00549             /* we check that in a block, after the header, samples are present on
00550              * 4-sample packet pattern
00551              * we also check that the block alignement is bigger than the expected size
00552              */
00553             if (((nspb - 1) & 3) != 0) goto theEnd;
00554             if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign)
00555                 goto theEnd;
00556         }
00557 #endif
00558 
00559     /* adpcm decoding... */
00560     if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2)
00561         aad->convert = cvtSSms16K;
00562     if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1)
00563         aad->convert = cvtMMms16K;
00564     }
00565     else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
00566              adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM)
00567     {
00568     if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
00569         adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
00570             adsi->pwfxSrc->wBitsPerSample != 16)
00571         goto theEnd;
00572 #if 0
00573         nspb = ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock;
00574         FIXME("spb=%u\n", nspb);
00575 
00576         /* we check that in a block, after the header, samples are present on
00577          * 4-sample packet pattern
00578          * we also check that the block alignement is bigger than the expected size
00579          */
00580         if (((nspb - 1) & 3) != 0) goto theEnd;
00581         if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign)
00582             goto theEnd;
00583 #endif
00584 #if 0
00585     /* adpcm coding... */
00586     if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2)
00587         aad->convert = cvtSS16msK;
00588     if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1)
00589         aad->convert = cvtMM16msK;
00590 #endif
00591         FIXME("We don't support encoding yet\n");
00592         goto theEnd;
00593     }
00594     else goto theEnd;
00595     ADPCM_Reset(adsi, aad);
00596 
00597     return MMSYSERR_NOERROR;
00598 
00599  theEnd:
00600     HeapFree(GetProcessHeap(), 0, aad);
00601     adsi->dwDriver = 0L;
00602     return MMSYSERR_NOTSUPPORTED;
00603 }
00604 
00605 /***********************************************************************
00606  *           ADPCM_StreamClose
00607  *
00608  */
00609 static  LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
00610 {
00611     HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
00612     return MMSYSERR_NOERROR;
00613 }
00614 
00615 /***********************************************************************
00616  *           ADPCM_round
00617  *
00618  */
00619 static  inline DWORD    ADPCM_round(DWORD a, DWORD b, DWORD c)
00620 {
00621     assert(a && b && c);
00622     /* to be sure, always return an entire number of c... */
00623     return ((double)a * (double)b + (double)c - 1) / (double)c;
00624 }
00625 
00626 /***********************************************************************
00627  *           ADPCM_StreamSize
00628  *
00629  */
00630 static  LRESULT ADPCM_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE adss)
00631 {
00632     switch (adss->fdwSize)
00633     {
00634     case ACM_STREAMSIZEF_DESTINATION:
00635     /* cbDstLength => cbSrcLength */
00636     if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
00637         adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM)
00638         {
00639         /* don't take block overhead into account, doesn't matter too much */
00640         adss->cbSrcLength = adss->cbDstLength * 4;
00641     }
00642         else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM &&
00643                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
00644         {
00645         FIXME("misses the block header overhead\n");
00646         adss->cbSrcLength = 256 + adss->cbDstLength / 4;
00647     }
00648         else
00649         {
00650         return MMSYSERR_NOTSUPPORTED;
00651     }
00652     break;
00653     case ACM_STREAMSIZEF_SOURCE:
00654     /* cbSrcLength => cbDstLength */
00655     if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
00656         adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM)
00657         {
00658         FIXME("misses the block header overhead\n");
00659         adss->cbDstLength = 256 + adss->cbSrcLength / 4;
00660     }
00661         else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM &&
00662                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
00663         {
00664         /* don't take block overhead into account, doesn't matter too much */
00665         adss->cbDstLength = adss->cbSrcLength * 4;
00666     }
00667         else
00668         {
00669         return MMSYSERR_NOTSUPPORTED;
00670     }
00671     break;
00672     default:
00673     WARN("Unsupported query %08lx\n", adss->fdwSize);
00674     return MMSYSERR_NOTSUPPORTED;
00675     }
00676     return MMSYSERR_NOERROR;
00677 }
00678 
00679 /***********************************************************************
00680  *           ADPCM_StreamConvert
00681  *
00682  */
00683 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
00684 {
00685     AcmAdpcmData*   aad = (AcmAdpcmData*)adsi->dwDriver;
00686     DWORD       nsrc = adsh->cbSrcLength;
00687     DWORD       ndst = adsh->cbDstLength;
00688 
00689     if (adsh->fdwConvert &
00690     ~(ACM_STREAMCONVERTF_BLOCKALIGN|
00691       ACM_STREAMCONVERTF_END|
00692       ACM_STREAMCONVERTF_START))
00693     {
00694     FIXME("Unsupported fdwConvert (%08lx), ignoring it\n", adsh->fdwConvert);
00695     }
00696     /* ACM_STREAMCONVERTF_BLOCKALIGN
00697      *  currently all conversions are block aligned, so do nothing for this flag
00698      * ACM_STREAMCONVERTF_END
00699      *  no pending data, so do nothing for this flag
00700      */
00701     if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
00702     {
00703     ADPCM_Reset(adsi, aad);
00704     }
00705 
00706     aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
00707     adsh->cbSrcLengthUsed = nsrc;
00708     adsh->cbDstLengthUsed = ndst;
00709 
00710     return MMSYSERR_NOERROR;
00711 }
00712 
00713 /**************************************************************************
00714  *          ADPCM_DriverProc            [exported]
00715  */
00716 LRESULT CALLBACK    ADPCM_DriverProc(DWORD dwDevID, HDRVR hDriv, UINT wMsg,
00717                      LPARAM dwParam1, LPARAM dwParam2)
00718 {
00719     TRACE("(%08lx %08lx %04x %08lx %08lx);\n",
00720       dwDevID, (DWORD)hDriv, wMsg, dwParam1, dwParam2);
00721 
00722     switch (wMsg)
00723     {
00724     case DRV_LOAD:      return 1;
00725     case DRV_FREE:      return 1;
00726     case DRV_OPEN:      return ADPCM_drvOpen((LPSTR)dwParam1);
00727     case DRV_CLOSE:     return ADPCM_drvClose(dwDevID);
00728     case DRV_ENABLE:        return 1;
00729     case DRV_DISABLE:       return 1;
00730     case DRV_QUERYCONFIGURE:    return 1;
00731     case DRV_CONFIGURE:     MessageBoxA(0, "MSACM MS ADPCM filter !", "Wine Driver", MB_OK); return 1;
00732     case DRV_INSTALL:       return DRVCNF_RESTART;
00733     case DRV_REMOVE:        return DRVCNF_RESTART;
00734 
00735     case ACMDM_DRIVER_NOTIFY:
00736     /* no caching from other ACM drivers is done so far */
00737     return MMSYSERR_NOERROR;
00738 
00739     case ACMDM_DRIVER_DETAILS:
00740     return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
00741 
00742     case ACMDM_FORMATTAG_DETAILS:
00743     return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
00744 
00745     case ACMDM_FORMAT_DETAILS:
00746     return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
00747 
00748     case ACMDM_FORMAT_SUGGEST:
00749     return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
00750 
00751     case ACMDM_STREAM_OPEN:
00752     return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
00753 
00754     case ACMDM_STREAM_CLOSE:
00755     return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
00756 
00757     case ACMDM_STREAM_SIZE:
00758     return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
00759 
00760     case ACMDM_STREAM_CONVERT:
00761     return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
00762 
00763     case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
00764     case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
00765     /* this converter is not a hardware driver */
00766     case ACMDM_FILTERTAG_DETAILS:
00767     case ACMDM_FILTER_DETAILS:
00768     /* this converter is not a filter */
00769     case ACMDM_STREAM_RESET:
00770     /* only needed for asynchronous driver... we aren't, so just say it */
00771     return MMSYSERR_NOTSUPPORTED;
00772     case ACMDM_STREAM_PREPARE:
00773     case ACMDM_STREAM_UNPREPARE:
00774     /* nothing special to do here... so don't do anything */
00775     return MMSYSERR_NOERROR;
00776 
00777     default:
00778     return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
00779     }
00780     return 0;
00781 }

Generated on Sat May 19 2012 04:22:32 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.