Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2985 lines
102 KiB

  1. //==========================================================================;
  2. //
  3. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. // PURPOSE.
  7. //
  8. // Copyright (c) 1992-1999 Microsoft Corporation
  9. //
  10. //--------------------------------------------------------------------------;
  11. //
  12. // codec.c
  13. //
  14. // Description:
  15. // This file contains the DriverProc and other routines which respond
  16. // to ACM messages.
  17. //
  18. //
  19. //==========================================================================;
  20. #include <windows.h>
  21. #include <windowsx.h>
  22. #include <mmsystem.h>
  23. #include <mmddk.h>
  24. #include <ctype.h>
  25. #include <mmreg.h>
  26. #include <msacm.h>
  27. #include <msacmdrv.h>
  28. #include "codec.h"
  29. #include "imaadpcm.h"
  30. #include "debug.h"
  31. const UINT gauFormatTagIndexToTag[] =
  32. {
  33. WAVE_FORMAT_PCM,
  34. WAVE_FORMAT_IMA_ADPCM
  35. };
  36. #define ACM_DRIVER_MAX_FORMAT_TAGS SIZEOF_ARRAY(gauFormatTagIndexToTag)
  37. #define ACM_DRIVER_MAX_FILTER_TAGS 0
  38. //
  39. // array of sample rates supported
  40. //
  41. //
  42. const UINT gauFormatIndexToSampleRate[] =
  43. {
  44. 8000,
  45. 11025,
  46. 22050,
  47. 44100
  48. };
  49. #ifdef IMAADPCM_USECONFIG
  50. //
  51. // Required by config.c as well as codec.c.
  52. //
  53. const UINT ACM_DRIVER_MAX_SAMPLE_RATES = SIZEOF_ARRAY(gauFormatIndexToSampleRate);
  54. const UINT ACM_DRIVER_MAX_CHANNELS = IMAADPCM_MAX_CHANNELS;
  55. #else
  56. #define ACM_DRIVER_MAX_SAMPLE_RATES SIZEOF_ARRAY(gauFormatIndexToSampleRate)
  57. #define ACM_DRIVER_MAX_CHANNELS IMAADPCM_MAX_CHANNELS
  58. #endif
  59. //
  60. // array of bits per sample supported
  61. //
  62. //
  63. const UINT gauFormatIndexToBitsPerSample[] =
  64. {
  65. 8,
  66. 16
  67. };
  68. #define ACM_DRIVER_MAX_BITSPERSAMPLE_PCM SIZEOF_ARRAY(gauFormatIndexToBitsPerSample)
  69. #define ACM_DRIVER_MAX_BITSPERSAMPLE_ADPCM 1
  70. //
  71. // number of formats we enumerate per channel is number of sample rates
  72. // times number of channels times number of types (bits per sample).
  73. //
  74. #define ACM_DRIVER_MAX_FORMATS_PCM (ACM_DRIVER_MAX_SAMPLE_RATES * \
  75. ACM_DRIVER_MAX_CHANNELS * \
  76. ACM_DRIVER_MAX_BITSPERSAMPLE_PCM)
  77. #define ACM_DRIVER_MAX_FORMATS_ADPCM (ACM_DRIVER_MAX_SAMPLE_RATES * \
  78. ACM_DRIVER_MAX_CHANNELS * \
  79. ACM_DRIVER_MAX_BITSPERSAMPLE_ADPCM)
  80. #ifdef IMAADPCM_USECONFIG
  81. //
  82. // This array describes the configuration settings for this codec.
  83. //
  84. // Each line in the realtime encode/decode rate listbox must have one of
  85. // these structures to describe it. The type of line is defined in
  86. // nFormatType, which can have one of the following values:
  87. //
  88. // CONFIG_RLF_NONUMBER - the string in idsFormat is displayed as is.
  89. // CONFIG_RLF_MONOONLY - dwMonoRate is written into idsFormat, then
  90. // displayed as a mono rate.
  91. // CONFIG_RLF_STEREOONLY - dwMonoRate is written into idsFormat, then
  92. // displayed as a stereo rate.
  93. // CONFIG_RLF_MONOSTEREO - dwMonoRate followed by nRate/2 are written
  94. // into idsFormat, then displayed as a pair
  95. // of mono and stereo rates.
  96. //
  97. // The index to the gaRateListFormat array corresponds to the value which
  98. // is stored as configuration information in the registry or .ini file.
  99. // To find out if a certain conversion can be performed in real time,
  100. // check that:
  101. //
  102. // SamplingRate <= gaRateListFormat[ConfigSetting].dwMonoRate / nChannels
  103. //
  104. // Note: The gaRateListFormat array must change when
  105. // gauFormatIndexToSampleRate changes.
  106. //
  107. const RATELISTFORMAT gaRateListFormat[] =
  108. {
  109. { CONFIG_RLF_NONUMBER, IDS_CONFIG_NORATES, 0 },
  110. { CONFIG_RLF_MONOONLY, IDS_CONFIG_MONOONLY, 8000 }, // gauFormatIndexToSampleRate[0]
  111. { CONFIG_RLF_MONOONLY, IDS_CONFIG_MONOONLY, 11025 }, // gauFormatIndexToSampleRate[1]
  112. { CONFIG_RLF_STEREOONLY, IDS_CONFIG_STEREOONLY, 16000 }, // 2 * gauFormatIndexToSampleRate[0]
  113. { CONFIG_RLF_MONOSTEREO, IDS_CONFIG_MONOSTEREO, 22050 }, // gauFormatIndexToSampleRate[2]
  114. { CONFIG_RLF_MONOSTEREO, IDS_CONFIG_MONOSTEREO, 44100 }, // gauFormatIndexToSampleRate[3]
  115. { CONFIG_RLF_NONUMBER, IDS_CONFIG_ALLRATES, 88200 } // 2 * gauFormatIndexToSampleRate[3]
  116. };
  117. const UINT IMAADPCM_CONFIG_NUMSETTINGS = SIZEOF_ARRAY( gaRateListFormat );
  118. #endif // IMAADPCM_USECONFIG
  119. //==========================================================================;
  120. //
  121. //
  122. //
  123. //
  124. //==========================================================================;
  125. //--------------------------------------------------------------------------;
  126. //
  127. // int LoadStringCodec
  128. //
  129. // Description:
  130. // This function should be used by all codecs to load resource strings
  131. // which will be passed back to the ACM. It works correctly for all
  132. // platforms, as follows:
  133. //
  134. // Win16: Compiled to LoadString to load ANSI strings.
  135. //
  136. // Win32: The 32-bit ACM always expects Unicode strings. Therefore,
  137. // when UNICODE is defined, this function is compiled to
  138. // LoadStringW to load a Unicode string. When UNICODE is
  139. // not defined, this function loads an ANSI string, converts
  140. // it to Unicode, and returns the Unicode string to the
  141. // codec.
  142. //
  143. // Note that you may use LoadString for other strings (strings which
  144. // will not be passed back to the ACM), because these strings will
  145. // always be consistent with the definition of UNICODE.
  146. //
  147. // Arguments:
  148. // Same as LoadString, except that it expects an LPSTR for Win16 and a
  149. // LPWSTR for Win32.
  150. //
  151. // Return (int):
  152. // Same as LoadString.
  153. //
  154. //--------------------------------------------------------------------------;
  155. #ifndef WIN32
  156. #define LoadStringCodec LoadString
  157. #else
  158. #ifdef UNICODE
  159. #define LoadStringCodec LoadStringW
  160. #else
  161. int FNGLOBAL LoadStringCodec
  162. (
  163. HINSTANCE hinst,
  164. UINT uID,
  165. LPWSTR lpwstr,
  166. int cch)
  167. {
  168. LPSTR lpstr;
  169. int iReturn;
  170. lpstr = (LPSTR)GlobalAlloc(GPTR, cch);
  171. if (NULL == lpstr)
  172. {
  173. return 0;
  174. }
  175. iReturn = LoadStringA(hinst, uID, lpstr, cch);
  176. if (0 == iReturn)
  177. {
  178. if (0 != cch)
  179. {
  180. lpwstr[0] = '\0';
  181. }
  182. }
  183. else
  184. {
  185. MultiByteToWideChar( GetACP(), 0, lpstr, cch, lpwstr, cch );
  186. }
  187. GlobalFree((HGLOBAL)lpstr);
  188. return iReturn;
  189. }
  190. #endif // UNICODE
  191. #endif // WIN32
  192. //==========================================================================;
  193. //
  194. //
  195. //
  196. //
  197. //==========================================================================;
  198. //--------------------------------------------------------------------------;
  199. //
  200. // WORD imaadpcmBlockAlign
  201. //
  202. // Description:
  203. // This function computes the standard block alignment that should
  204. // be used given the WAVEFORMATEX structure.
  205. //
  206. // NOTE! It is _assumed_ that the format is a valid IMA-ADPCM format
  207. // and that the following fields in the format structure are valid:
  208. //
  209. // nChannels
  210. // nSamplesPerSec
  211. //
  212. // Arguments:
  213. // LPWAVEFORMATEX pwfx: Pointer to format header.
  214. //
  215. // Return (UINT):
  216. // The return value is the block alignment that should be placed in
  217. // the pwfx->nBlockAlign field.
  218. //
  219. //--------------------------------------------------------------------------;
  220. WORD FNLOCAL imaadpcmBlockAlign
  221. (
  222. LPWAVEFORMATEX pwfx
  223. )
  224. {
  225. UINT uBlockAlign;
  226. UINT uChannelShift;
  227. //
  228. // The data must be an integral number of DWORDs for mono, an even
  229. // number of DWORDs for stereo.
  230. //
  231. uChannelShift = pwfx->nChannels >> 1;
  232. uBlockAlign = 256 << uChannelShift;
  233. //
  234. // choose a block alignment that makes sense for the sample rate
  235. // that the original PCM data is. basically, this needs to be
  236. // some reasonable number to allow efficient streaming, etc.
  237. //
  238. // don't let block alignment get too small...
  239. //
  240. if (pwfx->nSamplesPerSec > 11025)
  241. {
  242. uBlockAlign *= (UINT)(pwfx->nSamplesPerSec / 11000);
  243. }
  244. //
  245. // Just make sure that the alignment is valid.
  246. //
  247. ASSERT( 0 == uBlockAlign % (sizeof(DWORD)*pwfx->nChannels) );
  248. return (WORD)(uBlockAlign);
  249. } // imaadpcmBlockAlign()
  250. //--------------------------------------------------------------------------;
  251. //
  252. // WORD imaadpcmSamplesPerBlock
  253. //
  254. // Description:
  255. // This function computes the Samples Per Block that should be used
  256. // given the WAVEFORMATEX structure.
  257. //
  258. // NOTE! It is _assumed_ that the format is a valid IMA-ADPCM format
  259. // and that the following fields in the format structure are valid:
  260. //
  261. // nChannels = must be 1 or 2!
  262. // nSamplesPerSec
  263. // nBlockAlign
  264. //
  265. // Arguments:
  266. // LPWAVEFORMATEX pwfx: Pointer to format header.
  267. //
  268. // Return (DWORD):
  269. // The return value is the average bytes per second that should be
  270. // placed in the pwfx->nAvgBytesPerSec field.
  271. //
  272. //--------------------------------------------------------------------------;
  273. WORD FNLOCAL imaadpcmSamplesPerBlock
  274. (
  275. LPWAVEFORMATEX pwfx
  276. )
  277. {
  278. UINT uSamplesPerBlock;
  279. UINT uChannelShift;
  280. UINT uHeaderBytes;
  281. UINT uBitsPerSample;
  282. //
  283. //
  284. //
  285. uChannelShift = pwfx->nChannels >> 1;
  286. uHeaderBytes = 4 << uChannelShift;
  287. uBitsPerSample = IMAADPCM_BITS_PER_SAMPLE << uChannelShift;
  288. //
  289. // compute the 'samples per block' that will be in the encoded
  290. // ADPCM data blocks. this is determined by subtracting out the
  291. // 'other info' contained in each block--a block is composed of
  292. // a header followed by the encoded data.
  293. //
  294. // the block header is composed of the following data:
  295. // 2 bytes (16 bit) sample per channel
  296. // 1 byte for step table index per channel
  297. // 1 byte padding per channel (dword align)
  298. //
  299. // this gives us (4 * uChannels) bytes of header information that
  300. // contains our first full sample (so we add one below).
  301. //
  302. uSamplesPerBlock = (pwfx->nBlockAlign - uHeaderBytes) * 8;
  303. uSamplesPerBlock /= uBitsPerSample;
  304. uSamplesPerBlock += 1;
  305. return (WORD)(uSamplesPerBlock);
  306. } // imaadpcmSamplesPerBlock()
  307. //--------------------------------------------------------------------------;
  308. //
  309. // UINT imaadpcmAvgBytesPerSec
  310. //
  311. // Description:
  312. // This function computes the Average Bytes Per Second that should
  313. // be used given the WAVEFORMATEX structure.
  314. //
  315. // NOTE! It is _assumed_ that the format is a valid IMA-ADPCM format
  316. // and that the following fields in the format structure are valid:
  317. //
  318. // nChannels = must be 1 or 2!
  319. // nSamplesPerSec
  320. // nBlockAlign
  321. //
  322. // Arguments:
  323. // LPWAVEFORMATEX pwfx: Pointer to format header.
  324. //
  325. // Return (DWORD):
  326. // The return value is the average bytes per second that should be
  327. // placed in the pwfx->nAvgBytesPerSec field.
  328. //
  329. //--------------------------------------------------------------------------;
  330. DWORD FNLOCAL imaadpcmAvgBytesPerSec
  331. (
  332. LPWAVEFORMATEX pwfx
  333. )
  334. {
  335. DWORD dwAvgBytesPerSec;
  336. UINT uSamplesPerBlock;
  337. //
  338. //
  339. //
  340. uSamplesPerBlock = imaadpcmSamplesPerBlock(pwfx);
  341. //
  342. // compute bytes per second including header bytes
  343. //
  344. dwAvgBytesPerSec = (pwfx->nSamplesPerSec * pwfx->nBlockAlign) /
  345. uSamplesPerBlock;
  346. return (dwAvgBytesPerSec);
  347. } // imaadpcmAvgBytesPerSec()
  348. //==========================================================================;
  349. //
  350. //
  351. //
  352. //
  353. //==========================================================================;
  354. //--------------------------------------------------------------------------;
  355. //
  356. // BOOL pcmIsValidFormat
  357. //
  358. // Description:
  359. // This function verifies that a wave format header is a valid PCM
  360. // header that _this_ ACM driver can deal with.
  361. //
  362. // Arguments:
  363. // LPWAVEFORMATEX pwfx: Pointer to format header to verify.
  364. //
  365. // Return (BOOL):
  366. // The return value is non-zero if the format header looks valid. A
  367. // zero return means the header is not valid.
  368. //
  369. //--------------------------------------------------------------------------;
  370. BOOL FNLOCAL pcmIsValidFormat
  371. (
  372. LPWAVEFORMATEX pwfx
  373. )
  374. {
  375. if (NULL == pwfx)
  376. return (FALSE);
  377. if (WAVE_FORMAT_PCM != pwfx->wFormatTag)
  378. return (FALSE);
  379. //
  380. // verify nChannels member is within the allowed range
  381. //
  382. if ((pwfx->nChannels < 1) || (pwfx->nChannels > ACM_DRIVER_MAX_CHANNELS))
  383. return (FALSE);
  384. //
  385. // only allow the bits per sample that we can encode and decode with
  386. //
  387. if ((16 != pwfx->wBitsPerSample) && (8 != pwfx->wBitsPerSample))
  388. return (FALSE);
  389. //
  390. // now verify that the block alignment is correct..
  391. //
  392. if (PCM_BLOCKALIGNMENT(pwfx) != pwfx->nBlockAlign)
  393. return (FALSE);
  394. //
  395. // finally, verify that avg bytes per second is correct
  396. //
  397. if (PCM_AVGBYTESPERSEC(pwfx) != pwfx->nAvgBytesPerSec)
  398. return (FALSE);
  399. return (TRUE);
  400. } // pcmIsValidFormat()
  401. //--------------------------------------------------------------------------;
  402. //
  403. // BOOL imaadpcmIsValidFormat
  404. //
  405. // Description:
  406. // This function verifies that a wave format header is a valid
  407. // IMA ADPCM header that _this_ ACM driver can deal with.
  408. //
  409. // Arguments:
  410. // LPWAVEFORMATEX pwfx: Pointer to format header to verify.
  411. //
  412. // Return (BOOL):
  413. // The return value is non-zero if the format header looks valid. A
  414. // zero return means the header is not valid.
  415. //
  416. //--------------------------------------------------------------------------;
  417. BOOL FNLOCAL imaadpcmIsValidFormat
  418. (
  419. LPWAVEFORMATEX pwfx
  420. )
  421. {
  422. LPIMAADPCMWAVEFORMAT pwfadpcm;
  423. if (NULL == pwfx)
  424. return (FALSE);
  425. if (WAVE_FORMAT_IMA_ADPCM != pwfx->wFormatTag)
  426. return (FALSE);
  427. //
  428. // check wBitsPerSample
  429. //
  430. if (IMAADPCM_BITS_PER_SAMPLE != pwfx->wBitsPerSample)
  431. return (FALSE);
  432. //
  433. // check channels
  434. //
  435. if ((pwfx->nChannels < 1) || (pwfx->nChannels > IMAADPCM_MAX_CHANNELS))
  436. return (FALSE);
  437. //
  438. // Check block alignment - must be an integral number of DWORDs for
  439. // mono, or an even number of DWORDs for stereo.
  440. //
  441. if( 0 != pwfx->nBlockAlign % (sizeof(DWORD)*pwfx->nChannels) )
  442. return FALSE;
  443. //
  444. // cbSize must be 2 for IMA's ADPCM
  445. //
  446. if (IMAADPCM_WFX_EXTRA_BYTES != pwfx->cbSize)
  447. return (FALSE);
  448. //
  449. // wSamplesPerBlock must be equal to 4n+1, where n is at least 1.
  450. //
  451. pwfadpcm = (LPIMAADPCMWAVEFORMAT)pwfx;
  452. if( ( pwfadpcm->wSamplesPerBlock < 5 ) ||
  453. ( pwfadpcm->wSamplesPerBlock%4 != 1 ) )
  454. return FALSE;
  455. //
  456. // Verifying nBlockAlign and wSamplesPerBlock are consistent.
  457. //
  458. if ( (pwfadpcm->wSamplesPerBlock != imaadpcmSamplesPerBlock(pwfx)) )
  459. return FALSE;
  460. return (TRUE);
  461. } // imaadpcmIsValidFormat()
  462. //==========================================================================;
  463. //
  464. //
  465. //
  466. //
  467. //==========================================================================;
  468. //--------------------------------------------------------------------------;
  469. //
  470. // LRESULT acmdDriverOpen
  471. //
  472. // Description:
  473. // This function is used to handle the DRV_OPEN message for the ACM
  474. // driver. The driver is 'opened' for many reasons with the most common
  475. // being in preperation for conversion work. It is very important that
  476. // the driver be able to correctly handle multiple open driver
  477. // instances.
  478. //
  479. // Read the comments for this function carefully!
  480. //
  481. // Note that multiple _streams_ can (and will) be opened on a single
  482. // open _driver instance_. Do not store/create instance data that must
  483. // be unique for each stream in this function. See the acmdStreamOpen
  484. // function for information on conversion streams.
  485. //
  486. // Arguments:
  487. // HDRVR hdrvr: Driver handle that will be returned to caller of the
  488. // OpenDriver function. Normally, this will be the ACM--but this is
  489. // not guaranteed. For example, if an ACM driver is implemented within
  490. // a waveform driver, then the driver will be opened by both MMSYSTEM
  491. // and the ACM.
  492. //
  493. // LPACMDRVOPENDESC paod: Open description defining how the ACM driver
  494. // is being opened. This argument may be NULL--see the comments below
  495. // for more information.
  496. //
  497. // Return (LRESULT):
  498. // The return value is non-zero if the open is successful. A zero
  499. // return signifies that the driver cannot be opened.
  500. //
  501. //--------------------------------------------------------------------------;
  502. LRESULT FNLOCAL acmdDriverOpen
  503. (
  504. HDRVR hdrvr,
  505. LPACMDRVOPENDESC paod
  506. )
  507. {
  508. PDRIVERINSTANCE pdi;
  509. //
  510. // the [optional] open description that is passed to this driver can
  511. // be from multiple 'managers.' for example, AVI looks for installable
  512. // drivers that are tagged with 'vidc' and 'vcap'. we need to verify
  513. // that we are being opened as an Audio Compression Manager driver.
  514. //
  515. // if paod is NULL, then the driver is being opened for some purpose
  516. // other than converting (that is, there will be no stream open
  517. // requests for this instance of being opened). the most common case
  518. // of this is the Control Panel's Drivers option checking for config
  519. // support (DRV_[QUERY]CONFIGURE).
  520. //
  521. // we want to succeed this open, but be able to know that this
  522. // open instance is bogus for creating streams. for this purpose we
  523. // leave most of the members of our instance structure that we
  524. // allocate below as zero...
  525. //
  526. if (NULL != paod)
  527. {
  528. //
  529. // refuse to open if we are not being opened as an ACM driver.
  530. // note that we do NOT modify the value of paod->dwError in this
  531. // case.
  532. //
  533. if (ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC != paod->fccType)
  534. {
  535. return (0L);
  536. }
  537. }
  538. //
  539. // we are being opened as an installable driver--we can allocate some
  540. // instance data to be returned in dwId argument of the DriverProc;
  541. // or simply return non-zero to succeed the open.
  542. //
  543. // this driver allocates a small instance structure. note that we
  544. // rely on allocating the memory as zero-initialized!
  545. //
  546. pdi = (PDRIVERINSTANCE)LocalAlloc(LPTR, sizeof(*pdi));
  547. if (NULL == pdi)
  548. {
  549. //
  550. // if this open attempt was as an ACM driver, then return the
  551. // reason we are failing in the open description structure..
  552. //
  553. if (NULL != paod)
  554. {
  555. paod->dwError = MMSYSERR_NOMEM;
  556. }
  557. //
  558. // fail to open
  559. //
  560. return (0L);
  561. }
  562. //
  563. // fill in our instance structure... note that this instance data
  564. // can be anything that the ACM driver wishes to maintain the
  565. // open driver instance. this data should not contain any information
  566. // that must be maintained per open stream since multiple streams
  567. // can be opened on a single driver instance.
  568. //
  569. // also note that we do _not_ check the version of the ACM opening
  570. // us (paod->dwVersion) to see if it is at least new enough to work
  571. // with this driver (for example, if this driver required Version 3.0
  572. // of the ACM and a Version 2.0 installation tried to open us). the
  573. // reason we do not fail is to allow the ACM to get the driver details
  574. // which contains the version of the ACM that is _required_ by this
  575. // driver. the ACM will examine that value (in padd->vdwACM) and
  576. // do the right thing for this driver... like not load it and inform
  577. // the user of the problem.
  578. //
  579. pdi->hdrvr = hdrvr;
  580. pdi->hinst = GetDriverModuleHandle(hdrvr); // Module handle.
  581. if (NULL != paod)
  582. {
  583. pdi->fnDriverProc = NULL;
  584. pdi->fccType = paod->fccType;
  585. pdi->vdwACM = paod->dwVersion;
  586. pdi->fdwOpen = paod->dwFlags;
  587. paod->dwError = MMSYSERR_NOERROR;
  588. }
  589. #ifdef IMAADPCM_USECONFIG
  590. //
  591. // Get config info for this driver. If we're not passed an
  592. // an ACMDRVOPENDESC structure then we'll assume we are being
  593. // opened for configuration and will put off getting the config
  594. // info until we receive the DRV_CONFIGURE message. Otherwise we
  595. // get the config info now using the alias passed through the
  596. // ACMDRVOPENDESC structure.
  597. //
  598. pdi->hkey = NULL; // This is important!
  599. if (NULL != paod)
  600. {
  601. #if defined(WIN32) && !defined(UNICODE)
  602. //
  603. // We must translate the UNICODE alias name to an ANSI version
  604. // that we can use.
  605. //
  606. LPSTR lpstr;
  607. int iLen;
  608. //
  609. // Calculate required length without calling UNICODE APIs or CRT.
  610. //
  611. iLen = WideCharToMultiByte( GetACP(), 0, paod->pszAliasName,-1,
  612. NULL, 0, NULL, NULL );
  613. lpstr = (LPSTR)GlobalAllocPtr( GPTR, iLen );
  614. if (NULL != lpstr)
  615. {
  616. WideCharToMultiByte( GetACP(), 0, paod->pszAliasName, iLen,
  617. lpstr, iLen, NULL, NULL );
  618. }
  619. acmdDriverConfigInit(pdi, lpstr); // Note: OK to pass lpstr==NULL
  620. if (NULL != lpstr)
  621. {
  622. GlobalFreePtr( lpstr );
  623. }
  624. #else
  625. acmdDriverConfigInit(pdi, paod->pszAliasName);
  626. #endif // WIN32 && !UNICODE
  627. }
  628. #else
  629. //
  630. // Actually, fdwConfig is not used - there is no configuration data.
  631. //
  632. pdi->fdwConfig = 0L;
  633. #endif // IMAADPCM_USECONFIG
  634. //
  635. // non-zero return is success for DRV_OPEN
  636. //
  637. return ((LRESULT)pdi);
  638. } // acmdDriverOpen()
  639. //--------------------------------------------------------------------------;
  640. //
  641. // LRESULT acmdDriverClose
  642. //
  643. // Description:
  644. // This function handles the DRV_CLOSE message for the ACM driver. The
  645. // driver receives a DRV_CLOSE message for each succeeded DRV_OPEN
  646. // message (see acmdDriverOpen). The driver will only receive a close
  647. // message for _successful_ opens.
  648. //
  649. // Arguments:
  650. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  651. // This structure is [optionally] allocated during the DRV_OPEN message
  652. // which is handled by the acmdDriverOpen function.
  653. //
  654. // Return (LRESULT):
  655. // The return value is non-zero if the open instance can be closed.
  656. // A zero return signifies that the ACM driver instance could not be
  657. // closed.
  658. //
  659. // NOTE! It is _strongly_ recommended that the driver never fail to
  660. // close. Note that the ACM will never allow a driver instance to
  661. // be closed if there are open streams. An ACM driver does not need
  662. // to check for this case.
  663. //
  664. //--------------------------------------------------------------------------;
  665. LRESULT FNLOCAL acmdDriverClose
  666. (
  667. PDRIVERINSTANCE pdi
  668. )
  669. {
  670. #ifdef IMAADPCM_USECONFIG
  671. //
  672. // Release the registry key, if we allocated one.
  673. //
  674. if( NULL != pdi->hkey )
  675. {
  676. (void)RegCloseKey( pdi->hkey );
  677. }
  678. #endif
  679. //
  680. // check to see if we allocated instance data. if we did not, then
  681. // immediately succeed.
  682. //
  683. if (NULL != pdi)
  684. {
  685. //
  686. // close down the driver instance. this driver simply needs
  687. // to free the instance data structure... note that if this
  688. // 'free' fails, then this ACM driver probably trashed its
  689. // heap; assume we didn't do that.
  690. //
  691. LocalFree((HLOCAL)pdi);
  692. }
  693. //
  694. // non-zero return is success for DRV_CLOSE
  695. //
  696. return (1L);
  697. } // acmdDriverClose()
  698. //--------------------------------------------------------------------------;
  699. //
  700. // LRESULT acmdDriverConfigure
  701. //
  702. // Description:
  703. // This function is called to handle the DRV_[QUERY]CONFIGURE messages.
  704. // These messages are for 'configuration' support of the driver.
  705. // Normally this will be for 'hardware'--that is, a dialog should be
  706. // displayed to configure ports, IRQ's, memory mappings, etc if it
  707. // needs to. However, a software only ACM driver may also require
  708. // configuration for 'what is real time' or other quality vs time
  709. // issues.
  710. //
  711. // The most common way that these messages are generated under Win 3.1
  712. // and NT Product 1 is from the Control Panel's Drivers option. Other
  713. // sources may generate these messages in future versions of Windows.
  714. //
  715. // Arguments:
  716. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  717. // This structure is [optionally] allocated during the DRV_OPEN message
  718. // which is handled by the acmdDriverOpen function.
  719. //
  720. // HWND hwnd: Handle to parent window to use when displaying the
  721. // configuration dialog box. An ACM driver is _required_ to display a
  722. // modal dialog box using this hwnd argument as the parent. This
  723. // argument may be (HWND)-1 which tells the driver that it is only
  724. // being queried for configuration support.
  725. //
  726. // LPDRVCONFIGINFO pdci: Pointer to optional DRVCONFIGINFO structure.
  727. // If this argument is NULL, then the ACM driver should invent its own
  728. // storage location.
  729. //
  730. // Return (LRESULT):
  731. // If the driver is being 'queried' for configuration support (that is,
  732. // hwnd == (HWND)-1), then non-zero should be returned specifying
  733. // the driver does support a configuration dialog--or zero should be
  734. // returned specifying that no configuration dialog is supported.
  735. //
  736. // If the driver is being called to display the configuration dialog
  737. // (that is, hwnd != (HWND)-1), then one of the following values
  738. // should be returned:
  739. //
  740. // DRVCNF_CANCEL (0x0000): specifies that the dialog was displayed
  741. // and canceled by the user. this value should also be returned if
  742. // no configuration information was modified.
  743. //
  744. // DRVCNF_OK (0x0001): specifies that the dialog was displayed and
  745. // the user pressed OK. This value should be returned even if the
  746. // user didn't change anything - otherwise, the driver may not
  747. // install properly.
  748. //
  749. // DRVCNF_RESTART (0x0002): specifies that the dialog was displayed
  750. // and some configuration information was changed that requires
  751. // Windows to be restarted before the changes take affect. the driver
  752. // should remain configured with current values until the driver
  753. // has been 'rebooted'.
  754. //
  755. //--------------------------------------------------------------------------;
  756. LRESULT FNLOCAL acmdDriverConfigure
  757. (
  758. PDRIVERINSTANCE pdi,
  759. HWND hwnd,
  760. LPDRVCONFIGINFO pdci
  761. )
  762. {
  763. #ifdef IMAADPCM_USECONFIG
  764. INT_PTR n;
  765. #endif
  766. //
  767. // first check to see if we are only being queried for configuration
  768. // support. if hwnd == (HWND)-1 then we are being queried and should
  769. // return zero for 'not supported' and non-zero for 'supported'.
  770. //
  771. if ((HWND)-1 == hwnd)
  772. {
  773. #ifdef IMAADPCM_USECONFIG
  774. //
  775. // this ACM driver supports a configuration dialog box, so
  776. // return non-zero...
  777. //
  778. return (1L);
  779. #else
  780. //
  781. // this ACM driver does not support a configuration dialog box, so
  782. // return zero...
  783. //
  784. return (0L);
  785. #endif
  786. }
  787. //
  788. // we are being asked to bring up our configuration dialog. if this
  789. // driver supports a configuration dialog box, then after the dialog
  790. // is dismissed we must return one of the following values:
  791. //
  792. // DRVCNF_CANCEL (0x0000): specifies that the dialog was displayed
  793. // and canceled by the user. this value should also be returned if
  794. // no configuration information was modified.
  795. //
  796. // DRVCNF_OK (0x0001): specifies that the dialog was displayed and
  797. // the user pressed OK. This value should be returned even if the
  798. // user didn't change anything - otherwise, the driver may not
  799. // install properly.
  800. //
  801. // DRVCNF_RESTART (0x0002): specifies that the dialog was displayed
  802. // and some configuration information was changed that requires
  803. // Windows to be restarted before the changes take affect. the driver
  804. // should remain configured with current values until the driver
  805. // has been 'rebooted'.
  806. //
  807. #ifdef IMAADPCM_USECONFIG
  808. if (NULL == pdci)
  809. {
  810. //
  811. // !!!
  812. //
  813. DPF(2,"acmdDriverConfigure returning CANCEL due to NULL==pdci.");
  814. return (DRVCNF_CANCEL);
  815. }
  816. pdi->pdci = pdci;
  817. //
  818. // We may not have our config info yet if the driver has only been
  819. // opened specifically for configuration. So, read our configuration
  820. // using the alias passed in the DRVCONFIGINFO structure passed
  821. // through the DRV_CONFIGURE message
  822. //
  823. #if (defined(WIN32) && !defined(UNICODE))
  824. {
  825. //
  826. // We must translate the UNICODE alias name to an ANSI version
  827. // that we can use.
  828. //
  829. LPSTR lpstr;
  830. int iLen;
  831. //
  832. // Calculate required length without calling UNICODE APIs or CRT.
  833. //
  834. iLen = WideCharToMultiByte( GetACP(), 0, pdci->lpszDCIAliasName, -1,
  835. NULL, 0, NULL, NULL );
  836. lpstr = (LPSTR)GlobalAllocPtr( GPTR, iLen );
  837. if (NULL != lpstr)
  838. {
  839. WideCharToMultiByte( GetACP(), 0, pdci->lpszDCIAliasName, iLen,
  840. lpstr, iLen, NULL, NULL );
  841. }
  842. acmdDriverConfigInit(pdi, lpstr); // Note: OK to pass lpstr==NULL
  843. if (NULL != lpstr)
  844. {
  845. GlobalFreePtr( lpstr );
  846. }
  847. }
  848. #else
  849. acmdDriverConfigInit(pdi, pdci->lpszDCIAliasName);
  850. #endif // WIN32 && !UNICODE
  851. n = DialogBoxParam(pdi->hinst,
  852. IDD_CONFIG,
  853. hwnd,
  854. acmdDlgProcConfigure,
  855. (LPARAM)pdi);
  856. pdi->pdci = NULL;
  857. return ((LRESULT)n);
  858. #else
  859. //
  860. // return DRVCNF_CANCEL--this ACM driver does not support configuration
  861. //
  862. return (DRVCNF_CANCEL);
  863. #endif // IMAADPCM_USECONFIG
  864. } // acmdDriverConfigure()
  865. //--------------------------------------------------------------------------;
  866. //
  867. // LRESULT acmdDriverDetails
  868. //
  869. // Description:
  870. // This function handles the ACMDM_DRIVER_DETAILS message. The ACM
  871. // driver is responsible for filling in the ACMDRIVERDETAILS structure
  872. // with various information.
  873. //
  874. // NOTE! It is *VERY* important that you fill in your ACMDRIVERDETAILS
  875. // structure correctly. The ACM and applications must be able to
  876. // rely on this information.
  877. //
  878. // WARNING! The _reserved_ bits of any fields of the ACMDRIVERDETAILS
  879. // structure are _exactly that_: RESERVED. Do NOT use any extra
  880. // flag bits, etc. for custom information. The proper way to add
  881. // custom capabilities to your ACM driver is this:
  882. //
  883. // o define a new message in the ACMDM_USER range.
  884. //
  885. // o an application that wishes to use one of these extra features
  886. // should then:
  887. //
  888. // o open the driver with acmDriverOpen.
  889. //
  890. // o check for the proper wMid and wPid using acmDriverDetails.
  891. //
  892. // o send the 'user defined' message with acmDriverMessage
  893. // to retrieve additional information, etc.
  894. //
  895. // o close the driver with acmDriverClose.
  896. //
  897. // Arguments:
  898. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  899. // This structure is [optionally] allocated during the DRV_OPEN message
  900. // which is handled by the acmdDriverOpen function.
  901. //
  902. // LPACMDRIVERDETAILS padd: Pointer to ACMDRIVERDETAILS structure to
  903. // fill in for the caller. This structure may be larger or smaller than
  904. // the current definition of ACMDRIVERDETAILS--cbStruct specifies the
  905. // valid size.
  906. //
  907. // Return (LRESULT):
  908. // The return value is zero (MMSYSERR_NOERROR) for success. Non-zero
  909. // signifies that the driver details could not be retrieved.
  910. //
  911. // NOTE THAT THIS FUNCTION SHOULD NEVER FAIL! There are two possible
  912. // error conditions:
  913. //
  914. // o if padd is NULL or an invalid pointer.
  915. //
  916. // o if cbStruct is less than four; in this case, there is not enough
  917. // room to return the number of bytes filled in.
  918. //
  919. // Because these two error conditions are easily defined, the ACM
  920. // will catch these errors. The driver does NOT need to check for these
  921. // conditions.
  922. //
  923. //--------------------------------------------------------------------------;
  924. LRESULT FNLOCAL acmdDriverDetails
  925. (
  926. PDRIVERINSTANCE pdi,
  927. LPACMDRIVERDETAILS padd
  928. )
  929. {
  930. ACMDRIVERDETAILS add;
  931. DWORD cbStruct;
  932. //
  933. // it is easiest to fill in a temporary structure with valid info
  934. // and then copy the requested number of bytes to the destination
  935. // buffer.
  936. //
  937. cbStruct = min(padd->cbStruct, sizeof(ACMDRIVERDETAILS));
  938. add.cbStruct = cbStruct;
  939. //
  940. // for the current implementation of an ACM driver, the fccType and
  941. // fccComp members *MUST* always be ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC
  942. // ('audc') and ACMDRIVERDETAILS_FCCCOMP_UNDEFINED (0) respectively.
  943. //
  944. add.fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
  945. add.fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
  946. //
  947. // the manufacturer id (wMid) and product id (wPid) must be filled
  948. // in with your company's _registered_ identifier's. for more
  949. // information on these identifier's and how to get them registered
  950. // contact Microsoft and get the Multimedia Developer Registration Kit:
  951. //
  952. // Microsoft Corporation
  953. // Multimedia Technology Group
  954. // One Microsoft Way
  955. // Redmond, WA 98052-6399
  956. //
  957. // Developer Services Phone: (800) 227-4679 x11771
  958. //
  959. // note that during the development phase or your ACM driver, you may
  960. // use the reserved value of '0' for both wMid and wPid. however it
  961. // is not acceptable to ship a driver with these values.
  962. //
  963. add.wMid = MM_MICROSOFT;
  964. add.wPid = MM_MSFT_ACM_IMAADPCM;
  965. //
  966. // the vdwACM and vdwDriver members contain version information for
  967. // the driver.
  968. //
  969. // vdwACM: must contain the version of the *ACM* that the driver was
  970. // _designed_ for. this is the _minimum_ version number of the ACM
  971. // that the driver will work with. this value must be >= V2.00.000.
  972. //
  973. // vdwDriver: the version of this ACM driver.
  974. //
  975. // ACM driver versions are 32 bit numbers broken into three parts as
  976. // follows (note these parts are displayed as decimal values):
  977. //
  978. // bits 24 - 31: 8 bit _major_ version number
  979. // bits 16 - 23: 8 bit _minor_ version number
  980. // bits 0 - 15: 16 bit build number
  981. //
  982. add.vdwACM = VERSION_MSACM;
  983. add.vdwDriver = VERSION_ACM_DRIVER;
  984. //
  985. // the following flags are used to specify the type of conversion(s)
  986. // that the ACM driver supports. note that a driver may support one or
  987. // more of these flags in any combination.
  988. //
  989. // ACMDRIVERDETAILS_SUPPORTF_CODEC: this flag is set if the driver
  990. // supports conversions from one format tag to another format tag. for
  991. // example, if a converter compresses or decompresses WAVE_FORMAT_PCM
  992. // and WAVE_FORMAT_IMA_ADPCM, then this bit should be set. this is
  993. // true even if the data is not actually changed in size--for example
  994. // a conversion from u-Law to A-Law will still set this bit because
  995. // the format tags differ.
  996. //
  997. // ACMDRIVERDETAILS_SUPPORTF_CONVERTER: this flags is set if the
  998. // driver supports conversions on the same format tag. as an example,
  999. // the PCM converter that is built into the ACM sets this bit (and only
  1000. // this bit) because it converts only between PCM formats (bits, sample
  1001. // rate).
  1002. //
  1003. // ACMDRIVERDETAILS_SUPPORTF_FILTER: this flag is set if the driver
  1004. // supports transformations on a single format tag but does change
  1005. // the base characteristics of the format (bit depth, sample rate, etc
  1006. // will remain the same). for example, a driver that changed the
  1007. // 'volume' of PCM data or applied a low pass filter would set this bit.
  1008. //
  1009. add.fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
  1010. //
  1011. // the number of individual format tags this ACM driver supports. for
  1012. // example, if a driver uses the WAVE_FORMAT_IMA_ADPCM and
  1013. // WAVE_FORMAT_PCM format tags, then this value would be two. if the
  1014. // driver only supports filtering on WAVE_FORMAT_PCM, then this value
  1015. // would be one. if this driver supported WAVE_FORMAT_ALAW,
  1016. // WAVE_FORMAT_MULAW and WAVE_FORMAT_PCM, then this value would be
  1017. // three. etc, etc.
  1018. //
  1019. add.cFormatTags = ACM_DRIVER_MAX_FORMAT_TAGS;
  1020. //
  1021. // the number of individual filter tags this ACM driver supports. if
  1022. // a driver supports no filters (ACMDRIVERDETAILS_SUPPORTF_FILTER is
  1023. // NOT set in the fdwSupport member), then this value must be zero.
  1024. //
  1025. add.cFilterTags = ACM_DRIVER_MAX_FILTER_TAGS;
  1026. //
  1027. // the remaining members in the ACMDRIVERDETAILS structure are sometimes
  1028. // not needed. because of this we make a quick check to see if we
  1029. // should go through the effort of filling in these members.
  1030. //
  1031. if (FIELD_OFFSET(ACMDRIVERDETAILS, hicon) < cbStruct)
  1032. {
  1033. //
  1034. // fill in the hicon member will a handle to a custom icon for
  1035. // the ACM driver. this allows the driver to be represented by
  1036. // an application graphically (usually this will be a company
  1037. // logo or something). if a driver does not wish to have a custom
  1038. // icon displayed, then simply set this member to NULL and a
  1039. // generic icon will be displayed instead.
  1040. //
  1041. // See the MSFILTER sample for a codec which contains a custom icon.
  1042. //
  1043. add.hicon = NULL;
  1044. //
  1045. // the short name and long name are used to represent the driver
  1046. // in a unique description. the short name is intended for small
  1047. // display areas (for example, in a menu or combo box). the long
  1048. // name is intended for more descriptive displays (for example,
  1049. // in an 'about box').
  1050. //
  1051. // NOTE! an ACM driver should never place formatting characters
  1052. // of any sort in these strings (for example CR/LF's, etc). it
  1053. // is up to the application to format the text.
  1054. //
  1055. LoadStringCodec(pdi->hinst, IDS_ACM_DRIVER_SHORTNAME, add.szShortName, SIZEOFACMSTR(add.szShortName));
  1056. LoadStringCodec(pdi->hinst, IDS_ACM_DRIVER_LONGNAME, add.szLongName, SIZEOFACMSTR(add.szLongName));
  1057. //
  1058. // the last three members are intended for 'about box' information.
  1059. // these members are optional and may be zero length strings if
  1060. // the driver wishes.
  1061. //
  1062. // NOTE! an ACM driver should never place formatting characters
  1063. // of any sort in these strings (for example CR/LF's, etc). it
  1064. // is up to the application to format the text.
  1065. //
  1066. if (FIELD_OFFSET(ACMDRIVERDETAILS, szCopyright) < cbStruct)
  1067. {
  1068. LoadStringCodec(pdi->hinst, IDS_ACM_DRIVER_COPYRIGHT, add.szCopyright, SIZEOFACMSTR(add.szCopyright));
  1069. LoadStringCodec(pdi->hinst, IDS_ACM_DRIVER_LICENSING, add.szLicensing, SIZEOFACMSTR(add.szLicensing));
  1070. LoadStringCodec(pdi->hinst, IDS_ACM_DRIVER_FEATURES, add.szFeatures, SIZEOFACMSTR(add.szFeatures));
  1071. }
  1072. }
  1073. //
  1074. // now copy the correct number of bytes to the caller's buffer
  1075. //
  1076. _fmemcpy(padd, &add, (UINT)add.cbStruct);
  1077. //
  1078. // success!
  1079. //
  1080. return (MMSYSERR_NOERROR);
  1081. } // acmdDriverDetails()
  1082. //--------------------------------------------------------------------------;
  1083. //
  1084. // LRESULT acmdDriverAbout
  1085. //
  1086. // Description:
  1087. // This function is called to handle the ACMDM_DRIVER_ABOUT message.
  1088. // An ACM driver has the option of displaying its own 'about box' or
  1089. // letting the ACM (or calling application) display one for it. This
  1090. // message is normally sent by the Control Panel's Sound Mapper
  1091. // option.
  1092. //
  1093. // It is recommended that an ACM driver allow a default about box
  1094. // be displayed for it--there should be no reason to bloat the size
  1095. // of a driver to simply display copyright, etc information when that
  1096. // information is contained in the ACMDRIVERDETAILS structure.
  1097. //
  1098. // Arguments:
  1099. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  1100. // This structure is [optionally] allocated during the DRV_OPEN message
  1101. // which is handled by the acmdDriverOpen function.
  1102. //
  1103. // HWND hwnd: Handle to parent window to use when displaying the
  1104. // configuration dialog box. An ACM driver is _required_ to display a
  1105. // modal dialog box using this hwnd argument as the parent. This
  1106. // argument may be (HWND)-1 which tells the driver that it is only
  1107. // being queried for about box support.
  1108. //
  1109. // Return (LRESULT):
  1110. // The return value is MMSYSERR_NOTSUPPORTED if the ACM driver does
  1111. // not support a custom dialog box. In this case, the ACM or calling
  1112. // application will display a generic about box using the information
  1113. // contained in the ACMDRIVERDETAILS structure returned by the
  1114. // ACMDM_DRIVER_DETAILS message.
  1115. //
  1116. // If the driver chooses to display its own dialog box, then after
  1117. // the dialog is dismissed by the user, MMSYSERR_NOERROR should be
  1118. // returned.
  1119. //
  1120. // If the hwnd argument is equal to (HWND)-1, then no dialog should
  1121. // be displayed (the driver is only being queried for support). The
  1122. // driver must still return MMSYSERR_NOERROR (supported) or
  1123. // MMSYSERR_NOTSUPPORTED (no custom about box supported).
  1124. //
  1125. //--------------------------------------------------------------------------;
  1126. LRESULT FNLOCAL acmdDriverAbout
  1127. (
  1128. PDRIVERINSTANCE pdi,
  1129. HWND hwnd
  1130. )
  1131. {
  1132. //
  1133. // first check to see if we are only being queried for custom about
  1134. // box support. if hwnd == (HWND)-1 then we are being queried and
  1135. // should return MMSYSERR_NOTSUPPORTED for 'not supported' and
  1136. // MMSYSERR_NOERROR for 'supported'.
  1137. //
  1138. if ((HWND)-1 == hwnd)
  1139. {
  1140. //
  1141. // this ACM driver does NOT support a custom about box, so
  1142. // return MMSYSERR_NOTSUPPORTED...
  1143. //
  1144. return (MMSYSERR_NOTSUPPORTED);
  1145. }
  1146. //
  1147. // this driver does not support a custom dialog, so tell the ACM or
  1148. // calling application to display one for us. note that this is the
  1149. // _recommended_ method for consistency and simplicity of ACM drivers.
  1150. // why write code when you don't have to?
  1151. //
  1152. return (MMSYSERR_NOTSUPPORTED);
  1153. } // acmdDriverAbout()
  1154. //==========================================================================;
  1155. //
  1156. //
  1157. //
  1158. //
  1159. //==========================================================================;
  1160. //--------------------------------------------------------------------------;
  1161. //
  1162. // LRESULT acmdFormatSuggest
  1163. //
  1164. // Description:
  1165. // This function handles the ACMDM_FORMAT_SUGGEST message. The purpose
  1166. // of this function is to provide a way for the ACM, a wave mapper or
  1167. // an application to quickly get a destination format that this driver
  1168. // can convert the source format to. The 'suggested' format should
  1169. // be as close to a common format as possible. This message is normally
  1170. // sent in response to an acmFormatSuggest function call.
  1171. //
  1172. // Another way to think about this message is: what format would this
  1173. // driver like to convert the source format to?
  1174. //
  1175. // The caller may place restrictions on the destination format that
  1176. // should be suggested. The padfs->fdwSuggest member contains the
  1177. // restriction bits passed by the caller--see the description for
  1178. // the return value for more information.
  1179. //
  1180. // Arguments:
  1181. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  1182. // This structure is [optionally] allocated during the DRV_OPEN message
  1183. // which is handled by the acmdDriverOpen function.
  1184. //
  1185. // LPACMDRVFORMATSUGGEST padfs: Pointer to an ACMDRVFORMATSUGGEST
  1186. // structure that describes the source and destination (possibly with
  1187. // restrictions) for a conversion.
  1188. //
  1189. // Return (LRESULT):
  1190. // The return value is zero (MMSYSERR_NOERROR) if this function
  1191. // succeeds with no errors. The return value is a non-zero error code
  1192. // if the function fails.
  1193. //
  1194. // The driver should return MMSYSERR_NOTSUPPORTED if one or more of
  1195. // the destination restriction bits is not supported. It is strongly
  1196. // recommended that the driver support at least the following suggestion
  1197. // restriction bits:
  1198. //
  1199. // ACM_FORMATSUGGESTF_WFORMATTAG: The destination format tag must be
  1200. // the same as the wFormatTag member in the destination format header.
  1201. //
  1202. // ACM_FORMATSUGGESTF_NCHANNELS: The destination channel count must be
  1203. // the same as the nChannels member in the destination format header.
  1204. //
  1205. // ACM_FORMATSUGGESTF_NSAMPLESPERSEC: The destination samples per
  1206. // second must be the same as the nSamplesPerSec member in the
  1207. // destination format header.
  1208. //
  1209. // ACM_FORMATSUGGESTF_WBITSPERSAMPLE: The destination bits per sample
  1210. // must be the same as the wBitsPerSample member in the destination
  1211. // format header.
  1212. //
  1213. // If no destintation format can be suggested, then the driver should
  1214. // return ACMERR_NOTPOSSIBLE.
  1215. //
  1216. //--------------------------------------------------------------------------;
  1217. LRESULT FNLOCAL acmdFormatSuggest
  1218. (
  1219. PDRIVERINSTANCE pdi,
  1220. LPACMDRVFORMATSUGGEST padfs
  1221. )
  1222. {
  1223. #define ACMD_FORMAT_SUGGEST_SUPPORT (ACM_FORMATSUGGESTF_WFORMATTAG | \
  1224. ACM_FORMATSUGGESTF_NCHANNELS | \
  1225. ACM_FORMATSUGGESTF_NSAMPLESPERSEC |\
  1226. ACM_FORMATSUGGESTF_WBITSPERSAMPLE)
  1227. LPWAVEFORMATEX pwfxSrc;
  1228. LPWAVEFORMATEX pwfxDst;
  1229. LPIMAADPCMWAVEFORMAT pwfadpcm;
  1230. DWORD fdwSuggest;
  1231. //
  1232. // grab the suggestion restriction bits and verify that we support
  1233. // the ones that are specified... an ACM driver must return the
  1234. // MMSYSERR_NOTSUPPORTED if the suggestion restriction bits specified
  1235. // are not supported.
  1236. //
  1237. fdwSuggest = (ACM_FORMATSUGGESTF_TYPEMASK & padfs->fdwSuggest);
  1238. if (~ACMD_FORMAT_SUGGEST_SUPPORT & fdwSuggest)
  1239. return (MMSYSERR_NOTSUPPORTED);
  1240. //
  1241. // get the source and destination formats in more convenient variables
  1242. //
  1243. pwfxSrc = padfs->pwfxSrc;
  1244. pwfxDst = padfs->pwfxDst;
  1245. //
  1246. //
  1247. //
  1248. //
  1249. switch (pwfxSrc->wFormatTag)
  1250. {
  1251. case WAVE_FORMAT_PCM:
  1252. //
  1253. // strictly verify that the source format is acceptable for
  1254. // this driver
  1255. //
  1256. if (!pcmIsValidFormat(pwfxSrc))
  1257. break;
  1258. //
  1259. // if the destination format tag is restricted, verify that
  1260. // it is within our capabilities...
  1261. //
  1262. // this driver is only able to encode to IMA ADPCM
  1263. //
  1264. if (ACM_FORMATSUGGESTF_WFORMATTAG & fdwSuggest)
  1265. {
  1266. if (WAVE_FORMAT_IMA_ADPCM != pwfxDst->wFormatTag)
  1267. return (ACMERR_NOTPOSSIBLE);
  1268. }
  1269. else
  1270. {
  1271. pwfxDst->wFormatTag = WAVE_FORMAT_IMA_ADPCM;
  1272. }
  1273. //
  1274. // if the destination channel count is restricted, verify that
  1275. // it is within our capabilities...
  1276. //
  1277. // this driver is not able to change the number of channels
  1278. //
  1279. if (ACM_FORMATSUGGESTF_NCHANNELS & fdwSuggest)
  1280. {
  1281. if (pwfxSrc->nChannels != pwfxDst->nChannels)
  1282. return (ACMERR_NOTPOSSIBLE);
  1283. }
  1284. else
  1285. {
  1286. pwfxDst->nChannels = pwfxSrc->nChannels;
  1287. }
  1288. //
  1289. // if the destination samples per second is restricted, verify
  1290. // that it is within our capabilities...
  1291. //
  1292. // this driver is not able to change the sample rate
  1293. //
  1294. if (ACM_FORMATSUGGESTF_NSAMPLESPERSEC & fdwSuggest)
  1295. {
  1296. if (pwfxSrc->nSamplesPerSec != pwfxDst->nSamplesPerSec)
  1297. return (ACMERR_NOTPOSSIBLE);
  1298. }
  1299. else
  1300. {
  1301. pwfxDst->nSamplesPerSec = pwfxSrc->nSamplesPerSec;
  1302. }
  1303. //
  1304. // if the destination bits per sample is restricted, verify
  1305. // that it is within our capabilities...
  1306. //
  1307. // this driver is only able to encode to 4 bit
  1308. //
  1309. if (ACM_FORMATSUGGESTF_WBITSPERSAMPLE & fdwSuggest)
  1310. {
  1311. if (IMAADPCM_BITS_PER_SAMPLE != pwfxDst->wBitsPerSample)
  1312. return (ACMERR_NOTPOSSIBLE);
  1313. }
  1314. else
  1315. {
  1316. pwfxDst->wBitsPerSample = IMAADPCM_BITS_PER_SAMPLE;
  1317. }
  1318. //
  1319. // at this point, we have filled in all fields except the
  1320. // following for our 'suggested' destination format:
  1321. //
  1322. // nAvgBytesPerSec
  1323. // nBlockAlign
  1324. // cbSize
  1325. //
  1326. // wSamplesPerBlock -> IMA ADPCM extended information
  1327. //
  1328. pwfxDst->nBlockAlign = imaadpcmBlockAlign(pwfxDst);
  1329. pwfxDst->nAvgBytesPerSec = imaadpcmAvgBytesPerSec(pwfxDst);
  1330. pwfxDst->cbSize = IMAADPCM_WFX_EXTRA_BYTES;
  1331. pwfadpcm = (LPIMAADPCMWAVEFORMAT)pwfxDst;
  1332. pwfadpcm->wSamplesPerBlock = imaadpcmSamplesPerBlock(pwfxDst);
  1333. return (MMSYSERR_NOERROR);
  1334. case WAVE_FORMAT_IMA_ADPCM:
  1335. //
  1336. // strictly verify that the source format is acceptable for
  1337. // this driver
  1338. //
  1339. if (!imaadpcmIsValidFormat(pwfxSrc))
  1340. return (ACMERR_NOTPOSSIBLE);
  1341. //
  1342. // if the destination format tag is restricted, verify that
  1343. // it is within our capabilities...
  1344. //
  1345. // this driver is only able to decode to PCM
  1346. //
  1347. if (ACM_FORMATSUGGESTF_WFORMATTAG & fdwSuggest)
  1348. {
  1349. if (WAVE_FORMAT_PCM != pwfxDst->wFormatTag)
  1350. return (ACMERR_NOTPOSSIBLE);
  1351. }
  1352. else
  1353. {
  1354. pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
  1355. }
  1356. //
  1357. // if the destination channel count is restricted, verify that
  1358. // it is within our capabilities...
  1359. //
  1360. // this driver is not able to change the number of channels
  1361. //
  1362. if (ACM_FORMATSUGGESTF_NCHANNELS & fdwSuggest)
  1363. {
  1364. if (pwfxSrc->nChannels != pwfxDst->nChannels)
  1365. return (ACMERR_NOTPOSSIBLE);
  1366. }
  1367. else
  1368. {
  1369. pwfxDst->nChannels = pwfxSrc->nChannels;
  1370. }
  1371. //
  1372. // if the destination samples per second is restricted, verify
  1373. // that it is within our capabilities...
  1374. //
  1375. // this driver is not able to change the sample rate
  1376. //
  1377. if (ACM_FORMATSUGGESTF_NSAMPLESPERSEC & fdwSuggest)
  1378. {
  1379. if (pwfxSrc->nSamplesPerSec != pwfxDst->nSamplesPerSec)
  1380. return (ACMERR_NOTPOSSIBLE);
  1381. }
  1382. else
  1383. {
  1384. pwfxDst->nSamplesPerSec = pwfxSrc->nSamplesPerSec;
  1385. }
  1386. //
  1387. // if the destination bits per sample is restricted, verify
  1388. // that it is within our capabilities...
  1389. //
  1390. // this driver is only able to decode to 16 or 8 bit
  1391. //
  1392. if (ACM_FORMATSUGGESTF_WBITSPERSAMPLE & fdwSuggest)
  1393. {
  1394. if ((16 != pwfxDst->wBitsPerSample) &&
  1395. (8 != pwfxDst->wBitsPerSample))
  1396. return (ACMERR_NOTPOSSIBLE);
  1397. }
  1398. else
  1399. {
  1400. pwfxDst->wBitsPerSample = 16;
  1401. }
  1402. //
  1403. // at this point, we have filled in all fields except the
  1404. // following for our 'suggested' destination format:
  1405. //
  1406. // nAvgBytesPerSec
  1407. // nBlockAlign
  1408. // cbSize !!! not used for PCM !!!
  1409. //
  1410. pwfxDst->nBlockAlign = PCM_BLOCKALIGNMENT(pwfxDst);
  1411. pwfxDst->nAvgBytesPerSec = pwfxDst->nSamplesPerSec *
  1412. pwfxDst->nBlockAlign;
  1413. // pwfxDst->cbSize = not used;
  1414. return (MMSYSERR_NOERROR);
  1415. }
  1416. //
  1417. // can't suggest anything because either the source format is foreign
  1418. // or the destination format has restrictions that this ACM driver
  1419. // cannot deal with.
  1420. //
  1421. return (ACMERR_NOTPOSSIBLE);
  1422. } // acmdFormatSuggest()
  1423. //==========================================================================;
  1424. //
  1425. //
  1426. //
  1427. //
  1428. //==========================================================================;
  1429. //--------------------------------------------------------------------------;
  1430. //
  1431. // LRESULT acmdFormatTagDetails
  1432. //
  1433. // Description:
  1434. // This function handles the ACMDM_FORMATTAG_DETAILS message. This
  1435. // message is normally sent in response to an acmFormatTagDetails or
  1436. // acmFormatTagEnum function call. The purpose of this function is
  1437. // to get details about a specific format tag supported by this ACM
  1438. // driver.
  1439. //
  1440. // Arguments:
  1441. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  1442. // This structure is [optionally] allocated during the DRV_OPEN message
  1443. // which is handled by the acmdDriverOpen function.
  1444. //
  1445. // LPACMFORMATTAGDETAILS padft: Pointer to an ACMFORMATTAGDETAILS
  1446. // structure that describes what format tag to retrieve details for.
  1447. //
  1448. // DWORD fdwDetails: Flags defining what format tag to retrieve the
  1449. // details for.
  1450. //
  1451. // Return (LRESULT):
  1452. // The return value is zero (MMSYSERR_NOERROR) if this function
  1453. // succeeds with no errors. The return value is a non-zero error code
  1454. // if the function fails.
  1455. //
  1456. // The driver should return MMSYSERR_NOTSUPPORTED if the query type
  1457. // specified in fdwDetails is not supported. An ACM driver must
  1458. // support at least the following query types:
  1459. //
  1460. // ACM_FORMATTAGDETAILSF_INDEX: Indicates that a format tag index
  1461. // was given in the dwFormatTagIndex member of the ACMFORMATTAGDETAILS
  1462. // structure. The format tag and details must be returned in the
  1463. // structure specified by padft. The index ranges from zero to one less
  1464. // than the cFormatTags member returned in the ACMDRIVERDETAILS
  1465. // structure for this driver.
  1466. //
  1467. // ACM_FORMATTAGDETAILSF_FORMATTAG: Indicates that a format tag
  1468. // was given in the dwFormatTag member of the ACMFORMATTAGDETAILS
  1469. // structure. The format tag details must be returned in the structure
  1470. // specified by padft.
  1471. //
  1472. // ACM_FORMATTAGDETAILSF_LARGESTSIZE: Indicates that the details
  1473. // on the format tag with the largest format size in bytes must be
  1474. // returned. The dwFormatTag member will either be WAVE_FORMAT_UNKNOWN
  1475. // or the format tag to find the largest size for.
  1476. //
  1477. // If the details for the specified format tag cannot be retrieved
  1478. // from this driver, then ACMERR_NOTPOSSIBLE should be returned.
  1479. //
  1480. //--------------------------------------------------------------------------;
  1481. LRESULT FNLOCAL acmdFormatTagDetails
  1482. (
  1483. PDRIVERINSTANCE pdi,
  1484. LPACMFORMATTAGDETAILS padft,
  1485. DWORD fdwDetails
  1486. )
  1487. {
  1488. UINT uFormatTag;
  1489. //
  1490. //
  1491. //
  1492. //
  1493. //
  1494. switch (ACM_FORMATTAGDETAILSF_QUERYMASK & fdwDetails)
  1495. {
  1496. case ACM_FORMATTAGDETAILSF_INDEX:
  1497. //
  1498. // if the index is too large, then they are asking for a
  1499. // non-existant format. return error.
  1500. //
  1501. if (ACM_DRIVER_MAX_FORMAT_TAGS <= padft->dwFormatTagIndex)
  1502. return (ACMERR_NOTPOSSIBLE);
  1503. uFormatTag = gauFormatTagIndexToTag[(UINT)padft->dwFormatTagIndex];
  1504. break;
  1505. case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
  1506. switch (padft->dwFormatTag)
  1507. {
  1508. case WAVE_FORMAT_UNKNOWN:
  1509. case WAVE_FORMAT_IMA_ADPCM:
  1510. uFormatTag = WAVE_FORMAT_IMA_ADPCM;
  1511. break;
  1512. case WAVE_FORMAT_PCM:
  1513. uFormatTag = WAVE_FORMAT_PCM;
  1514. break;
  1515. default:
  1516. return (ACMERR_NOTPOSSIBLE);
  1517. }
  1518. break;
  1519. case ACM_FORMATTAGDETAILSF_FORMATTAG:
  1520. switch (padft->dwFormatTag)
  1521. {
  1522. case WAVE_FORMAT_IMA_ADPCM:
  1523. uFormatTag = WAVE_FORMAT_IMA_ADPCM;
  1524. break;
  1525. case WAVE_FORMAT_PCM:
  1526. uFormatTag = WAVE_FORMAT_PCM;
  1527. break;
  1528. default:
  1529. return (ACMERR_NOTPOSSIBLE);
  1530. }
  1531. break;
  1532. //
  1533. // if this ACM driver does not understand a query type, then
  1534. // return 'not supported'
  1535. //
  1536. default:
  1537. return (MMSYSERR_NOTSUPPORTED);
  1538. }
  1539. //
  1540. //
  1541. //
  1542. //
  1543. switch (uFormatTag)
  1544. {
  1545. case WAVE_FORMAT_PCM:
  1546. padft->dwFormatTagIndex = 0;
  1547. padft->dwFormatTag = WAVE_FORMAT_PCM;
  1548. padft->cbFormatSize = sizeof(PCMWAVEFORMAT);
  1549. padft->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
  1550. padft->cStandardFormats = ACM_DRIVER_MAX_FORMATS_PCM;
  1551. //
  1552. // the ACM is responsible for the PCM format tag name
  1553. //
  1554. padft->szFormatTag[0] = '\0';
  1555. break;
  1556. case WAVE_FORMAT_IMA_ADPCM:
  1557. padft->dwFormatTagIndex = 1;
  1558. padft->dwFormatTag = WAVE_FORMAT_IMA_ADPCM;
  1559. padft->cbFormatSize = sizeof(WAVEFORMATEX) +
  1560. IMAADPCM_WFX_EXTRA_BYTES;
  1561. padft->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
  1562. padft->cStandardFormats = ACM_DRIVER_MAX_FORMATS_ADPCM;
  1563. LoadStringCodec(pdi->hinst,
  1564. IDS_ACM_DRIVER_TAG_NAME,
  1565. padft->szFormatTag,
  1566. SIZEOFACMSTR(padft->szFormatTag));
  1567. break;
  1568. default:
  1569. return (ACMERR_NOTPOSSIBLE);
  1570. }
  1571. //
  1572. // return only the requested info
  1573. //
  1574. // the ACM will guarantee that the ACMFORMATTAGDETAILS structure
  1575. // passed is at least large enough to hold the base information of
  1576. // the details structure
  1577. //
  1578. padft->cbStruct = min(padft->cbStruct, sizeof(*padft));
  1579. //
  1580. //
  1581. //
  1582. return (MMSYSERR_NOERROR);
  1583. } // acmdFormatTagDetails()
  1584. //--------------------------------------------------------------------------;
  1585. //
  1586. // LRESULT acmdFormatDetails
  1587. //
  1588. // Description:
  1589. // This function handles the ACMDM_FORMAT_DETAILS message. This
  1590. // message is normally sent in response to an acmFormatDetails or
  1591. // acmFormatEnum function call. The purpose of this function is
  1592. // to get details about a specific format for a specified format tag
  1593. // supported by this ACM driver.
  1594. //
  1595. // Note that an ACM driver can return a zero length string for the
  1596. // format name if it wishes to have the ACM create a format string
  1597. // for it. This is strongly recommended to simplify internationalizing
  1598. // the driver--the ACM will automatically take care of that. The
  1599. // following formula is used to format a string by the ACM:
  1600. //
  1601. // <nSamplesPerSec> kHz, <bit depth> bit, [Mono | Stereo | nChannels]
  1602. //
  1603. // <bit depth> = <nAvgBytesPerSec> * 8 / nSamplesPerSec / nChannels;
  1604. //
  1605. // Arguments:
  1606. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  1607. // This structure is [optionally] allocated during the DRV_OPEN message
  1608. // which is handled by the acmdDriverOpen function.
  1609. //
  1610. // LPACMFORMATDETAILS padf: Pointer to an ACMFORMATDETAILS structure
  1611. // that describes what format (for a specified format tag) to retrieve
  1612. // details for.
  1613. //
  1614. // DWORD fdwDetails: Flags defining what format for a specified format
  1615. // tag to retrieve the details for.
  1616. //
  1617. // Return (LRESULT):
  1618. // The return value is zero (MMSYSERR_NOERROR) if this function
  1619. // succeeds with no errors. The return value is a non-zero error code
  1620. // if the function fails.
  1621. //
  1622. // The driver should return MMSYSERR_NOTSUPPORTED if the query type
  1623. // specified in fdwDetails is not supported. An ACM driver must
  1624. // support at least the following query types:
  1625. //
  1626. // ACM_FORMATDETAILSF_INDEX: Indicates that a format index for the
  1627. // format tag was given in the dwFormatIndex member of the
  1628. // ACMFORMATDETAILS structure. The format details must be returned in
  1629. // the structure specified by padf. The index ranges from zero to one
  1630. // less than the cStandardFormats member returned in the
  1631. // ACMFORMATTAGDETAILS structure for a format tag.
  1632. //
  1633. // ACM_FORMATDETAILSF_FORMAT: Indicates that a WAVEFORMATEX structure
  1634. // pointed to by pwfx of the ACMFORMATDETAILS structure was given and
  1635. // the remaining details should be returned. The dwFormatTag member
  1636. // of the ACMFORMATDETAILS will be initialized to the same format
  1637. // tag as the pwfx member specifies. This query type may be used to
  1638. // get a string description of an arbitrary format structure.
  1639. //
  1640. // If the details for the specified format cannot be retrieved
  1641. // from this driver, then ACMERR_NOTPOSSIBLE should be returned.
  1642. //
  1643. //--------------------------------------------------------------------------;
  1644. LRESULT FNLOCAL acmdFormatDetails
  1645. (
  1646. PDRIVERINSTANCE pdi,
  1647. LPACMFORMATDETAILS padf,
  1648. DWORD fdwDetails
  1649. )
  1650. {
  1651. LPWAVEFORMATEX pwfx;
  1652. LPIMAADPCMWAVEFORMAT pwfadpcm;
  1653. UINT uFormatIndex;
  1654. UINT u;
  1655. //
  1656. //
  1657. //
  1658. //
  1659. //
  1660. switch (ACM_FORMATDETAILSF_QUERYMASK & fdwDetails)
  1661. {
  1662. //
  1663. // enumerate by index
  1664. //
  1665. // verify that the format tag is something we know about and
  1666. // return the details on the 'standard format' supported by
  1667. // this driver at the specified index...
  1668. //
  1669. case ACM_FORMATDETAILSF_INDEX:
  1670. //
  1671. // put some stuff in more accessible variables--note that we
  1672. // bring variable sizes down to a reasonable size for 16 bit
  1673. // code...
  1674. //
  1675. pwfx = padf->pwfx;
  1676. uFormatIndex = (UINT)padf->dwFormatIndex;
  1677. switch (padf->dwFormatTag)
  1678. {
  1679. case WAVE_FORMAT_PCM:
  1680. if (ACM_DRIVER_MAX_FORMATS_PCM <= padf->dwFormatIndex)
  1681. return (ACMERR_NOTPOSSIBLE);
  1682. //
  1683. // now fill in the format structure
  1684. //
  1685. pwfx->wFormatTag = WAVE_FORMAT_PCM;
  1686. u = uFormatIndex / (ACM_DRIVER_MAX_BITSPERSAMPLE_PCM * ACM_DRIVER_MAX_CHANNELS);
  1687. pwfx->nSamplesPerSec = gauFormatIndexToSampleRate[u];
  1688. u = uFormatIndex % ACM_DRIVER_MAX_CHANNELS;
  1689. pwfx->nChannels = u + 1;
  1690. u = (uFormatIndex / ACM_DRIVER_MAX_CHANNELS) % ACM_DRIVER_MAX_CHANNELS;
  1691. pwfx->wBitsPerSample = (WORD)gauFormatIndexToBitsPerSample[u];
  1692. pwfx->nBlockAlign = PCM_BLOCKALIGNMENT(pwfx);
  1693. pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign;
  1694. //
  1695. // note that the cbSize field is NOT valid for PCM
  1696. // formats
  1697. //
  1698. // pwfx->cbSize = 0;
  1699. break;
  1700. case WAVE_FORMAT_IMA_ADPCM:
  1701. if (ACM_DRIVER_MAX_FORMATS_ADPCM <= padf->dwFormatIndex)
  1702. return (ACMERR_NOTPOSSIBLE);
  1703. pwfx->wFormatTag = WAVE_FORMAT_IMA_ADPCM;
  1704. u = uFormatIndex / (ACM_DRIVER_MAX_BITSPERSAMPLE_ADPCM * ACM_DRIVER_MAX_CHANNELS);
  1705. pwfx->nSamplesPerSec = gauFormatIndexToSampleRate[u];
  1706. u = uFormatIndex % ACM_DRIVER_MAX_CHANNELS;
  1707. pwfx->nChannels = u + 1;
  1708. pwfx->wBitsPerSample = IMAADPCM_BITS_PER_SAMPLE;
  1709. pwfx->nBlockAlign = imaadpcmBlockAlign(pwfx);
  1710. pwfx->nAvgBytesPerSec = imaadpcmAvgBytesPerSec(pwfx);
  1711. pwfx->cbSize = IMAADPCM_WFX_EXTRA_BYTES;
  1712. pwfadpcm = (LPIMAADPCMWAVEFORMAT)pwfx;
  1713. pwfadpcm->wSamplesPerBlock = imaadpcmSamplesPerBlock(pwfx);
  1714. break;
  1715. default:
  1716. return (ACMERR_NOTPOSSIBLE);
  1717. }
  1718. //
  1719. // return details on specified format
  1720. //
  1721. // the caller normally uses this to verify that the format is
  1722. // supported and to retrieve a string description...
  1723. //
  1724. case ACM_FORMATDETAILSF_FORMAT:
  1725. pwfx = padf->pwfx;
  1726. switch (pwfx->wFormatTag)
  1727. {
  1728. case WAVE_FORMAT_PCM:
  1729. if (!pcmIsValidFormat(pwfx))
  1730. return (ACMERR_NOTPOSSIBLE);
  1731. break;
  1732. case WAVE_FORMAT_IMA_ADPCM:
  1733. if (!imaadpcmIsValidFormat(pwfx))
  1734. return (ACMERR_NOTPOSSIBLE);
  1735. break;
  1736. default:
  1737. return (ACMERR_NOTPOSSIBLE);
  1738. }
  1739. break;
  1740. default:
  1741. //
  1742. // don't know how to do the query type passed--return 'not
  1743. // supported'.
  1744. //
  1745. return (MMSYSERR_NOTSUPPORTED);
  1746. }
  1747. //
  1748. // return the size of the valid information we are returning
  1749. //
  1750. // the ACM will guarantee that the ACMFORMATDETAILS structure
  1751. // passed is at least large enough to hold the base structure
  1752. //
  1753. // note that we let the ACM create the format string for us since
  1754. // we require no special formatting (and don't want to deal with
  1755. // internationalization issues, etc). simply set the string to
  1756. // a zero length.
  1757. //
  1758. padf->cbStruct = min(padf->cbStruct, sizeof(*padf));
  1759. padf->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
  1760. padf->szFormat[0] = '\0';
  1761. //
  1762. //
  1763. //
  1764. return (MMSYSERR_NOERROR);
  1765. } // acmdFormatDetails()
  1766. //==========================================================================;
  1767. //
  1768. //
  1769. //
  1770. //
  1771. //==========================================================================;
  1772. //--------------------------------------------------------------------------;
  1773. //
  1774. // LRESULT acmdStreamOpen
  1775. //
  1776. // Description:
  1777. // This function handles the ACMDM_STREAM_OPEN message. This message
  1778. // is sent to initiate a new conversion stream. This is usually caused
  1779. // by an application calling acmStreamOpen. If this function is
  1780. // successful, then one or more ACMDM_STREAM_CONVERT messages will be
  1781. // sent to convert individual buffers (user calls acmStreamConvert).
  1782. //
  1783. // Note that an ACM driver will not receive open requests for ASYNC
  1784. // or FILTER operations unless the ACMDRIVERDETAILS_SUPPORTF_ASYNC
  1785. // or ACMDRIVERDETAILS_SUPPORTF_FILTER flags are set in the
  1786. // ACMDRIVERDETAILS structure. There is no need for the driver to
  1787. // check for these requests unless it sets those support bits.
  1788. //
  1789. // If the ACM_STREAMOPENF_QUERY flag is set in the padsi->fdwOpen
  1790. // member, then no resources should be allocated. Just verify that
  1791. // the conversion request is possible by this driver and return the
  1792. // appropriate error (either ACMERR_NOTPOSSIBLE or MMSYSERR_NOERROR).
  1793. // The driver will NOT receive an ACMDM_STREAM_CLOSE for queries.
  1794. //
  1795. // If the ACM_STREAMOPENF_NONREALTIME bit is NOT set, then conversion
  1796. // must be done in 'real-time'. This is a tough one to describe
  1797. // exactly. If the driver may have trouble doing the conversion without
  1798. // breaking up the audio, then a configuration dialog might be used
  1799. // to allow the user to specify whether the real-time conversion
  1800. // request should be succeeded. DO NOT SUCCEED THE CALL UNLESS YOU
  1801. // ACTUALLY CAN DO REAL-TIME CONVERSIONS! There may be another driver
  1802. // installed that can--so if you succeed the call you are hindering
  1803. // the performance of the user's system!
  1804. //
  1805. // Arguments:
  1806. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  1807. // This structure is [optionally] allocated during the DRV_OPEN message
  1808. // which is handled by the acmdDriverOpen function.
  1809. //
  1810. // LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
  1811. // conversion stream. This structure was allocated by the ACM and
  1812. // filled with the most common instance data needed for conversions.
  1813. // This structure will be passed back to all future stream messages
  1814. // if the open succeeds. The information in this structure will never
  1815. // change during the lifetime of the stream--so it is not necessary
  1816. // to re-verify the information referenced by this structure.
  1817. //
  1818. // Return (LRESULT):
  1819. // The return value is zero (MMSYSERR_NOERROR) if this function
  1820. // succeeds with no errors. The return value is a non-zero error code
  1821. // if the function fails.
  1822. //
  1823. // A driver should return ACMERR_NOTPOSSIBLE if the conversion cannot
  1824. // be performed due to incompatible source and destination formats.
  1825. //
  1826. // A driver should return MMSYSERR_NOTSUPPORTED if the conversion
  1827. // cannot be performed in real-time and the request does not specify
  1828. // the ACM_STREAMOPENF_NONREALTIME flag.
  1829. //
  1830. //--------------------------------------------------------------------------;
  1831. LRESULT FNLOCAL acmdStreamOpen
  1832. (
  1833. PDRIVERINSTANCE pdi,
  1834. LPACMDRVSTREAMINSTANCE padsi
  1835. )
  1836. {
  1837. LPWAVEFORMATEX pwfxSrc;
  1838. LPWAVEFORMATEX pwfxDst;
  1839. BOOL fRealTime;
  1840. STREAMCONVERTPROC fnConvert;
  1841. PSTREAMINSTANCE psi;
  1842. #ifdef IMAADPCM_USECONFIG
  1843. DWORD nConfigMaxRTEncodeSamplesPerSec;
  1844. DWORD nConfigMaxRTDecodeSamplesPerSec;
  1845. DWORD dw;
  1846. #endif
  1847. //
  1848. //
  1849. //
  1850. pwfxSrc = padsi->pwfxSrc;
  1851. pwfxDst = padsi->pwfxDst;
  1852. #ifdef IMAADPCM_USECONFIG
  1853. nConfigMaxRTEncodeSamplesPerSec =
  1854. gaRateListFormat[pdi->nConfigMaxRTEncodeSetting].dwMonoRate;
  1855. DPF(2,"nConfigMaxRTEncodeSamplesPerSec=%u",nConfigMaxRTEncodeSamplesPerSec);
  1856. nConfigMaxRTDecodeSamplesPerSec =
  1857. gaRateListFormat[pdi->nConfigMaxRTDecodeSetting].dwMonoRate;
  1858. DPF(2,"nConfigMaxRTDecodeSamplesPerSec=%u",nConfigMaxRTDecodeSamplesPerSec);
  1859. #endif
  1860. fRealTime = (0 == (padsi->fdwOpen & ACM_STREAMOPENF_NONREALTIME));
  1861. //
  1862. // the most important condition to check before doing anything else
  1863. // is that this ACM driver can actually perform the conversion we are
  1864. // being opened for. this check should fail as quickly as possible
  1865. // if the conversion is not possible by this driver.
  1866. //
  1867. // it is VERY important to fail quickly so the ACM can attempt to
  1868. // find a driver that is suitable for the conversion. also note that
  1869. // the ACM may call this driver several times with slightly different
  1870. // format specifications before giving up.
  1871. //
  1872. // this driver first verifies that the source and destination formats
  1873. // are acceptable...
  1874. //
  1875. switch (pwfxSrc->wFormatTag)
  1876. {
  1877. case WAVE_FORMAT_PCM:
  1878. if (!pcmIsValidFormat(pwfxSrc))
  1879. return (ACMERR_NOTPOSSIBLE);
  1880. if (!imaadpcmIsValidFormat(pwfxDst))
  1881. return (ACMERR_NOTPOSSIBLE);
  1882. #ifdef IMAADPCM_USECONFIG
  1883. //
  1884. // if a driver cannot perform real-time encoding then
  1885. // the driver should fail when opened for a real-time
  1886. // conversion. note that the driver MUST return
  1887. // MMSYSERR_NOTSUPPORTED in this case!
  1888. //
  1889. // this driver may or may not be able to perform real-time
  1890. // encoding, depending on the system on which it is running.
  1891. // this driver allows the user to select whether to support
  1892. // real-time encoding thru the config dialog.
  1893. //
  1894. // if this open is for a real-time conversion, fail if
  1895. // real-time encoding hasn't been enabled in the config
  1896. // dialog. Note that nConfigMaxRTDecodeSamplesPerSec is
  1897. // the value for a mono conversion - if it's a stereo
  1898. // conversion, we can only convert half as high...
  1899. //
  1900. if (fRealTime)
  1901. {
  1902. dw = nConfigMaxRTEncodeSamplesPerSec / pwfxSrc->nChannels;
  1903. if (dw < pwfxSrc->nSamplesPerSec)
  1904. {
  1905. return (MMSYSERR_NOTSUPPORTED);
  1906. }
  1907. }
  1908. #endif
  1909. //
  1910. // Determine the correct conversion routine.
  1911. //
  1912. switch (pwfxSrc->nChannels)
  1913. {
  1914. case 1:
  1915. if (8 == pwfxSrc->wBitsPerSample)
  1916. fnConvert = imaadpcmEncode4Bit_M08;
  1917. else
  1918. fnConvert = imaadpcmEncode4Bit_M16;
  1919. break;
  1920. case 2:
  1921. if (8 == pwfxSrc->wBitsPerSample)
  1922. fnConvert = imaadpcmEncode4Bit_S08;
  1923. else
  1924. fnConvert = imaadpcmEncode4Bit_S16;
  1925. break;
  1926. default:
  1927. return ACMERR_NOTPOSSIBLE;
  1928. }
  1929. break;
  1930. case WAVE_FORMAT_IMA_ADPCM:
  1931. if (!imaadpcmIsValidFormat(pwfxSrc))
  1932. return (ACMERR_NOTPOSSIBLE);
  1933. if (!pcmIsValidFormat(pwfxDst))
  1934. return (ACMERR_NOTPOSSIBLE);
  1935. #ifdef IMAADPCM_USECONFIG
  1936. //
  1937. // if a driver cannot perform real-time encoding then
  1938. // the driver should fail when opened for a real-time
  1939. // conversion. note that the driver MUST return
  1940. // MMSYSERR_NOTSUPPORTED in this case!
  1941. //
  1942. // this driver may or may not be able to perform real-time
  1943. // encoding, depending on the system on which it is running.
  1944. // this driver allows the user to select whether to support
  1945. // real-time encoding thru the config dialog.
  1946. //
  1947. // if this open is for a real-time conversion, fail if
  1948. // real-time decoding hasn't been enabled in the config
  1949. // dialog. Note that nConfigMaxRTDecodeSamplesPerSec is
  1950. // the value for a mono conversion - if it's a stereo
  1951. // conversion, we can only convert half as high...
  1952. //
  1953. if (fRealTime)
  1954. {
  1955. dw = nConfigMaxRTDecodeSamplesPerSec / pwfxSrc->nChannels;
  1956. if( dw < pwfxSrc->nSamplesPerSec )
  1957. {
  1958. return (MMSYSERR_NOTSUPPORTED);
  1959. }
  1960. }
  1961. #endif
  1962. //
  1963. // Determine the correct conversion routine.
  1964. //
  1965. switch (pwfxSrc->nChannels)
  1966. {
  1967. case 1:
  1968. if (8 == pwfxDst->wBitsPerSample)
  1969. fnConvert = imaadpcmDecode4Bit_M08;
  1970. else
  1971. fnConvert = imaadpcmDecode4Bit_M16;
  1972. break;
  1973. case 2:
  1974. if (8 == pwfxDst->wBitsPerSample)
  1975. fnConvert = imaadpcmDecode4Bit_S08;
  1976. else
  1977. fnConvert = imaadpcmDecode4Bit_S16;
  1978. break;
  1979. default:
  1980. return ACMERR_NOTPOSSIBLE;
  1981. }
  1982. break;
  1983. default:
  1984. return (ACMERR_NOTPOSSIBLE);
  1985. }
  1986. //
  1987. // for this driver, we must also verify that the nChannels and
  1988. // nSamplesPerSec members are the same between the source and
  1989. // destination formats.
  1990. //
  1991. if (pwfxSrc->nChannels != pwfxDst->nChannels)
  1992. return (MMSYSERR_NOTSUPPORTED);
  1993. if (pwfxSrc->nSamplesPerSec != pwfxDst->nSamplesPerSec)
  1994. return (MMSYSERR_NOTSUPPORTED);
  1995. //
  1996. // we have determined that the conversion requested is possible by
  1997. // this driver. now check if we are just being queried for support.
  1998. // if this is just a query, then do NOT allocate any instance data
  1999. // or create tables, etc. just succeed the call.
  2000. //
  2001. if (0 != (ACM_STREAMOPENF_QUERY & padsi->fdwOpen))
  2002. {
  2003. return (MMSYSERR_NOERROR);
  2004. }
  2005. //
  2006. // we have decided that this driver can handle the conversion stream.
  2007. // so we want to do _AS MUCH WORK AS POSSIBLE_ right now to prepare
  2008. // for converting data. any resource allocation, table building, etc
  2009. // that can be dealt with at this time should be done.
  2010. //
  2011. // THIS IS VERY IMPORTANT! all ACMDM_STREAM_CONVERT messages need to
  2012. // be handled as quickly as possible.
  2013. //
  2014. // this driver allocates a small instance structure for each stream
  2015. //
  2016. //
  2017. psi = (PSTREAMINSTANCE)LocalAlloc(LPTR, sizeof(*psi));
  2018. if (NULL == psi)
  2019. {
  2020. return (MMSYSERR_NOMEM);
  2021. }
  2022. //
  2023. // fill out our instance structure
  2024. //
  2025. // this driver stores a pointer to the conversion function that will
  2026. // be used for each conversion on this stream. we also store a
  2027. // copy of the _current_ configuration of the driver instance we
  2028. // are opened on. this must not change during the life of the stream
  2029. // instance.
  2030. //
  2031. // this is also very important! if the user is able to configure how
  2032. // the driver performs conversions, the changes should only affect
  2033. // future open streams. all current open streams should behave as
  2034. // they were configured during the open.
  2035. //
  2036. psi->fnConvert = fnConvert;
  2037. psi->fdwConfig = pdi->fdwConfig;
  2038. psi->nStepIndexL = 0;
  2039. psi->nStepIndexR = 0;
  2040. //
  2041. // fill in our instance data--this will be passed back to all stream
  2042. // messages in the ACMDRVSTREAMINSTANCE structure. it is entirely
  2043. // up to the driver what gets stored (and maintained) in the
  2044. // fdwDriver and dwDriver members.
  2045. //
  2046. padsi->fdwDriver = 0L;
  2047. padsi->dwDriver = (DWORD_PTR)psi;
  2048. return (MMSYSERR_NOERROR);
  2049. } // acmdStreamOpen()
  2050. //--------------------------------------------------------------------------;
  2051. //
  2052. // LRESULT acmdStreamClose
  2053. //
  2054. // Description:
  2055. // This function is called to handle the ACMDM_STREAM_CLOSE message.
  2056. // This message is sent when a conversion stream is no longer being
  2057. // used (the stream is being closed; usually by an application
  2058. // calling acmStreamClose). The ACM driver should clean up any resources
  2059. // that were allocated for the stream.
  2060. //
  2061. // Arguments:
  2062. // LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
  2063. // conversion stream. This structure was allocated by the ACM and
  2064. // filled with the most common instance data needed for conversions.
  2065. // The information in this structure is exactly the same as it was
  2066. // during the ACMDM_STREAM_OPEN message--so it is not necessary
  2067. // to re-verify the information referenced by this structure.
  2068. //
  2069. // Return (LRESULT):
  2070. // The return value is zero (MMSYSERR_NOERROR) if this function
  2071. // succeeds with no errors. The return value is a non-zero error code
  2072. // if the function fails.
  2073. //
  2074. // NOTE! It is _strongly_ recommended that a driver not fail to close
  2075. // a conversion stream.
  2076. //
  2077. // An asyncronous conversion stream may fail with ACMERR_BUSY if there
  2078. // are pending buffers. An application may call acmStreamReset to
  2079. // force all pending buffers to be posted.
  2080. //
  2081. //--------------------------------------------------------------------------;
  2082. LRESULT FNLOCAL acmdStreamClose
  2083. (
  2084. LPACMDRVSTREAMINSTANCE padsi
  2085. )
  2086. {
  2087. PSTREAMINSTANCE psi;
  2088. //
  2089. // the driver should clean up all privately allocated resources that
  2090. // were created for maintaining the stream instance. if no resources
  2091. // were allocated, then simply succeed.
  2092. //
  2093. // in the case of this driver, we need to free the stream instance
  2094. // structure that we allocated during acmdStreamOpen.
  2095. //
  2096. psi = (PSTREAMINSTANCE)padsi->dwDriver;
  2097. if (NULL != psi)
  2098. {
  2099. //
  2100. // free the stream instance structure
  2101. //
  2102. LocalFree((HLOCAL)psi);
  2103. }
  2104. return (MMSYSERR_NOERROR);
  2105. } // acmdStreamClose()
  2106. //--------------------------------------------------------------------------;
  2107. //
  2108. // LRESULT acmdStreamSize
  2109. //
  2110. // Description:
  2111. // This function handles the ACMDM_STREAM_SIZE message. The purpose
  2112. // of this function is to provide the _largest size in bytes_ that
  2113. // the source or destination buffer needs to be given the input and
  2114. // output formats and the size in bytes of the source or destination
  2115. // data buffer.
  2116. //
  2117. // In other words: how big does my destination buffer need to be to
  2118. // hold the converted data? (ACM_STREAMSIZEF_SOURCE)
  2119. //
  2120. // Or: how big can my source buffer be given the destination buffer?
  2121. // (ACM_STREAMSIZEF_DESTINATION)
  2122. //
  2123. // Arguments:
  2124. // LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
  2125. // conversion stream. This structure was allocated by the ACM and
  2126. // filled with the most common instance data needed for conversions.
  2127. // The information in this structure is exactly the same as it was
  2128. // during the ACMDM_STREAM_OPEN message--so it is not necessary
  2129. // to re-verify the information referenced by this structure.
  2130. //
  2131. // LPACMDRVSTREAMSIZE padss: Specifies a pointer to the ACMDRVSTREAMSIZE
  2132. // structure that defines the conversion stream size query attributes.
  2133. //
  2134. // Return (LRESULT):
  2135. // The return value is zero (MMSYSERR_NOERROR) if this function
  2136. // succeeds with no errors. The return value is a non-zero error code
  2137. // if the function fails.
  2138. //
  2139. // An ACM driver should return MMSYSERR_NOTSUPPORTED if a query type
  2140. // is requested that the driver does not understand. Note that a driver
  2141. // must support both the ACM_STREAMSIZEF_DESTINATION and
  2142. // ACM_STREAMSIZEF_SOURCE queries.
  2143. //
  2144. // If the conversion would be 'out of range' given the input arguments,
  2145. // then ACMERR_NOTPOSSIBLE should be returned.
  2146. //
  2147. //--------------------------------------------------------------------------;
  2148. LRESULT FNLOCAL acmdStreamSize
  2149. (
  2150. LPACMDRVSTREAMINSTANCE padsi,
  2151. LPACMDRVSTREAMSIZE padss
  2152. )
  2153. {
  2154. PSTREAMINSTANCE psi;
  2155. LPWAVEFORMATEX pwfxSrc;
  2156. LPWAVEFORMATEX pwfxDst;
  2157. LPIMAADPCMWAVEFORMAT pwfadpcm;
  2158. DWORD cb;
  2159. DWORD cBlocks;
  2160. DWORD cbBytesPerBlock;
  2161. pwfxSrc = padsi->pwfxSrc;
  2162. pwfxDst = padsi->pwfxDst;
  2163. psi = (PSTREAMINSTANCE)padsi->dwDriver;
  2164. //
  2165. //
  2166. //
  2167. //
  2168. //
  2169. switch (ACM_STREAMSIZEF_QUERYMASK & padss->fdwSize)
  2170. {
  2171. case ACM_STREAMSIZEF_SOURCE:
  2172. cb = padss->cbSrcLength;
  2173. if (WAVE_FORMAT_IMA_ADPCM == pwfxSrc->wFormatTag)
  2174. {
  2175. //
  2176. // how many destination PCM bytes are needed to hold
  2177. // the decoded ADPCM data of padss->cbSrcLength bytes
  2178. //
  2179. // always round UP
  2180. //
  2181. cBlocks = cb / pwfxSrc->nBlockAlign;
  2182. if (0 == cBlocks)
  2183. {
  2184. return (ACMERR_NOTPOSSIBLE);
  2185. }
  2186. pwfadpcm = (LPIMAADPCMWAVEFORMAT)pwfxSrc;
  2187. cbBytesPerBlock = pwfadpcm->wSamplesPerBlock * pwfxDst->nBlockAlign;
  2188. if ((0xFFFFFFFFL / cbBytesPerBlock) < cBlocks)
  2189. {
  2190. return (ACMERR_NOTPOSSIBLE);
  2191. }
  2192. if (0 == (cb % pwfxSrc->nBlockAlign))
  2193. {
  2194. cb = cBlocks * cbBytesPerBlock;
  2195. }
  2196. else
  2197. {
  2198. cb = (cBlocks + 1) * cbBytesPerBlock;
  2199. }
  2200. }
  2201. else
  2202. {
  2203. //
  2204. // how many destination ADPCM bytes are needed to hold
  2205. // the encoded PCM data of padss->cbSrcLength bytes
  2206. //
  2207. // always round UP
  2208. //
  2209. pwfadpcm = (LPIMAADPCMWAVEFORMAT)pwfxDst;
  2210. cbBytesPerBlock = pwfadpcm->wSamplesPerBlock * pwfxSrc->nBlockAlign;
  2211. cBlocks = cb / cbBytesPerBlock;
  2212. if (0 == (cb % cbBytesPerBlock))
  2213. {
  2214. cb = cBlocks * pwfxDst->nBlockAlign;
  2215. }
  2216. else
  2217. {
  2218. cb = (cBlocks + 1) * pwfxDst->nBlockAlign;
  2219. }
  2220. if (0L == cb)
  2221. {
  2222. return (ACMERR_NOTPOSSIBLE);
  2223. }
  2224. }
  2225. padss->cbDstLength = cb;
  2226. return (MMSYSERR_NOERROR);
  2227. case ACM_STREAMSIZEF_DESTINATION:
  2228. cb = padss->cbDstLength;
  2229. if (WAVE_FORMAT_IMA_ADPCM == pwfxDst->wFormatTag)
  2230. {
  2231. //
  2232. // how many source PCM bytes can be encoded into a
  2233. // destination buffer of padss->cbDstLength bytes
  2234. //
  2235. // always round DOWN
  2236. //
  2237. cBlocks = cb / pwfxDst->nBlockAlign;
  2238. if (0 == cBlocks)
  2239. {
  2240. return (ACMERR_NOTPOSSIBLE);
  2241. }
  2242. pwfadpcm = (LPIMAADPCMWAVEFORMAT)pwfxDst;
  2243. cbBytesPerBlock = pwfadpcm->wSamplesPerBlock * pwfxSrc->nBlockAlign;
  2244. if ((0xFFFFFFFFL / cbBytesPerBlock) < cBlocks)
  2245. {
  2246. return (ACMERR_NOTPOSSIBLE);
  2247. }
  2248. cb = cBlocks * cbBytesPerBlock;
  2249. }
  2250. else
  2251. {
  2252. //
  2253. // how many source ADPCM bytes can be decoded into a
  2254. // destination buffer of padss->cbDstLength bytes
  2255. //
  2256. // always round DOWN
  2257. //
  2258. pwfadpcm = (LPIMAADPCMWAVEFORMAT)pwfxSrc;
  2259. cbBytesPerBlock = pwfadpcm->wSamplesPerBlock * pwfxDst->nBlockAlign;
  2260. cBlocks = cb / cbBytesPerBlock;
  2261. if (0 == cBlocks)
  2262. {
  2263. return (ACMERR_NOTPOSSIBLE);
  2264. }
  2265. cb = cBlocks * pwfxSrc->nBlockAlign;
  2266. }
  2267. padss->cbSrcLength = cb;
  2268. return (MMSYSERR_NOERROR);
  2269. }
  2270. //
  2271. //
  2272. //
  2273. return (MMSYSERR_NOTSUPPORTED);
  2274. } // acmdStreamSize()
  2275. //--------------------------------------------------------------------------;
  2276. //
  2277. // LRESULT acmdStreamConvert
  2278. //
  2279. // Description:
  2280. // This function handles the ACMDM_STREAM_CONVERT message. This is the
  2281. // whole purpose of writing an ACM driver--to convert data. This message
  2282. // is sent after a stream has been opened (the driver receives and
  2283. // succeeds the ACMDM_STREAM_OPEN message).
  2284. //
  2285. // Arguments:
  2286. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  2287. // This structure is [optionally] allocated during the DRV_OPEN message
  2288. // which is handled by the acmdDriverOpen function.
  2289. //
  2290. // LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
  2291. // conversion stream. This structure was allocated by the ACM and
  2292. // filled with the most common instance data needed for conversions.
  2293. // The information in this structure is exactly the same as it was
  2294. // during the ACMDM_STREAM_OPEN message--so it is not necessary
  2295. // to re-verify the information referenced by this structure.
  2296. //
  2297. // LPACMDRVSTREAMHEADER padsh: Pointer to stream header structure
  2298. // that defines the source data and destination buffer to convert.
  2299. //
  2300. // Return (LRESULT):
  2301. // The return value is zero (MMSYSERR_NOERROR) if this function
  2302. // succeeds with no errors. The return value is a non-zero error code
  2303. // if the function fails.
  2304. //
  2305. //--------------------------------------------------------------------------;
  2306. LRESULT FNLOCAL acmdStreamConvert
  2307. (
  2308. PDRIVERINSTANCE pdi,
  2309. LPACMDRVSTREAMINSTANCE padsi,
  2310. LPACMDRVSTREAMHEADER padsh
  2311. )
  2312. {
  2313. BOOL fBlockAlign;
  2314. BOOL fStart;
  2315. LPWAVEFORMATEX pwfpcm;
  2316. LPIMAADPCMWAVEFORMAT pwfadpcm;
  2317. DWORD dw;
  2318. DWORD cbConvert;
  2319. PSTREAMINSTANCE psi;
  2320. //
  2321. // Determine the conversion flags.
  2322. //
  2323. fBlockAlign = (0 != (ACM_STREAMCONVERTF_BLOCKALIGN & padsh->fdwConvert));
  2324. fStart = (0 != (ACM_STREAMCONVERTF_START & padsh->fdwConvert));
  2325. psi = (PSTREAMINSTANCE)padsi->dwDriver;
  2326. DPF(4,"acmdStreamConvert: fBlockAlign=%d, fStart=%d, cbSrcLength=%ld",fBlockAlign,fStart,padsh->cbSrcLength);
  2327. if (WAVE_FORMAT_PCM == padsi->pwfxSrc->wFormatTag) {
  2328. //
  2329. // Encode.
  2330. //
  2331. pwfpcm = padsi->pwfxSrc;
  2332. pwfadpcm = (LPIMAADPCMWAVEFORMAT)padsi->pwfxDst;
  2333. //
  2334. // Determine the number of samples to convert. We ALWAYS convert
  2335. // block-aligned.
  2336. //
  2337. dw = PCM_BYTESTOSAMPLES(pwfpcm, padsh->cbSrcLength);
  2338. dw = (dw / pwfadpcm->wSamplesPerBlock) * pwfadpcm->wSamplesPerBlock;
  2339. cbConvert = PCM_SAMPLESTOBYTES(pwfpcm, dw);
  2340. //
  2341. // Reset step index if we have a start condition.
  2342. //
  2343. if( fStart ) {
  2344. psi->nStepIndexL = 0;
  2345. psi->nStepIndexR = 0; // Not necessary for mono, but...
  2346. }
  2347. } else {
  2348. //
  2349. // Decode.
  2350. //
  2351. pwfadpcm = (LPIMAADPCMWAVEFORMAT)padsi->pwfxSrc;
  2352. pwfpcm = padsi->pwfxDst;
  2353. //
  2354. // Determine the number of bytes to convert. We ALWAYS convert
  2355. // block-aligned.
  2356. //
  2357. cbConvert = (padsh->cbSrcLength/pwfadpcm->wfx.nBlockAlign) *
  2358. pwfadpcm->wfx.nBlockAlign;
  2359. }
  2360. //
  2361. // Set the number of Src bytes used. If fBlockAlign is not set, then
  2362. // we throw away any bytes which aren't used, by marking them as used
  2363. // even though we don't actually convert them.
  2364. //
  2365. padsh->cbSrcLengthUsed = ( fBlockAlign ?
  2366. cbConvert :
  2367. padsh->cbSrcLength );
  2368. //
  2369. // Call the conversion routine.
  2370. //
  2371. padsh->cbDstLengthUsed = psi->fnConvert(
  2372. (HPBYTE)padsh->pbSrc,
  2373. cbConvert,
  2374. (HPBYTE)padsh->pbDst,
  2375. (UINT)pwfadpcm->wfx.nBlockAlign, // Used for decode only.
  2376. (UINT)pwfadpcm->wSamplesPerBlock, // Used for encode only.
  2377. &psi->nStepIndexL, // Used for encode only.
  2378. &psi->nStepIndexR // For stereo encode only.
  2379. );
  2380. return (MMSYSERR_NOERROR);
  2381. } // acmdStreamConvert()
  2382. //==========================================================================;
  2383. //
  2384. //
  2385. //
  2386. //
  2387. //==========================================================================;
  2388. //--------------------------------------------------------------------------;
  2389. //
  2390. // LRESULT DriverProc
  2391. //
  2392. // Description:
  2393. //
  2394. //
  2395. // Arguments:
  2396. // DWORD dwId: For most messages, dwId is the DWORD value that
  2397. // the driver returns in response to a DRV_OPEN message. Each time
  2398. // the driver is opened, through the OpenDriver API, the driver
  2399. // receives a DRV_OPEN message and can return an arbitrary, non-zero
  2400. // value. The installable driver interface saves this value and returns
  2401. // a unique driver handle to the application. Whenever the application
  2402. // sends a message to the driver using the driver handle, the interface
  2403. // routes the message to this entry point and passes the corresponding
  2404. // dwId. This mechanism allows the driver to use the same or different
  2405. // identifiers for multiple opens but ensures that driver handles are
  2406. // unique at the application interface layer.
  2407. //
  2408. // The following messages are not related to a particular open instance
  2409. // of the driver. For these messages, the dwId will always be zero.
  2410. //
  2411. // DRV_LOAD, DRV_FREE, DRV_ENABLE, DRV_DISABLE, DRV_OPEN
  2412. //
  2413. // HDRVR hdrvr: This is the handle returned to the application
  2414. // by the driver interface.
  2415. //
  2416. // UINT uMsg: The requested action to be performed. Message
  2417. // values below DRV_RESERVED are used for globally defined messages.
  2418. // Message values from DRV_RESERVED to DRV_USER are used for defined
  2419. // driver protocols. Messages above DRV_USER are used for driver
  2420. // specific messages.
  2421. //
  2422. // LPARAM lParam1: Data for this message. Defined separately for
  2423. // each message.
  2424. //
  2425. // LPARAM lParam2: Data for this message. Defined separately for
  2426. // each message.
  2427. //
  2428. // Return (LRESULT):
  2429. // Defined separately for each message.
  2430. //
  2431. //--------------------------------------------------------------------------;
  2432. EXTERN_C LRESULT FNEXPORT DriverProc
  2433. (
  2434. DWORD_PTR dwpId,
  2435. HDRVR hdrvr,
  2436. UINT uMsg,
  2437. LPARAM lParam1,
  2438. LPARAM lParam2
  2439. )
  2440. {
  2441. LRESULT lr;
  2442. PDRIVERINSTANCE pdi;
  2443. //
  2444. // make pdi either NULL or a valid instance pointer. note that dwpId
  2445. // is 0 for several of the DRV_* messages (ie DRV_LOAD, DRV_OPEN...)
  2446. // see acmdDriverOpen for information on what dwpId is for other
  2447. // messages (instance data).
  2448. //
  2449. pdi = (PDRIVERINSTANCE)dwpId;
  2450. switch (uMsg)
  2451. {
  2452. //
  2453. // lParam1: Unused.
  2454. //
  2455. // lParam2: Unused.
  2456. //
  2457. case DRV_LOAD:
  2458. #ifdef WIN32
  2459. DbgInitialize(TRUE);
  2460. #endif
  2461. return(1L);
  2462. //
  2463. // lParam1: Unused.
  2464. //
  2465. // lParam2: Unused.
  2466. //
  2467. case DRV_FREE:
  2468. return (1L);
  2469. //
  2470. // lParam1: Not used. Ignore this argument.
  2471. //
  2472. // lParam2: Pointer to ACMDRVOPENDESC (or NULL).
  2473. //
  2474. case DRV_OPEN:
  2475. lr = acmdDriverOpen(hdrvr, (LPACMDRVOPENDESC)lParam2);
  2476. return (lr);
  2477. //
  2478. // lParam1: Unused.
  2479. //
  2480. // lParam2: Unused.
  2481. //
  2482. case DRV_CLOSE:
  2483. lr = acmdDriverClose(pdi);
  2484. return (lr);
  2485. //
  2486. // lParam1: Unused.
  2487. //
  2488. // lParam2: Unused.
  2489. //
  2490. case DRV_INSTALL:
  2491. return ((LRESULT)DRVCNF_RESTART);
  2492. //
  2493. // lParam1: Unused.
  2494. //
  2495. // lParam2: Unused.
  2496. //
  2497. case DRV_REMOVE:
  2498. return ((LRESULT)DRVCNF_RESTART);
  2499. //
  2500. // lParam1: Not used.
  2501. //
  2502. // lParam2: Not used.
  2503. //
  2504. case DRV_QUERYCONFIGURE:
  2505. //
  2506. // set up lParam1 and lParam2 to values that can be used by
  2507. // acmdDriverConfigure to know that it is being 'queried'
  2508. // for configuration support.
  2509. //
  2510. lParam1 = -1L;
  2511. lParam2 = 0L;
  2512. //--fall through--//
  2513. //
  2514. // lParam1: Handle to parent window for the configuration dialog
  2515. // box.
  2516. //
  2517. // lParam2: Optional pointer to DRVCONFIGINFO structure.
  2518. //
  2519. case DRV_CONFIGURE:
  2520. lr = acmdDriverConfigure(pdi, (HWND)lParam1, (LPDRVCONFIGINFO)lParam2);
  2521. return (lr);
  2522. //
  2523. // lParam1: Pointer to ACMDRIVERDETAILS structure.
  2524. //
  2525. // lParam2: Size in bytes of ACMDRIVERDETAILS stucture passed.
  2526. //
  2527. case ACMDM_DRIVER_DETAILS:
  2528. lr = acmdDriverDetails(pdi, (LPACMDRIVERDETAILS)lParam1);
  2529. return (lr);
  2530. //
  2531. // lParam1: Handle to parent window to use if displaying your own
  2532. // about box.
  2533. //
  2534. // lParam2: Not used.
  2535. //
  2536. case ACMDM_DRIVER_ABOUT:
  2537. lr = acmdDriverAbout(pdi, (HWND)lParam1);
  2538. return (lr);
  2539. //--------------------------------------------------------------------------;
  2540. //--------------------------------------------------------------------------;
  2541. //
  2542. // lParam1: Pointer to ACMDRVFORMATSUGGEST structure.
  2543. //
  2544. // lParam2: Not used.
  2545. //
  2546. case ACMDM_FORMAT_SUGGEST:
  2547. lr = acmdFormatSuggest(pdi, (LPACMDRVFORMATSUGGEST)lParam1);
  2548. return (lr);
  2549. //
  2550. // lParam1: Pointer to FORMATTAGDETAILS structure.
  2551. //
  2552. // lParam2: fdwDetails
  2553. //
  2554. case ACMDM_FORMATTAG_DETAILS:
  2555. lr = acmdFormatTagDetails(pdi, (LPACMFORMATTAGDETAILS)lParam1, (DWORD)lParam2);
  2556. return (lr);
  2557. //
  2558. // lParam1: Pointer to FORMATDETAILS structure.
  2559. //
  2560. // lParam2: fdwDetails
  2561. //
  2562. case ACMDM_FORMAT_DETAILS:
  2563. lr = acmdFormatDetails(pdi, (LPACMFORMATDETAILS)lParam1, (DWORD)lParam2);
  2564. return (lr);
  2565. //--------------------------------------------------------------------------;
  2566. //--------------------------------------------------------------------------;
  2567. //
  2568. // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
  2569. //
  2570. // lParam2: Not used.
  2571. //
  2572. case ACMDM_STREAM_OPEN:
  2573. lr = acmdStreamOpen(pdi, (LPACMDRVSTREAMINSTANCE)lParam1);
  2574. return (lr);
  2575. //
  2576. // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
  2577. //
  2578. // lParam2: Not Used.
  2579. //
  2580. case ACMDM_STREAM_CLOSE:
  2581. lr = acmdStreamClose((LPACMDRVSTREAMINSTANCE)lParam1);
  2582. return (lr);
  2583. //
  2584. // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
  2585. //
  2586. // lParam2: Pointer to ACMDRVSTREAMSIZE structure.
  2587. //
  2588. case ACMDM_STREAM_SIZE:
  2589. lr = acmdStreamSize((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMDRVSTREAMSIZE)lParam2);
  2590. return (lr);
  2591. //
  2592. // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
  2593. //
  2594. // lParam2: Pointer to ACMDRVSTREAMHEADER structure.
  2595. //
  2596. case ACMDM_STREAM_CONVERT:
  2597. lr = acmdStreamConvert(pdi, (LPACMDRVSTREAMINSTANCE)lParam1, (LPACMDRVSTREAMHEADER)lParam2);
  2598. return (lr);
  2599. }
  2600. //
  2601. // if we are executing the following code, then this ACM driver does not
  2602. // handle the message that was sent. there are two ranges of messages
  2603. // we need to deal with:
  2604. //
  2605. // o ACM specific driver messages: if an ACM driver does not answer a
  2606. // message sent in the ACM driver message range, then it must
  2607. // return MMSYSERR_NOTSUPPORTED. this applies to the 'user'
  2608. // range as well (for consistency).
  2609. //
  2610. // o other installable driver messages: if an ACM driver does not
  2611. // answer a message that is NOT in the ACM driver message range,
  2612. // then it must call DefDriverProc and return that result.
  2613. // the exception to this is ACM driver procedures installed as
  2614. // ACM_DRIVERADDF_FUNCTION through acmDriverAdd. in this case,
  2615. // the driver procedure should conform to the ACMDRIVERPROC
  2616. // prototype and also return zero instead of calling DefDriverProc.
  2617. //
  2618. if (uMsg >= ACMDM_USER)
  2619. return (MMSYSERR_NOTSUPPORTED);
  2620. else
  2621. return (DefDriverProc(dwpId, hdrvr, uMsg, lParam1, lParam2));
  2622. } // DriverProc()
  2623.