Source code of Windows XP (NT5)
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.

900 lines
24 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 - 1994 Microsoft Corporation. All Rights Reserved.
  9. //--------------------------------------------------------------------------;
  10. //
  11. // aaprops.c
  12. //
  13. // Description:
  14. //
  15. //
  16. //
  17. //==========================================================================;
  18. #include <windows.h>
  19. #include <windowsx.h>
  20. #include <mmsystem.h>
  21. #include <memory.h>
  22. #include <mmreg.h>
  23. #include <msacm.h>
  24. #include "muldiv32.h"
  25. #include "appport.h"
  26. #include "acmapp.h"
  27. #include "debug.h"
  28. //==========================================================================;
  29. //
  30. //
  31. //
  32. //
  33. //==========================================================================;
  34. //--------------------------------------------------------------------------;
  35. //
  36. // BOOL AcmAppGetErrorString
  37. //
  38. // Description:
  39. //
  40. //
  41. // Arguments:
  42. // MMRESULT mmr:
  43. //
  44. // PTSTR psz:
  45. //
  46. // Return (BOOL):
  47. //
  48. //
  49. //--------------------------------------------------------------------------;
  50. BOOL FNGLOBAL AcmAppGetErrorString
  51. (
  52. MMRESULT mmr,
  53. LPTSTR pszError
  54. )
  55. {
  56. PTSTR psz;
  57. switch (mmr)
  58. {
  59. case MMSYSERR_NOERROR:
  60. psz = TEXT("MMSYSERR_NOERROR");
  61. break;
  62. case MMSYSERR_ERROR:
  63. psz = TEXT("MMSYSERR_ERROR");
  64. break;
  65. case MMSYSERR_BADDEVICEID:
  66. psz = TEXT("MMSYSERR_BADDEVICEID");
  67. break;
  68. case MMSYSERR_NOTENABLED:
  69. psz = TEXT("MMSYSERR_NOTENABLED");
  70. break;
  71. case MMSYSERR_ALLOCATED:
  72. psz = TEXT("MMSYSERR_ALLOCATED");
  73. break;
  74. case MMSYSERR_INVALHANDLE:
  75. psz = TEXT("MMSYSERR_INVALHANDLE");
  76. break;
  77. case MMSYSERR_NODRIVER:
  78. psz = TEXT("MMSYSERR_NODRIVER");
  79. break;
  80. case MMSYSERR_NOMEM:
  81. psz = TEXT("MMSYSERR_NOMEM");
  82. break;
  83. case MMSYSERR_NOTSUPPORTED:
  84. psz = TEXT("MMSYSERR_NOTSUPPORTED");
  85. break;
  86. case MMSYSERR_BADERRNUM:
  87. psz = TEXT("MMSYSERR_BADERRNUM");
  88. break;
  89. case MMSYSERR_INVALFLAG:
  90. psz = TEXT("MMSYSERR_INVALFLAG");
  91. break;
  92. case MMSYSERR_INVALPARAM:
  93. psz = TEXT("MMSYSERR_INVALPARAM");
  94. break;
  95. case WAVERR_BADFORMAT:
  96. psz = TEXT("WAVERR_BADFORMAT");
  97. break;
  98. case WAVERR_STILLPLAYING:
  99. psz = TEXT("WAVERR_STILLPLAYING");
  100. break;
  101. case WAVERR_UNPREPARED:
  102. psz = TEXT("WAVERR_UNPREPARED");
  103. break;
  104. case WAVERR_SYNC:
  105. psz = TEXT("WAVERR_SYNC");
  106. break;
  107. case ACMERR_NOTPOSSIBLE:
  108. psz = TEXT("ACMERR_NOTPOSSIBLE");
  109. break;
  110. case ACMERR_BUSY:
  111. psz = TEXT("ACMERR_BUSY");
  112. break;
  113. case ACMERR_UNPREPARED:
  114. psz = TEXT("ACMERR_UNPREPARED");
  115. break;
  116. case ACMERR_CANCELED:
  117. psz = TEXT("ACMERR_CANCELED");
  118. break;
  119. default:
  120. lstrcpy(pszError, TEXT("(unknown)"));
  121. return (FALSE);
  122. }
  123. lstrcpy(pszError, psz);
  124. return (TRUE);
  125. } // AcmAppGetErrorString()
  126. //--------------------------------------------------------------------------;
  127. //
  128. // BOOL AcmAppGetFormatDescription
  129. //
  130. // Description:
  131. //
  132. //
  133. // Arguments:
  134. // LPWAVEFORMATEX pwfx:
  135. //
  136. // LPSTR pszFormatTag:
  137. //
  138. // LPSTR pszFormat:
  139. //
  140. // Return (BOOL):
  141. //
  142. //
  143. //--------------------------------------------------------------------------;
  144. TCHAR gszIntl[] = TEXT("Intl");
  145. TCHAR gszIntlList[] = TEXT("sList");
  146. TCHAR gszIntlDecimal[] = TEXT("sDecimal");
  147. TCHAR gchIntlList = ',';
  148. TCHAR gchIntlDecimal = '.';
  149. BOOL FNGLOBAL AcmAppGetFormatDescription
  150. (
  151. LPWAVEFORMATEX pwfx,
  152. LPTSTR pszFormatTag,
  153. LPTSTR pszFormat
  154. )
  155. {
  156. MMRESULT mmr;
  157. BOOL f;
  158. f = TRUE;
  159. //
  160. // get the name for the format tag of the specified format
  161. //
  162. if (NULL != pszFormatTag)
  163. {
  164. ACMFORMATTAGDETAILS aftd;
  165. //
  166. // initialize all unused members of the ACMFORMATTAGDETAILS
  167. // structure to zero
  168. //
  169. memset(&aftd, 0, sizeof(aftd));
  170. //
  171. // fill in the required members of the ACMFORMATTAGDETAILS
  172. // structure for the ACM_FORMATTAGDETAILSF_FORMATTAG query
  173. //
  174. aftd.cbStruct = sizeof(aftd);
  175. aftd.dwFormatTag = pwfx->wFormatTag;
  176. //
  177. // ask the ACM to find the first available driver that
  178. // supports the specified format tag
  179. //
  180. mmr = acmFormatTagDetails(NULL,
  181. &aftd,
  182. ACM_FORMATTAGDETAILSF_FORMATTAG);
  183. if (MMSYSERR_NOERROR == mmr)
  184. {
  185. //
  186. // copy the format tag name into the caller's buffer
  187. //
  188. lstrcpy(pszFormatTag, aftd.szFormatTag);
  189. }
  190. else
  191. {
  192. PTSTR psz;
  193. //
  194. // no ACM driver is available that supports the
  195. // specified format tag
  196. //
  197. f = FALSE;
  198. psz = NULL;
  199. //
  200. // the following stuff if proof that the world does NOT need
  201. // yet another ADPCM algorithm!!
  202. //
  203. switch (pwfx->wFormatTag)
  204. {
  205. case WAVE_FORMAT_UNKNOWN:
  206. psz = TEXT("** RESERVED INVALID TAG **");
  207. break;
  208. case WAVE_FORMAT_PCM:
  209. psz = TEXT("PCM");
  210. break;
  211. case WAVE_FORMAT_ADPCM:
  212. psz = TEXT("Microsoft ADPCM");
  213. break;
  214. case 0x0003:
  215. psz = TEXT("MV's *UNREGISTERED* ADPCM");
  216. break;
  217. case WAVE_FORMAT_IBM_CVSD:
  218. psz = TEXT("IBM CVSD");
  219. break;
  220. case WAVE_FORMAT_ALAW:
  221. psz = TEXT("A-Law");
  222. break;
  223. case WAVE_FORMAT_MULAW:
  224. psz = TEXT("u-Law");
  225. break;
  226. case WAVE_FORMAT_OKI_ADPCM:
  227. psz = TEXT("OKI ADPCM");
  228. break;
  229. case WAVE_FORMAT_IMA_ADPCM:
  230. psz = TEXT("IMA/DVI ADPCM");
  231. break;
  232. case WAVE_FORMAT_DIGISTD:
  233. psz = TEXT("DIGI STD");
  234. break;
  235. case WAVE_FORMAT_DIGIFIX:
  236. psz = TEXT("DIGI FIX");
  237. break;
  238. case WAVE_FORMAT_YAMAHA_ADPCM:
  239. psz = TEXT("Yamaha ADPCM");
  240. break;
  241. case WAVE_FORMAT_SONARC:
  242. psz = TEXT("Sonarc");
  243. break;
  244. case WAVE_FORMAT_DSPGROUP_TRUESPEECH:
  245. psz = TEXT("DSP Group TrueSpeech");
  246. break;
  247. case WAVE_FORMAT_ECHOSC1:
  248. psz = TEXT("Echo SC1");
  249. break;
  250. case WAVE_FORMAT_AUDIOFILE_AF36:
  251. psz = TEXT("Audiofile AF36");
  252. break;
  253. case WAVE_FORMAT_CREATIVE_ADPCM:
  254. psz = TEXT("Creative Labs ADPCM");
  255. break;
  256. case WAVE_FORMAT_APTX:
  257. psz = TEXT("APTX");
  258. break;
  259. case WAVE_FORMAT_AUDIOFILE_AF10:
  260. psz = TEXT("Audiofile AF10");
  261. break;
  262. case WAVE_FORMAT_DOLBY_AC2:
  263. psz = TEXT("Dolby AC2");
  264. break;
  265. case WAVE_FORMAT_MEDIASPACE_ADPCM:
  266. psz = TEXT("Media Space ADPCM");
  267. break;
  268. case WAVE_FORMAT_SIERRA_ADPCM:
  269. psz = TEXT("Sierra ADPCM");
  270. break;
  271. case WAVE_FORMAT_G723_ADPCM:
  272. psz = TEXT("CCITT G.723 ADPCM");
  273. break;
  274. case WAVE_FORMAT_GSM610:
  275. psz = TEXT("GSM 6.10");
  276. break;
  277. case WAVE_FORMAT_G721_ADPCM:
  278. psz = TEXT("CCITT G.721 ADPCM");
  279. break;
  280. case WAVE_FORMAT_DEVELOPMENT:
  281. psz = TEXT("** RESERVED DEVELOPMENT ONLY TAG **");
  282. break;
  283. default:
  284. wsprintf(pszFormatTag, TEXT("[%u] (unknown)"), pwfx->wFormatTag);
  285. break;
  286. }
  287. if (NULL != psz)
  288. {
  289. lstrcpy(pszFormatTag, psz);
  290. }
  291. }
  292. }
  293. //
  294. // get the description of the attributes for the specified
  295. // format
  296. //
  297. if (NULL != pszFormat)
  298. {
  299. ACMFORMATDETAILS afd;
  300. //
  301. // initialize all unused members of the ACMFORMATDETAILS
  302. // structure to zero
  303. //
  304. memset(&afd, 0, sizeof(afd));
  305. //
  306. // fill in the required members of the ACMFORMATDETAILS
  307. // structure for the ACM_FORMATDETAILSF_FORMAT query
  308. //
  309. afd.cbStruct = sizeof(afd);
  310. afd.dwFormatTag = pwfx->wFormatTag;
  311. afd.pwfx = pwfx;
  312. //
  313. // the cbwfx member must be initialized to the total size
  314. // in bytes needed for the specified format. for a PCM
  315. // format, the cbSize member of the WAVEFORMATEX structure
  316. // is not valid.
  317. //
  318. if (WAVE_FORMAT_PCM == pwfx->wFormatTag)
  319. {
  320. afd.cbwfx = sizeof(PCMWAVEFORMAT);
  321. }
  322. else
  323. {
  324. afd.cbwfx = sizeof(WAVEFORMATEX) + pwfx->cbSize;
  325. }
  326. //
  327. // ask the ACM to find the first available driver that
  328. // supports the specified format
  329. //
  330. mmr = acmFormatDetails(NULL, &afd, ACM_FORMATDETAILSF_FORMAT);
  331. if (MMSYSERR_NOERROR == mmr)
  332. {
  333. //
  334. // copy the format attributes description into the caller's
  335. // buffer
  336. //
  337. lstrcpy(pszFormat, afd.szFormat);
  338. }
  339. else
  340. {
  341. TCHAR ach[2];
  342. TCHAR szChannels[24];
  343. UINT cBits;
  344. //
  345. // no ACM driver is available that supports the
  346. // specified format
  347. //
  348. f = FALSE;
  349. //
  350. //
  351. //
  352. ach[0] = gchIntlList;
  353. ach[1] = '\0';
  354. GetProfileString(gszIntl, gszIntlList, ach, ach, sizeof(ach));
  355. gchIntlList = ach[0];
  356. ach[0] = gchIntlDecimal;
  357. ach[1] = '\0';
  358. GetProfileString(gszIntl, gszIntlDecimal, ach, ach, sizeof(ach));
  359. gchIntlDecimal = ach[0];
  360. //
  361. // compute the bit depth--this _should_ be the same as
  362. // wBitsPerSample, but isn't always...
  363. //
  364. cBits = (UINT)(pwfx->nAvgBytesPerSec * 8 /
  365. pwfx->nSamplesPerSec /
  366. pwfx->nChannels);
  367. if ((1 == pwfx->nChannels) || (2 == pwfx->nChannels))
  368. {
  369. if (1 == pwfx->nChannels)
  370. lstrcpy(szChannels, TEXT("Mono"));
  371. else
  372. lstrcpy(szChannels, TEXT("Stereo"));
  373. wsprintf(pszFormat, TEXT("%lu%c%.03u kHz%c %u Bit%c %s"),
  374. pwfx->nSamplesPerSec / 1000,
  375. gchIntlDecimal,
  376. (UINT)(pwfx->nSamplesPerSec % 1000),
  377. gchIntlList,
  378. cBits,
  379. gchIntlList,
  380. (LPTSTR)szChannels);
  381. }
  382. else
  383. {
  384. wsprintf(pszFormat, TEXT("%lu%c%.03u kHz%c %u Bit%c %u Channels"),
  385. pwfx->nSamplesPerSec / 1000,
  386. gchIntlDecimal,
  387. (UINT)(pwfx->nSamplesPerSec % 1000),
  388. gchIntlList,
  389. cBits,
  390. gchIntlList,
  391. pwfx->nChannels);
  392. }
  393. }
  394. }
  395. //
  396. //
  397. //
  398. return (f);
  399. } // AcmAppGetFormatDescription()
  400. //--------------------------------------------------------------------------;
  401. //
  402. // BOOL AcmAppGetFilterDescription
  403. //
  404. // Description:
  405. //
  406. //
  407. // Arguments:
  408. // LPWAVEFILTER pwfltr:
  409. //
  410. // LPSTR pszFilterTag:
  411. //
  412. // LPSTR pszFilter:
  413. //
  414. // Return (BOOL):
  415. //
  416. //
  417. //--------------------------------------------------------------------------;
  418. BOOL FNGLOBAL AcmAppGetFilterDescription
  419. (
  420. LPWAVEFILTER pwfltr,
  421. LPTSTR pszFilterTag,
  422. LPTSTR pszFilter
  423. )
  424. {
  425. MMRESULT mmr;
  426. BOOL f;
  427. f = TRUE;
  428. //
  429. // get the name for the filter tag of the specified filter
  430. //
  431. if (NULL != pszFilterTag)
  432. {
  433. ACMFILTERTAGDETAILS aftd;
  434. //
  435. // initialize all unused members of the ACMFILTERTAGDETAILS
  436. // structure to zero
  437. //
  438. memset(&aftd, 0, sizeof(aftd));
  439. //
  440. // fill in the required members of the ACMFILTERTAGDETAILS
  441. // structure for the ACM_FILTERTAGDETAILSF_FILTERTAG query
  442. //
  443. aftd.cbStruct = sizeof(aftd);
  444. aftd.dwFilterTag = pwfltr->dwFilterTag;
  445. //
  446. // ask the ACM to find the first available driver that
  447. // supports the specified filter tag
  448. //
  449. mmr = acmFilterTagDetails(NULL,
  450. &aftd,
  451. ACM_FILTERTAGDETAILSF_FILTERTAG);
  452. if (MMSYSERR_NOERROR == mmr)
  453. {
  454. //
  455. // copy the filter tag name into the caller's buffer
  456. //
  457. lstrcpy(pszFilterTag, aftd.szFilterTag);
  458. }
  459. else
  460. {
  461. PTSTR psz;
  462. psz = NULL;
  463. f = FALSE;
  464. //
  465. // no ACM driver is available that supports the
  466. // specified filter tag
  467. //
  468. switch (pwfltr->dwFilterTag)
  469. {
  470. case WAVE_FILTER_UNKNOWN:
  471. psz = TEXT("** RESERVED INVALID TAG **");
  472. break;
  473. case WAVE_FILTER_VOLUME:
  474. psz = TEXT("Microsoft Volume Filter");
  475. break;
  476. case WAVE_FILTER_ECHO:
  477. psz = TEXT("Microsoft Echo Filter");
  478. break;
  479. case WAVE_FILTER_DEVELOPMENT:
  480. psz = TEXT("** RESERVED DEVELOPMENT ONLY TAG **");
  481. break;
  482. default:
  483. wsprintf(pszFilterTag, TEXT("[%lu] (unknown)"),pwfltr->dwFilterTag);
  484. break;
  485. }
  486. if (NULL != psz)
  487. {
  488. lstrcpy(pszFilterTag, psz);
  489. }
  490. }
  491. }
  492. //
  493. // get the description of the attributes for the specified
  494. // filter
  495. //
  496. if (NULL != pszFilter)
  497. {
  498. ACMFILTERDETAILS afd;
  499. //
  500. // initialize all unused members of the ACMFILTERDETAILS
  501. // structure to zero
  502. //
  503. memset(&afd, 0, sizeof(afd));
  504. //
  505. // fill in the required members of the ACMFILTERDETAILS
  506. // structure for the ACM_FILTERDETAILSF_FILTER query
  507. //
  508. afd.cbStruct = sizeof(afd);
  509. afd.dwFilterTag = pwfltr->dwFilterTag;
  510. afd.pwfltr = pwfltr;
  511. afd.cbwfltr = pwfltr->cbStruct;
  512. //
  513. // ask the ACM to find the first available driver that
  514. // supports the specified filter
  515. //
  516. mmr = acmFilterDetails(NULL, &afd, ACM_FILTERDETAILSF_FILTER);
  517. if (MMSYSERR_NOERROR == mmr)
  518. {
  519. //
  520. // copy the filter attributes description into the caller's
  521. // buffer
  522. //
  523. lstrcpy(pszFilter, afd.szFilter);
  524. }
  525. else
  526. {
  527. //
  528. // no ACM driver is available that supports the
  529. // specified filter
  530. //
  531. f = FALSE;
  532. wsprintf(pszFilter, TEXT("Unknown Filter %lu, %.08lXh"),
  533. pwfltr->dwFilterTag, pwfltr->fdwFilter);
  534. }
  535. }
  536. //
  537. //
  538. //
  539. return (f);
  540. } // AcmAppGetFilterDescription()
  541. //--------------------------------------------------------------------------;
  542. //
  543. // BOOL AcmAppDumpExtraHeaderData
  544. //
  545. // Description:
  546. //
  547. //
  548. // Arguments:
  549. // HWND hedit:
  550. //
  551. // LPWAVEFORMATEX pwfx:
  552. //
  553. // Return (BOOL):
  554. //
  555. //
  556. //--------------------------------------------------------------------------;
  557. BOOL FNLOCAL AcmAppDumpExtraHeaderData
  558. (
  559. HWND hedit,
  560. LPWAVEFORMATEX pwfx
  561. )
  562. {
  563. static TCHAR szDisplayTitle[] = TEXT("Offset Data Bytes");
  564. if ((WAVE_FORMAT_PCM == pwfx->wFormatTag) || (0 == pwfx->cbSize))
  565. return (TRUE);
  566. MEditPrintF(hedit, szDisplayTitle);
  567. MEditPrintF(hedit, TEXT("------ -----------------------------------------------"));
  568. //
  569. // !!! this is really horrible code !!!
  570. //
  571. {
  572. #define ACMAPP_DUMP_BYTES_PER_LINE 16
  573. UINT u;
  574. UINT v;
  575. for (u = 0; u < pwfx->cbSize; u += ACMAPP_DUMP_BYTES_PER_LINE)
  576. {
  577. MEditPrintF(hedit, TEXT("~0x%.04X"), u);
  578. for (v = 0; v < ACMAPP_DUMP_BYTES_PER_LINE; v++)
  579. {
  580. if ((u + v) >= pwfx->cbSize)
  581. break;
  582. MEditPrintF(hedit, TEXT("~ %.02X"), ((LPBYTE)(pwfx + 1))[u + v]);
  583. }
  584. MEditPrintF(hedit, gszNull);
  585. }
  586. #undef ACMAPP_DUMP_BYTES_PER_LINE
  587. }
  588. return (TRUE);
  589. } // AcmAppDumpExtraHeaderData()
  590. //--------------------------------------------------------------------------;
  591. //
  592. // BOOL AcmAppDisplayFileProperties
  593. //
  594. // Description:
  595. //
  596. //
  597. // Arguments:
  598. // HWND hwnd:
  599. //
  600. // PACMAPPFILEDESC paafd:
  601. //
  602. // Return (BOOL):
  603. //
  604. //--------------------------------------------------------------------------;
  605. BOOL FNGLOBAL AcmAppDisplayFileProperties
  606. (
  607. HWND hwnd,
  608. PACMAPPFILEDESC paafd
  609. )
  610. {
  611. static TCHAR szInvalidWaveFile[] = TEXT("No File");
  612. static TCHAR szDisplayTitle[] = TEXT("[Wave File Format Properties]\r\n");
  613. MMRESULT mmr;
  614. TCHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS];
  615. TCHAR ach[APP_MAX_STRING_CHARS];
  616. DWORD dw;
  617. LPWAVEFORMATEX pwfx;
  618. HWND hedit;
  619. HMENU hmenu;
  620. BOOL fCanPlayRecord;
  621. BOOL f;
  622. //
  623. // clear the display
  624. //
  625. AppHourGlass(TRUE);
  626. hedit = GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY);
  627. SetWindowRedraw(hedit, FALSE);
  628. MEditPrintF(hedit, NULL);
  629. //
  630. //
  631. //
  632. MEditPrintF(hedit, szDisplayTitle);
  633. MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Title"), (LPTSTR)paafd->szFileTitle);
  634. MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Full Path"), (LPTSTR)paafd->szFilePath);
  635. AppFormatBigNumber(ach, paafd->cbFileSize);
  636. MEditPrintF(hedit, TEXT("%25s: %s bytes"), (LPTSTR)TEXT("Total File Size"), (LPTSTR)ach);
  637. AppFormatDosDateTime(ach, paafd->uDosChangeDate, paafd->uDosChangeTime);
  638. MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Last Change Date/Time"), (LPTSTR)ach);
  639. dw = paafd->fdwFileAttributes;
  640. MEditPrintF(hedit, TEXT("%25s: %c %c%c%c%c %c%c%c%c (%.08lXh)"),
  641. (LPTSTR)TEXT("Attributes"),
  642. (dw & FILE_ATTRIBUTE_TEMPORARY) ? 't' : '-',
  643. (dw & FILE_ATTRIBUTE_NORMAL) ? 'n' : '-',
  644. (dw & 0x00000040) ? '?' : '-',
  645. (dw & FILE_ATTRIBUTE_ARCHIVE) ? 'a' : '-',
  646. (dw & FILE_ATTRIBUTE_DIRECTORY) ? 'd' : '-',
  647. (dw & 0x00000008) ? '?' : '-',
  648. (dw & FILE_ATTRIBUTE_SYSTEM) ? 's' : '-',
  649. (dw & FILE_ATTRIBUTE_HIDDEN) ? 'h' : '-',
  650. (dw & FILE_ATTRIBUTE_READONLY) ? 'r' : '-',
  651. dw);
  652. pwfx = paafd->pwfx;
  653. if (NULL == pwfx)
  654. {
  655. fCanPlayRecord = FALSE;
  656. goto AA_Display_File_Properties_Exit;
  657. }
  658. //
  659. //
  660. //
  661. //
  662. f = AcmAppGetFormatDescription(pwfx, szFormatTag, ach);
  663. MEditPrintF(hedit, TEXT("\r\n%25s: %s%s"), (LPTSTR)TEXT("Format"),
  664. f ? (LPTSTR)gszNull : (LPTSTR)TEXT("*"),
  665. (LPTSTR)szFormatTag);
  666. MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Attributes"), (LPTSTR)ach);
  667. AppFormatBigNumber(ach, paafd->dwDataBytes);
  668. MEditPrintF(hedit, TEXT("\r\n%25s: %s bytes"), (LPTSTR)TEXT("Data Size"), (LPTSTR)ach);
  669. AppFormatBigNumber(ach, paafd->dwDataBytes / pwfx->nAvgBytesPerSec);
  670. dw = paafd->dwDataBytes % pwfx->nAvgBytesPerSec;
  671. dw = (dw * 1000) / pwfx->nAvgBytesPerSec;
  672. MEditPrintF(hedit, TEXT("%25s: %s.%.03lu seconds"), (LPTSTR)TEXT("Play Time (avg bytes)"), (LPTSTR)ach, dw);
  673. AppFormatBigNumber(ach, paafd->dwDataSamples);
  674. MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Total Samples"), (LPTSTR)ach);
  675. AppFormatBigNumber(ach, paafd->dwDataSamples / pwfx->nSamplesPerSec);
  676. dw = paafd->dwDataSamples % pwfx->nSamplesPerSec;
  677. dw = (dw * 1000) / pwfx->nSamplesPerSec;
  678. MEditPrintF(hedit, TEXT("%25s: %s.%.03lu seconds"), (LPTSTR)TEXT("Play Time (samples)"), (LPTSTR)ach, dw);
  679. //
  680. //
  681. //
  682. MEditPrintF(hedit, TEXT("\r\n%25s: %u"), (LPTSTR)TEXT("Format Tag"), pwfx->wFormatTag);
  683. MEditPrintF(hedit, TEXT("%25s: %u"), (LPTSTR)TEXT("Channels"), pwfx->nChannels);
  684. AppFormatBigNumber(ach, pwfx->nSamplesPerSec);
  685. MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Samples Per Second"), (LPTSTR)ach);
  686. AppFormatBigNumber(ach, pwfx->nAvgBytesPerSec);
  687. MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Avg Bytes Per Second"), (LPTSTR)ach);
  688. AppFormatBigNumber(ach, pwfx->nBlockAlign);
  689. MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Block Alignment"), (LPTSTR)ach);
  690. MEditPrintF(hedit, TEXT("%25s: %u"), (LPTSTR)TEXT("Bits Per Sample"), pwfx->wBitsPerSample);
  691. if (WAVE_FORMAT_PCM != pwfx->wFormatTag)
  692. {
  693. AppFormatBigNumber(ach, pwfx->cbSize);
  694. MEditPrintF(hedit, TEXT("%25s: %s bytes\r\n"), (LPTSTR)TEXT("Extra Format Information"), (LPTSTR)ach);
  695. AcmAppDumpExtraHeaderData(hedit, pwfx);
  696. }
  697. //
  698. // note that we do NOT set the 'WAVE_ALLOWSYNC' bit on queries because
  699. // the player/recorder dialog uses MCIWAVE--which cannot work with
  700. // SYNC devices.
  701. //
  702. mmr = waveOutOpen(NULL,
  703. guWaveOutId,
  704. #if (WINVER < 0x0400)
  705. (LPWAVEFORMAT)pwfx,
  706. #else
  707. pwfx,
  708. #endif
  709. 0L, 0L, WAVE_FORMAT_QUERY);
  710. fCanPlayRecord = (MMSYSERR_NOERROR == mmr);
  711. if (!fCanPlayRecord)
  712. {
  713. //
  714. // this situation can happen with the 'preferred' device settings
  715. // for the Sound Mapper.
  716. //
  717. mmr = waveInOpen(NULL,
  718. guWaveInId,
  719. #if (WINVER < 0x0400)
  720. (LPWAVEFORMAT)pwfx,
  721. #else
  722. pwfx,
  723. #endif
  724. 0L, 0L, WAVE_FORMAT_QUERY);
  725. fCanPlayRecord = (MMSYSERR_NOERROR == mmr);
  726. }
  727. AA_Display_File_Properties_Exit:
  728. hmenu = GetMenu(hwnd);
  729. EnableMenuItem(hmenu, IDM_PLAYRECORD,
  730. MF_BYCOMMAND | (fCanPlayRecord ? MF_ENABLED : MF_GRAYED));
  731. DrawMenuBar(hwnd);
  732. Edit_SetSel(hedit, (WPARAM)0, (LPARAM)0);
  733. SetWindowRedraw(hedit, TRUE);
  734. AppHourGlass(FALSE);
  735. return (fCanPlayRecord);
  736. } // AcmAppDisplayFileProperties()
  737.