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

imaadp32.c
Go to the documentation of this file.
00001 /*
00002  * IMA ADPCM handling
00003  *
00004  *      Copyright (C) 2001,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_drvClose
00042  */
00043 static LRESULT ADPCM_drvClose(DWORD_PTR dwDevID)
00044 {
00045     return 1;
00046 }
00047 
00048 typedef struct tagAcmAdpcmData
00049 {
00050     void (*convert)(PACMDRVSTREAMINSTANCE adsi,
00051             const unsigned char*, LPDWORD, unsigned char*, LPDWORD);
00052     /* IMA encoding only */
00053     BYTE    stepIndexL;
00054     BYTE    stepIndexR;
00055     /* short    sample; */
00056 } AcmAdpcmData;
00057 
00058 /* table to list all supported formats... those are the basic ones. this
00059  * also helps given a unique index to each of the supported formats
00060  */
00061 typedef struct
00062 {
00063     int     nChannels;
00064     int     nBits;
00065     int     rate;
00066 } Format;
00067 
00068 static const Format PCM_Formats[] =
00069 {
00070     {1,  8,  8000}, {2,  8,  8000}, {1, 16,  8000}, {2, 16,  8000},
00071     {1,  8, 11025}, {2,  8, 11025}, {1, 16, 11025}, {2, 16, 11025},
00072     {1,  8, 22050}, {2,  8, 22050}, {1, 16, 22050}, {2, 16, 22050},
00073     {1,  8, 44100}, {2,  8, 44100}, {1, 16, 44100}, {2, 16, 44100},
00074 };
00075 
00076 static const Format ADPCM_Formats[] =
00077 {
00078     {1,  4,  8000}, {2, 4,  8000},  {1,  4, 11025}, {2,  4, 11025},
00079     {1,  4, 22050}, {2, 4, 22050},  {1,  4, 44100}, {2,  4, 44100},
00080 };
00081 
00082 #define NUM_PCM_FORMATS     (sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
00083 #define NUM_ADPCM_FORMATS   (sizeof(ADPCM_Formats) / sizeof(ADPCM_Formats[0]))
00084 
00085 /***********************************************************************
00086  *           ADPCM_GetFormatIndex
00087  */
00088 static  DWORD   ADPCM_GetFormatIndex(const WAVEFORMATEX *wfx)
00089 {
00090     int             i, hi;
00091     const Format*   fmts;
00092 
00093     switch (wfx->wFormatTag)
00094     {
00095     case WAVE_FORMAT_PCM:
00096     hi = NUM_PCM_FORMATS;
00097     fmts = PCM_Formats;
00098     break;
00099     case WAVE_FORMAT_IMA_ADPCM:
00100     hi = NUM_ADPCM_FORMATS;
00101     fmts = ADPCM_Formats;
00102     break;
00103     default:
00104     return 0xFFFFFFFF;
00105     }
00106 
00107     for (i = 0; i < hi; i++)
00108     {
00109     if (wfx->nChannels == fmts[i].nChannels &&
00110         wfx->nSamplesPerSec == fmts[i].rate &&
00111         wfx->wBitsPerSample == fmts[i].nBits)
00112         return i;
00113     }
00114 
00115     switch (wfx->wFormatTag)
00116     {
00117     case WAVE_FORMAT_PCM:
00118     if(3 > wfx->nChannels &&
00119        wfx->nChannels > 0 &&
00120        wfx->nAvgBytesPerSec == 2 * wfx->nSamplesPerSec * wfx->nChannels &&
00121        wfx->nBlockAlign == 2 * wfx->nChannels &&
00122        wfx->wBitsPerSample == 16)
00123        return hi;
00124     break;
00125     case WAVE_FORMAT_IMA_ADPCM:
00126     if(3 > wfx->nChannels &&
00127        wfx->nChannels > 0 &&
00128        wfx->wBitsPerSample == 4 &&
00129        wfx->cbSize == 2)
00130        return hi;
00131     break;
00132     }
00133 
00134     return 0xFFFFFFFF;
00135 }
00136 
00137 static void     init_wfx_ima_adpcm(IMAADPCMWAVEFORMAT* awfx/*, DWORD nba*/)
00138 {
00139     register WAVEFORMATEX*      pwfx = &awfx->wfx;
00140 
00141     /* we assume wFormatTag, nChannels, nSamplesPerSec and wBitsPerSample
00142      * have been initialized... */
00143 
00144     if (pwfx->wFormatTag != WAVE_FORMAT_IMA_ADPCM) {FIXME("wrong FT\n"); return;}
00145     if (ADPCM_GetFormatIndex(pwfx) == 0xFFFFFFFF) {FIXME("wrong fmt\n"); return;}
00146 
00147     switch (pwfx->nSamplesPerSec)
00148     {
00149     case  8000: pwfx->nBlockAlign = 256 * pwfx->nChannels;   break;
00150     case 11025: pwfx->nBlockAlign = 256 * pwfx->nChannels;   break;
00151     case 22050: pwfx->nBlockAlign = 512 * pwfx->nChannels;   break;
00152     case 44100: pwfx->nBlockAlign = 1024 * pwfx->nChannels;  break;
00153     default: /*pwfx->nBlockAlign = nba;*/  break;
00154     }
00155     pwfx->cbSize = sizeof(WORD);
00156 
00157     awfx->wSamplesPerBlock = (pwfx->nBlockAlign - (4 * pwfx->nChannels) * 2) / pwfx->nChannels + 1;
00158     pwfx->nAvgBytesPerSec = (pwfx->nSamplesPerSec * pwfx->nBlockAlign) / awfx->wSamplesPerBlock;
00159 }
00160 
00161 /***********************************************************************
00162  *           R16
00163  *
00164  * Read a 16 bit sample (correctly handles endianness)
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 endianness)
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 /* IMA (or DVI) APDCM codec routines */
00183 
00184 static const unsigned IMA_StepTable[89] =
00185 {
00186     7, 8, 9, 10, 11, 12, 13, 14,
00187     16, 17, 19, 21, 23, 25, 28, 31,
00188     34, 37, 41, 45, 50, 55, 60, 66,
00189     73, 80, 88, 97, 107, 118, 130, 143,
00190     157, 173, 190, 209, 230, 253, 279, 307,
00191     337, 371, 408, 449, 494, 544, 598, 658,
00192     724, 796, 876, 963, 1060, 1166, 1282, 1411,
00193     1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
00194     3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
00195     7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
00196     15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
00197     32767
00198 };
00199 
00200 static const int IMA_IndexTable[16] =
00201 {
00202     -1, -1, -1, -1, 2, 4, 6, 8,
00203     -1, -1, -1, -1, 2, 4, 6, 8
00204 };
00205 
00206 static inline void clamp_step_index(int* stepIndex)
00207 {
00208     if (*stepIndex < 0 ) *stepIndex = 0;
00209     if (*stepIndex > 88) *stepIndex = 88;
00210 }
00211 
00212 static inline void clamp_sample(int* sample)
00213 {
00214     if (*sample < -32768) *sample = -32768;
00215     if (*sample >  32767) *sample =  32767;
00216 }
00217 
00218 static inline void process_nibble(unsigned char code, int* stepIndex, int* sample)
00219 {
00220     unsigned step;
00221     int diff;
00222 
00223     code &= 0x0F;
00224 
00225     step = IMA_StepTable[*stepIndex];
00226     diff = step >> 3;
00227     if (code & 1) diff += step >> 2;
00228     if (code & 2) diff += step >> 1;
00229     if (code & 4) diff += step;
00230     if (code & 8)   *sample -= diff;
00231     else        *sample += diff;
00232     clamp_sample(sample);
00233     *stepIndex += IMA_IndexTable[code];
00234     clamp_step_index(stepIndex);
00235 }
00236 
00237 static inline unsigned char generate_nibble(int in, int* stepIndex, int* sample)
00238 {
00239     int effdiff, diff = in - *sample;
00240     unsigned step;
00241     unsigned char code;
00242 
00243     if (diff < 0)
00244     {
00245         diff = -diff;
00246         code = 8;
00247     }
00248     else
00249     {
00250         code = 0;
00251     }
00252 
00253     step = IMA_StepTable[*stepIndex];
00254     effdiff = (step >> 3);
00255     if (diff >= step)
00256     {
00257         code |= 4;
00258         diff -= step;
00259         effdiff += step;
00260     }
00261     step >>= 1;
00262     if (diff >= step)
00263     {
00264         code |= 2;
00265         diff -= step;
00266         effdiff += step;
00267     }
00268     step >>= 1;
00269     if (diff >= step)
00270     {
00271         code |= 1;
00272         effdiff += step;
00273     }
00274     if (code & 8)       *sample -= effdiff;
00275     else                *sample += effdiff;
00276     clamp_sample(sample);
00277     *stepIndex += IMA_IndexTable[code];
00278     clamp_step_index(stepIndex);
00279     return code;
00280 }
00281 
00282 static  void cvtSSima16K(PACMDRVSTREAMINSTANCE adsi,
00283                          const unsigned char* src, LPDWORD nsrc,
00284                          unsigned char* dst, LPDWORD ndst)
00285 {
00286     int         i;
00287     int         sampleL, sampleR;
00288     int     stepIndexL, stepIndexR;
00289     int     nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
00290     int     nsamp;
00291     /* compute the number of entire blocks we can decode...
00292      * it's the min of the number of entire blocks in source buffer and the number
00293      * of entire blocks in destination buffer
00294      */
00295     DWORD   nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
00296                              *ndst / (nsamp_blk * 2 * 2));
00297 
00298     *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
00299     *ndst = nblock * (nsamp_blk * 2 * 2);
00300 
00301     nsamp_blk--; /* remove the sample in block header */
00302     for (; nblock > 0; nblock--)
00303     {
00304         const unsigned char* in_src = src;
00305 
00306     /* handle headers first */
00307     sampleL = R16(src);
00308     stepIndexL = (unsigned)*(src + 2);
00309         clamp_step_index(&stepIndexL);
00310     src += 4;
00311     W16(dst, sampleL);  dst += 2;
00312 
00313     sampleR = R16(src);
00314     stepIndexR = (unsigned)*(src + 2);
00315         clamp_step_index(&stepIndexR);
00316     src += 4;
00317     W16(dst, sampleR);  dst += 2;
00318 
00319     for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
00320         {
00321             for (i = 0; i < 4; i++)
00322             {
00323                 process_nibble(*src, &stepIndexL, &sampleL);
00324                 W16(dst + (2 * i + 0) * 4 + 0, sampleL);
00325                 process_nibble(*src++ >> 4, &stepIndexL, &sampleL);
00326                 W16(dst + (2 * i + 1) * 4 + 0, sampleL);
00327             }
00328             for (i = 0; i < 4; i++)
00329             {
00330                 process_nibble(*src , &stepIndexR, &sampleR);
00331                 W16(dst + (2 * i + 0) * 4 + 2, sampleR);
00332                 process_nibble(*src++ >>4, &stepIndexR, &sampleR);
00333                 W16(dst + (2 * i + 1) * 4 + 2, sampleR);
00334             }
00335             dst += 32;
00336         }
00337         /* we have now to realign the source pointer on block */
00338         src = in_src + adsi->pwfxSrc->nBlockAlign;
00339     }
00340 }
00341 
00342 static  void cvtMMima16K(PACMDRVSTREAMINSTANCE adsi,
00343                          const unsigned char* src, LPDWORD nsrc,
00344                          unsigned char* dst, LPDWORD ndst)
00345 {
00346     int     sample;
00347     int     stepIndex;
00348     int     nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
00349     int     nsamp;
00350     /* compute the number of entire blocks we can decode...
00351      * it's the min of the number of entire blocks in source buffer and the number
00352      * of entire blocks in destination buffer
00353      */
00354     DWORD   nblock = min(*nsrc / adsi->pwfxSrc->nBlockAlign,
00355                              *ndst / (nsamp_blk * 2));
00356 
00357     *nsrc = nblock * adsi->pwfxSrc->nBlockAlign;
00358     *ndst = nblock * nsamp_blk * 2;
00359 
00360     nsamp_blk--; /* remove the sample in block header */
00361     for (; nblock > 0; nblock--)
00362     {
00363         const unsigned char*    in_src = src;
00364 
00365     /* handle header first */
00366     sample = R16(src);
00367     stepIndex = (unsigned)*(src + 2);
00368         clamp_step_index(&stepIndex);
00369     src += 4;
00370     W16(dst, sample);   dst += 2;
00371 
00372     for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
00373         {
00374             process_nibble(*src, &stepIndex, &sample);
00375         W16(dst, sample); dst += 2;
00376             process_nibble(*src++ >> 4, &stepIndex, &sample);
00377         W16(dst, sample); dst += 2;
00378     }
00379         /* we have now to realign the source pointer on block */
00380         src = in_src + adsi->pwfxSrc->nBlockAlign;
00381     }
00382 }
00383 
00384 static  void cvtSS16imaK(PACMDRVSTREAMINSTANCE adsi,
00385                          const unsigned char* src, LPDWORD nsrc,
00386                          unsigned char* dst, LPDWORD ndst)
00387 {
00388     int     stepIndexL, stepIndexR;
00389     int     sampleL, sampleR;
00390     BYTE    code1, code2;
00391     int     nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
00392     int     i, nsamp;
00393     /* compute the number of entire blocks we can decode...
00394      * it's the min of the number of entire blocks in source buffer and the number
00395      * of entire blocks in destination buffer
00396      */
00397     DWORD   nblock = min(*nsrc / (nsamp_blk * 2 * 2),
00398                              *ndst / adsi->pwfxDst->nBlockAlign);
00399 
00400     *nsrc = nblock * (nsamp_blk * 2 * 2);
00401     *ndst = nblock * adsi->pwfxDst->nBlockAlign;
00402 
00403     stepIndexL = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
00404     stepIndexR = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR;
00405 
00406     nsamp_blk--; /* so that we won't count the sample in header while filling the block */
00407 
00408     for (; nblock > 0; nblock--)
00409     {
00410         unsigned char*   in_dst = dst;
00411 
00412         /* generate header */
00413         sampleL = R16(src);  src += 2;
00414     W16(dst, sampleL); dst += 2;
00415     *dst = (unsigned char)(unsigned)stepIndexL;
00416     dst += 2;
00417 
00418         sampleR = R16(src); src += 2;
00419     W16(dst, sampleR); dst += 2;
00420     *dst = (unsigned char)(unsigned)stepIndexR;
00421     dst += 2;
00422 
00423     for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 8)
00424         {
00425             for (i = 0; i < 4; i++)
00426             {
00427                 code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 0),
00428                                         &stepIndexL, &sampleL);
00429                 code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 0),
00430                                         &stepIndexL, &sampleL);
00431                 *dst++ = (code1 << 4) | code2;
00432             }
00433             for (i = 0; i < 4; i++)
00434             {
00435                 code1 = generate_nibble(R16(src + (2 * i + 0) * 2 + 1),
00436                                         &stepIndexR, &sampleR);
00437                 code2 = generate_nibble(R16(src + (2 * i + 1) * 2 + 1),
00438                                         &stepIndexR, &sampleR);
00439                 *dst++ = (code1 << 4) | code2;
00440             }
00441             src += 32;
00442     }
00443     dst = in_dst + adsi->pwfxDst->nBlockAlign;
00444     }
00445     ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndexL;
00446     ((AcmAdpcmData*)adsi->dwDriver)->stepIndexR = stepIndexR;
00447 }
00448 
00449 static  void cvtMM16imaK(PACMDRVSTREAMINSTANCE adsi,
00450                          const unsigned char* src, LPDWORD nsrc,
00451                          unsigned char* dst, LPDWORD ndst)
00452 {
00453     int     stepIndex;
00454     int     sample;
00455     BYTE    code1, code2;
00456     int     nsamp_blk = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
00457     int     nsamp;
00458     /* compute the number of entire blocks we can decode...
00459      * it's the min of the number of entire blocks in source buffer and the number
00460      * of entire blocks in destination buffer
00461      */
00462     DWORD   nblock = min(*nsrc / (nsamp_blk * 2),
00463                              *ndst / adsi->pwfxDst->nBlockAlign);
00464 
00465     *nsrc = nblock * (nsamp_blk * 2);
00466     *ndst = nblock * adsi->pwfxDst->nBlockAlign;
00467 
00468     stepIndex = ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL;
00469     nsamp_blk--; /* so that we won't count the sample in header while filling the block */
00470 
00471     for (; nblock > 0; nblock--)
00472     {
00473         unsigned char*   in_dst = dst;
00474 
00475         /* generate header */
00476         /* FIXME: what about the last effective sample from previous block ??? */
00477         /* perhaps something like:
00478          *      sample += R16(src);
00479          *      clamp_sample(sample);
00480          * and with :
00481          *      + saving the sample in adsi->dwDriver when all blocks are done
00482          +      + reset should set the field in adsi->dwDriver to 0 too
00483          */
00484         sample = R16(src); src += 2;
00485     W16(dst, sample); dst += 2;
00486     *dst = (unsigned char)(unsigned)stepIndex;
00487     dst += 2;
00488 
00489     for (nsamp = nsamp_blk; nsamp > 0; nsamp -= 2)
00490         {
00491             code1 = generate_nibble(R16(src), &stepIndex, &sample);
00492             src += 2;
00493             code2 = generate_nibble(R16(src), &stepIndex, &sample);
00494             src += 2;
00495             *dst++ = (code1 << 4) | code2;
00496     }
00497     dst = in_dst + adsi->pwfxDst->nBlockAlign;
00498     }
00499     ((AcmAdpcmData*)adsi->dwDriver)->stepIndexL = stepIndex;
00500 }
00501 
00502 /***********************************************************************
00503  *           ADPCM_DriverDetails
00504  *
00505  */
00506 static  LRESULT ADPCM_DriverDetails(PACMDRIVERDETAILSW add)
00507 {
00508     add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
00509     add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
00510     add->wMid = 0x1;
00511     add->wPid = 0x22;
00512     add->vdwACM = 0x3320000;
00513     add->vdwDriver = 0x04000000;
00514     add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
00515     add->cFormatTags = 2; /* PCM, IMA ADPCM */
00516     add->cFilterTags = 0;
00517     add->hicon = NULL;
00518     MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM", -1,
00519                          add->szShortName, sizeof(add->szShortName)/sizeof(WCHAR) );
00520     MultiByteToWideChar( CP_ACP, 0, "Microsoft IMA ADPCM CODEC", -1,
00521                          add->szLongName, sizeof(add->szLongName)/sizeof(WCHAR) );
00522     MultiByteToWideChar( CP_ACP, 0, "Brought to you by the Wine team...", -1,
00523                          add->szCopyright, sizeof(add->szCopyright)/sizeof(WCHAR) );
00524     MultiByteToWideChar( CP_ACP, 0, "Refer to LICENSE file", -1,
00525                          add->szLicensing, sizeof(add->szLicensing)/sizeof(WCHAR) );
00526     add->szFeatures[0] = 0;
00527 
00528     return MMSYSERR_NOERROR;
00529 }
00530 
00531 /***********************************************************************
00532  *           ADPCM_FormatTagDetails
00533  *
00534  */
00535 static  LRESULT ADPCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
00536 {
00537     static const WCHAR szPcm[]={'P','C','M',0};
00538     static const WCHAR szImaAdPcm[]={'I','M','A',' ','A','D','P','C','M',0};
00539 
00540     switch (dwQuery)
00541     {
00542     case ACM_FORMATTAGDETAILSF_INDEX:
00543     if (aftd->dwFormatTagIndex >= 2) return ACMERR_NOTPOSSIBLE;
00544     break;
00545     case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
00546     if (aftd->dwFormatTag == WAVE_FORMAT_UNKNOWN)
00547         {
00548             aftd->dwFormatTagIndex = 1; /* WAVE_FORMAT_IMA_ADPCM is bigger than PCM */
00549         break;
00550     }
00551     /* fall thru */
00552     case ACM_FORMATTAGDETAILSF_FORMATTAG:
00553     switch (aftd->dwFormatTag)
00554         {
00555     case WAVE_FORMAT_PCM:       aftd->dwFormatTagIndex = 0; break;
00556     case WAVE_FORMAT_IMA_ADPCM:     aftd->dwFormatTagIndex = 1; break;
00557     default:            return ACMERR_NOTPOSSIBLE;
00558     }
00559     break;
00560     default:
00561     WARN("Unsupported query %08x\n", dwQuery);
00562     return MMSYSERR_NOTSUPPORTED;
00563     }
00564 
00565     aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
00566     switch (aftd->dwFormatTagIndex)
00567     {
00568     case 0:
00569     aftd->dwFormatTag = WAVE_FORMAT_PCM;
00570     aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
00571     aftd->cStandardFormats = NUM_PCM_FORMATS;
00572         lstrcpyW(aftd->szFormatTag, szPcm);
00573         break;
00574     case 1:
00575     aftd->dwFormatTag = WAVE_FORMAT_IMA_ADPCM;
00576     aftd->cbFormatSize = sizeof(IMAADPCMWAVEFORMAT);
00577     aftd->cStandardFormats = NUM_ADPCM_FORMATS;
00578         lstrcpyW(aftd->szFormatTag, szImaAdPcm);
00579     break;
00580     }
00581     return MMSYSERR_NOERROR;
00582 }
00583 
00584 /***********************************************************************
00585  *           ADPCM_FormatDetails
00586  *
00587  */
00588 static  LRESULT ADPCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
00589 {
00590     switch (dwQuery)
00591     {
00592     case ACM_FORMATDETAILSF_FORMAT:
00593     if (ADPCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
00594     break;
00595     case ACM_FORMATDETAILSF_INDEX:
00596     afd->pwfx->wFormatTag = afd->dwFormatTag;
00597     switch (afd->dwFormatTag)
00598         {
00599     case WAVE_FORMAT_PCM:
00600         if (afd->dwFormatIndex >= NUM_PCM_FORMATS) return ACMERR_NOTPOSSIBLE;
00601         afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
00602         afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
00603         afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
00604         /* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not accessible
00605          * afd->pwfx->cbSize = 0;
00606          */
00607         afd->pwfx->nBlockAlign =
00608         (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
00609         afd->pwfx->nAvgBytesPerSec =
00610         afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
00611         break;
00612     case WAVE_FORMAT_IMA_ADPCM:
00613         if (afd->dwFormatIndex >= NUM_ADPCM_FORMATS) return ACMERR_NOTPOSSIBLE;
00614         afd->pwfx->nChannels = ADPCM_Formats[afd->dwFormatIndex].nChannels;
00615         afd->pwfx->nSamplesPerSec = ADPCM_Formats[afd->dwFormatIndex].rate;
00616         afd->pwfx->wBitsPerSample = ADPCM_Formats[afd->dwFormatIndex].nBits;
00617         afd->pwfx->nBlockAlign = 1024;
00618         /* we got 4 bits per sample */
00619         afd->pwfx->nAvgBytesPerSec =
00620         (afd->pwfx->nSamplesPerSec * 4) / 8;
00621             if (afd->cbwfx >= sizeof(WAVEFORMATEX))
00622                 afd->pwfx->cbSize = sizeof(WORD);
00623             if (afd->cbwfx >= sizeof(IMAADPCMWAVEFORMAT))
00624                 ((IMAADPCMWAVEFORMAT*)afd->pwfx)->wSamplesPerBlock = (1024 - 4 * afd->pwfx->nChannels) * (2 / afd->pwfx->nChannels) + 1;
00625         break;
00626     default:
00627             WARN("Unsupported tag %08x\n", afd->dwFormatTag);
00628         return MMSYSERR_INVALPARAM;
00629     }
00630     break;
00631     default:
00632     WARN("Unsupported query %08x\n", dwQuery);
00633     return MMSYSERR_NOTSUPPORTED;
00634     }
00635     afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
00636     afd->szFormat[0] = 0; /* let MSACM format this for us... */
00637 
00638     return MMSYSERR_NOERROR;
00639 }
00640 
00641 /***********************************************************************
00642  *           ADPCM_FormatSuggest
00643  *
00644  */
00645 static  LRESULT ADPCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
00646 {
00647     /* some tests ... */
00648     if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
00649     adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
00650     adfs->pwfxSrc->wFormatTag == adfs->pwfxDst->wFormatTag ||
00651     ADPCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
00652 
00653     /* If no suggestion for destination, then copy source value */
00654     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS))
00655     adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
00656     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
00657         adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
00658 
00659     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE))
00660     {
00661     if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
00662             adfs->pwfxDst->wBitsPerSample = 4;
00663         else
00664             adfs->pwfxDst->wBitsPerSample = 16;
00665     }
00666     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG))
00667     {
00668     if (adfs->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
00669             adfs->pwfxDst->wFormatTag = WAVE_FORMAT_IMA_ADPCM;
00670         else
00671             adfs->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
00672     }
00673 
00674     /* recompute other values */
00675     switch (adfs->pwfxDst->wFormatTag)
00676     {
00677     case WAVE_FORMAT_PCM:
00678         if (adfs->cbwfxSrc < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
00679         adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
00680         adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
00681         /* check if result is ok */
00682         if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
00683         break;
00684     case WAVE_FORMAT_IMA_ADPCM:
00685         if (adfs->cbwfxDst < sizeof(IMAADPCMWAVEFORMAT)) return ACMERR_NOTPOSSIBLE;
00686         init_wfx_ima_adpcm((IMAADPCMWAVEFORMAT*)adfs->pwfxDst);
00687         /* FIXME: not handling header overhead */
00688         TRACE("setting spb=%u\n", ((IMAADPCMWAVEFORMAT*)adfs->pwfxDst)->wSamplesPerBlock);
00689         /* check if result is ok */
00690         if (ADPCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
00691         break;
00692     default:
00693         return ACMERR_NOTPOSSIBLE;
00694     }
00695 
00696     return MMSYSERR_NOERROR;
00697 }
00698 
00699 /***********************************************************************
00700  *           ADPCM_Reset
00701  *
00702  */
00703 static  void    ADPCM_Reset(PACMDRVSTREAMINSTANCE adsi, AcmAdpcmData* aad)
00704 {
00705     aad->stepIndexL = aad->stepIndexR = 0;
00706 }
00707 
00708 /***********************************************************************
00709  *           ADPCM_StreamOpen
00710  *
00711  */
00712 static  LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
00713 {
00714     AcmAdpcmData*   aad;
00715     unsigned            nspb;
00716 
00717     assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
00718 
00719     if (ADPCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
00720     ADPCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
00721     return ACMERR_NOTPOSSIBLE;
00722 
00723     aad = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmAdpcmData));
00724     if (aad == 0) return MMSYSERR_NOMEM;
00725 
00726     adsi->dwDriver = (DWORD_PTR)aad;
00727 
00728     if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
00729     adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
00730     {
00731     goto theEnd;
00732     }
00733     else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
00734              adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
00735     {
00736     /* resampling or mono <=> stereo not available
00737          * ADPCM algo only define 16 bit per sample output
00738          */
00739     if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
00740         adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
00741             adsi->pwfxDst->wBitsPerSample != 16)
00742         goto theEnd;
00743 
00744         nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxSrc)->wSamplesPerBlock;
00745         TRACE("spb=%u\n", nspb);
00746 
00747         /* we check that in a block, after the header, samples are present on
00748          * 4-sample packet pattern
00749          * we also check that the block alignment is bigger than the expected size
00750          */
00751         if (((nspb - 1) & 3) != 0) goto theEnd;
00752         if ((((nspb - 1) / 2) + 4) * adsi->pwfxSrc->nChannels < adsi->pwfxSrc->nBlockAlign)
00753             goto theEnd;
00754 
00755     /* adpcm decoding... */
00756     if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 2)
00757         aad->convert = cvtSSima16K;
00758     if (adsi->pwfxDst->wBitsPerSample == 16 && adsi->pwfxDst->nChannels == 1)
00759         aad->convert = cvtMMima16K;
00760     }
00761     else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
00762              adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
00763     {
00764     if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
00765         adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
00766             adsi->pwfxSrc->wBitsPerSample != 16)
00767         goto theEnd;
00768 
00769         nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
00770         TRACE("spb=%u\n", nspb);
00771 
00772         /* we check that in a block, after the header, samples are present on
00773          * 4-sample packet pattern
00774          * we also check that the block alignment is bigger than the expected size
00775          */
00776         if (((nspb - 1) & 3) != 0) goto theEnd;
00777         if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels < adsi->pwfxDst->nBlockAlign)
00778             goto theEnd;
00779 
00780     /* adpcm coding... */
00781     if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 2)
00782         aad->convert = cvtSS16imaK;
00783     if (adsi->pwfxSrc->wBitsPerSample == 16 && adsi->pwfxSrc->nChannels == 1)
00784         aad->convert = cvtMM16imaK;
00785     }
00786     else goto theEnd;
00787     ADPCM_Reset(adsi, aad);
00788 
00789     return MMSYSERR_NOERROR;
00790 
00791  theEnd:
00792     HeapFree(GetProcessHeap(), 0, aad);
00793     adsi->dwDriver = 0L;
00794     return MMSYSERR_NOTSUPPORTED;
00795 }
00796 
00797 /***********************************************************************
00798  *           ADPCM_StreamClose
00799  *
00800  */
00801 static  LRESULT ADPCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
00802 {
00803     HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
00804     return MMSYSERR_NOERROR;
00805 }
00806 
00807 /***********************************************************************
00808  *           ADPCM_StreamSize
00809  *
00810  */
00811 static  LRESULT ADPCM_StreamSize(const ACMDRVSTREAMINSTANCE *adsi, PACMDRVSTREAMSIZE adss)
00812 {
00813     DWORD nblocks;
00814 
00815     switch (adss->fdwSize)
00816     {
00817     case ACM_STREAMSIZEF_DESTINATION:
00818     /* cbDstLength => cbSrcLength */
00819     if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
00820         adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
00821         {
00822             nblocks = adss->cbDstLength / adsi->pwfxDst->nBlockAlign;
00823             if (nblocks == 0)
00824                 return ACMERR_NOTPOSSIBLE;
00825             adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock;
00826     }
00827         else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
00828                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
00829         {
00830             nblocks = adss->cbDstLength / (adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock);
00831             if (nblocks == 0)
00832                 return ACMERR_NOTPOSSIBLE;
00833             adss->cbSrcLength = nblocks * adsi->pwfxSrc->nBlockAlign;
00834     }
00835         else
00836         {
00837         return MMSYSERR_NOTSUPPORTED;
00838     }
00839     break;
00840     case ACM_STREAMSIZEF_SOURCE:
00841     /* cbSrcLength => cbDstLength */
00842     if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_PCM &&
00843         adsi->pwfxDst->wFormatTag == WAVE_FORMAT_IMA_ADPCM)
00844         {
00845             nblocks = adss->cbSrcLength / (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock);
00846             if (nblocks == 0)
00847                 return ACMERR_NOTPOSSIBLE;
00848             if (adss->cbSrcLength % (adsi->pwfxSrc->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxDst)->wSamplesPerBlock))
00849                 /* Round block count up. */
00850                 nblocks++;
00851             adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign;
00852     }
00853         else if (adsi->pwfxSrc->wFormatTag == WAVE_FORMAT_IMA_ADPCM &&
00854                  adsi->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
00855         {
00856             nblocks = adss->cbSrcLength / adsi->pwfxSrc->nBlockAlign;
00857             if (nblocks == 0)
00858                 return ACMERR_NOTPOSSIBLE;
00859             if (adss->cbSrcLength % adsi->pwfxSrc->nBlockAlign)
00860                 /* Round block count up. */
00861                 nblocks++;
00862             adss->cbDstLength = nblocks * adsi->pwfxDst->nBlockAlign * ((IMAADPCMWAVEFORMAT*)adsi->pwfxSrc)->wSamplesPerBlock;
00863     }
00864         else
00865         {
00866         return MMSYSERR_NOTSUPPORTED;
00867     }
00868     break;
00869     default:
00870     WARN("Unsupported query %08x\n", adss->fdwSize);
00871     return MMSYSERR_NOTSUPPORTED;
00872     }
00873     return MMSYSERR_NOERROR;
00874 }
00875 
00876 /***********************************************************************
00877  *           ADPCM_StreamConvert
00878  *
00879  */
00880 static LRESULT ADPCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
00881 {
00882     AcmAdpcmData*   aad = (AcmAdpcmData*)adsi->dwDriver;
00883     DWORD       nsrc = adsh->cbSrcLength;
00884     DWORD       ndst = adsh->cbDstLength;
00885 
00886     if (adsh->fdwConvert &
00887     ~(ACM_STREAMCONVERTF_BLOCKALIGN|
00888       ACM_STREAMCONVERTF_END|
00889       ACM_STREAMCONVERTF_START))
00890     {
00891     FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert);
00892     }
00893     /* ACM_STREAMCONVERTF_BLOCKALIGN
00894      *  currently all conversions are block aligned, so do nothing for this flag
00895      * ACM_STREAMCONVERTF_END
00896      *  no pending data, so do nothing for this flag
00897      */
00898     if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START))
00899     {
00900     ADPCM_Reset(adsi, aad);
00901     }
00902 
00903     aad->convert(adsi, adsh->pbSrc, &nsrc, adsh->pbDst, &ndst);
00904     adsh->cbSrcLengthUsed = nsrc;
00905     adsh->cbDstLengthUsed = ndst;
00906 
00907     return MMSYSERR_NOERROR;
00908 }
00909 
00910 /**************************************************************************
00911  *          ADPCM_DriverProc            [exported]
00912  */
00913 LRESULT CALLBACK ADPCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
00914                      LPARAM dwParam1, LPARAM dwParam2)
00915 {
00916     TRACE("(%08lx %p %04x %08lx %08lx);\n",
00917       dwDevID, hDriv, wMsg, dwParam1, dwParam2);
00918 
00919     switch (wMsg)
00920     {
00921     case DRV_LOAD:      return 1;
00922     case DRV_FREE:      return 1;
00923     case DRV_OPEN:      return 1;
00924     case DRV_CLOSE:     return ADPCM_drvClose(dwDevID);
00925     case DRV_ENABLE:        return 1;
00926     case DRV_DISABLE:       return 1;
00927     case DRV_QUERYCONFIGURE:    return 1;
00928     case DRV_CONFIGURE:     MessageBoxA(0, "MSACM IMA ADPCM filter !", "Wine Driver", MB_OK); return 1;
00929     case DRV_INSTALL:       return DRVCNF_RESTART;
00930     case DRV_REMOVE:        return DRVCNF_RESTART;
00931 
00932     case ACMDM_DRIVER_NOTIFY:
00933     /* no caching from other ACM drivers is done so far */
00934     return MMSYSERR_NOERROR;
00935 
00936     case ACMDM_DRIVER_DETAILS:
00937     return ADPCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
00938 
00939     case ACMDM_FORMATTAG_DETAILS:
00940     return ADPCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
00941 
00942     case ACMDM_FORMAT_DETAILS:
00943     return ADPCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
00944 
00945     case ACMDM_FORMAT_SUGGEST:
00946     return ADPCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
00947 
00948     case ACMDM_STREAM_OPEN:
00949     return ADPCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
00950 
00951     case ACMDM_STREAM_CLOSE:
00952     return ADPCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
00953 
00954     case ACMDM_STREAM_SIZE:
00955     return ADPCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
00956 
00957     case ACMDM_STREAM_CONVERT:
00958     return ADPCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
00959 
00960     case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
00961     case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
00962     /* this converter is not a hardware driver */
00963     case ACMDM_FILTERTAG_DETAILS:
00964     case ACMDM_FILTER_DETAILS:
00965     /* this converter is not a filter */
00966     case ACMDM_STREAM_RESET:
00967     /* only needed for asynchronous driver... we aren't, so just say it */
00968     return MMSYSERR_NOTSUPPORTED;
00969     case ACMDM_STREAM_PREPARE:
00970     case ACMDM_STREAM_UNPREPARE:
00971     /* nothing special to do here... so don't do anything */
00972     return MMSYSERR_NOERROR;
00973 
00974     default:
00975     return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
00976     }
00977 }

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