ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 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 St, 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 LRESULT ADPCM_drvOpen(LPCSTR str)
00044 {
00045     return 1;
00046 }
00047 
00048 /***********************************************************************
00049  *           ADPCM_drvClose
00050  */
00051 static LRESULT ADPCM_drvClose(DWORD_PTR dwDevID)
00052 {
00053     return 1;
00054 }
00055 
00056 typedef struct tagAcmAdpcmData
00057 {
00058     void (*convert)(const ACMDRVSTREAMINSTANCE *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 const 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 const 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(const WAVEFORMATEX* wfx)
00105 {
00106     int             i, hi;
00107     const 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     switch (wfx->wFormatTag)
00132     {
00133     case WAVE_FORMAT_PCM:
00134     if(3 > wfx->nChannels &&
00135        wfx->nChannels > 0 &&
00136        wfx->nAvgBytesPerSec == 2 * wfx->nSamplesPerSec * wfx->nChannels &&
00137        wfx->nBlockAlign == 2 * wfx->nChannels &&
00138        wfx->wBitsPerSample == 16)
00139        return hi;
00140     break;
00141     case WAVE_FORMAT_ADPCM:
00142     if(3 > wfx->nChannels &&
00143        wfx->nChannels > 0 &&
00144        wfx->wBitsPerSample == 4 &&
00145        wfx->cbSize == 32)
00146        return hi;
00147     break;
00148     }
00149 
00150     return 0xFFFFFFFF;
00151 }
00152 
00153 static void     init_wfx_adpcm(ADPCMWAVEFORMAT* awfx)
00154 {
00155     register WAVEFORMATEX*      pwfx = &awfx->wfx;
00156 
00157     /* we assume wFormatTag, nChannels, nSamplesPerSec and wBitsPerSample
00158      * have been initialized... */
00159 
00160     if (pwfx->wFormatTag != WAVE_FORMAT_ADPCM) {FIXME("wrong FT\n"); return;}
00161     if (ADPCM_GetFormatIndex(pwfx) == 0xFFFFFFFF) {FIXME("wrong fmt\n"); return;}
00162 
00163     switch (pwfx->nSamplesPerSec)
00164     {
00165     case  8000: pwfx->nBlockAlign = 256 * pwfx->nChannels;   break;
00166     case 11025: pwfx->nBlockAlign = 256 * pwfx->nChannels;   break;
00167     case 22050: pwfx->nBlockAlign = 512 * pwfx->nChannels;   break;
00168     case 44100: pwfx->nBlockAlign = 1024 * pwfx->nChannels;  break;
00169     default:                               break;
00170     }
00171     pwfx->cbSize = 2 * sizeof(WORD) + 7 * sizeof(ADPCMCOEFSET);
00172     /* 7 is the size of the block head (which contains two samples) */
00173 
00174     awfx->wSamplesPerBlock = pwfx->nBlockAlign * 2 / pwfx->nChannels - 12;
00175     pwfx->nAvgBytesPerSec = (pwfx->nSamplesPerSec * pwfx->nBlockAlign) / awfx->wSamplesPerBlock;
00176     awfx->wNumCoef = 7;
00177     memcpy(awfx->aCoef, MSADPCM_CoeffSet, 7 * sizeof(ADPCMCOEFSET));
00178 }
00179 
00180 /***********************************************************************
00181  *           R16
00182  *
00183  * Read a 16 bit sample (correctly handles endianness)
00184  */
00185 static inline short  R16(const unsigned char* src)
00186 {
00187     return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8));
00188 }
00189 
00190 /***********************************************************************
00191  *           W16
00192  *
00193  * Write a 16 bit sample (correctly handles endianness)
00194  */
00195 static inline void  W16(unsigned char* dst, short s)
00196 {
00197     dst[0] = LOBYTE(s);
00198     dst[1] = HIBYTE(s);
00199 }
00200 
00201 static inline void clamp_sample(int* sample)
00202 {
00203     if (*sample < -32768) *sample = -32768;
00204     if (*sample >  32767) *sample =  32767;
00205 }
00206 
00207 static inline void process_nibble(unsigned nibble, int* idelta,
00208                                   int* sample1, int* sample2,
00209                                   const ADPCMCOEFSET* coeff)
00210 {
00211     int sample;
00212     int snibble;
00213 
00214     /* nibble is in fact a signed 4 bit integer => propagate sign if needed */
00215     snibble = (nibble & 0x08) ? (nibble - 16) : nibble;
00216     sample = ((*sample1 * coeff->iCoef1) + (*sample2 * coeff->iCoef2)) / 256 +
00217         snibble * *idelta;
00218     clamp_sample(&sample);
00219 
00220     *sample2 = *sample1;
00221     *sample1 = sample;
00222     *idelta = ((MS_Delta[nibble] * *idelta) / 256);
00223     if (*idelta < 16) *idelta = 16;
00224 }
00225 
00226 static  void cvtSSms16K(const ACMDRVSTREAMINSTANCE *adsi,
00227                         const unsigned char* src, LPDWORD nsrc,
00228                         unsigned char* dst, LPDWORD ndst)
00229 {
00230     int                 ideltaL, ideltaR;
00231     int                 sample1L, sample2L;
00232     int                 sample1R, sample2R;
00233     ADPCMCOEFSET        coeffL, coeffR;
00234     int                 nsamp;
00235     int             nsamp_blk = ((ADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
00236     DWORD           nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
00237                                      *ndst / (nsamp_blk * 2 * 2));
00238 
00239     *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
00240     *ndst = nblock * nsamp_blk * 2 * 2;
00241 
00242     nsamp_blk -= 2; /* see below for samples from block head */
00243     for (; nblock > 0; nblock--)
00244     {
00245         const unsigned char*    in_src = src;
00246 
00247         assert(*src <= 6);
00248         coeffL = MSADPCM_CoeffSet[*src++];
00249         assert(*src <= 6);
00250         coeffR = MSADPCM_CoeffSet[*src++];
00251 
00252         ideltaL  = R16(src);    src += 2;
00253         ideltaR  = R16(src);    src += 2;
00254         sample1L = R16(src);    src += 2;
00255         sample1R = R16(src);    src += 2;
00256         sample2L = R16(src);    src += 2;
00257         sample2R = R16(src);    src += 2;
00258 
00259         /* store samples from block head */
00260         W16(dst, sample2L);      dst += 2;
00261         W16(dst, sample2R);      dst += 2;
00262         W16(dst, sample1L);      dst += 2;
00263         W16(dst, sample1R);      dst += 2;
00264 
00265         for (nsamp = nsamp_blk; nsamp > 0; nsamp--)
00266         {
00267             process_nibble(*src >> 4, &ideltaL, &sample1L, &sample2L, &coeffL);
00268             W16(dst, sample1L); dst += 2;
00269             process_nibble(*src++ & 0x0F, &ideltaR, &sample1R, &sample2R, &coeffR);
00270             W16(dst, sample1R); dst += 2;
00271         }
00272         src = in_src + adsi->pwfxSrc->nBlockAlign;
00273     }
00274 }
00275 
00276 static  void cvtMMms16K(const ACMDRVSTREAMINSTANCE *adsi,
00277                         const unsigned char* src, LPDWORD nsrc,
00278                         unsigned char* dst, LPDWORD ndst)
00279 {
00280     int                 idelta;
00281     int                 sample1, sample2;
00282     ADPCMCOEFSET        coeff;
00283     int                 nsamp;
00284     int             nsamp_blk = ((ADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
00285     DWORD           nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
00286                                      *ndst / (nsamp_blk * 2));
00287 
00288     *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
00289     *ndst = nblock * nsamp_blk * 2;
00290 
00291     nsamp_blk -= 2; /* see below for samples from block head */
00292     for (; nblock > 0; nblock--)
00293     {
00294         const unsigned char*    in_src = src;
00295 
00296         assert(*src <= 6);
00297         coeff = MSADPCM_CoeffSet[*src++];
00298 
00299         idelta =  R16(src);     src += 2;
00300         sample1 = R16(src);     src += 2;
00301         sample2 = R16(src);     src += 2;
00302 
00303         /* store samples from block head */
00304         W16(dst, sample2);      dst += 2;
00305         W16(dst, sample1);      dst += 2;
00306 
00307         for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
00308         {
00309             process_nibble(*src >> 4, &idelta, &sample1, &sample2, &coeff);
00310             W16(dst, sample1); dst += 2;
00311             process_nibble(*src++ & 0x0F, &idelta, &sample1, &sample2, &coeff);
00312             W16(dst, sample1); dst += 2;
00313         }
00314         src = in_src + adsi->pwfxSrc->nBlockAlign;
00315     }
00316 }
00317 
00318 #if 0
00319 static  void cvtSS16msK(PACMDRVSTREAMINSTANCE adsi,
00320                         const unsigned char* src, LPDWORD nsrc,
00321                         unsigned char* dst, LPDWORD ndst)
00322 {
00323 }
00324 
00325 static  void cvtMM16msK(PACMDRVSTREAMINSTANCE adsi,
00326                         const unsigned char* src, LPDWORD nsrc,
00327                         unsigned char* dst, LPDWORD ndst)
00328 {
00329 }
00330 #endif
00331 
00332 /***********************************************************************
00333  *           ADPCM_DriverDetails
00334  *
00335  */
00336 static  LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
00337 {
00338     add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
00339     add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
00340     add->wMid = 0xFF;
00341     add->wPid = 0x00;
00342     add->vdwACM = 0x01000000;
00343     add->vdwDriver = 0x01000000;
00344     add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
00345     add->cFormatTags = 2; /* PCM, MS ADPCM */
00346     add->cFilterTags = 0;
00347     add->hicon = NULL;
00348     MultiByteToWideChar( CP_ACP, 0, "MS-ADPCM", -1,
00349                          add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
00350     MultiByteToWideChar( CP_ACP, 0, "Wine MS ADPCM converter", -1,
00351                          add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
00352     MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
00353                          add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
00354     MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
00355                          add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
00356     add->szFeatures[0] = 0;
00357 
00358     return MMSYSERR_NOERROR;
00359 }
00360 
00361 /***********************************************************************
00362  *           ADPCM_FormatTagDetails
00363  *
00364  */
00365 static  LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
00366 {
00367     static const WCHAR szPcm[]={'P','C','M',0};
00368     static const WCHAR szMsAdPcm[]={'M','i','c','r','o','s','o','f','t',' ','A','D','P','C','M',0};
00369 
00370     switch (dwQuery)
00371     {
00372     case ACM_FORMATTAGDETAILSF_INDEX:
00373     if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
00374     break;
00375     case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
00376     if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
00377         {
00378             aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_ADPCM is bigger than PCM */
00379         break;
00380     }
00381     /* fall thru */
00382     case ACM_FORMATTAGDETAILSF_FORMATTAG:
00383     switch (aftd->dwFormatTag)
00384         {
00385     case WAVE_FORMAT_PCM:   aftd->dwFormatTagIndex = 0; break;
00386     case WAVE_FORMAT_ADPCM: aftd->dwFormatTagIndex = 1; break;
00387     default:        return ACMERR_NOTPOSSIBLE;
00388     }
00389     break;
00390     default:
00391     WARN("Unsupported query %08x\n", dwQuery);
00392     return MMSYSERR_NOTSUPPORTED;
00393     }
00394 
00395     aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
00396     switch (aftd->dwFormatTagIndex)
00397     {
00398     case 0:
00399     aftd->dwFormatTag = WAVE_FORMAT_PCM;
00400     aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
00401     aftd->cStandardFormats = NUM_PCM_FORMATS;
00402         lstrcpyW(aftd->szFormatTag, szPcm);
00403         break;
00404     case 1:
00405     aftd->dwFormatTag = WAVE_FORMAT_ADPCM;
00406     aftd->cbFormatSize = sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET);
00407     aftd->cStandardFormats = NUM_ADPCM_FORMATS;
00408         lstrcpyW(aftd->szFormatTag, szMsAdPcm);
00409     break;
00410     }
00411     return MMSYSERR_NOERROR;
00412 }
00413 
00414 /***********************************************************************
00415  *           ADPCM_FormatDetails
00416  *
00417  */
00418 static  LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
00419 {
00420     switch (dwQuery)
00421     {
00422     case ACM_FORMATDETAILSF_FORMAT:
00423     if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
00424     break;
00425     case ACM_FORMATDETAILSF_INDEX:
00426     afd->pwfx->wFormatTag = afd->dwFormatTag;
00427     switch (afd->dwFormatTag)
00428         {
00429     case WAVE_FORMAT_PCM:
00430         if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE;
00431         afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
00432         afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
00433         afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
00434         /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
00435          * afd->pwfx->cbSize = 0;
00436          */
00437         afd->pwfx->nBlockAlign =
00438         (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
00439         afd->pwfx->nAvgBytesPerSec =
00440         afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
00441         break;
00442     case WAVE_FORMAT_ADPCM:
00443         if (afd->dwFormatIndex >= NUM_ADPCM_FORMATS) return ACMERR_NOTPOSSIBLE;
00444             if (afd->cbwfx < sizeof(ADPCMWAVEFORMAT) + (7 - 1) * sizeof(ADPCMCOEFSET))
00445                 return ACMERR_NOTPOSSIBLE;
00446         afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels;
00447         afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate;
00448         afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits;
00449             init_wfx_adpcm((ADPCMWAVEFORMAT*)afd->pwfx);
00450         break;
00451     default:
00452             WARN("Unsupported tag %08x\n", afd->dwFormatTag);
00453         return MMSYSERR_INVALPARAM;
00454     }
00455     break;
00456     default:
00457     WARN("Unsupported query %08x\n", dwQuery);
00458     return MMSYSERR_NOTSUPPORTED;
00459     }
00460     afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
00461     afd->szFormat[0] = 0; /* let MSACM format this for us... */
00462 
00463     return MMSYSERR_NOERROR;
00464 }
00465 
00466 /***********************************************************************
00467  *           ADPCM_FormatSuggest
00468  *
00469  */
00470 static  LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
00471 {
00472     /* some tests ... */
00473     if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
00474     adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
00475     adfs->pwfxSrc->wFormatTag == adfs->pwfxDst->wFormatTag ||
00476     ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
00477     /* FIXME: should do those tests against the real size (according to format tag */
00478 
00479     /* If no suggestion for destination, then copy source value */
00480     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
00481     adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
00482     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
00483         adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
00484 
00485     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
00486     {
00487     if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
00488             adfs->pwfxDst->wBitsPerSample = 4;
00489         else
00490             adfs->pwfxDst->wBitsPerSample = 16;
00491     }
00492     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
00493     {
00494     if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
00495             adfs->pwfxDst->wFormatTag = WAVE_FORMAT_ADPCM;
00496         else
00497             adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
00498     }
00499 
00500     /* recompute other values */
00501     switch (adfs->pwfxDst->wFormatTag)
00502     {
00503     case WAVE_FORMAT_PCM:
00504         adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
00505         adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
00506         /* check if result is ok */
00507         if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
00508         break;
00509     case WAVE_FORMAT_ADPCM:
00510         init_wfx_adpcm((ADPCMWAVEFORMAT*)adfs->pwfxDst);
00511         /* check if result is ok */
00512         if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
00513         break;
00514     default:
00515         return ACMERR_NOTPOSSIBLE;
00516     }
00517 
00518     return MMSYSERR_NOERROR;
00519 }
00520 
00521 /***********************************************************************
00522  *           ADPCM_Reset
00523  *
00524  */
00525 static  void    ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad)
00526 {
00527 }
00528 
00529 /***********************************************************************
00530  *           ADPCM_StreamOpen
00531  *
00532  */
00533 static  LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
00534 {
00535     AcmAdpcmData*   aad;
00536 
00537     assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
00538 
00539     if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
00540     ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
00541     return ACMERR_NOTPOSSIBLE;
00542 
00543     aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData));
00544     if (aad == 0) return MMSYSERR_NOMEM;
00545 
00546     adsi->dwDriver = (DWORD_PTR)aad;
00547 
00548     if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
00549     adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
00550     {
00551     goto theEnd;
00552     }
00553     else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM &&
00554              adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
00555     {
00556     /* resampling or mono <=> stereo not available
00557          * ADPCM algo only define 16 bit per sample output
00558          */
00559     if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
00560         adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
00561             adsi->pwfxDst->wBitsPerSample != 16)
00562         goto theEnd;
00563 
00564 #if 0
00565         {
00566             unsigned int nspb = ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
00567             FIXME("spb=%u\n", nspb);
00568 
00569             /* we check that in a block, after the header, samples are present on
00570              * 4-sample packet pattern
00571              * we also check that the block alignment is bigger than the expected size
00572              */
00573             if (((nspb - 1) & 3) != 0) goto theEnd;
00574             if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign)
00575                 goto theEnd;
00576         }
00577 #endif
00578 
00579     /* adpcm decoding... */
00580     if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2)
00581         aad->convert = cvtSSms16K;
00582     if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1)
00583         aad->convert = cvtMMms16K;
00584     }
00585     else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
00586              adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM)
00587     {
00588     if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
00589         adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
00590             adsi->pwfxSrc->wBitsPerSample != 16)
00591         goto theEnd;
00592 #if 0
00593         nspb = ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock;
00594         FIXME("spb=%u\n", nspb);
00595 
00596         /* we check that in a block, after the header, samples are present on
00597          * 4-sample packet pattern
00598          * we also check that the block alignment is bigger than the expected size
00599          */
00600         if (((nspb - 1) & 3) != 0) goto theEnd;
00601         if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign)
00602             goto theEnd;
00603 #endif
00604 #if 0
00605     /* adpcm coding... */
00606     if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2)
00607         aad->convert = cvtSS16msK;
00608     if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1)
00609         aad->convert = cvtMM16msK;
00610 #endif
00611         FIXME("We don't support encoding yet\n");
00612         goto theEnd;
00613     }
00614     else goto theEnd;
00615     ADPCM_Reset(adsi, aad);
00616 
00617     return MMSYSERR_NOERROR;
00618 
00619  theEnd:
00620     HeapFree(GetProcessHeap(), 0, aad);
00621     adsi->dwDriver = 0L;
00622     return MMSYSERR_NOTSUPPORTED;
00623 }
00624 
00625 /***********************************************************************
00626  *           ADPCM_StreamClose
00627  *
00628  */
00629 static  LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
00630 {
00631     HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
00632     return MMSYSERR_NOERROR;
00633 }
00634 
00635 /***********************************************************************
00636  *           ADPCM_StreamSize
00637  *
00638  */
00639 static  LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss)
00640 {
00641     DWORD nblocks;
00642     WORD wSamplesPerBlock;
00643     /* wSamplesPerBlock formula comes from MSDN ADPCMWAVEFORMAT page.*/
00644     switch (adss->fdwSize)
00645     {
00646     case ACM_STREAMSIZEF_DESTINATION:
00647     /* cbDstLength => cbSrcLength */
00648     if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
00649         adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM)
00650         {
00651         wSamplesPerBlock = adsi->pwfxDst->nBlockAlign * 2 / adsi->pwfxDst->nChannels - 12;
00652         nblocks = adss->cbDstLength / adsi->pwfxDst->nBlockAlign;
00653         if (nblocks == 0)
00654         return ACMERR_NOTPOSSIBLE;
00655         adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign * wSamplesPerBlock;
00656     }
00657         else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM &&
00658                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
00659         {
00660         wSamplesPerBlock = adsi->pwfxSrc->nBlockAlign * 2 / adsi->pwfxSrc->nChannels - 12;
00661         nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * wSamplesPerBlock);
00662         if (nblocks == 0)
00663         return ACMERR_NOTPOSSIBLE;
00664         adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign;
00665     }
00666         else
00667         {
00668         return MMSYSERR_NOTSUPPORTED;
00669     }
00670     break;
00671     case ACM_STREAMSIZEF_SOURCE:
00672     /* cbSrcLength => cbDstLength */
00673     if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
00674         adsi->pwfxDst->wFormatTag == WAVE_FORMAT_ADPCM)
00675         {
00676         wSamplesPerBlock = adsi->pwfxDst->nBlockAlign * 2 / adsi->pwfxDst->nChannels - 12;
00677         nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * wSamplesPerBlock);
00678         if (nblocks == 0)
00679         return ACMERR_NOTPOSSIBLE;
00680         if (adss->cbSrcLength % (adsi->pwfxSrc->nBlockAlign * wSamplesPerBlock))
00681         /* Round block count up. */
00682         nblocks++;
00683         adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign;
00684     }
00685         else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM &&
00686                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
00687         {
00688         wSamplesPerBlock = adsi->pwfxSrc->nBlockAlign * 2 / adsi->pwfxSrc->nChannels - 12;
00689         nblocks = adss->cbSrcLength / adsi->pwfxSrc->nBlockAlign;
00690         if (nblocks == 0)
00691         return ACMERR_NOTPOSSIBLE;
00692         if (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign)
00693         /* Round block count up. */
00694         nblocks++;
00695         adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign * wSamplesPerBlock;
00696     }
00697         else
00698         {
00699         return MMSYSERR_NOTSUPPORTED;
00700     }
00701     break;
00702     default:
00703     WARN("Unsupported query %08x\n", adss->fdwSize);
00704     return MMSYSERR_NOTSUPPORTED;
00705     }
00706     return MMSYSERR_NOERROR;
00707 }
00708 
00709 /***********************************************************************
00710  *           ADPCM_StreamConvert
00711  *
00712  */
00713 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
00714 {
00715     AcmAdpcmData*   aad = (AcmAdpcmData*)adsi->dwDriver;
00716     DWORD       nsrc = adsh->cbSrcLength;
00717     DWORD       ndst = adsh->cbDstLength;
00718 
00719     if (adsh->fdwConvert &
00720     ~(ACM_STREAMCONVERTF_BLOCKALIGN|
00721       ACM_STREAMCONVERTF_END|
00722       ACM_STREAMCONVERTF_START))
00723     {
00724     FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert);
00725     }
00726     /* ACM_STREAMCONVERTF_BLOCKALIGN
00727      *  currently all conversions are block aligned, so do nothing for this flag
00728      * ACM_STREAMCONVERTF_END
00729      *  no pending data, so do nothing for this flag
00730      */
00731     if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
00732     {
00733     ADPCM_Reset(adsi, aad);
00734     }
00735 
00736     aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
00737     adsh->cbSrcLengthUsed = nsrc;
00738     adsh->cbDstLengthUsed = ndst;
00739 
00740     return MMSYSERR_NOERROR;
00741 }
00742 
00743 /**************************************************************************
00744  *          ADPCM_DriverProc            [exported]
00745  */
00746 LRESULT CALLBACK ADPCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
00747                      LPARAM dwParam1, LPARAM dwParam2)
00748 {
00749     TRACE("(%08lx %p %04x %08lx %08lx);\n",
00750           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
00751 
00752     switch (wMsg)
00753     {
00754     case DRV_LOAD:      return 1;
00755     case DRV_FREE:      return 1;
00756     case DRV_OPEN:      return ADPCM_drvOpen((LPSTR)dwParam1);
00757     case DRV_CLOSE:     return ADPCM_drvClose(dwDevID);
00758     case DRV_ENABLE:        return 1;
00759     case DRV_DISABLE:       return 1;
00760     case DRV_QUERYCONFIGURE:    return 1;
00761     case DRV_CONFIGURE:     MessageBoxA(0, "MSACM MS ADPCM filter !", "Wine Driver", MB_OK); return 1;
00762     case DRV_INSTALL:       return DRVCNF_RESTART;
00763     case DRV_REMOVE:        return DRVCNF_RESTART;
00764 
00765     case ACMDM_DRIVER_NOTIFY:
00766     /* no caching from other ACM drivers is done so far */
00767     return MMSYSERR_NOERROR;
00768 
00769     case ACMDM_DRIVER_DETAILS:
00770     return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
00771 
00772     case ACMDM_FORMATTAG_DETAILS:
00773     return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
00774 
00775     case ACMDM_FORMAT_DETAILS:
00776     return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
00777 
00778     case ACMDM_FORMAT_SUGGEST:
00779     return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
00780 
00781     case ACMDM_STREAM_OPEN:
00782     return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
00783 
00784     case ACMDM_STREAM_CLOSE:
00785     return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
00786 
00787     case ACMDM_STREAM_SIZE:
00788     return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
00789 
00790     case ACMDM_STREAM_CONVERT:
00791     return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
00792 
00793     case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
00794     case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
00795     /* this converter is not a hardware driver */
00796     case ACMDM_FILTERTAG_DETAILS:
00797     case ACMDM_FILTER_DETAILS:
00798     /* this converter is not a filter */
00799     case ACMDM_STREAM_RESET:
00800     /* only needed for asynchronous driver... we aren't, so just say it */
00801     return MMSYSERR_NOTSUPPORTED;
00802     case ACMDM_STREAM_PREPARE:
00803     case ACMDM_STREAM_UNPREPARE:
00804     /* nothing special to do here... so don't do anything */
00805     return MMSYSERR_NOERROR;
00806 
00807     default:
00808     return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
00809     }
00810 }

Generated on Sun May 27 2012 04:24:45 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.