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

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.