Windows NT 4.0 source code leak
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.

2603 lines
82 KiB

4 years ago
  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 - 1994 Microsoft Corporation. All Rights Reserved.
  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 <mmreg.h>
  25. #include <msacm.h>
  26. #include <msacmdrv.h>
  27. #include <memory.h>
  28. #include "codec.h"
  29. #include "msfilter.h"
  30. #include "debug.h"
  31. //
  32. // array of WAVE format tags supported.
  33. //
  34. // NOTE! if you change anything in this structure (order, addition, removal)
  35. // you must also fix acmdFormatTagDetails!
  36. //
  37. const UINT gauFormatTagIndexToTag[] =
  38. {
  39. WAVE_FORMAT_PCM
  40. };
  41. #define ACM_DRIVER_MAX_FORMAT_TAGS SIZEOF_ARRAY(gauFormatTagIndexToTag)
  42. //
  43. // array of _standard_ sample rates supported
  44. //
  45. //
  46. const UINT gauFormatIndexToSampleRate[] =
  47. {
  48. 8000,
  49. 11025,
  50. 22050,
  51. 44100
  52. };
  53. #define ACM_DRIVER_MAX_SAMPLE_RATES SIZEOF_ARRAY(gauFormatIndexToSampleRate)
  54. //
  55. //
  56. //
  57. //
  58. #define ACM_DRIVER_MAX_CHANNELS (MSFILTER_MAX_CHANNELS)
  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. //
  70. // number of formats we enumerate per channel is number of sample rates
  71. // times number of channels times number of types (bits per sample).
  72. //
  73. #define ACM_DRIVER_MAX_STANDARD_FORMATS_PCM (ACM_DRIVER_MAX_SAMPLE_RATES * \
  74. ACM_DRIVER_MAX_CHANNELS * \
  75. ACM_DRIVER_MAX_BITSPERSAMPLE_PCM)
  76. //
  77. // Array of WAVE filter tags supported.
  78. //
  79. const DWORD gadwFilterTagIndexToTag[] =
  80. {
  81. WAVE_FILTER_VOLUME,
  82. WAVE_FILTER_ECHO
  83. };
  84. #define ACM_DRIVER_MAX_FILTER_TAGS SIZEOF_ARRAY(gadwFilterTagIndexToTag)
  85. //
  86. // Array of filters supported.
  87. //
  88. const DWORD gdwFilterIndexToVolume[] =
  89. {
  90. 0x00001000,
  91. 0x00002000,
  92. 0x00004000,
  93. 0x00006000,
  94. 0x00008000,
  95. 0x0000A000,
  96. 0x0000C000,
  97. 0x0000E000,
  98. 0x0000F000,
  99. 0x00011000,
  100. 0x00012000,
  101. 0x00014000,
  102. 0x00016000,
  103. 0x00018000,
  104. 0x0001A000,
  105. 0x0001C000,
  106. 0x00020000
  107. };
  108. #define ACM_DRIVER_MAX_VOLUME_FILTERS SIZEOF_ARRAY(gdwFilterIndexToVolume)
  109. const DWORD gdwFilterIndexToDelay[] =
  110. {
  111. 0x00000040,
  112. 0x00000080,
  113. 0x00000100,
  114. 0x00000180,
  115. 0x00000200,
  116. 0x00000300,
  117. 0x00000400,
  118. 0x00000800,
  119. };
  120. #define ACM_DRIVER_NUM_DELAY SIZEOF_ARRAY(gdwFilterIndexToDelay)
  121. const DWORD gdwFilterIndexToEchoVol[] =
  122. {
  123. 0x00001000,
  124. 0x00002000,
  125. 0x00004000,
  126. 0x00008000,
  127. 0x0000C000
  128. };
  129. #define ACM_DRIVER_NUM_ECHOVOL SIZEOF_ARRAY(gdwFilterIndexToEchoVol)
  130. #define ACM_DRIVER_MAX_ECHO_FILTERS (ACM_DRIVER_NUM_DELAY * \
  131. ACM_DRIVER_NUM_ECHOVOL)
  132. //==========================================================================;
  133. //
  134. // SUPPORT ROUTINES FOR COMMON-BINARY CODECS.
  135. //
  136. //==========================================================================;
  137. //--------------------------------------------------------------------------;
  138. //
  139. // int LoadStringCodec
  140. //
  141. // Description:
  142. // This function should be used by all codecs to load resource strings
  143. // which will be passed back to the ACM. It works correctly for all
  144. // platforms, as follows:
  145. //
  146. // Win16: Compiled to LoadString to load ANSI strings.
  147. //
  148. // Win32: The 32-bit ACM always expects Unicode strings. Therefore,
  149. // when UNICODE is defined, this function is compiled to
  150. // LoadStringW to load a Unicode string. When UNICODE is
  151. // not defined, this function loads an ANSI string, converts
  152. // it to Unicode, and returns the Unicode string to the
  153. // codec.
  154. //
  155. // Note that you may use LoadString for other strings (strings which
  156. // will not be passed back to the ACM), because these strings will
  157. // always be consistent with the definition of UNICODE.
  158. //
  159. // Arguments:
  160. // Same as LoadString, except that it expects an LPSTR for Win16 and a
  161. // LPWSTR for Win32.
  162. //
  163. // Return (int):
  164. // Same as LoadString.
  165. //
  166. //--------------------------------------------------------------------------;
  167. #ifndef WIN32
  168. #define LoadStringCodec LoadString
  169. #else
  170. #ifdef UNICODE
  171. #define LoadStringCodec LoadStringW
  172. #else
  173. int FNGLOBAL LoadStringCodec
  174. (
  175. HINSTANCE hinst,
  176. UINT uID,
  177. LPWSTR lpwstr,
  178. int cch)
  179. {
  180. LPSTR lpstr;
  181. int iReturn;
  182. lpstr = (LPSTR)GlobalAlloc(GPTR, cch);
  183. if (NULL == lpstr)
  184. {
  185. return 0;
  186. }
  187. iReturn = LoadStringA(hinst, uID, lpstr, cch);
  188. if (0 == iReturn)
  189. {
  190. if (0 != cch)
  191. {
  192. lpwstr[0] = '\0';
  193. }
  194. }
  195. else
  196. {
  197. MultiByteToWideChar( GetACP(), 0, lpstr, cch, lpwstr, cch );
  198. }
  199. GlobalFree((HGLOBAL)lpstr);
  200. return iReturn;
  201. }
  202. #endif // UNICODE
  203. #endif // WIN32
  204. //==========================================================================;
  205. //
  206. //
  207. //
  208. //
  209. //==========================================================================;
  210. //--------------------------------------------------------------------------;
  211. //
  212. // BOOL pcmIsValidFormat
  213. //
  214. // Description:
  215. // This function verifies that a wave format header is a valid PCM
  216. // header that _this_ ACM driver can deal with.
  217. //
  218. // Arguments:
  219. // LPWAVEFORMATEX pwfx: Pointer to format header to verify.
  220. //
  221. // Return (BOOL):
  222. // The return value is non-zero if the format header looks valid. A
  223. // zero return means the header is not valid.
  224. //
  225. //--------------------------------------------------------------------------;
  226. BOOL FNLOCAL pcmIsValidFormat
  227. (
  228. LPWAVEFORMATEX pwfx
  229. )
  230. {
  231. if (NULL == pwfx)
  232. return (FALSE);
  233. if (WAVE_FORMAT_PCM != pwfx->wFormatTag)
  234. return (FALSE);
  235. //
  236. // verify nChannels member is within the allowed range
  237. //
  238. if ((pwfx->nChannels < 1) || (pwfx->nChannels > ACM_DRIVER_MAX_CHANNELS))
  239. return (FALSE);
  240. //
  241. // only allow the bits per sample that we can encode and decode with
  242. //
  243. if ((8 != pwfx->wBitsPerSample) && (16 != pwfx->wBitsPerSample))
  244. return (FALSE);
  245. //
  246. // now verify that the block alignment is correct..
  247. //
  248. if (PCM_BLOCKALIGNMENT(pwfx) != pwfx->nBlockAlign)
  249. return (FALSE);
  250. //
  251. // verify samples per second is within our capabilities
  252. //
  253. if ((0L == pwfx->nSamplesPerSec) || (0x3FFFFFFF < pwfx->nSamplesPerSec))
  254. {
  255. return (FALSE);
  256. }
  257. //
  258. // finally, verify that avg bytes per second is correct
  259. //
  260. if (PCM_AVGBYTESPERSEC(pwfx) != pwfx->nAvgBytesPerSec)
  261. return (FALSE);
  262. return (TRUE);
  263. } // pcmIsValidFormat()
  264. //--------------------------------------------------------------------------;
  265. //
  266. // BOOL volumeIsValidFilter
  267. //
  268. // Description:
  269. // This function verifies that a wave filter header is a valid volume
  270. // header that our volume converter can deal with.
  271. //
  272. // Arguments:
  273. // LPWAVEFILTER pwf: Pointer to filter header to verify.
  274. //
  275. // Return (BOOL):
  276. // The return value is non-zero if the format header looks valid. A
  277. // zero return means the header is not valid.
  278. //
  279. // History:
  280. // 06/05/93 Created.
  281. //
  282. //--------------------------------------------------------------------------;
  283. BOOL FNLOCAL volumeIsValidFilter
  284. (
  285. LPWAVEFILTER pwf
  286. )
  287. {
  288. if (!pwf)
  289. return (FALSE);
  290. if (pwf->cbStruct < sizeof(VOLUMEWAVEFILTER))
  291. return (FALSE);
  292. if (pwf->dwFilterTag != WAVE_FILTER_VOLUME)
  293. return (FALSE);
  294. if (0L != pwf->fdwFilter)
  295. return (FALSE);
  296. return (TRUE);
  297. } // volumeIsValidFilter()
  298. //--------------------------------------------------------------------------;
  299. //
  300. // BOOL echoIsValidFilter
  301. //
  302. // Description:
  303. // This function verifies that a wave filter header is a valid echo
  304. // header that our echo converter can deal with.
  305. //
  306. // Arguments:
  307. // LPWAVEFILTER pwf: Pointer to filter header to verify.
  308. //
  309. // Return (BOOL):
  310. // The return value is non-zero if the format header looks valid. A
  311. // zero return means the header is not valid.
  312. //
  313. // History:
  314. // 06/05/93 Created.
  315. //
  316. //--------------------------------------------------------------------------;
  317. BOOL FNLOCAL echoIsValidFilter
  318. (
  319. LPWAVEFILTER pwf
  320. )
  321. {
  322. LPECHOWAVEFILTER pwfEcho;
  323. if (!pwf)
  324. return (FALSE);
  325. if (pwf->cbStruct < sizeof(ECHOWAVEFILTER))
  326. return (FALSE);
  327. if (pwf->dwFilterTag != WAVE_FILTER_ECHO)
  328. return (FALSE);
  329. if (0L != pwf->fdwFilter)
  330. return (FALSE);
  331. pwfEcho = (LPECHOWAVEFILTER)pwf;
  332. // We only support a delay value up to 10 sec or 10 000 msec.
  333. if (pwfEcho->dwDelay > 10000L)
  334. return (FALSE);
  335. return (TRUE);
  336. } // echoIsValidFilter()
  337. //==========================================================================;
  338. //
  339. //
  340. //
  341. //
  342. //==========================================================================;
  343. //--------------------------------------------------------------------------;
  344. //
  345. // LRESULT acmdDriverOpen
  346. //
  347. // Description:
  348. // This function is used to handle the DRV_OPEN message for the ACM
  349. // driver. The driver is 'opened' for many reasons with the most common
  350. // being in preperation for conversion work. It is very important that
  351. // the driver be able to correctly handle multiple open driver
  352. // instances.
  353. //
  354. // Read the comments for this function carefully!
  355. //
  356. // Note that multiple _streams_ can (and will) be opened on a single
  357. // open _driver instance_. Do not store/create instance data that must
  358. // be unique for each stream in this function. See the acmdStreamOpen
  359. // function for information on conversion streams.
  360. //
  361. // Arguments:
  362. // HDRVR hdrvr: Driver handle that will be returned to caller of the
  363. // OpenDriver function. Normally, this will be the ACM--but this is
  364. // not guaranteed. For example, if an ACM driver is implemented within
  365. // a waveform driver, then the driver will be opened by both MMSYSTEM
  366. // and the ACM.
  367. //
  368. // LPACMDRVOPENDESC paod: Open description defining how the ACM driver
  369. // is being opened. This argument may be NULL--see the comments below
  370. // for more information.
  371. //
  372. // Return (LRESULT):
  373. // The return value is non-zero if the open is successful. A zero
  374. // return signifies that the driver cannot be opened.
  375. //
  376. //--------------------------------------------------------------------------;
  377. LRESULT FNLOCAL acmdDriverOpen
  378. (
  379. HDRVR hdrvr,
  380. LPACMDRVOPENDESC paod
  381. )
  382. {
  383. PDRIVERINSTANCE pdi;
  384. //
  385. // the [optional] open description that is passed to this driver can
  386. // be from multiple 'managers.' for example, AVI looks for installable
  387. // drivers that are tagged with 'vidc' and 'vcap'. we need to verify
  388. // that we are being opened as an Audio Compression Manager driver.
  389. //
  390. // if paod is NULL, then the driver is being opened for some purpose
  391. // other than converting (that is, there will be no stream open
  392. // requests for this instance of being opened). the most common case
  393. // of this is the Control Panel's Drivers option checking for config
  394. // support (DRV_[QUERY]CONFIGURE).
  395. //
  396. // we want to succeed this open, but be able to know that this
  397. // open instance is bogus for creating streams. for this purpose we
  398. // leave most of the members of our instance structure that we
  399. // allocate below as zero...
  400. //
  401. if (NULL != paod)
  402. {
  403. //
  404. // refuse to open if we are not being opened as an ACM driver.
  405. // note that we do NOT modify the value of paod->dwError in this
  406. // case.
  407. //
  408. if (ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC != paod->fccType)
  409. {
  410. return (0L);
  411. }
  412. }
  413. //
  414. // we are being opened as an installable driver--we can allocate some
  415. // instance data to be returned in dwId argument of the DriverProc;
  416. // or simply return non-zero to succeed the open.
  417. //
  418. // this driver allocates a small instance structure. note that we
  419. // rely on allocating the memory as zero-initialized!
  420. //
  421. pdi = (PDRIVERINSTANCE)LocalAlloc(LPTR, sizeof(*pdi));
  422. if (NULL == pdi)
  423. {
  424. //
  425. // if this open attempt was as an ACM driver, then return the
  426. // reason we are failing in the open description structure..
  427. //
  428. if (NULL != paod)
  429. {
  430. paod->dwError = MMSYSERR_NOMEM;
  431. }
  432. //
  433. // fail to open
  434. //
  435. return (0L);
  436. }
  437. //
  438. // fill in our instance structure... note that this instance data
  439. // can be anything that the ACM driver wishes to maintain the
  440. // open driver instance. this data should not contain any information
  441. // that must be maintained per open stream since multiple streams
  442. // can be opened on a single driver instance.
  443. //
  444. // also note that we do _not_ check the version of the ACM opening
  445. // us (paod->dwVersion) to see if it is at least new enough to work
  446. // with this driver (for example, if this driver required Version 3.0
  447. // of the ACM and a Version 2.0 installation tried to open us). the
  448. // reason we do not fail is to allow the ACM to get the driver details
  449. // which contains the version of the ACM that is _required_ by this
  450. // driver. the ACM will examine that value (in padd->vdwACM) and
  451. // do the right thing for this driver... like not load it and inform
  452. // the user of the problem.
  453. //
  454. pdi->hdrvr = hdrvr;
  455. pdi->hinst = GetDriverModuleHandle(hdrvr); // Module handle.
  456. if (NULL != paod)
  457. {
  458. pdi->fnDriverProc = NULL;
  459. pdi->fccType = paod->fccType;
  460. pdi->vdwACM = paod->dwVersion;
  461. pdi->fdwOpen = paod->dwFlags;
  462. paod->dwError = MMSYSERR_NOERROR;
  463. }
  464. //
  465. // non-zero return is success for DRV_OPEN
  466. //
  467. return ((LRESULT)(UINT)pdi);
  468. } // acmdDriverOpen()
  469. //--------------------------------------------------------------------------;
  470. //
  471. // LRESULT acmdDriverClose
  472. //
  473. // Description:
  474. // This function handles the DRV_CLOSE message for the ACM driver. The
  475. // driver receives a DRV_CLOSE message for each succeeded DRV_OPEN
  476. // message (see acmdDriverOpen). The driver will only receive a close
  477. // message for _successful_ opens.
  478. //
  479. // Arguments:
  480. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  481. // This structure is [optionally] allocated during the DRV_OPEN message
  482. // which is handled by the acmdDriverOpen function.
  483. //
  484. // Return (LRESULT):
  485. // The return value is non-zero if the open instance can be closed.
  486. // A zero return signifies that the ACM driver instance could not be
  487. // closed.
  488. //
  489. // NOTE! It is _strongly_ recommended that the driver never fail to
  490. // close. Note that the ACM will never allow a driver instance to
  491. // be closed if there are open streams. An ACM driver does not need
  492. // to check for this case.
  493. //
  494. //--------------------------------------------------------------------------;
  495. LRESULT FNLOCAL acmdDriverClose
  496. (
  497. PDRIVERINSTANCE pdi
  498. )
  499. {
  500. //
  501. // check to see if we allocated instance data. if we did not, then
  502. // immediately succeed.
  503. //
  504. if (NULL != pdi)
  505. {
  506. //
  507. // close down the driver instance. this driver simply needs
  508. // to free the instance data structure... note that if this
  509. // 'free' fails, then this ACM driver probably trashed its
  510. // heap; assume we didn't do that.
  511. //
  512. LocalFree((HLOCAL)pdi);
  513. }
  514. //
  515. // non-zero return is success for DRV_CLOSE
  516. //
  517. return (1L);
  518. } // acmdDriverClose()
  519. //--------------------------------------------------------------------------;
  520. //
  521. // LRESULT acmdDriverConfigure
  522. //
  523. // Description:
  524. // This function is called to handle the DRV_[QUERY]CONFIGURE messages.
  525. // These messages are for 'configuration' support of the driver.
  526. // Normally this will be for 'hardware'--that is, a dialog should be
  527. // displayed to configure ports, IRQ's, memory mappings, etc if it
  528. // needs to. However, a software only ACM driver may also require
  529. // configuration for 'what is real time' or other quality vs time
  530. // issues.
  531. //
  532. // The most common way that these messages are generated under Win 3.1
  533. // and NT Product 1 is from the Control Panel's Drivers option. Other
  534. // sources may generate these messages in future versions of Windows.
  535. //
  536. // Arguments:
  537. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  538. // This structure is [optionally] allocated during the DRV_OPEN message
  539. // which is handled by the acmdDriverOpen function.
  540. //
  541. // HWND hwnd: Handle to parent window to use when displaying the
  542. // configuration dialog box. An ACM driver is _required_ to display a
  543. // modal dialog box using this hwnd argument as the parent. This
  544. // argument may be (HWND)-1 which tells the driver that it is only
  545. // being queried for configuration support.
  546. //
  547. // LPDRVCONFIGINFO pdci: Pointer to optional DRVCONFIGINFO structure.
  548. // If this argument is NULL, then the ACM driver should invent its own
  549. // storage location.
  550. //
  551. // Return (LRESULT):
  552. // If the driver is being 'queried' for configuration support (that is,
  553. // hwnd == (HWND)-1), then non-zero should be returned specifying
  554. // the driver does support a configuration dialog--or zero should be
  555. // returned specifying that no configuration dialog is supported.
  556. //
  557. // If the driver is being called to display the configuration dialog
  558. // (that is, hwnd != (HWND)-1), then one of the following values
  559. // should be returned:
  560. //
  561. // DRVCNF_CANCEL (0x0000): specifies that the dialog was displayed
  562. // and canceled by the user. this value should also be returned if
  563. // no configuration information was modified.
  564. //
  565. // DRVCNF_OK (0x0001): specifies that the dialog was displayed and
  566. // the user pressed OK. This value should be returned even if the
  567. // user didn't change anything - otherwise, the driver may not
  568. // install properly.
  569. //
  570. // DRVCNF_RESTART (0x0002): specifies that the dialog was displayed
  571. // and some configuration information was changed that requires
  572. // Windows to be restarted before the changes take affect. the driver
  573. // should remain configured with current values until the driver
  574. // has been 'rebooted'.
  575. //
  576. //--------------------------------------------------------------------------;
  577. LRESULT FNLOCAL acmdDriverConfigure
  578. (
  579. PDRIVERINSTANCE pdi,
  580. HWND hwnd,
  581. LPDRVCONFIGINFO pdci
  582. )
  583. {
  584. //
  585. // first check to see if we are only being queried for configuration
  586. // support. if hwnd == (HWND)-1 then we are being queried and should
  587. // return zero for 'not supported' and non-zero for 'supported'.
  588. //
  589. if ((HWND)-1 == hwnd)
  590. {
  591. //
  592. // this ACM driver does not support a configuration dialog box, so
  593. // return zero...
  594. //
  595. return (0L);
  596. }
  597. //
  598. // we are being asked to bring up our configuration dialog. if this
  599. // driver supports a configuration dialog box, then after the dialog
  600. // is dismissed we must return one of the following values:
  601. //
  602. // DRVCNF_CANCEL (0x0000): specifies that the dialog was displayed
  603. // and canceled by the user. this value should also be returned if
  604. // no configuration information was modified.
  605. //
  606. // DRVCNF_OK (0x0001): specifies that the dialog was displayed and
  607. // the user pressed OK. This value should be returned even if the
  608. // user didn't change anything - otherwise, the driver may not
  609. // install properly.
  610. //
  611. // DRVCNF_RESTART (0x0002): specifies that the dialog was displayed
  612. // and some configuration information was changed that requires
  613. // Windows to be restarted before the changes take affect. the driver
  614. // should remain configured with current values until the driver
  615. // has been 'rebooted'.
  616. //
  617. //
  618. return (DRVCNF_CANCEL);
  619. } // acmdDriverConfigure()
  620. //--------------------------------------------------------------------------;
  621. //
  622. // LRESULT acmdDriverDetails
  623. //
  624. // Description:
  625. // This function handles the ACMDM_DRIVER_DETAILS message. The ACM
  626. // driver is responsible for filling in the ACMDRIVERDETAILS structure
  627. // with various information.
  628. //
  629. // NOTE! It is *VERY* important that you fill in your ACMDRIVERDETAILS
  630. // structure correctly. The ACM and applications must be able to
  631. // rely on this information.
  632. //
  633. // WARNING! The _reserved_ bits of any fields of the ACMDRIVERDETAILS
  634. // structure are _exactly that_: RESERVED. Do NOT use any extra
  635. // flag bits, etc. for custom information. The proper way to add
  636. // custom capabilities to your ACM driver is this:
  637. //
  638. // o define a new message in the ACMDM_USER range.
  639. //
  640. // o an application that wishes to use one of these extra features
  641. // should then:
  642. //
  643. // o open the driver with acmDriverOpen.
  644. //
  645. // o check for the proper wMid and wPid using acmDriverDetails.
  646. //
  647. // o send the 'user defined' message with acmDriverMessage
  648. // to retrieve additional information, etc.
  649. //
  650. // o close the driver with acmDriverClose.
  651. //
  652. // Arguments:
  653. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  654. // This structure is [optionally] allocated during the DRV_OPEN message
  655. // which is handled by the acmdDriverOpen function.
  656. //
  657. // LPACMDRIVERDETAILS padd: Pointer to ACMDRIVERDETAILS structure to
  658. // fill in for the caller. This structure may be larger or smaller than
  659. // the current definition of ACMDRIVERDETAILS--cbStruct specifies the
  660. // valid size.
  661. //
  662. // Return (LRESULT):
  663. // The return value is zero (MMSYSERR_NOERROR) for success. Non-zero
  664. // signifies that the driver details could not be retrieved.
  665. //
  666. // NOTE THAT THIS FUNCTION SHOULD NEVER FAIL! There are two possible
  667. // error conditions:
  668. //
  669. // o if padd is NULL or an invalid pointer.
  670. //
  671. // o if cbStruct is less than four; in this case, there is not enough
  672. // room to return the number of bytes filled in.
  673. //
  674. // Because these two error conditions are easily defined, the ACM
  675. // will catch these errors. The driver does NOT need to check for these
  676. // conditions.
  677. //
  678. //--------------------------------------------------------------------------;
  679. LRESULT FNLOCAL acmdDriverDetails
  680. (
  681. PDRIVERINSTANCE pdi,
  682. LPACMDRIVERDETAILS padd
  683. )
  684. {
  685. ACMDRIVERDETAILS add;
  686. DWORD cbStruct;
  687. //
  688. // it is easiest to fill in a temporary structure with valid info
  689. // and then copy the requested number of bytes to the destination
  690. // buffer.
  691. //
  692. cbStruct = min(padd->cbStruct, sizeof(ACMDRIVERDETAILS));
  693. add.cbStruct = cbStruct;
  694. //
  695. // for the current implementation of an ACM driver, the fccType and
  696. // fccComp members *MUST* always be ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC
  697. // ('audc') and ACMDRIVERDETAILS_FCCCOMP_UNDEFINED (0) respectively.
  698. //
  699. add.fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
  700. add.fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
  701. //
  702. // the manufacturer id (wMid) and product id (wPid) must be filled
  703. // in with your company's _registered_ identifier's. for more
  704. // information on these identifier's and how to get them registered
  705. // contact Microsoft and get the Multimedia Developer Registration Kit:
  706. //
  707. // Microsoft Corporation
  708. // Multimedia Technology Group
  709. // One Microsoft Way
  710. // Redmond, WA 98052-6399
  711. //
  712. // Developer Services Phone: (800) 227-4679 x11771
  713. //
  714. // note that during the development phase or your ACM driver, you may
  715. // use the reserved value of '0' for both wMid and wPid. however it
  716. // is not acceptable to ship a driver with these values.
  717. //
  718. add.wMid = MM_MICROSOFT;
  719. add.wPid = MM_MSFT_ACM_MSFILTER;
  720. //
  721. // the vdwACM and vdwDriver members contain version information for
  722. // the driver.
  723. //
  724. // vdwACM: must contain the version of the *ACM* that the driver was
  725. // _designed_ for. this is the _minimum_ version number of the ACM
  726. // that the driver will work with. this value must be >= V2.00.000.
  727. //
  728. // vdwDriver: the version of this ACM driver.
  729. //
  730. // ACM driver versions are 32 bit numbers broken into three parts as
  731. // follows (note these parts are displayed as decimal values):
  732. //
  733. // bits 24 - 31: 8 bit _major_ version number
  734. // bits 16 - 23: 8 bit _minor_ version number
  735. // bits 0 - 15: 16 bit build number
  736. //
  737. add.vdwACM = VERSION_MSACM;
  738. add.vdwDriver = VERSION_ACM_DRIVER;
  739. //
  740. // the following flags are used to specify the type of conversion(s)
  741. // that the ACM driver supports. note that a driver may support one or
  742. // more of these flags in any combination.
  743. //
  744. // ACMDRIVERDETAILS_SUPPORTF_CODEC: this flag is set if the driver
  745. // supports conversions from one format tag to another format tag. for
  746. // example, if a converter compresses or decompresses WAVE_FORMAT_PCM
  747. // and WAVE_FORMAT_IMA_ADPCM, then this bit should be set. this is
  748. // true even if the data is not actually changed in size--for example
  749. // a conversion from u-Law to A-Law will still set this bit because
  750. // the format tags differ.
  751. //
  752. // ACMDRIVERDETAILS_SUPPORTF_CONVERTER: this flags is set if the
  753. // driver supports conversions on the same format tag. as an example,
  754. // the PCM converter that is built into the ACM sets this bit (and only
  755. // this bit) because it converts only between PCM formats (bits, sample
  756. // rate).
  757. //
  758. // ACMDRIVERDETAILS_SUPPORTF_FILTER: this flag is set if the driver
  759. // supports transformations on a single format tag but does change
  760. // the base characteristics of the format (bit depth, sample rate, etc
  761. // will remain the same). for example, a driver that changed the
  762. // 'volume' of PCM data or applied a low pass filter would set this bit.
  763. //
  764. add.fdwSupport = ACMDRIVERDETAILS_SUPPORTF_FILTER;
  765. //
  766. // the number of individual format tags this ACM driver supports. for
  767. // example, if a driver uses the WAVE_FORMAT_IMA_ADPCM and
  768. // WAVE_FORMAT_PCM format tags, then this value would be two. if the
  769. // driver only supports filtering on WAVE_FORMAT_PCM, then this value
  770. // would be one. if this driver supported WAVE_FORMAT_ALAW,
  771. // WAVE_FORMAT_MULAW and WAVE_FORMAT_PCM, then this value would be
  772. // three. etc, etc.
  773. //
  774. add.cFormatTags = ACM_DRIVER_MAX_FORMAT_TAGS;
  775. //
  776. // the number of individual filter tags this ACM driver supports. if
  777. // a driver supports no filters (ACMDRIVERDETAILS_SUPPORTF_FILTER is
  778. // NOT set in the fdwSupport member), then this value must be zero.
  779. //
  780. add.cFilterTags = ACM_DRIVER_MAX_FILTER_TAGS;
  781. //
  782. // the remaining members in the ACMDRIVERDETAILS structure are sometimes
  783. // not needed. because of this we make a quick check to see if we
  784. // should go through the effort of filling in these members.
  785. //
  786. if (FIELD_OFFSET(ACMDRIVERDETAILS, hicon) < cbStruct)
  787. {
  788. //
  789. // fill in the hicon member will a handle to a custom icon for
  790. // the ACM driver. this allows the driver to be represented by
  791. // an application graphically (usually this will be a company
  792. // logo or something). if a driver does not wish to have a custom
  793. // icon displayed, then simply set this member to NULL and a
  794. // generic icon will be displayed instead.
  795. //
  796. add.hicon = LoadIcon(pdi->hinst, ICON_ACM_DRIVER);
  797. //
  798. // the short name and long name are used to represent the driver
  799. // in a unique description. the short name is intended for small
  800. // display areas (for example, in a menu or combo box). the long
  801. // name is intended for more descriptive displays (for example,
  802. // in an 'about box').
  803. //
  804. // NOTE! an ACM driver should never place formatting characters
  805. // of any sort in these strings (for example CR/LF's, etc). it
  806. // is up to the application to format the text.
  807. //
  808. LoadStringCodec(pdi->hinst, IDS_ACM_DRIVER_SHORTNAME, add.szShortName, SIZEOFACMSTR(add.szShortName));
  809. LoadStringCodec(pdi->hinst, IDS_ACM_DRIVER_LONGNAME, add.szLongName, SIZEOFACMSTR(add.szLongName));
  810. //
  811. // the last three members are intended for 'about box' information.
  812. // these members are optional and may be zero length strings if
  813. // the driver wishes.
  814. //
  815. // NOTE! an ACM driver should never place formatting characters
  816. // of any sort in these strings (for example CR/LF's, etc). it
  817. // is up to the application to format the text.
  818. //
  819. if (FIELD_OFFSET(ACMDRIVERDETAILS, szCopyright) < cbStruct)
  820. {
  821. LoadStringCodec(pdi->hinst, IDS_ACM_DRIVER_COPYRIGHT, add.szCopyright, SIZEOFACMSTR(add.szCopyright));
  822. LoadStringCodec(pdi->hinst, IDS_ACM_DRIVER_LICENSING, add.szLicensing, SIZEOFACMSTR(add.szLicensing));
  823. LoadStringCodec(pdi->hinst, IDS_ACM_DRIVER_FEATURES, add.szFeatures, SIZEOFACMSTR(add.szFeatures));
  824. }
  825. }
  826. //
  827. // now copy the correct number of bytes to the caller's buffer
  828. //
  829. _fmemcpy(padd, &add, (UINT)add.cbStruct);
  830. //
  831. // success!
  832. //
  833. return (MMSYSERR_NOERROR);
  834. } // acmdDriverDetails()
  835. //--------------------------------------------------------------------------;
  836. //
  837. // BOOL acmdDlgProcAbout
  838. //
  839. // Description:
  840. //
  841. // This dialog procedure is used for the ubiquitous about box.
  842. //
  843. // Note that we need to create a brush and store the handle between
  844. // messages. In order to avoid using global memory, we store the
  845. // handle to this brush in the Window structure using the DWL_USER
  846. // index.
  847. //
  848. // Arguments:
  849. // HWND hwnd: Handle to window.
  850. //
  851. // UINT uMsg: Message being sent to the window.
  852. //
  853. // WPARAM wParam: Specific argument to message.
  854. //
  855. // LPARAM lParam: Specific argument to message.
  856. //
  857. // Return (BOOL):
  858. // The return value is specific to the message that was received. For
  859. // the most part, it is FALSE if this dialog procedure does not handle
  860. // a message. Note, however, that we must return an HBRUSH for Windows
  861. // to use for painting the background for the WM_CTLCOLORxxx messages.
  862. //
  863. //
  864. //--------------------------------------------------------------------------;
  865. #define ABOUT_BACKGROUNDCOLOR RGB(128,128,128)
  866. #define ABOUT_HILIGHTCOLOR RGB(0,255,255)
  867. BOOL FNEXPORT acmdDlgProcAbout
  868. (
  869. HWND hwnd,
  870. UINT uMsg,
  871. WPARAM wParam,
  872. LPARAM lParam
  873. )
  874. {
  875. HBRUSH hbr;
  876. HWND hctrl;
  877. UINT u;
  878. hbr = (HBRUSH)GetWindowLong( hwnd, DWL_USER );
  879. switch (uMsg)
  880. {
  881. case WM_INITDIALOG:
  882. hbr = CreateSolidBrush( ABOUT_BACKGROUNDCOLOR );
  883. SetWindowLong( hwnd, DWL_USER, (LONG)hbr );
  884. return TRUE;
  885. case WM_CTLCOLORSTATIC:
  886. hctrl = GetDlgItem( hwnd, IDC_ABOUT_CATCHTHEWAVE );
  887. if( (HWND)lParam == hctrl )
  888. {
  889. SetTextColor( (HDC)wParam, ABOUT_HILIGHTCOLOR );
  890. }
  891. // Fall through...
  892. case WM_CTLCOLORDLG:
  893. case WM_CTLCOLORBTN:
  894. SetBkColor( (HDC)wParam, ABOUT_BACKGROUNDCOLOR );
  895. return (BOOL)hbr;
  896. case WM_COMMAND:
  897. u = GET_WM_COMMAND_ID(wParam, lParam);
  898. if ((IDOK == u) || (IDCANCEL == u))
  899. {
  900. EndDialog(hwnd, (IDOK == u));
  901. }
  902. return FALSE;
  903. case WM_DESTROY:
  904. DeleteObject( hbr );
  905. return FALSE;
  906. }
  907. return (FALSE);
  908. } // acmdDlgProcAbout()
  909. //--------------------------------------------------------------------------;
  910. //
  911. // LRESULT acmdDriverAbout
  912. //
  913. // Description:
  914. // This function is called to handle the ACMDM_DRIVER_ABOUT message.
  915. // An ACM driver has the option of displaying its own 'about box' or
  916. // letting the ACM (or calling application) display one for it. This
  917. // message is normally sent by the Control Panel's Sound Mapper
  918. // option.
  919. //
  920. // It is recommended that an ACM driver allow a default about box
  921. // be displayed for it--there should be no reason to bloat the size
  922. // of a driver to simply display copyright, etc information when that
  923. // information is contained in the ACMDRIVERDETAILS structure.
  924. //
  925. // Arguments:
  926. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  927. // This structure is [optionally] allocated during the DRV_OPEN message
  928. // which is handled by the acmdDriverOpen function.
  929. //
  930. // HWND hwnd: Handle to parent window to use when displaying the
  931. // configuration dialog box. An ACM driver is _required_ to display a
  932. // modal dialog box using this hwnd argument as the parent. This
  933. // argument may be (HWND)-1 which tells the driver that it is only
  934. // being queried for about box support.
  935. //
  936. // Return (LRESULT):
  937. // The return value is MMSYSERR_NOTSUPPORTED if the ACM driver does
  938. // not support a custom dialog box. In this case, the ACM or calling
  939. // application will display a generic about box using the information
  940. // contained in the ACMDRIVERDETAILS structure returned by the
  941. // ACMDM_DRIVER_DETAILS message.
  942. //
  943. // If the driver chooses to display its own dialog box, then after
  944. // the dialog is dismissed by the user, MMSYSERR_NOERROR should be
  945. // returned.
  946. //
  947. // If the hwnd argument is equal to (HWND)-1, then no dialog should
  948. // be displayed (the driver is only being queried for support). The
  949. // driver must still return MMSYSERR_NOERROR (supported) or
  950. // MMSYSERR_NOTSUPPORTED (no custom about box supported).
  951. //
  952. //--------------------------------------------------------------------------;
  953. LRESULT FNLOCAL acmdDriverAbout
  954. (
  955. PDRIVERINSTANCE pdi,
  956. HWND hwnd
  957. )
  958. {
  959. //
  960. // first check to see if we are only being queried for custom about
  961. // box support. if hwnd == (HWND)-1 then we are being queried and
  962. // should return MMSYSERR_NOTSUPPORTED for 'not supported' and
  963. // MMSYSERR_NOERROR for 'supported'.
  964. //
  965. if ((HWND)-1 == hwnd)
  966. {
  967. //
  968. // this ACM driver supports a custom about box, so
  969. // return MMSYSERR_NOERROR...
  970. //
  971. return (MMSYSERR_NOERROR);
  972. }
  973. //
  974. // this driver does support a custom dialog, so display it. Note,
  975. // however, that it is better to let the ACM display the About box
  976. // for us - that means smaller code, and fewer bugs!
  977. //
  978. DialogBox( pdi->hinst, IDD_ABOUT, hwnd, acmdDlgProcAbout );
  979. return (MMSYSERR_NOERROR);
  980. } // acmdDriverAbout()
  981. //==========================================================================;
  982. //
  983. //
  984. //
  985. //
  986. //==========================================================================;
  987. //--------------------------------------------------------------------------;
  988. //
  989. // LRESULT acmdFormatTagDetails
  990. //
  991. // Description:
  992. // This function handles the ACMDM_FORMATTAG_DETAILS message. This
  993. // message is normally sent in response to an acmFormatTagDetails or
  994. // acmFormatTagEnum function call. The purpose of this function is
  995. // to get details about a specific format tag supported by this ACM
  996. // driver.
  997. //
  998. // Arguments:
  999. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  1000. // This structure is [optionally] allocated during the DRV_OPEN message
  1001. // which is handled by the acmdDriverOpen function.
  1002. //
  1003. // LPACMFORMATTAGDETAILS padft: Pointer to an ACMFORMATTAGDETAILS
  1004. // structure that describes what format tag to retrieve details for.
  1005. //
  1006. // DWORD fdwDetails: Flags defining what format tag to retrieve the
  1007. // details for.
  1008. //
  1009. // Return (LRESULT):
  1010. // The return value is zero (MMSYSERR_NOERROR) if this function
  1011. // succeeds with no errors. The return value is a non-zero error code
  1012. // if the function fails.
  1013. //
  1014. // The driver should return MMSYSERR_NOTSUPPORTED if the query type
  1015. // specified in fdwDetails is not supported. An ACM driver must
  1016. // support at least the following query types:
  1017. //
  1018. // ACM_FORMATTAGDETAILSF_INDEX: Indicates that a format tag index
  1019. // was given in the dwFormatTagIndex member of the ACMFORMATTAGDETAILS
  1020. // structure. The format tag and details must be returned in the
  1021. // structure specified by padft. The index ranges from zero to one less
  1022. // than the cFormatTags member returned in the ACMDRIVERDETAILS
  1023. // structure for this driver.
  1024. //
  1025. // ACM_FORMATTAGDETAILSF_FORMATTAG: Indicates that a format tag
  1026. // was given in the dwFormatTag member of the ACMFORMATTAGDETAILS
  1027. // structure. The format tag details must be returned in the structure
  1028. // specified by padft.
  1029. //
  1030. // ACM_FORMATTAGDETAILSF_LARGESTSIZE: Indicates that the details
  1031. // on the format tag with the largest format size in bytes must be
  1032. // returned. The dwFormatTag member will either be WAVE_FORMAT_UNKNOWN
  1033. // or the format tag to find the largest size for.
  1034. //
  1035. // If the details for the specified format tag cannot be retrieved
  1036. // from this driver, then ACMERR_NOTPOSSIBLE should be returned.
  1037. //
  1038. //--------------------------------------------------------------------------;
  1039. LRESULT FNLOCAL acmdFormatTagDetails
  1040. (
  1041. PDRIVERINSTANCE pdi,
  1042. LPACMFORMATTAGDETAILS padft,
  1043. DWORD fdwDetails
  1044. )
  1045. {
  1046. UINT uFormatTag;
  1047. //
  1048. //
  1049. //
  1050. //
  1051. //
  1052. switch (ACM_FORMATTAGDETAILSF_QUERYMASK & fdwDetails)
  1053. {
  1054. case ACM_FORMATTAGDETAILSF_INDEX:
  1055. //
  1056. // if the index is too large, then they are asking for a
  1057. // non-existant format. return error.
  1058. //
  1059. if (ACM_DRIVER_MAX_FORMAT_TAGS <= padft->dwFormatTagIndex)
  1060. return (ACMERR_NOTPOSSIBLE);
  1061. uFormatTag = gauFormatTagIndexToTag[(UINT)padft->dwFormatTagIndex];
  1062. break;
  1063. case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
  1064. switch (padft->dwFormatTag)
  1065. {
  1066. case WAVE_FORMAT_UNKNOWN:
  1067. case WAVE_FORMAT_PCM:
  1068. uFormatTag = WAVE_FORMAT_PCM;
  1069. break;
  1070. default:
  1071. return (ACMERR_NOTPOSSIBLE);
  1072. }
  1073. break;
  1074. case ACM_FORMATTAGDETAILSF_FORMATTAG:
  1075. if (WAVE_FORMAT_PCM != padft->dwFormatTag)
  1076. return (ACMERR_NOTPOSSIBLE);
  1077. uFormatTag = WAVE_FORMAT_PCM;
  1078. break;
  1079. //
  1080. // if this ACM driver does not understand a query type, then
  1081. // return 'not supported'
  1082. //
  1083. default:
  1084. return (MMSYSERR_NOTSUPPORTED);
  1085. }
  1086. //
  1087. //
  1088. //
  1089. //
  1090. switch (uFormatTag)
  1091. {
  1092. case WAVE_FORMAT_PCM:
  1093. padft->dwFormatTagIndex = 0;
  1094. padft->dwFormatTag = WAVE_FORMAT_PCM;
  1095. padft->cbFormatSize = sizeof(PCMWAVEFORMAT);
  1096. padft->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_FILTER;
  1097. padft->cStandardFormats = ACM_DRIVER_MAX_STANDARD_FORMATS_PCM;
  1098. //
  1099. // the ACM is responsible for the PCM format tag name
  1100. //
  1101. padft->szFormatTag[0] = '\0';
  1102. break;
  1103. default:
  1104. return (ACMERR_NOTPOSSIBLE);
  1105. }
  1106. //
  1107. // return only the requested info
  1108. //
  1109. // the ACM will guarantee that the ACMFORMATTAGDETAILS structure
  1110. // passed is at least large enough to hold the base information of
  1111. // the details structure
  1112. //
  1113. padft->cbStruct = min(padft->cbStruct, sizeof(*padft));
  1114. //
  1115. //
  1116. //
  1117. return (MMSYSERR_NOERROR);
  1118. } // acmdFormatTagDetails()
  1119. //--------------------------------------------------------------------------;
  1120. //
  1121. // LRESULT acmdFormatDetails
  1122. //
  1123. // Description:
  1124. // This function handles the ACMDM_FORMAT_DETAILS message. This
  1125. // message is normally sent in response to an acmFormatDetails or
  1126. // acmFormatEnum function call. The purpose of this function is
  1127. // to get details about a specific format for a specified format tag
  1128. // supported by this ACM driver.
  1129. //
  1130. // Note that an ACM driver can return a zero length string for the
  1131. // format name if it wishes to have the ACM create a format string
  1132. // for it. This is strongly recommended to simplify internationalizing
  1133. // the driver--the ACM will automatically take care of that. The
  1134. // following formula is used to format a string by the ACM:
  1135. //
  1136. // <nSamplesPerSec> kHz, <bit depth> bit, [Mono | Stereo | nChannels]
  1137. //
  1138. // <bit depth> = <nAvgBytesPerSec> * 8 / nSamplesPerSec / nChannels;
  1139. //
  1140. // Arguments:
  1141. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  1142. // This structure is [optionally] allocated during the DRV_OPEN message
  1143. // which is handled by the acmdDriverOpen function.
  1144. //
  1145. // LPACMFORMATDETAILS padf: Pointer to an ACMFORMATDETAILS structure
  1146. // that describes what format (for a specified format tag) to retrieve
  1147. // details for.
  1148. //
  1149. // DWORD fdwDetails: Flags defining what format for a specified format
  1150. // tag to retrieve the details for.
  1151. //
  1152. // Return (LRESULT):
  1153. // The return value is zero (MMSYSERR_NOERROR) if this function
  1154. // succeeds with no errors. The return value is a non-zero error code
  1155. // if the function fails.
  1156. //
  1157. // The driver should return MMSYSERR_NOTSUPPORTED if the query type
  1158. // specified in fdwDetails is not supported. An ACM driver must
  1159. // support at least the following query types:
  1160. //
  1161. // ACM_FORMATDETAILSF_INDEX: Indicates that a format index for the
  1162. // format tag was given in the dwFormatIndex member of the
  1163. // ACMFORMATDETAILS structure. The format details must be returned in
  1164. // the structure specified by padf. The index ranges from zero to one
  1165. // less than the cStandardFormats member returned in the
  1166. // ACMFORMATTAGDETAILS structure for a format tag.
  1167. //
  1168. // ACM_FORMATDETAILSF_FORMAT: Indicates that a WAVEFORMATEX structure
  1169. // pointed to by pwfx of the ACMFORMATDETAILS structure was given and
  1170. // the remaining details should be returned. The dwFormatTag member
  1171. // of the ACMFORMATDETAILS will be initialized to the same format
  1172. // tag as the pwfx member specifies. This query type may be used to
  1173. // get a string description of an arbitrary format structure.
  1174. //
  1175. // If the details for the specified format cannot be retrieved
  1176. // from this driver, then ACMERR_NOTPOSSIBLE should be returned.
  1177. //
  1178. //--------------------------------------------------------------------------;
  1179. LRESULT FNLOCAL acmdFormatDetails
  1180. (
  1181. PDRIVERINSTANCE pdi,
  1182. LPACMFORMATDETAILS padf,
  1183. DWORD fdwDetails
  1184. )
  1185. {
  1186. LPWAVEFORMATEX pwfx;
  1187. UINT uFormatIndex;
  1188. UINT u;
  1189. //
  1190. //
  1191. //
  1192. //
  1193. //
  1194. switch (ACM_FORMATDETAILSF_QUERYMASK & fdwDetails)
  1195. {
  1196. //
  1197. // enumerate by index
  1198. //
  1199. // verify that the format tag is something we know about and
  1200. // return the details on the 'standard format' supported by
  1201. // this driver at the specified index...
  1202. //
  1203. case ACM_FORMATDETAILSF_INDEX:
  1204. //
  1205. // verify that the format tag is something we know about
  1206. //
  1207. if (WAVE_FORMAT_PCM != padf->dwFormatTag)
  1208. return (ACMERR_NOTPOSSIBLE);
  1209. if (ACM_DRIVER_MAX_STANDARD_FORMATS_PCM <= padf->dwFormatIndex)
  1210. return (ACMERR_NOTPOSSIBLE);
  1211. //
  1212. // put some stuff in more accessible variables--note that we
  1213. // bring variable sizes down to a reasonable size for 16 bit
  1214. // code...
  1215. //
  1216. pwfx = padf->pwfx;
  1217. uFormatIndex = (UINT)padf->dwFormatIndex;
  1218. //
  1219. // now fill in the format structure
  1220. //
  1221. pwfx->wFormatTag = WAVE_FORMAT_PCM;
  1222. u = uFormatIndex / (ACM_DRIVER_MAX_BITSPERSAMPLE_PCM * ACM_DRIVER_MAX_CHANNELS);
  1223. pwfx->nSamplesPerSec = gauFormatIndexToSampleRate[u];
  1224. u = uFormatIndex % ACM_DRIVER_MAX_CHANNELS;
  1225. pwfx->nChannels = u + 1;
  1226. u = (uFormatIndex / ACM_DRIVER_MAX_CHANNELS) % ACM_DRIVER_MAX_CHANNELS;
  1227. pwfx->wBitsPerSample = gauFormatIndexToBitsPerSample[u];
  1228. pwfx->nBlockAlign = PCM_BLOCKALIGNMENT(pwfx);
  1229. pwfx->nAvgBytesPerSec = PCM_AVGBYTESPERSEC(pwfx);
  1230. //
  1231. // note that the cbSize field is NOT valid for PCM formats
  1232. //
  1233. // pwfx->cbSize = 0;
  1234. break;
  1235. //
  1236. // return details on specified format
  1237. //
  1238. // the caller normally uses this to verify that the format is
  1239. // supported and to retrieve a string description...
  1240. //
  1241. case ACM_FORMATDETAILSF_FORMAT:
  1242. if (!pcmIsValidFormat(padf->pwfx))
  1243. return (ACMERR_NOTPOSSIBLE);
  1244. break;
  1245. default:
  1246. //
  1247. // don't know how to do the query type passed--return 'not
  1248. // supported'.
  1249. //
  1250. return (MMSYSERR_NOTSUPPORTED);
  1251. }
  1252. //
  1253. // return the size of the valid information we are returning
  1254. //
  1255. // the ACM will guarantee that the ACMFORMATDETAILS structure
  1256. // passed is at least large enough to hold the base structure
  1257. //
  1258. // note that we let the ACM create the format string for us since
  1259. // we require no special formatting (and don't want to deal with
  1260. // internationalization issues, etc). simply set the string to
  1261. // a zero length.
  1262. //
  1263. padf->cbStruct = min(padf->cbStruct, sizeof(*padf));
  1264. padf->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_FILTER;
  1265. padf->szFormat[0] = '\0';
  1266. //
  1267. //
  1268. //
  1269. return (MMSYSERR_NOERROR);
  1270. } // acmdFormatDetails()
  1271. //==========================================================================;
  1272. //
  1273. //
  1274. //
  1275. //
  1276. //==========================================================================;
  1277. //--------------------------------------------------------------------------;
  1278. //
  1279. // LRESULT acmdFilterTagDetails
  1280. //
  1281. // Description:
  1282. //
  1283. //
  1284. // Arguments:
  1285. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  1286. // This structure is [optionally] allocated during the DRV_OPEN message
  1287. // which is handled by the acmdDriverOpen function.
  1288. //
  1289. // LPACMFILTERTAGDETAILS padft:
  1290. //
  1291. // DWORD fdwDetails:
  1292. //
  1293. // Return (LRESULT):
  1294. //
  1295. //
  1296. //--------------------------------------------------------------------------;
  1297. LRESULT FNLOCAL acmdFilterTagDetails
  1298. (
  1299. PDRIVERINSTANCE pdi,
  1300. LPACMFILTERTAGDETAILS padft,
  1301. DWORD fdwDetails
  1302. )
  1303. {
  1304. UINT uIds;
  1305. UINT uFilterTag;
  1306. //
  1307. //
  1308. //
  1309. //
  1310. //
  1311. switch (ACM_FILTERTAGDETAILSF_QUERYMASK & fdwDetails)
  1312. {
  1313. case ACM_FILTERTAGDETAILSF_INDEX:
  1314. //
  1315. // if the index is too large, then they are asking for a
  1316. // non-existant filter. return error.
  1317. //
  1318. if (ACM_DRIVER_MAX_FILTER_TAGS <= padft->dwFilterTagIndex)
  1319. return (ACMERR_NOTPOSSIBLE);
  1320. uFilterTag = (UINT)gadwFilterTagIndexToTag[(UINT)padft->dwFilterTagIndex];
  1321. break;
  1322. case ACM_FILTERTAGDETAILSF_LARGESTSIZE:
  1323. switch (padft->dwFilterTag)
  1324. {
  1325. case WAVE_FILTER_UNKNOWN:
  1326. case WAVE_FILTER_ECHO:
  1327. uFilterTag = WAVE_FILTER_ECHO;
  1328. break;
  1329. case WAVE_FILTER_VOLUME:
  1330. uFilterTag = WAVE_FILTER_VOLUME;
  1331. break;
  1332. default:
  1333. return (ACMERR_NOTPOSSIBLE);
  1334. }
  1335. break;
  1336. case ACM_FILTERTAGDETAILSF_FILTERTAG:
  1337. switch (padft->dwFilterTag)
  1338. {
  1339. case WAVE_FILTER_VOLUME:
  1340. uFilterTag = WAVE_FILTER_VOLUME;
  1341. break;
  1342. case WAVE_FILTER_ECHO:
  1343. uFilterTag = WAVE_FILTER_ECHO;
  1344. break;
  1345. default:
  1346. return (ACMERR_NOTPOSSIBLE);
  1347. }
  1348. break;
  1349. //
  1350. // if this driver does not understand a query type, then
  1351. // return 'not supported'
  1352. //
  1353. default:
  1354. return (MMSYSERR_NOTSUPPORTED);
  1355. }
  1356. //
  1357. //
  1358. //
  1359. //
  1360. switch (uFilterTag)
  1361. {
  1362. case WAVE_FILTER_VOLUME:
  1363. padft->dwFilterTagIndex = 0;
  1364. padft->dwFilterTag = WAVE_FILTER_VOLUME;
  1365. padft->cbFilterSize = sizeof(VOLUMEWAVEFILTER);
  1366. padft->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_FILTER;
  1367. padft->cStandardFilters = ACM_DRIVER_MAX_VOLUME_FILTERS;
  1368. uIds = IDS_ACM_DRIVER_TAG_NAME_VOLUME;
  1369. break;
  1370. case WAVE_FILTER_ECHO:
  1371. padft->dwFilterTagIndex = 1;
  1372. padft->dwFilterTag = WAVE_FILTER_ECHO;
  1373. padft->cbFilterSize = sizeof(ECHOWAVEFILTER);
  1374. padft->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_FILTER;
  1375. padft->cStandardFilters = ACM_DRIVER_MAX_ECHO_FILTERS;
  1376. uIds = IDS_ACM_DRIVER_TAG_NAME_ECHO;
  1377. break;
  1378. default:
  1379. return (ACMERR_NOTPOSSIBLE);
  1380. }
  1381. //
  1382. // return only the requested info
  1383. //
  1384. // the ACM will guarantee that the ACMFILTERTAGDETAILS structure
  1385. // passed is at least large enough to hold the base structure
  1386. //
  1387. padft->cbStruct = min(padft->cbStruct, sizeof(*padft));
  1388. LoadStringCodec(pdi->hinst, uIds, padft->szFilterTag, SIZEOFACMSTR(padft->szFilterTag));
  1389. //
  1390. //
  1391. //
  1392. return (MMSYSERR_NOERROR);
  1393. } // acmdFilterTagDetails()
  1394. //--------------------------------------------------------------------------;
  1395. //
  1396. // UINT acmdFilterDetailsToString
  1397. //
  1398. // Description:
  1399. // This function has a special UNICODE string implementation for common
  1400. // binary codecs between Chicago and Daytona.
  1401. //
  1402. // Arguments:
  1403. // LPWAVEFILTER pwf:
  1404. //
  1405. // LPTSTR szFilter:
  1406. //
  1407. // Return (UINT):
  1408. //
  1409. //
  1410. //--------------------------------------------------------------------------;
  1411. #if defined(WIN32) && !defined(UNICODE)
  1412. UINT FNLOCAL acmdFilterDetailsToString
  1413. (
  1414. PDRIVERINSTANCE pdi,
  1415. LPWAVEFILTER pwf,
  1416. LPWSTR szFilter
  1417. )
  1418. {
  1419. UINT u;
  1420. CHAR ach1[ACMFILTERDETAILS_FILTER_CHARS];
  1421. CHAR ach2[ACMFILTERDETAILS_FILTER_CHARS];
  1422. LPVOLUMEWAVEFILTER pwfVol;
  1423. LPECHOWAVEFILTER pwfEcho;
  1424. if( !szFilter ) {
  1425. return 0L;
  1426. }
  1427. *szFilter = L'\0';
  1428. if (volumeIsValidFilter(pwf))
  1429. {
  1430. pwfVol = (LPVOLUMEWAVEFILTER)pwf;
  1431. LoadStringA(pdi->hinst, IDS_ACM_DRIVER_FORMAT_VOLUME, ach1, SIZEOF(ach1));
  1432. u = wsprintfA( ach2, ach1,
  1433. (WORD)(((pwfVol->dwVolume * 100) / 0x10000)) );
  1434. MultiByteToWideChar( GetACP(), 0, ach2, u+1, szFilter,
  1435. ACMFILTERDETAILS_FILTER_CHARS );
  1436. return( u );
  1437. }
  1438. else if (echoIsValidFilter(pwf))
  1439. {
  1440. pwfEcho = (LPECHOWAVEFILTER)pwf;
  1441. LoadStringA(pdi->hinst, IDS_ACM_DRIVER_FORMAT_ECHO, ach1, SIZEOF(ach1));
  1442. u = wsprintfA( ach2, ach1,
  1443. (WORD)(((pwfEcho->dwVolume * 100) / 0x10000)),
  1444. (WORD)pwfEcho->dwDelay );
  1445. MultiByteToWideChar( GetACP(), 0, ach2, u+1, szFilter,
  1446. ACMFILTERDETAILS_FILTER_CHARS );
  1447. return( u );
  1448. }
  1449. return ( 0 );
  1450. } // acmdFilterDetailsToString()
  1451. #else
  1452. UINT FNLOCAL acmdFilterDetailsToString
  1453. (
  1454. PDRIVERINSTANCE pdi,
  1455. LPWAVEFILTER pwf,
  1456. LPTSTR szFilter
  1457. )
  1458. {
  1459. UINT u;
  1460. TCHAR ach[ACMFILTERDETAILS_FILTER_CHARS];
  1461. LPVOLUMEWAVEFILTER pwfVol;
  1462. LPECHOWAVEFILTER pwfEcho;
  1463. if( !szFilter ) {
  1464. return 0L;
  1465. }
  1466. *szFilter = TEXT('\0');
  1467. if (volumeIsValidFilter(pwf))
  1468. {
  1469. pwfVol = (LPVOLUMEWAVEFILTER)pwf;
  1470. LoadString(pdi->hinst, IDS_ACM_DRIVER_FORMAT_VOLUME, ach, SIZEOF(ach));
  1471. u = wsprintf( szFilter, ach,
  1472. (WORD)(((pwfVol->dwVolume * 100) / 0x10000)) );
  1473. return( u );
  1474. }
  1475. else if (echoIsValidFilter(pwf))
  1476. {
  1477. pwfEcho = (LPECHOWAVEFILTER)pwf;
  1478. LoadString(pdi->hinst, IDS_ACM_DRIVER_FORMAT_ECHO, ach, SIZEOF(ach));
  1479. u = wsprintf( szFilter, ach,
  1480. (WORD)(((pwfEcho->dwVolume * 100) / 0x10000)),
  1481. (WORD)pwfEcho->dwDelay );
  1482. return( u );
  1483. }
  1484. return ( 0 );
  1485. } // acmdFilterDetailsToString()
  1486. #endif
  1487. //--------------------------------------------------------------------------;
  1488. //
  1489. // LRESULT acmdFilterDetails
  1490. //
  1491. // Description:
  1492. //
  1493. //
  1494. // Arguments:
  1495. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  1496. // This structure is [optionally] allocated during the DRV_OPEN message
  1497. // which is handled by the acmdDriverOpen function.
  1498. //
  1499. // LPACMFILTERDETAILS padf:
  1500. //
  1501. // DWORD fdwDetails:
  1502. //
  1503. // Return (LRESULT):
  1504. //
  1505. //
  1506. //--------------------------------------------------------------------------;
  1507. LRESULT FNLOCAL acmdFilterDetails
  1508. (
  1509. PDRIVERINSTANCE pdi,
  1510. LPACMFILTERDETAILS padf,
  1511. DWORD fdwDetails
  1512. )
  1513. {
  1514. UINT uFilterIndex;
  1515. LPWAVEFILTER pwf;
  1516. LPVOLUMEWAVEFILTER pwfVolume;
  1517. LPECHOWAVEFILTER pwfEcho;
  1518. UINT u;
  1519. pwf = padf->pwfltr;
  1520. //
  1521. //
  1522. //
  1523. //
  1524. //
  1525. switch (ACM_FILTERDETAILSF_QUERYMASK & fdwDetails)
  1526. {
  1527. case ACM_FILTERDETAILSF_INDEX:
  1528. //
  1529. // enumerate by index
  1530. //
  1531. // for this converter, this is more code than necessary... just
  1532. // verify that the filter tag is something we know about
  1533. //
  1534. switch (padf->dwFilterTag)
  1535. {
  1536. case WAVE_FILTER_VOLUME:
  1537. if (ACM_DRIVER_MAX_VOLUME_FILTERS <= padf->dwFilterIndex)
  1538. return (ACMERR_NOTPOSSIBLE);
  1539. pwfVolume = (LPVOLUMEWAVEFILTER)padf->pwfltr;
  1540. pwf->cbStruct = sizeof(VOLUMEWAVEFILTER);
  1541. pwf->dwFilterTag = WAVE_FILTER_VOLUME;
  1542. pwf->fdwFilter = 0;
  1543. pwfVolume->dwVolume = gdwFilterIndexToVolume[(UINT)padf->dwFilterIndex];
  1544. break;
  1545. case WAVE_FILTER_ECHO:
  1546. if (ACM_DRIVER_MAX_ECHO_FILTERS <= padf->dwFilterIndex)
  1547. return (ACMERR_NOTPOSSIBLE);
  1548. pwfEcho = (LPECHOWAVEFILTER)padf->pwfltr;
  1549. pwf->cbStruct = sizeof(ECHOWAVEFILTER);
  1550. pwf->dwFilterTag = WAVE_FILTER_ECHO;
  1551. pwf->fdwFilter = 0;
  1552. uFilterIndex = (UINT)padf->dwFilterIndex;
  1553. u = uFilterIndex / ACM_DRIVER_NUM_DELAY;
  1554. pwfEcho->dwVolume = gdwFilterIndexToEchoVol[u];
  1555. u = uFilterIndex % ACM_DRIVER_NUM_DELAY;
  1556. pwfEcho->dwDelay = gdwFilterIndexToDelay[u];
  1557. break;
  1558. default:
  1559. return (ACMERR_NOTPOSSIBLE);
  1560. }
  1561. case ACM_FILTERDETAILSF_FILTER:
  1562. //
  1563. // must want to verify that the filter passed in is supported
  1564. // and return a string description...
  1565. //
  1566. switch (pwf->dwFilterTag)
  1567. {
  1568. case WAVE_FILTER_VOLUME:
  1569. if (!volumeIsValidFilter(pwf))
  1570. return (ACMERR_NOTPOSSIBLE);
  1571. break;
  1572. case WAVE_FILTER_ECHO:
  1573. if (!echoIsValidFilter(pwf))
  1574. return (ACMERR_NOTPOSSIBLE);
  1575. break;
  1576. default:
  1577. return (ACMERR_NOTPOSSIBLE);
  1578. }
  1579. break;
  1580. default:
  1581. //
  1582. // don't know how to do the query type passed--return 'not
  1583. // supported'.
  1584. //
  1585. return (MMSYSERR_NOTSUPPORTED);
  1586. }
  1587. //
  1588. // return only the requested info
  1589. //
  1590. // the ACM will guarantee that the ACMFILTERDETAILS structure
  1591. // passed is at least large enough to hold everything in the base
  1592. // filter details structure...
  1593. //
  1594. // get a nice friendly string for the filter we made
  1595. //
  1596. acmdFilterDetailsToString(pdi, pwf, padf->szFilter);
  1597. //
  1598. // if they asked for more info than we know how to return, then
  1599. // set size of valid structure bytes to correct value.
  1600. //
  1601. padf->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_FILTER;
  1602. padf->cbStruct = min(padf->cbStruct, sizeof(*padf));
  1603. //
  1604. //
  1605. //
  1606. return (MMSYSERR_NOERROR);
  1607. } // acmdFilterDetails()
  1608. //==========================================================================;
  1609. //
  1610. //
  1611. //
  1612. //
  1613. //==========================================================================;
  1614. //--------------------------------------------------------------------------;
  1615. //
  1616. // LRESULT acmdStreamOpen
  1617. //
  1618. // Description:
  1619. // This function handles the ACMDM_STREAM_OPEN message. This message
  1620. // is sent to initiate a new conversion stream. This is usually caused
  1621. // by an application calling acmStreamOpen. If this function is
  1622. // successful, then one or more ACMDM_STREAM_CONVERT messages will be
  1623. // sent to convert individual buffers (user calls acmStreamConvert).
  1624. //
  1625. // Note that an ACM driver will not receive open requests for ASYNC
  1626. // or FILTER operations unless the ACMDRIVERDETAILS_SUPPORTF_ASYNC
  1627. // or ACMDRIVERDETAILS_SUPPORTF_FILTER flags are set in the
  1628. // ACMDRIVERDETAILS structure. There is no need for the driver to
  1629. // check for these requests unless it sets those support bits.
  1630. //
  1631. // If the ACM_STREAMOPENF_QUERY flag is set in the padsi->fdwOpen
  1632. // member, then no resources should be allocated. Just verify that
  1633. // the conversion request is possible by this driver and return the
  1634. // appropriate error (either ACMERR_NOTPOSSIBLE or MMSYSERR_NOERROR).
  1635. // The driver will NOT receive an ACMDM_STREAM_CLOSE for queries.
  1636. //
  1637. // If the ACM_STREAMOPENF_NONREALTIME bit is NOT set, then conversion
  1638. // must be done in 'real-time'. This is a tough one to describe
  1639. // exactly. If the driver may have trouble doing the conversion without
  1640. // breaking up the audio, then a configuration dialog might be used
  1641. // to allow the user to specify whether the real-time conversion
  1642. // request should be succeeded. DO NOT SUCCEED THE CALL UNLESS YOU
  1643. // ACTUALLY CAN DO REAL-TIME CONVERSIONS! There may be another driver
  1644. // installed that can--so if you succeed the call you are hindering
  1645. // the performance of the user's system! Don't be foolish.
  1646. //
  1647. // Arguments:
  1648. // PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
  1649. // This structure is [optionally] allocated during the DRV_OPEN message
  1650. // which is handled by the acmdDriverOpen function.
  1651. //
  1652. // LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
  1653. // conversion stream. This structure was allocated by the ACM and
  1654. // filled with the most common instance data needed for conversions.
  1655. // This structure will be passed back to all future stream messages
  1656. // if the open succeeds. The information in this structure will never
  1657. // change during the lifetime of the stream--so it is not necessary
  1658. // to re-verify the information referenced by this structure.
  1659. //
  1660. // Return (LRESULT):
  1661. // The return value is zero (MMSYSERR_NOERROR) if this function
  1662. // succeeds with no errors. The return value is a non-zero error code
  1663. // if the function fails.
  1664. //
  1665. // A driver should return ACMERR_NOTPOSSIBLE if the conversion cannot
  1666. // be performed due to incompatible source and destination formats.
  1667. //
  1668. // A driver should return MMSYSERR_NOTSUPPORTED if the conversion
  1669. // cannot be performed in real-time and the request does not specify
  1670. // the ACM_STREAMOPENF_NONREALTIME flag.
  1671. //
  1672. //--------------------------------------------------------------------------;
  1673. LRESULT FNLOCAL acmdStreamOpen
  1674. (
  1675. PDRIVERINSTANCE pdi,
  1676. LPACMDRVSTREAMINSTANCE padsi
  1677. )
  1678. {
  1679. PSTREAMINSTANCE psi;
  1680. LPWAVEFORMATEX pwfxSrc;
  1681. LPWAVEFORMATEX pwfxDst;
  1682. LPWAVEFILTER pwfltr;
  1683. BOOL fRealTime;
  1684. //
  1685. //
  1686. //
  1687. pwfxSrc = padsi->pwfxSrc;
  1688. pwfxDst = padsi->pwfxDst;
  1689. pwfltr = padsi->pwfltr;
  1690. fRealTime = (0 == (padsi->fdwOpen & ACM_STREAMOPENF_NONREALTIME));
  1691. if( fRealTime )
  1692. {
  1693. //
  1694. // We only do non-realtime conversions.
  1695. // Return failure if we are asked for realtime.
  1696. //
  1697. return (ACMERR_NOTPOSSIBLE);
  1698. }
  1699. //
  1700. // the most important condition to check before doing anything else
  1701. // is that this ACM driver can actually perform the conversion we are
  1702. // being opened for. this check should fail as quickly as possible
  1703. // if the conversion is not possible by this driver.
  1704. //
  1705. // it is VERY important to fail quickly so the ACM can attempt to
  1706. // find a driver that is suitable for the conversion. also note that
  1707. // the ACM may call this driver several times with slightly different
  1708. // format specifications before giving up.
  1709. //
  1710. // this driver first verifies that the source and destination formats
  1711. // are acceptable...
  1712. //
  1713. // NOTE! for a 'filter only' driver, you only need to check one
  1714. // of the formats. the ACM will have already verified that the source
  1715. // and destination formats are equal. so if one is acceptable to this
  1716. // driver, they both are.
  1717. //
  1718. if (!pcmIsValidFormat(pwfxSrc))
  1719. {
  1720. //
  1721. // either the source or destination format is illegal for this
  1722. // driver--or the conversion between the formats can not be
  1723. // performed by this driver.
  1724. //
  1725. return (ACMERR_NOTPOSSIBLE);
  1726. }
  1727. //
  1728. // now verify the filter..
  1729. //
  1730. if (!volumeIsValidFilter(pwfltr) && !echoIsValidFilter(pwfltr))
  1731. {
  1732. return (ACMERR_NOTPOSSIBLE);
  1733. }
  1734. //
  1735. // we have determined that the conversion requested is possible by
  1736. // this driver. now check if we are just being queried for support.
  1737. // if this is just a query, then do NOT allocate any instance data
  1738. // or create tables, etc. just succeed the call.
  1739. //
  1740. if (0 != (ACM_STREAMOPENF_QUERY & padsi->fdwOpen))
  1741. {
  1742. return (MMSYSERR_NOERROR);
  1743. }
  1744. //
  1745. // we have decided that this driver can handle the conversion stream.
  1746. // so we want to do _AS MUCH WORK AS POSSIBLE_ right now to prepare
  1747. // for converting data. any resource allocation, table building, etc
  1748. // that can be dealt with at this time should be done.
  1749. //
  1750. // THIS IS VERY IMPORTANT! all ACMDM_STREAM_CONVERT messages need to
  1751. // be handled as quickly as possible.
  1752. //
  1753. //
  1754. //
  1755. // we have decided that this driver can handle the conversion stream.
  1756. // so we want to do _AS MUCH WORK AS POSSIBLE_ right now to prepare
  1757. // for converting data. any resource allocation, table building, etc
  1758. // that can be dealt with at this time should be done.
  1759. //
  1760. // THIS IS VERY IMPORTANT! all ACMDM_STREAM_CONVERT messages need to
  1761. // be handled as quickly as possible.
  1762. //
  1763. // this driver allocates a small instance structure for each stream
  1764. //
  1765. //
  1766. psi = (PSTREAMINSTANCE)LocalAlloc(LPTR, sizeof(*psi));
  1767. if (NULL == psi)
  1768. {
  1769. return (MMSYSERR_NOMEM);
  1770. }
  1771. //
  1772. // fill out our instance structure
  1773. //
  1774. // this driver stores a pointer to the conversion function that will
  1775. // be used for each conversion on this stream. we also store a
  1776. // copy of the _current_ configuration of the driver instance we
  1777. // are opened on. this must not change during the life of the stream
  1778. // instance.
  1779. //
  1780. // this is also very important! if the user is able to configure how
  1781. // the driver performs conversions, the changes should only affect
  1782. // future open streams. all current open streams should behave as
  1783. // they were configured during the open.
  1784. //
  1785. //
  1786. //
  1787. //
  1788. //
  1789. if (WAVE_FILTER_VOLUME == pwfltr->dwFilterTag)
  1790. {
  1791. psi->fnConvert = msfilterVolume;
  1792. psi->fdwConfig = pdi->fdwConfig;
  1793. psi->hpbHistory = NULL;
  1794. psi->dwPlace = 0L;
  1795. psi->dwHistoryDone = 0L;
  1796. }
  1797. else
  1798. {
  1799. LPECHOWAVEFILTER pwfEcho;
  1800. DWORD cb;
  1801. LPBYTE pb;
  1802. psi->fnConvert = msfilterEcho;
  1803. psi->fdwConfig = pdi->fdwConfig;
  1804. psi->hpbHistory = NULL;
  1805. psi->dwPlace = 0L;
  1806. psi->dwHistoryDone = 0L;
  1807. pwfEcho = (LPECHOWAVEFILTER)pwfltr;
  1808. //
  1809. // compute size of delay buffer--add 4 because we're lame!
  1810. //
  1811. cb = (pwfxSrc->nSamplesPerSec * pwfEcho->dwDelay / 1000) *
  1812. pwfxSrc->nBlockAlign;
  1813. cb += 4;
  1814. pb = (LPBYTE)GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE|GMEM_ZEROINIT, cb);
  1815. if (NULL == pb)
  1816. {
  1817. //
  1818. // free the stream instance structure and fail with no memory
  1819. //
  1820. LocalFree((HLOCAL)psi);
  1821. return (MMSYSERR_NOMEM);
  1822. }
  1823. psi->hpbHistory = (HPBYTE)pb;
  1824. }
  1825. //
  1826. // fill in our instance data--this will be passed back to all stream
  1827. // messages in the ACMDRVSTREAMINSTANCE structure. it is entirely
  1828. // up to the driver what gets stored (and maintained) in the
  1829. // fdwDriver and dwDriver members.
  1830. //
  1831. padsi->fdwDriver = 0L;
  1832. padsi->dwDriver = (DWORD)(UINT)psi;
  1833. return (MMSYSERR_NOERROR);
  1834. } // acmdStreamOpen()
  1835. //--------------------------------------------------------------------------;
  1836. //
  1837. // LRESULT acmdStreamClose
  1838. //
  1839. // Description:
  1840. // This function is called to handle the ACMDM_STREAM_CLOSE message.
  1841. // This message is sent when a conversion stream is no longer being
  1842. // used (the stream is being closed; usually by an application
  1843. // calling acmStreamClose). The ACM driver should clean up any resources
  1844. // that were allocated for the stream.
  1845. //
  1846. // Arguments:
  1847. // LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
  1848. // conversion stream. This structure was allocated by the ACM and
  1849. // filled with the most common instance data needed for conversions.
  1850. // The information in this structure is exactly the same as it was
  1851. // during the ACMDM_STREAM_OPEN message--so it is not necessary
  1852. // to re-verify the information referenced by this structure.
  1853. //
  1854. // Return (LRESULT):
  1855. // The return value is zero (MMSYSERR_NOERROR) if this function
  1856. // succeeds with no errors. The return value is a non-zero error code
  1857. // if the function fails.
  1858. //
  1859. // NOTE! It is _strongly_ recommended that a driver not fail to close
  1860. // a conversion stream.
  1861. //
  1862. // An asyncronous conversion stream may fail with ACMERR_BUSY if there
  1863. // are pending buffers. An application may call acmStreamReset to
  1864. // force all pending buffers to be posted.
  1865. //
  1866. //--------------------------------------------------------------------------;
  1867. LRESULT FNLOCAL acmdStreamClose
  1868. (
  1869. LPACMDRVSTREAMINSTANCE padsi
  1870. )
  1871. {
  1872. PSTREAMINSTANCE psi;
  1873. //
  1874. // the driver should clean up all privately allocated resources that
  1875. // were created for maintaining the stream instance. if no resources
  1876. // were allocated, then simply succeed.
  1877. //
  1878. // in the case of this driver, we need to free the stream instance
  1879. // structure that we allocated during acmdStreamOpen.
  1880. //
  1881. psi = (PSTREAMINSTANCE)(UINT)padsi->dwDriver;
  1882. if (NULL != psi)
  1883. {
  1884. //
  1885. // free up the delay buffer if one was allocated (will be for
  1886. // the echo filter
  1887. //
  1888. if (NULL != psi->hpbHistory)
  1889. {
  1890. GlobalFreePtr((LPVOID)psi->hpbHistory);
  1891. }
  1892. //
  1893. // free the stream instance structure
  1894. //
  1895. LocalFree((HLOCAL)psi);
  1896. }
  1897. return (MMSYSERR_NOERROR);
  1898. } // acmdStreamClose()
  1899. //--------------------------------------------------------------------------;
  1900. //
  1901. // LRESULT acmdStreamSize
  1902. //
  1903. // Description:
  1904. // This function handles the ACMDM_STREAM_SIZE message. The purpose
  1905. // of this function is to provide the _largest size in bytes_ that
  1906. // the source or destination buffer needs to be given the input and
  1907. // output formats and the size in bytes of the source or destination
  1908. // data buffer.
  1909. //
  1910. // In other words: how big does my destination buffer need to be to
  1911. // hold the converted data? (ACM_STREAMSIZEF_SOURCE)
  1912. //
  1913. // Or: how big can my source buffer be given the destination buffer?
  1914. // (ACM_STREAMSIZEF_DESTINATION)
  1915. //
  1916. // Arguments:
  1917. // LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
  1918. // conversion stream. This structure was allocated by the ACM and
  1919. // filled with the most common instance data needed for conversions.
  1920. // The information in this structure is exactly the same as it was
  1921. // during the ACMDM_STREAM_OPEN message--so it is not necessary
  1922. // to re-verify the information referenced by this structure.
  1923. //
  1924. // LPACMDRVSTREAMSIZE padss: Specifies a pointer to the ACMDRVSTREAMSIZE
  1925. // structure that defines the conversion stream size query attributes.
  1926. //
  1927. // Return (LRESULT):
  1928. // The return value is zero (MMSYSERR_NOERROR) if this function
  1929. // succeeds with no errors. The return value is a non-zero error code
  1930. // if the function fails.
  1931. //
  1932. // An ACM driver should return MMSYSERR_NOTSUPPORTED if a query type
  1933. // is requested that the driver does not understand. Note that a driver
  1934. // must support both the ACM_STREAMSIZEF_DESTINATION and
  1935. // ACM_STREAMSIZEF_SOURCE queries.
  1936. //
  1937. // If the conversion would be 'out of range' given the input arguments,
  1938. // then ACMERR_NOTPOSSIBLE should be returned.
  1939. //
  1940. //--------------------------------------------------------------------------;
  1941. LRESULT FNLOCAL acmdStreamSize
  1942. (
  1943. LPACMDRVSTREAMINSTANCE padsi,
  1944. LPACMDRVSTREAMSIZE padss
  1945. )
  1946. {
  1947. LPWAVEFORMATEX pwfxSrc;
  1948. LPWAVEFORMATEX pwfxDst;
  1949. LPWAVEFILTER pwfltr;
  1950. DWORD dw;
  1951. pwfxSrc = padsi->pwfxSrc;
  1952. pwfxDst = padsi->pwfxDst;
  1953. pwfltr = padsi->pwfltr;
  1954. //
  1955. //
  1956. //
  1957. switch (ACM_STREAMSIZEF_QUERYMASK & padss->fdwSize)
  1958. {
  1959. case ACM_STREAMSIZEF_SOURCE:
  1960. dw = padss->cbSrcLength;
  1961. if( pwfltr->dwFilterTag == WAVE_FILTER_VOLUME )
  1962. {
  1963. //
  1964. // Source and dest sizes are the same for volume.
  1965. //
  1966. // block align the destination
  1967. //
  1968. dw = PCM_BYTESTOSAMPLES(pwfxSrc, padss->cbSrcLength);
  1969. dw = PCM_SAMPLESTOBYTES(pwfxSrc, dw);
  1970. }
  1971. else if( pwfltr->dwFilterTag == WAVE_FILTER_ECHO )
  1972. {
  1973. dw = PCM_BYTESTOSAMPLES(pwfxSrc, padss->cbSrcLength);
  1974. dw = PCM_SAMPLESTOBYTES(pwfxSrc, dw);
  1975. }
  1976. if (0 == dw)
  1977. {
  1978. return (ACMERR_NOTPOSSIBLE);
  1979. }
  1980. padss->cbDstLength = dw;
  1981. return (MMSYSERR_NOERROR);
  1982. case ACM_STREAMSIZEF_DESTINATION:
  1983. dw = padss->cbDstLength;
  1984. if( pwfltr->dwFilterTag == WAVE_FILTER_VOLUME )
  1985. {
  1986. //
  1987. // Source and dest sizes are the same for volume.
  1988. //
  1989. // block align the destination
  1990. //
  1991. dw = PCM_BYTESTOSAMPLES(pwfxDst, padss->cbDstLength);
  1992. dw = PCM_SAMPLESTOBYTES(pwfxDst, dw);
  1993. }
  1994. else if( pwfltr->dwFilterTag == WAVE_FILTER_ECHO )
  1995. {
  1996. dw = PCM_BYTESTOSAMPLES(pwfxDst, padss->cbDstLength);
  1997. dw = PCM_SAMPLESTOBYTES(pwfxDst, dw);
  1998. }
  1999. if (0 == dw)
  2000. {
  2001. return (ACMERR_NOTPOSSIBLE);
  2002. }
  2003. padss->cbSrcLength = dw;
  2004. return (MMSYSERR_NOERROR);
  2005. }
  2006. //
  2007. //
  2008. //
  2009. return (MMSYSERR_NOTSUPPORTED);
  2010. } // acmdStreamSize()
  2011. //==========================================================================;
  2012. //
  2013. //
  2014. //
  2015. //
  2016. //==========================================================================;
  2017. //--------------------------------------------------------------------------;
  2018. //
  2019. // LRESULT DriverProc
  2020. //
  2021. // Description:
  2022. //
  2023. //
  2024. // Arguments:
  2025. // DWORD dwId: For most messages, dwId is the DWORD value that
  2026. // the driver returns in response to a DRV_OPEN message. Each time
  2027. // the driver is opened, through the OpenDriver API, the driver
  2028. // receives a DRV_OPEN message and can return an arbitrary, non-zero
  2029. // value. The installable driver interface saves this value and returns
  2030. // a unique driver handle to the application. Whenever the application
  2031. // sends a message to the driver using the driver handle, the interface
  2032. // routes the message to this entry point and passes the corresponding
  2033. // dwId. This mechanism allows the driver to use the same or different
  2034. // identifiers for multiple opens but ensures that driver handles are
  2035. // unique at the application interface layer.
  2036. //
  2037. // The following messages are not related to a particular open instance
  2038. // of the driver. For these messages, the dwId will always be zero.
  2039. //
  2040. // DRV_LOAD, DRV_FREE, DRV_ENABLE, DRV_DISABLE, DRV_OPEN
  2041. //
  2042. // HDRVR hdrvr: This is the handle returned to the application
  2043. // by the driver interface.
  2044. //
  2045. // UINT uMsg: The requested action to be performed. Message
  2046. // values below DRV_RESERVED are used for globally defined messages.
  2047. // Message values from DRV_RESERVED to DRV_USER are used for defined
  2048. // driver protocols. Messages above DRV_USER are used for driver
  2049. // specific messages.
  2050. //
  2051. // LPARAM lParam1: Data for this message. Defined separately for
  2052. // each message.
  2053. //
  2054. // LPARAM lParam2: Data for this message. Defined separately for
  2055. // each message.
  2056. //
  2057. // Return (LRESULT):
  2058. // Defined separately for each message.
  2059. //
  2060. //--------------------------------------------------------------------------;
  2061. EXTERN_C LRESULT FNEXPORT DriverProc
  2062. (
  2063. DWORD dwId,
  2064. HDRVR hdrvr,
  2065. UINT uMsg,
  2066. LPARAM lParam1,
  2067. LPARAM lParam2
  2068. )
  2069. {
  2070. LRESULT lr;
  2071. PDRIVERINSTANCE pdi;
  2072. //
  2073. // make pdi either NULL or a valid instance pointer. note that dwId
  2074. // is 0 for several of the DRV_* messages (ie DRV_LOAD, DRV_OPEN...)
  2075. // see acmdDriverOpen for information on what dwId is for other
  2076. // messages (instance data).
  2077. //
  2078. pdi = (PDRIVERINSTANCE)(UINT)dwId;
  2079. switch (uMsg)
  2080. {
  2081. //
  2082. // lParam1: Unused.
  2083. //
  2084. // lParam2: Unused.
  2085. //
  2086. case DRV_LOAD:
  2087. #ifdef WIN32
  2088. DbgInitialize(TRUE);
  2089. #endif
  2090. return(1L);
  2091. //
  2092. // lParam1: Unused.
  2093. //
  2094. // lParam2: Unused.
  2095. //
  2096. case DRV_FREE:
  2097. return (1L);
  2098. //
  2099. // lParam1: Not used. Ignore this argument.
  2100. //
  2101. // lParam2: Pointer to ACMDRVOPENDESC (or NULL).
  2102. //
  2103. case DRV_OPEN:
  2104. lr = acmdDriverOpen(hdrvr, (LPACMDRVOPENDESC)lParam2);
  2105. return (lr);
  2106. //
  2107. // lParam1: Unused.
  2108. //
  2109. // lParam2: Unused.
  2110. //
  2111. case DRV_CLOSE:
  2112. lr = acmdDriverClose(pdi);
  2113. return (lr);
  2114. //
  2115. // lParam1: Unused.
  2116. //
  2117. // lParam2: Unused.
  2118. //
  2119. case DRV_INSTALL:
  2120. return ((LRESULT)DRVCNF_RESTART);
  2121. //
  2122. // lParam1: Unused.
  2123. //
  2124. // lParam2: Unused.
  2125. //
  2126. case DRV_REMOVE:
  2127. return ((LRESULT)DRVCNF_RESTART);
  2128. //
  2129. // lParam1: Not used.
  2130. //
  2131. // lParam2: Not used.
  2132. //
  2133. case DRV_QUERYCONFIGURE:
  2134. //
  2135. // set up lParam1 and lParam2 to values that can be used by
  2136. // acmdDriverConfigure to know that it is being 'queried'
  2137. // for configuration support.
  2138. //
  2139. lParam1 = -1L;
  2140. lParam2 = 0L;
  2141. //--fall through--//
  2142. //
  2143. // lParam1: Handle to parent window for the configuration dialog
  2144. // box.
  2145. //
  2146. // lParam2: Optional pointer to DRVCONFIGINFO structure.
  2147. //
  2148. case DRV_CONFIGURE:
  2149. lr = acmdDriverConfigure(pdi, (HWND)lParam1, (LPDRVCONFIGINFO)lParam2);
  2150. return (lr);
  2151. //
  2152. // lParam1: Pointer to ACMDRIVERDETAILS structure.
  2153. //
  2154. // lParam2: Size in bytes of ACMDRIVERDETAILS stucture passed.
  2155. //
  2156. case ACMDM_DRIVER_DETAILS:
  2157. lr = acmdDriverDetails(pdi, (LPACMDRIVERDETAILS)lParam1);
  2158. return (lr);
  2159. //
  2160. // lParam1: Handle to parent window to use if displaying your own
  2161. // about box.
  2162. //
  2163. // lParam2: Not used.
  2164. //
  2165. case ACMDM_DRIVER_ABOUT:
  2166. lr = acmdDriverAbout(pdi, (HWND)lParam1);
  2167. return (lr);
  2168. //--------------------------------------------------------------------------;
  2169. //--------------------------------------------------------------------------;
  2170. //
  2171. // lParam1: Pointer to FORMATTAGDETAILS structure.
  2172. //
  2173. // lParam2: fdwDetails
  2174. //
  2175. case ACMDM_FORMATTAG_DETAILS:
  2176. lr = acmdFormatTagDetails(pdi, (LPACMFORMATTAGDETAILS)lParam1, lParam2);
  2177. return (lr);
  2178. //
  2179. // lParam1: Pointer to FORMATDETAILS structure.
  2180. //
  2181. // lParam2: fdwDetails
  2182. //
  2183. case ACMDM_FORMAT_DETAILS:
  2184. lr = acmdFormatDetails(pdi, (LPACMFORMATDETAILS)lParam1, lParam2);
  2185. return (lr);
  2186. //--------------------------------------------------------------------------;
  2187. //--------------------------------------------------------------------------;
  2188. //
  2189. // lParam1: FILTERTAGDETAILS
  2190. //
  2191. // lParam2: fdwDetails
  2192. //
  2193. case ACMDM_FILTERTAG_DETAILS:
  2194. lr = acmdFilterTagDetails(pdi, (LPACMFILTERTAGDETAILS)lParam1, lParam2);
  2195. return (lr);
  2196. //
  2197. // lParam1: Pointer to the details structure.
  2198. //
  2199. // lParam2: fdwDetails
  2200. //
  2201. case ACMDM_FILTER_DETAILS:
  2202. lr = acmdFilterDetails(pdi, (LPACMFILTERDETAILS)lParam1, lParam2);
  2203. return (lr);
  2204. //--------------------------------------------------------------------------;
  2205. //--------------------------------------------------------------------------;
  2206. //
  2207. // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
  2208. //
  2209. // lParam2: Not used.
  2210. //
  2211. case ACMDM_STREAM_OPEN:
  2212. lr = acmdStreamOpen(pdi, (LPACMDRVSTREAMINSTANCE)lParam1);
  2213. return (lr);
  2214. //
  2215. // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
  2216. //
  2217. // lParam2: Not Used.
  2218. //
  2219. case ACMDM_STREAM_CLOSE:
  2220. lr = acmdStreamClose((LPACMDRVSTREAMINSTANCE)lParam1);
  2221. return (lr);
  2222. //
  2223. // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
  2224. //
  2225. // lParam2: Pointer to ACMDRVSTREAMSIZE structure.
  2226. //
  2227. case ACMDM_STREAM_SIZE:
  2228. lr = acmdStreamSize((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMDRVSTREAMSIZE)lParam2);
  2229. return (lr);
  2230. //
  2231. // lParam1: Pointer to ACMDRVSTREAMINSTANCE structure.
  2232. //
  2233. // lParam2: Pointer to ACMDRVSTREAMHEADER structure.
  2234. //
  2235. case ACMDM_STREAM_CONVERT:
  2236. {
  2237. PSTREAMINSTANCE psi;
  2238. LPACMDRVSTREAMINSTANCE padsi;
  2239. LPACMDRVSTREAMHEADER padsh;
  2240. //
  2241. // our stream instance data is a pointer to the conversion
  2242. // procedure needed to convert the pwfxSrc data to pwfxDst.
  2243. // the correct procedure to use was decided in acmdStreamOpen
  2244. //
  2245. padsi = (LPACMDRVSTREAMINSTANCE)lParam1;
  2246. padsh = (LPACMDRVSTREAMHEADER)lParam2;
  2247. psi = (PSTREAMINSTANCE)(UINT)padsi->dwDriver;
  2248. lr = psi->fnConvert(padsi, padsh);
  2249. return (lr);
  2250. }
  2251. }
  2252. //
  2253. // if we are executing the following code, then this ACM driver does not
  2254. // handle the message that was sent. there are two ranges of messages
  2255. // we need to deal with:
  2256. //
  2257. // o ACM specific driver messages: if an ACM driver does not answer a
  2258. // message sent in the ACM driver message range, then it must
  2259. // return MMSYSERR_NOTSUPPORTED. this applies to the 'user'
  2260. // range as well (for consistency).
  2261. //
  2262. // o other installable driver messages: if an ACM driver does not
  2263. // answer a message that is NOT in the ACM driver message range,
  2264. // then it must call DefDriverProc and return that result.
  2265. // the exception to this is ACM driver procedures installed as
  2266. // ACM_DRIVERADDF_FUNCTION through acmDriverAdd. in this case,
  2267. // the driver procedure should conform to the ACMDRIVERPROC
  2268. // prototype and also return zero instead of calling DefDriverProc.
  2269. //
  2270. if (uMsg >= ACMDM_USER)
  2271. return (MMSYSERR_NOTSUPPORTED);
  2272. else
  2273. return (DefDriverProc(dwId, hdrvr, uMsg, lParam1, lParam2));
  2274. } // DriverProc()