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.

1633 lines
45 KiB

  1. /* (C) Copyright Microsoft Corporation 1991-1994. All Rights Reserved */
  2. /* convert.c
  3. *
  4. * conversion utilites.
  5. */
  6. #include <windows.h>
  7. #include <windowsx.h>
  8. #include <mmsystem.h>
  9. #include <mmreg.h>
  10. #include <commctrl.h>
  11. #if WINVER >= 0x0400
  12. # include "..\..\msacm\msacm\msacm.h"
  13. #else
  14. # include <msacm.h>
  15. #endif
  16. #include <commdlg.h>
  17. #include <dlgs.h>
  18. #include <convert.h>
  19. #include <msacmdlg.h>
  20. #include "soundrec.h"
  21. #ifdef CHICAGO
  22. #include "helpids.h"
  23. #endif
  24. BOOL gfBreakOfDeath;
  25. /*
  26. **/
  27. LPTSTR SoundRec_GetFormatName(
  28. LPWAVEFORMATEX pwfx)
  29. {
  30. ACMFORMATTAGDETAILS aftd;
  31. ACMFORMATDETAILS afd;
  32. const TCHAR szFormat[] = TEXT("%s %s");
  33. LPTSTR lpstr;
  34. UINT cbstr;
  35. ZeroMemory(&aftd, sizeof(ACMFORMATTAGDETAILS));
  36. aftd.cbStruct = sizeof(ACMFORMATTAGDETAILS);
  37. aftd.dwFormatTag = pwfx->wFormatTag;
  38. if (MMSYSERR_NOERROR != acmFormatTagDetails( NULL
  39. , &aftd
  40. , ACM_FORMATTAGDETAILSF_FORMATTAG))
  41. {
  42. aftd.szFormatTag[0] = 0;
  43. }
  44. ZeroMemory(&afd, sizeof(ACMFORMATDETAILS));
  45. afd.cbStruct = sizeof(ACMFORMATDETAILS);
  46. afd.pwfx = pwfx;
  47. afd.dwFormatTag = pwfx->wFormatTag;
  48. afd.cbwfx = sizeof(WAVEFORMATEX);
  49. if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
  50. afd.cbwfx += pwfx->cbSize;
  51. if (MMSYSERR_NOERROR != acmFormatDetails( NULL
  52. , &afd
  53. , ACM_FORMATDETAILSF_FORMAT))
  54. {
  55. afd.szFormat[0] = 0;
  56. }
  57. cbstr = sizeof(LPTSTR) * ( lstrlen(aftd.szFormatTag) + lstrlen(afd.szFormat) + lstrlen(szFormat));
  58. lpstr = (LPTSTR) GlobalAllocPtr(GHND, cbstr);
  59. if (lpstr)
  60. wsprintf(lpstr, szFormat, aftd.szFormatTag, afd.szFormat);
  61. return lpstr;
  62. }
  63. /*
  64. * SaveAsHookProc
  65. *
  66. * This is a hook proc for the Save As common dialog to support conversion
  67. * upon save.
  68. **/
  69. UINT_PTR CALLBACK SaveAsHookProc(
  70. HWND hdlg,
  71. UINT msg,
  72. WPARAM wParam,
  73. LPARAM lParam)
  74. {
  75. #ifdef CHICAGO
  76. int DlgItem;
  77. static const DWORD aHelpIds[] = {
  78. IDC_TXT_FORMAT, IDH_SOUNDREC_CHANGE,
  79. IDC_CONVERTTO, IDH_SOUNDREC_CHANGE,
  80. IDC_CONVERT_TO, IDH_SOUNDREC_CHANGE,
  81. 0, 0
  82. };
  83. extern DWORD aChooserHelpIds[];
  84. extern UINT guChooserContextMenu;
  85. extern UINT guChooserContextHelp;
  86. //
  87. // Handle context-sensitive help messages from acm dialog
  88. //
  89. if( msg == guChooserContextMenu )
  90. {
  91. WinHelp( (HWND)wParam, NULL, HELP_CONTEXTMENU,
  92. (UINT_PTR)(LPSTR)aChooserHelpIds );
  93. return TRUE;
  94. }
  95. else if( msg == guChooserContextHelp )
  96. {
  97. WinHelp( ((LPHELPINFO)lParam)->hItemHandle, NULL,
  98. HELP_WM_HELP, (UINT_PTR)(LPSTR)aChooserHelpIds );
  99. return TRUE;
  100. }
  101. #endif
  102. switch (msg)
  103. {
  104. #ifdef CHICAGO
  105. case WM_CONTEXTMENU:
  106. DlgItem = GetDlgCtrlID((HWND)wParam);
  107. //
  108. // Only process the id's we are responsible for
  109. //
  110. if (DlgItem != IDC_CONVERTTO && DlgItem != IDC_CONVERT_TO && DlgItem != IDC_TXT_FORMAT)
  111. break;
  112. WinHelp((HWND)wParam, gachHelpFile, HELP_CONTEXTMENU,
  113. (UINT_PTR)(LPSTR)aHelpIds);
  114. return TRUE;
  115. case WM_HELP:
  116. {
  117. LPHELPINFO lphi = (LPVOID) lParam;
  118. //
  119. // Only process the id's we are responsible for
  120. //
  121. DlgItem = GetDlgCtrlID(lphi->hItemHandle);
  122. if (DlgItem != IDC_CONVERTTO && DlgItem != IDC_CONVERT_TO && DlgItem != IDC_TXT_FORMAT)
  123. break;
  124. WinHelp (lphi->hItemHandle, gachHelpFile, HELP_WM_HELP,
  125. (UINT_PTR) (LPSTR) aHelpIds);
  126. return TRUE;
  127. }
  128. #endif
  129. case WM_INITDIALOG:
  130. {
  131. LPTSTR lpszFormat;
  132. PWAVEFORMATEX * ppwfx;
  133. // passed in through lCustData
  134. ppwfx = (PWAVEFORMATEX *)((OPENFILENAME *)(LPVOID)lParam)->lCustData;
  135. SetProp(hdlg, TEXT("DATA"), (HANDLE)ppwfx);
  136. lpszFormat = SoundRec_GetFormatName(gpWaveFormat);
  137. if (lpszFormat)
  138. {
  139. SetDlgItemText(hdlg, IDC_CONVERT_TO, lpszFormat);
  140. SetDlgItemText(hdlg, IDC_CONVERT_FROM, lpszFormat);
  141. GlobalFreePtr(lpszFormat);
  142. }
  143. return FALSE;
  144. }
  145. case WM_COMMAND:
  146. {
  147. PWAVEFORMATEX *ppwfx = (PWAVEFORMATEX *)GetProp(hdlg, TEXT("DATA"));
  148. int id = GET_WM_COMMAND_ID(wParam, lParam);
  149. switch (id)
  150. {
  151. case IDC_CONVERTTO:
  152. {
  153. PWAVEFORMATEX pwfxNew = NULL;
  154. if (ChooseDestinationFormat(ghInst
  155. ,hdlg
  156. ,NULL
  157. ,&pwfxNew
  158. ,0L) == MMSYSERR_NOERROR)
  159. {
  160. LPTSTR lpszFormat;
  161. if (*ppwfx)
  162. GlobalFreePtr(*ppwfx);
  163. //
  164. // set string name
  165. //
  166. lpszFormat = SoundRec_GetFormatName(pwfxNew);
  167. if (lpszFormat)
  168. {
  169. SetDlgItemText(hdlg, IDC_CONVERT_TO, lpszFormat);
  170. GlobalFreePtr(lpszFormat);
  171. }
  172. //
  173. // do something
  174. //
  175. *ppwfx = pwfxNew;
  176. }
  177. return TRUE;
  178. }
  179. default:
  180. break;
  181. }
  182. break;
  183. }
  184. case WM_DESTROY:
  185. RemoveProp(hdlg, TEXT("DATA"));
  186. break;
  187. default:
  188. break;
  189. }
  190. return FALSE;
  191. }
  192. /*
  193. * Launches the chooser dialog for changing the destination format.
  194. */
  195. MMRESULT FAR PASCAL
  196. ChooseDestinationFormat(
  197. HINSTANCE hInst,
  198. HWND hwndParent,
  199. PWAVEFORMATEX pwfxIn,
  200. PWAVEFORMATEX *ppwfxOut,
  201. DWORD fdwEnum)
  202. {
  203. ACMFORMATCHOOSE cwf;
  204. MMRESULT mmr;
  205. LPWAVEFORMATEX pwfx;
  206. DWORD dwMaxFormatSize;
  207. mmr = acmMetrics(NULL
  208. , ACM_METRIC_MAX_SIZE_FORMAT
  209. , (LPVOID)&dwMaxFormatSize);
  210. if (mmr != MMSYSERR_NOERROR)
  211. return mmr;
  212. pwfx = (LPWAVEFORMATEX)GlobalAllocPtr(GHND, (UINT)dwMaxFormatSize);
  213. if (pwfx == NULL)
  214. return MMSYSERR_NOMEM;
  215. memset(&cwf, 0, sizeof(cwf));
  216. cwf.cbStruct = sizeof(cwf);
  217. cwf.hwndOwner = hwndParent;
  218. cwf.fdwStyle = 0L;
  219. cwf.fdwEnum = 0L; // all formats!
  220. cwf.pwfxEnum = NULL; // all formats!
  221. if (fdwEnum)
  222. {
  223. cwf.fdwEnum = fdwEnum;
  224. cwf.pwfxEnum = pwfxIn;
  225. }
  226. cwf.pwfx = (LPWAVEFORMATEX)pwfx;
  227. cwf.cbwfx = dwMaxFormatSize;
  228. #ifdef CHICAGO
  229. cwf.fdwStyle |= ACMFORMATCHOOSE_STYLEF_CONTEXTHELP;
  230. #endif
  231. mmr = acmFormatChoose(&cwf);
  232. if (mmr == MMSYSERR_NOERROR)
  233. *ppwfxOut = pwfx;
  234. else
  235. {
  236. *ppwfxOut = NULL;
  237. GlobalFreePtr(pwfx);
  238. }
  239. return mmr;
  240. }
  241. #ifndef WM_APP
  242. #define WM_APP 0x8000
  243. #endif
  244. #define MYWM_CANCEL (WM_APP+0)
  245. #define MYWM_PROGRESS (WM_APP+1)
  246. /* Update a progress dialog
  247. */
  248. BOOL
  249. ProgressUpdate (
  250. PPROGRESS pPrg,
  251. DWORD dwCompleted)
  252. {
  253. DWORD dwDone;
  254. BOOL fCancel;
  255. if (pPrg == NULL)
  256. return TRUE;
  257. dwDone = (dwCompleted * pPrg->dwTotal) / 100L + pPrg->dwComplete;
  258. if (!IsWindow(pPrg->hPrg))
  259. return FALSE;
  260. SendMessage( pPrg->hPrg, MYWM_CANCEL, (WPARAM)&fCancel, 0L);
  261. if (fCancel)
  262. {
  263. return FALSE;
  264. }
  265. PostMessage( pPrg->hPrg, MYWM_PROGRESS, (WPARAM)dwDone, 0L);
  266. return TRUE;
  267. }
  268. //
  269. // should support a file handle as well.
  270. //
  271. typedef struct tConvertParam {
  272. PWAVEFORMATEX pwfxSrc; // pwfx specifying source format
  273. DWORD cbSrc; // size of the source buffer
  274. LPBYTE pbSrc; // source buffer
  275. PWAVEFORMATEX pwfxDst; // pwfx specifying dest format
  276. DWORD * pcbDst; // return size of the dest buffer
  277. LPBYTE * ppbDst; // dest buffer
  278. DWORD cBlks; // number of blocks
  279. PROGRESS Prg; // progress update
  280. MMRESULT mmr; // MMSYSERR result
  281. HANDLE hThread; // private
  282. } ConvertParam, *PConvertParam;
  283. /*
  284. * */
  285. DWORD ConvertThreadProc(LPVOID lpv)
  286. {
  287. PConvertParam pcp = (PConvertParam)lpv;
  288. MMRESULT mmr;
  289. mmr = ConvertMultipleFormats(pcp->pwfxSrc
  290. , pcp->cbSrc
  291. , pcp->pbSrc
  292. , pcp->pwfxDst
  293. , pcp->pcbDst
  294. , pcp->ppbDst
  295. , pcp->cBlks
  296. , &pcp->Prg);
  297. pcp->mmr = mmr;
  298. PostMessage(pcp->Prg.hPrg, WM_CLOSE, 0, 0);
  299. return 0; // end of thread!
  300. }
  301. static BOOL gfCancel = FALSE;
  302. /*
  303. * Progress_OnCommand
  304. * */
  305. void Progress_OnCommand(
  306. HWND hdlg,
  307. int id,
  308. HWND hctl,
  309. UINT unotify)
  310. {
  311. switch (id)
  312. {
  313. case IDCANCEL:
  314. gfCancel = TRUE;
  315. EndDialog(hdlg, FALSE);
  316. break;
  317. default:
  318. break;
  319. }
  320. }
  321. /*
  322. * Progress_Proc
  323. * */
  324. INT_PTR CALLBACK
  325. Progress_Proc(
  326. HWND hdlg,
  327. UINT umsg,
  328. WPARAM wparam,
  329. LPARAM lparam)
  330. {
  331. switch (umsg)
  332. {
  333. case WM_INITDIALOG:
  334. {
  335. HANDLE hThread;
  336. PConvertParam pcp = (PConvertParam)(LPVOID)lparam;
  337. HWND hprg;
  338. DWORD thid;
  339. LPTSTR lpsz;
  340. hprg = GetDlgItem(hdlg, IDC_PROGRESSBAR);
  341. SendMessage(hprg, PBM_SETRANGE, 0, MAKELONG(0, 100));
  342. SendMessage(hprg, PBM_SETPOS, 0, 0);
  343. SetProp(hdlg, TEXT("DATA"), (HANDLE)pcp);
  344. pcp->Prg.hPrg = hdlg;
  345. pcp->Prg.dwTotal = 100;
  346. gfCancel = FALSE;
  347. lpsz = SoundRec_GetFormatName(pcp->pwfxSrc);
  348. if (lpsz)
  349. {
  350. SetDlgItemText(hdlg, IDC_CONVERT_FROM, lpsz);
  351. GlobalFreePtr(lpsz);
  352. }
  353. lpsz = SoundRec_GetFormatName(pcp->pwfxDst);
  354. if (lpsz)
  355. {
  356. SetDlgItemText(hdlg, IDC_CONVERT_TO, lpsz);
  357. GlobalFreePtr(lpsz);
  358. }
  359. hThread = CreateThread( NULL // no special security
  360. , 0 // default stack size
  361. , (LPTHREAD_START_ROUTINE)ConvertThreadProc
  362. , (LPVOID)pcp
  363. , 0 // start running at once
  364. , &thid );
  365. pcp->hThread = hThread;
  366. break;
  367. }
  368. case WM_COMMAND:
  369. HANDLE_WM_COMMAND(hdlg, wparam, lparam, Progress_OnCommand);
  370. break;
  371. case MYWM_CANCEL:
  372. {
  373. BOOL *pf = (BOOL *)wparam;
  374. if (pf)
  375. *pf = gfCancel;
  376. break;
  377. }
  378. case MYWM_PROGRESS:
  379. {
  380. HWND hprg = GetDlgItem(hdlg, IDC_PROGRESSBAR);
  381. SendMessage(hprg, PBM_SETPOS, wparam, 0);
  382. break;
  383. }
  384. case WM_DESTROY:
  385. {
  386. PConvertParam pcp = (ConvertParam *)GetProp(hdlg, TEXT("DATA"));
  387. if (pcp)
  388. {
  389. //
  390. // Make sure the thread exits
  391. //
  392. if (pcp->hThread)
  393. {
  394. WaitForSingleObject(pcp->hThread, 1000);
  395. CloseHandle(pcp->hThread);
  396. pcp->hThread = NULL;
  397. }
  398. RemoveProp(hdlg, TEXT("DATA"));
  399. }
  400. break;
  401. }
  402. default:
  403. break;
  404. }
  405. return FALSE;
  406. }
  407. /* Generic single step conversion.
  408. */
  409. MMRESULT
  410. ConvertFormatDialog(
  411. HWND hParent,
  412. PWAVEFORMATEX pwfxSrc, // pwfx specifying source format
  413. DWORD cbSrc, // size of the source buffer
  414. LPBYTE pbSrc, // source buffer
  415. PWAVEFORMATEX pwfxDst, // pwfx specifying dest format
  416. DWORD * pcbDst, // return size of the dest buffer
  417. LPBYTE * ppbDst, // dest buffer
  418. DWORD cBlks, // number of blocks
  419. PPROGRESS pPrg) // progress update
  420. {
  421. ConvertParam cp;
  422. *pcbDst = 0;
  423. *ppbDst = NULL;
  424. if (cbSrc == 0)
  425. return MMSYSERR_NOERROR;
  426. cp.pwfxSrc = pwfxSrc;
  427. cp.cbSrc = cbSrc;
  428. cp.pbSrc = pbSrc;
  429. cp.pwfxDst = pwfxDst;
  430. cp.pcbDst = pcbDst;
  431. cp.ppbDst = ppbDst;
  432. cp.cBlks = cBlks;
  433. cp.mmr = MMSYSERR_ERROR; // fail on abnormal thread termination!
  434. cp.hThread = NULL;
  435. DialogBoxParam(ghInst
  436. , MAKEINTRESOURCE(IDD_CONVERTING)
  437. , hParent
  438. , Progress_Proc
  439. , (LPARAM)(LPVOID)&cp);
  440. return cp.mmr;
  441. }
  442. #if DBG
  443. void DumpASH(
  444. MMRESULT mmr,
  445. ACMSTREAMHEADER *pash)
  446. {
  447. TCHAR sz[256];
  448. wsprintf(sz,TEXT("mmr = %lx\r\n"), mmr);
  449. OutputDebugString(sz);
  450. wsprintf(sz,TEXT("pash is %s\r\n"),IsBadWritePtr(pash, pash->cbStruct)?TEXT("bad"):TEXT("good"));
  451. OutputDebugString(sz);
  452. OutputDebugString(TEXT("ACMSTREAMHEADER {\r\n"));
  453. wsprintf(sz,TEXT("ash.cbStruct = %lx\r\n"),pash->cbStruct);
  454. OutputDebugString(sz);
  455. wsprintf(sz,TEXT("ash.fdwStatus = %lx\r\n"),pash->fdwStatus);
  456. OutputDebugString(sz);
  457. wsprintf(sz,TEXT("ash.pbSrc = %lx\r\n"),pash->pbSrc);
  458. OutputDebugString(sz);
  459. wsprintf(sz,TEXT("ash.cbSrcLength = %lx\r\n"),pash->cbSrcLength);
  460. OutputDebugString(sz);
  461. wsprintf(sz,TEXT("pbSrc is %s\r\n"),IsBadWritePtr(pash->pbSrc, pash->cbSrcLength)?TEXT("bad"):TEXT("good"));
  462. OutputDebugString(sz);
  463. wsprintf(sz,TEXT("ash.cbSrcLengthUsed= %lx\r\n"),pash->cbSrcLengthUsed);
  464. OutputDebugString(sz);
  465. wsprintf(sz,TEXT("ash.pbDst = %lx\r\n"),pash->pbDst);
  466. OutputDebugString(sz);
  467. wsprintf(sz,TEXT("ash.cbDstLength = %lx\r\n"),pash->cbDstLength);
  468. OutputDebugString(sz);
  469. wsprintf(sz,TEXT("pbDst is %s\r\n"),IsBadWritePtr(pash->pbDst, pash->cbDstLength)?TEXT("bad"):TEXT("good"));
  470. OutputDebugString(sz);
  471. wsprintf(sz,TEXT("ash.cbDstLengthUsed= %lx\r\n"),pash->cbDstLengthUsed);
  472. OutputDebugString(sz);
  473. OutputDebugString(TEXT("} ACMSTREAMHEADER\r\n"));
  474. if (mmr != MMSYSERR_NOERROR)
  475. DebugBreak();
  476. }
  477. void DumpWFX(
  478. LPTSTR psz,
  479. LPWAVEFORMATEX pwfx,
  480. LPBYTE pbSamples,
  481. DWORD cbSamples)
  482. {
  483. TCHAR sz[256];
  484. if (psz)
  485. {
  486. OutputDebugString(psz);
  487. OutputDebugString(TEXT("\r\n"));
  488. }
  489. OutputDebugString(TEXT("WAVEFORMATEX {\r\n"));
  490. wsprintf(sz , TEXT("wfx.wFormatTag = %x\r\n")
  491. , pwfx->wFormatTag);
  492. OutputDebugString(sz);
  493. wsprintf(sz , TEXT("wfx.nChannels = %x\r\n")
  494. , pwfx->nChannels);
  495. OutputDebugString(sz);
  496. wsprintf(sz , TEXT("wfx.nSamplesPerSec = %lx\r\n")
  497. , pwfx->nSamplesPerSec);
  498. OutputDebugString(sz);
  499. wsprintf(sz , TEXT("wfx.nAvgBytesPerSec = %lx\r\n")
  500. , pwfx->nAvgBytesPerSec);
  501. OutputDebugString(sz);
  502. wsprintf(sz , TEXT("wfx.nBlockAlign = %x\r\n")
  503. , pwfx->nBlockAlign);
  504. OutputDebugString(sz);
  505. wsprintf(sz , TEXT("wfx.wBitsPerSample = %x\r\n")
  506. , pwfx->wBitsPerSample);
  507. OutputDebugString(sz);
  508. wsprintf(sz , TEXT("wfx.cbSize = %x\r\n")
  509. , pwfx->cbSize);
  510. OutputDebugString(sz);
  511. OutputDebugString(TEXT("} WAVEFORMATEX\r\n"));
  512. wsprintf(sz , TEXT("cbSamples = %d, that's %d ms\r\n")
  513. , cbSamples
  514. , wfSamplesToTime(pwfx, wfBytesToSamples(pwfx, cbSamples)));
  515. OutputDebugString(sz);
  516. if (IsBadReadPtr(pbSamples, cbSamples))
  517. {
  518. OutputDebugString(TEXT("Bad Data (READ)!!!!!\r\n"));
  519. DebugBreak();
  520. }
  521. if (IsBadWritePtr(pbSamples, cbSamples))
  522. {
  523. OutputDebugString(TEXT("Bad Data (WRITE)!!!!!\r\n"));
  524. DebugBreak();
  525. }
  526. }
  527. #else
  528. #define DumpASH(x,y)
  529. #define DumpWFX(x,y,z,a)
  530. #endif
  531. MMRESULT
  532. ConvertMultipleFormats(
  533. PWAVEFORMATEX pwfxSrc, // pwfx specifying source format
  534. DWORD cbSrc, // size of the source buffer
  535. LPBYTE pbSrc, // source buffer
  536. PWAVEFORMATEX pwfxDst, // pwfx specifying dest format
  537. DWORD * pcbDst, // return size of the dest buffer
  538. LPBYTE * ppbDst, // dest buffer
  539. DWORD cBlks, // number of blocks
  540. PPROGRESS pPrg) // progress update
  541. {
  542. MMRESULT mmr;
  543. WAVEFORMATEX wfxPCM1, wfxPCM2;
  544. LPBYTE pbPCM1, pbPCM2;
  545. DWORD cbPCM1, cbPCM2;
  546. if (cbSrc == 0 || pbSrc == NULL)
  547. {
  548. pPrg->dwTotal = 100;
  549. pPrg->dwComplete = 100;
  550. ProgressUpdate(pPrg, 100);
  551. *pcbDst = 0;
  552. *ppbDst = NULL;
  553. return MMSYSERR_NOERROR;
  554. }
  555. //
  556. // Ask ACM to suggest a PCM format to convert to.
  557. //
  558. wfxPCM1.wFormatTag = WAVE_FORMAT_PCM;
  559. mmr = acmFormatSuggest(NULL, pwfxSrc, &wfxPCM1, sizeof(WAVEFORMATEX),
  560. ACM_FORMATSUGGESTF_WFORMATTAG);
  561. if (mmr != MMSYSERR_NOERROR)
  562. return mmr;
  563. //
  564. // Ask ACM to suggest a PCM format to convert from.
  565. //
  566. wfxPCM2.wFormatTag = WAVE_FORMAT_PCM;
  567. mmr = acmFormatSuggest(NULL, pwfxDst, &wfxPCM2, sizeof(WAVEFORMATEX),
  568. ACM_FORMATSUGGESTF_WFORMATTAG);
  569. if (mmr != MMSYSERR_NOERROR)
  570. return mmr;
  571. //
  572. // if either of the above suggestions failed, we cannot complete the
  573. // conversion.
  574. //
  575. // now, we have the following steps to execute:
  576. //
  577. // *pwfxSrc -> wfxPCM1
  578. // wfxPCM1 -> wfxPCM2
  579. // wfxPCM2 -> *pwfxDst
  580. //
  581. // if either *pwfxSrc or *pwfxDst are PCM, we only need a two or one step
  582. // conversion.
  583. //
  584. if (pwfxSrc->wFormatTag == WAVE_FORMAT_PCM
  585. || pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
  586. {
  587. LPWAVEFORMATEX pwfx;
  588. DWORD * pcb;
  589. LPBYTE * ppb;
  590. //
  591. // single step conversion
  592. //
  593. if ((pwfxSrc->wFormatTag == WAVE_FORMAT_PCM
  594. && pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
  595. || (pwfxSrc->wFormatTag == WAVE_FORMAT_PCM
  596. && memcmp(pwfxSrc, &wfxPCM2, sizeof(PCMWAVEFORMAT)) == 0)
  597. || (pwfxDst->wFormatTag == WAVE_FORMAT_PCM
  598. && memcmp(pwfxDst, &wfxPCM1, sizeof(PCMWAVEFORMAT)) == 0))
  599. {
  600. pPrg->dwTotal = 100;
  601. pPrg->dwComplete = 0;
  602. mmr = ConvertFormat(pwfxSrc
  603. , cbSrc
  604. , pbSrc
  605. , pwfxDst
  606. , pcbDst
  607. , ppbDst
  608. , cBlks
  609. , pPrg);
  610. return mmr;
  611. }
  612. //
  613. // two step conversion required
  614. //
  615. if (pwfxSrc->wFormatTag == WAVE_FORMAT_PCM)
  616. {
  617. pwfx = &wfxPCM2;
  618. pcb = &cbPCM2;
  619. ppb = &pbPCM2;
  620. }
  621. else
  622. {
  623. pwfx = &wfxPCM1;
  624. pcb = &cbPCM1;
  625. ppb = &pbPCM1;
  626. }
  627. pPrg->dwTotal = 50;
  628. pPrg->dwComplete = 0;
  629. mmr = ConvertFormat(pwfxSrc
  630. , cbSrc
  631. , pbSrc
  632. , pwfx
  633. , pcb
  634. , ppb
  635. , cBlks
  636. , pPrg);
  637. if (mmr != MMSYSERR_NOERROR)
  638. return mmr;
  639. pPrg->dwTotal = 50;
  640. pPrg->dwComplete = 50;
  641. mmr = ConvertFormat(pwfx
  642. , *pcb
  643. , *ppb
  644. , pwfxDst
  645. , pcbDst
  646. , ppbDst
  647. , cBlks
  648. , pPrg);
  649. GlobalFreePtr(*ppb);
  650. return mmr;
  651. }
  652. else
  653. {
  654. //
  655. // three step conversion required
  656. //
  657. pPrg->dwTotal = 33;
  658. pPrg->dwComplete = 1;
  659. //
  660. // Convert from Src to PCM1
  661. //
  662. mmr = ConvertFormat(pwfxSrc
  663. , cbSrc
  664. , pbSrc
  665. , &wfxPCM1
  666. , &cbPCM1
  667. , &pbPCM1
  668. , cBlks
  669. , pPrg);
  670. if (mmr != MMSYSERR_NOERROR)
  671. return mmr;
  672. pPrg->dwTotal = 33;
  673. pPrg->dwComplete = 34;
  674. //
  675. // Convert from PCM1 to PCM2
  676. //
  677. mmr = ConvertFormat (&wfxPCM1
  678. , cbPCM1
  679. , pbPCM1
  680. , &wfxPCM2
  681. , &cbPCM2
  682. , &pbPCM2
  683. , cBlks
  684. , pPrg);
  685. GlobalFreePtr(pbPCM1);
  686. if (mmr != MMSYSERR_NOERROR)
  687. return mmr;
  688. pPrg->dwTotal = 33;
  689. pPrg->dwComplete = 67;
  690. //
  691. // Convert from PCM2 to DST
  692. //
  693. mmr = ConvertFormat (&wfxPCM2
  694. , cbPCM2
  695. , pbPCM2
  696. , pwfxDst
  697. , pcbDst
  698. , ppbDst
  699. , cBlks
  700. , pPrg);
  701. GlobalFreePtr(pbPCM2);
  702. }
  703. return mmr;
  704. }
  705. //
  706. // add spilage to/from file i/o
  707. //
  708. /* Generic single step conversion.
  709. */
  710. MMRESULT
  711. ConvertFormat(
  712. PWAVEFORMATEX pwfxSrc, // pwfx specifying source format
  713. DWORD cbSrc, // size of the source buffer
  714. LPBYTE pbSrc, // source buffer
  715. PWAVEFORMATEX pwfxDst, // pwfx specifying dest format
  716. DWORD * pcbDst, // return size of the dest buffer
  717. LPBYTE * ppbDst, // dest buffer
  718. DWORD cBlks, // number of blocks
  719. PPROGRESS pPrg) // progress update
  720. {
  721. HACMSTREAM hasStream = NULL;
  722. MMRESULT mmr = MMSYSERR_NOERROR;
  723. //
  724. // temporary copy buffers
  725. //
  726. DWORD cbSrcBuf = 0L;
  727. LPBYTE pbSrcBuf = NULL;
  728. DWORD cbDstBuf = 0L;
  729. LPBYTE pbDstBuf = NULL;
  730. //
  731. // full destination buffers
  732. //
  733. DWORD cbDst = 0L;
  734. LPBYTE pbDst = NULL;
  735. DWORD cbSrcUsed = 0L;
  736. DWORD cbDstUsed = 0L;
  737. DWORD cbCopySrc = 0L;
  738. DWORD cbCopyDst = 0L;
  739. DWORD cbRem;
  740. ACMSTREAMHEADER ash;
  741. WORD nBlockAlign;
  742. gfBreakOfDeath = FALSE;
  743. DumpWFX(TEXT("ConvertFormat Input"), pwfxSrc, pbSrc, cbSrc);
  744. if (cbSrc == 0 || pbSrc == NULL)
  745. {
  746. pPrg->dwTotal = 100;
  747. pPrg->dwComplete = 100;
  748. ProgressUpdate(pPrg, 100);
  749. *pcbDst = 0;
  750. *ppbDst = NULL;
  751. return MMSYSERR_NOERROR;
  752. }
  753. //
  754. // synchronous conversion
  755. //
  756. mmr = acmStreamOpen(&hasStream
  757. , NULL
  758. , pwfxSrc
  759. , pwfxDst
  760. , NULL // no filter. maybe later
  761. , 0L
  762. , 0L
  763. , ACM_STREAMOPENF_NONREALTIME );
  764. if (MMSYSERR_NOERROR != mmr)
  765. {
  766. return mmr;
  767. }
  768. //
  769. // How big of a destination buffer do we need?
  770. //
  771. // WARNING: acmStreamSize only gives us an estimation. if, in the event
  772. // it *underestimates* the destination buffer size we currently ignore
  773. // it, causing a clipping of the end buffer
  774. //
  775. mmr = acmStreamSize(hasStream
  776. , cbSrc
  777. , &cbDst
  778. , ACM_STREAMSIZEF_SOURCE);
  779. if (MMSYSERR_NOERROR != mmr)
  780. {
  781. goto ExitCloseStream;
  782. }
  783. //
  784. // allocate the destination buffer
  785. //
  786. pbDst = (LPBYTE)GlobalAllocPtr(GHND | GMEM_SHARE,cbDst);
  787. if (pbDst == NULL)
  788. {
  789. mmr = MMSYSERR_NOMEM;
  790. goto ExitCloseStream;
  791. }
  792. *ppbDst = pbDst;
  793. *pcbDst = cbDst;
  794. //
  795. // chop up the data into 10 bitesize pieces
  796. //
  797. nBlockAlign = pwfxSrc->nBlockAlign;
  798. cbSrcBuf = cbSrc / 10;
  799. cbSrcBuf = cbSrcBuf - (cbSrcBuf % nBlockAlign);
  800. cbSrcBuf = ( 0L == cbSrcBuf ) ? nBlockAlign : cbSrcBuf;
  801. mmr = acmStreamSize(hasStream
  802. , cbSrcBuf
  803. , &cbDstBuf
  804. , ACM_STREAMSIZEF_SOURCE);
  805. if (MMSYSERR_NOERROR != mmr)
  806. goto ExitFreeDestData;
  807. //
  808. // allocate source copy buffer
  809. //
  810. pbSrcBuf = (LPBYTE)GlobalAllocPtr(GHND | GMEM_SHARE,cbSrcBuf);
  811. if (pbSrcBuf == NULL)
  812. {
  813. mmr = MMSYSERR_NOMEM;
  814. goto ExitFreeDestData;
  815. }
  816. //
  817. // allocate destination copy buffer
  818. //
  819. pbDstBuf = (LPBYTE)GlobalAllocPtr(GHND | GMEM_SHARE,cbDstBuf);
  820. if (pbDstBuf == NULL)
  821. {
  822. mmr = MMSYSERR_NOMEM;
  823. GlobalFreePtr(pbSrcBuf);
  824. pbSrcBuf = NULL;
  825. goto ExitFreeDestData;
  826. }
  827. //
  828. // initialize the ash
  829. //
  830. ash.cbStruct = sizeof(ash);
  831. ash.fdwStatus = 0L;
  832. ash.pbSrc = pbSrcBuf;
  833. ash.cbSrcLength = cbSrcBuf;
  834. ash.cbSrcLengthUsed = 0L;
  835. ash.pbDst = pbDstBuf;
  836. ash.cbDstLength = cbDstBuf;
  837. ash.cbDstLengthUsed = 0L;
  838. //
  839. // we will only need to prepare once, since the buffers are
  840. // never moved.
  841. //
  842. mmr = acmStreamPrepareHeader(hasStream, &ash, 0L);
  843. if (MMSYSERR_NOERROR != mmr)
  844. goto ExitFreeTempBuffers;
  845. //
  846. // main blockalign conversion loop
  847. //
  848. while (cbSrcUsed < cbSrc)
  849. {
  850. cbCopySrc = min(cbSrcBuf, cbSrc - cbSrcUsed);
  851. if (cbCopySrc > 0L)
  852. memmove(pbSrcBuf, pbSrc, cbCopySrc);
  853. #ifdef ACMBUG
  854. //
  855. // ACM has a bug wherein the destination buffer is validated for too
  856. // much. If we exactly calculate the cbCopyDst here, ACM is sure to
  857. // puke on the conversion before the last.
  858. //
  859. cbCopyDst = min(cbDstBuf, cbDst - cbDstUsed);
  860. #else
  861. cbCopyDst = cbDstBuf;
  862. #endif
  863. if (cbCopyDst == 0L || cbCopyDst == 0L)
  864. break;
  865. ash.cbSrcLength = cbCopySrc;
  866. ash.cbSrcLengthUsed = 0L;
  867. ash.cbDstLength = cbCopyDst;
  868. ash.cbDstLengthUsed = 0L;
  869. mmr = acmStreamConvert(hasStream
  870. , &ash
  871. , ACM_STREAMCONVERTF_BLOCKALIGN );
  872. if (MMSYSERR_NOERROR != mmr)
  873. {
  874. DumpASH(mmr, &ash);
  875. goto ExitUnprepareHeader;
  876. }
  877. //
  878. // Update the user and test for cancel
  879. //
  880. if (!ProgressUpdate(pPrg, (cbSrcUsed * 100)/cbSrc))
  881. {
  882. mmr = MMSYSERR_ERROR;
  883. goto ExitUnprepareHeader;
  884. }
  885. while (0 == (ACMSTREAMHEADER_STATUSF_DONE & ash.fdwStatus))
  886. {
  887. //
  888. // I don't trust an infinite loop.
  889. //
  890. if (gfBreakOfDeath)
  891. {
  892. mmr = MMSYSERR_HANDLEBUSY; // Bad bad bad condition
  893. goto ExitUnprepareHeader;
  894. }
  895. }
  896. //
  897. // always increment. we will have to carry over whatever the
  898. // last conversion gives us back since this determined by.
  899. //
  900. cbSrcUsed += ash.cbSrcLengthUsed;
  901. pbSrc += ash.cbSrcLengthUsed;
  902. //
  903. // loop terminating condition. if the conversion yields no
  904. // destination data without error, we can only flush end data.
  905. //
  906. if (0L == ash.cbDstLengthUsed || cbDstUsed >= cbDst)
  907. break;
  908. #ifdef ACMBUG
  909. memmove(pbDst, pbDstBuf, ash.cbDstLengthUsed );
  910. cbDstUsed += ash.cbDstLengthUsed;
  911. pbDst += ash.cbDstLengthUsed;
  912. #else
  913. cbRem = min(ash.cbDstLengthUsed, cbDst - cbDstUsed);
  914. memmove(pbDst, pbDstBuf, cbRem);
  915. cbDstUsed += cbRem;
  916. pbDst += cbRem;
  917. #endif
  918. }
  919. //
  920. // Flush remaining block-aligned end data to the destination stream.
  921. // Example: A few bytes of source data were left unconverted because
  922. // for some reason, the last
  923. //
  924. for (;cbDst - cbDstUsed > 0; )
  925. {
  926. cbCopySrc = min(cbSrcBuf, cbSrc - cbSrcUsed);
  927. if (cbCopySrc > 0L)
  928. memmove(pbSrcBuf, pbSrc, cbCopySrc);
  929. #ifdef ACMBUG
  930. cbCopyDst = min(cbDstBuf, cbDst - cbDstUsed);
  931. #else
  932. cbCopyDst = cbDstBuf;
  933. #endif
  934. ash.cbSrcLength = cbCopySrc;
  935. ash.cbSrcLengthUsed = 0L;
  936. ash.cbDstLength = cbCopyDst;
  937. ash.cbDstLengthUsed = 0L;
  938. mmr = acmStreamConvert(hasStream
  939. , &ash
  940. , ACM_STREAMCONVERTF_BLOCKALIGN |
  941. ACM_STREAMCONVERTF_END );
  942. if (MMSYSERR_NOERROR != mmr)
  943. {
  944. DumpASH(mmr, &ash);
  945. goto ExitUnprepareHeader;
  946. }
  947. //
  948. // Update the user and test for cancel
  949. //
  950. if (!ProgressUpdate(pPrg, (cbSrcUsed * 100)/cbSrc))
  951. {
  952. mmr = MMSYSERR_ERROR;
  953. goto ExitUnprepareHeader;
  954. }
  955. while (0 == (ACMSTREAMHEADER_STATUSF_DONE & ash.fdwStatus))
  956. {
  957. //
  958. // I don't trust an infinite loop.
  959. //
  960. if (gfBreakOfDeath)
  961. {
  962. mmr = MMSYSERR_HANDLEBUSY; // Bad bad bad condition
  963. goto ExitUnprepareHeader;
  964. }
  965. }
  966. cbSrcUsed += ash.cbSrcLengthUsed;
  967. pbSrc += ash.cbSrcLengthUsed;
  968. if (0L != ash.cbDstLengthUsed && cbDstUsed < cbDst)
  969. {
  970. #ifdef ACMBUG
  971. memmove(pbDst, pbDstBuf, ash.cbDstLengthUsed);
  972. cbDstUsed += ash.cbDstLengthUsed;
  973. pbDst += ash.cbDstLengthUsed;
  974. #else
  975. cbRem = min(ash.cbDstLengthUsed, cbDst - cbDstUsed);
  976. memmove(pbDst, pbDstBuf, cbRem);
  977. cbDstUsed += cbRem;
  978. pbDst += cbRem;
  979. #endif
  980. }
  981. //
  982. // Last pass non-blockaligned end data
  983. //
  984. cbCopySrc = min(cbSrcBuf, cbSrc - cbSrcUsed);
  985. if (cbCopySrc > 0L)
  986. memmove(pbSrcBuf, pbSrc, cbCopySrc);
  987. #ifdef ACMBUG
  988. cbCopyDst = min(cbDstBuf, cbDst - cbDstUsed);
  989. if (0L == cbCopyDst)
  990. break;
  991. #else
  992. cbCopyDst = cbDstBuf;
  993. #endif
  994. ash.cbSrcLength = cbCopySrc;
  995. ash.cbSrcLengthUsed = 0L;
  996. ash.cbDstLength = cbCopyDst;
  997. ash.cbDstLengthUsed = 0L;
  998. mmr = acmStreamConvert(hasStream
  999. , &ash
  1000. , ACM_STREAMCONVERTF_END );
  1001. if (MMSYSERR_NOERROR != mmr)
  1002. {
  1003. DumpASH(mmr, &ash);
  1004. goto ExitUnprepareHeader;
  1005. }
  1006. //
  1007. // Update the user and test for cancel
  1008. //
  1009. if (!ProgressUpdate(pPrg, (cbSrcUsed * 100)/cbSrc))
  1010. {
  1011. mmr = MMSYSERR_ERROR;
  1012. goto ExitUnprepareHeader;
  1013. }
  1014. while (0 == (ACMSTREAMHEADER_STATUSF_DONE & ash.fdwStatus))
  1015. {
  1016. //
  1017. // I don't trust an infinite loop.
  1018. //
  1019. if (gfBreakOfDeath)
  1020. {
  1021. mmr = MMSYSERR_HANDLEBUSY; // Bad bad bad condition
  1022. goto ExitUnprepareHeader;
  1023. }
  1024. }
  1025. cbSrcUsed += ash.cbSrcLengthUsed;
  1026. pbSrc += ash.cbSrcLengthUsed;
  1027. if (0L != ash.cbDstLengthUsed && cbDstUsed < cbDst)
  1028. {
  1029. #ifdef ACMBUG
  1030. memmove(pbDst, pbDstBuf, ash.cbDstLengthUsed);
  1031. cbDstUsed += ash.cbDstLengthUsed;
  1032. pbDst += ash.cbDstLengthUsed;
  1033. #else
  1034. cbRem = min(ash.cbDstLengthUsed, cbDst - cbDstUsed);
  1035. memmove(pbDst, pbDstBuf, cbRem);
  1036. cbDstUsed += cbRem;
  1037. pbDst += cbRem;
  1038. #endif
  1039. }
  1040. else // nothing's going to work
  1041. break;
  1042. }
  1043. *pcbDst = cbDstUsed;
  1044. DumpWFX(TEXT("ConvertFormat Output"), pwfxDst, *ppbDst, cbDstUsed);
  1045. ExitUnprepareHeader:
  1046. acmStreamUnprepareHeader(hasStream, &ash, 0L);
  1047. ExitFreeTempBuffers:
  1048. GlobalFreePtr(pbDstBuf);
  1049. GlobalFreePtr(pbSrcBuf);
  1050. if (MMSYSERR_NOERROR == mmr)
  1051. goto ExitCloseStream;
  1052. ExitFreeDestData:
  1053. GlobalFreePtr(*ppbDst);
  1054. *ppbDst = NULL;
  1055. *pcbDst = 0L;
  1056. ExitCloseStream:
  1057. acmStreamClose(hasStream,0L);
  1058. return mmr;
  1059. }
  1060. /* - - - - - - - - - */
  1061. void Properties_InitDocVars(
  1062. HWND hwnd,
  1063. PWAVEDOC pwd)
  1064. {
  1065. if (pwd->pwfx)
  1066. {
  1067. LPTSTR lpstr;
  1068. TCHAR sz[128];
  1069. TCHAR szFmt[128];
  1070. LONG lTime;
  1071. HINSTANCE hinst;
  1072. lpstr = SoundRec_GetFormatName(pwd->pwfx);
  1073. if (lpstr)
  1074. {
  1075. SetDlgItemText(hwnd, IDC_AUDIOFORMAT, lpstr);
  1076. GlobalFreePtr(lpstr);
  1077. }
  1078. lTime = wfSamplesToTime(pwd->pwfx,wfBytesToSamples(pwd->pwfx,pwd->cbdata));
  1079. if (gfLZero || ((int)(lTime/1000) != 0))
  1080. wsprintf(sz, aszPositionFormat, (int)(lTime/1000), chDecimal,
  1081. (int)((lTime/10)%100));
  1082. else
  1083. wsprintf(sz, aszNoZeroPositionFormat, chDecimal,
  1084. (int)((lTime/10)%100));
  1085. SetDlgItemText(hwnd, IDC_FILELEN, sz);
  1086. hinst = GetWindowInstance(hwnd);
  1087. if (hinst && LoadString(hinst, IDS_DATASIZE, szFmt, SIZEOF(szFmt)))
  1088. {
  1089. wsprintf(sz, szFmt, pwd->cbdata);
  1090. SetDlgItemText(hwnd, IDC_DATASIZE, sz);
  1091. }
  1092. }
  1093. }
  1094. /*
  1095. * */
  1096. BOOL Properties_OnInitDialog(
  1097. HWND hwnd,
  1098. HWND hwndFocus,
  1099. LPARAM lParam)
  1100. {
  1101. HINSTANCE hinst;
  1102. HWND hChoice;
  1103. TCHAR sz[256];
  1104. int i;
  1105. //
  1106. // commence initialization
  1107. //
  1108. PWAVEDOC pwd = (PWAVEDOC)((LPPROPSHEETPAGE)lParam)->lParam;
  1109. if (pwd == NULL)
  1110. {
  1111. EndDialog(hwnd, FALSE);
  1112. return FALSE;
  1113. }
  1114. SetProp(hwnd, TEXT("DATA"), (HANDLE)pwd);
  1115. hinst = GetWindowInstance(hwnd);
  1116. //
  1117. // Set "static" property information
  1118. //
  1119. if (pwd->pszFileName)
  1120. SetDlgItemText(hwnd, IDC_FILENAME, pwd->pszFileName);
  1121. if (pwd->pszCopyright)
  1122. SetDlgItemText(hwnd, IDC_COPYRIGHT, pwd->pszCopyright);
  1123. else if (LoadString(hinst, IDS_NOCOPYRIGHT, sz, SIZEOF(sz)))
  1124. {
  1125. SetDlgItemText(hwnd, IDC_COPYRIGHT, sz);
  1126. }
  1127. if (pwd->hIcon)
  1128. Static_SetIcon(GetDlgItem(hwnd, IDC_DISPICON), pwd->hIcon);
  1129. //
  1130. // Set "volatile" property information
  1131. //
  1132. Properties_InitDocVars(hwnd, pwd);
  1133. //
  1134. // Initialize the enumeration choice combobox
  1135. //
  1136. hChoice = GetDlgItem(hwnd, IDC_CONVERTCHOOSEFROM);
  1137. if (waveOutGetNumDevs())
  1138. {
  1139. if (LoadString(hinst, IDS_SHOWPLAYABLE, sz, SIZEOF(sz)))
  1140. {
  1141. i = ComboBox_AddString(hChoice, sz);
  1142. ComboBox_SetItemData(hChoice, i, ACM_FORMATENUMF_OUTPUT);
  1143. }
  1144. }
  1145. if (waveInGetNumDevs())
  1146. {
  1147. if (LoadString(hinst, IDS_SHOWRECORDABLE, sz, SIZEOF(sz)))
  1148. {
  1149. i = ComboBox_AddString(hChoice, sz);
  1150. ComboBox_SetItemData(hChoice, i, ACM_FORMATENUMF_INPUT);
  1151. }
  1152. }
  1153. if (LoadString(hinst, IDS_SHOWALL, sz, SIZEOF(sz)))
  1154. {
  1155. i = ComboBox_AddString(hChoice, sz);
  1156. ComboBox_SetItemData(hChoice, i, 0L);
  1157. }
  1158. ComboBox_SetCurSel(hChoice, i);
  1159. return FALSE;
  1160. }
  1161. /*
  1162. * */
  1163. void Properties_OnDestroy(
  1164. HWND hwnd)
  1165. {
  1166. //
  1167. // commence cleanup
  1168. //
  1169. PWAVEDOC pwd = (PWAVEDOC)GetProp(hwnd, TEXT("DATA"));
  1170. if (pwd)
  1171. {
  1172. RemoveProp(hwnd, TEXT("DATA"));
  1173. }
  1174. }
  1175. /*
  1176. * */
  1177. BOOL PASCAL Properties_OnCommand(
  1178. HWND hwnd,
  1179. int id,
  1180. HWND hwndCtl,
  1181. UINT codeNotify)
  1182. {
  1183. switch (id)
  1184. {
  1185. case ID_APPLY:
  1186. return TRUE;
  1187. case IDOK:
  1188. break;
  1189. case IDCANCEL:
  1190. break;
  1191. case ID_INIT:
  1192. break;
  1193. case IDC_CONVERTTO:
  1194. {
  1195. PWAVEDOC pwd = (PWAVEDOC)GetProp(hwnd, TEXT("DATA"));
  1196. PWAVEFORMATEX pwfxNew = NULL;
  1197. DWORD fdwEnum = 0L;
  1198. int i;
  1199. HWND hChoice;
  1200. hChoice = GetDlgItem(hwnd, IDC_CONVERTCHOOSEFROM);
  1201. i = ComboBox_GetCurSel(hChoice);
  1202. fdwEnum = (DWORD)ComboBox_GetItemData(hChoice, i);
  1203. if (ChooseDestinationFormat(ghInst
  1204. ,hwnd
  1205. ,NULL
  1206. ,&pwfxNew
  1207. ,fdwEnum) == MMSYSERR_NOERROR)
  1208. {
  1209. DWORD cbNew;
  1210. LPBYTE pbNew;
  1211. DWORD cbSize = (pwfxNew->wFormatTag == WAVE_FORMAT_PCM)?
  1212. sizeof(PCMWAVEFORMAT):
  1213. sizeof(WAVEFORMATEX)+pwfxNew->cbSize;
  1214. if (memcmp(pwfxNew, pwd->pwfx, cbSize) == 0)
  1215. break;
  1216. StopWave();
  1217. BeginWaveEdit();
  1218. if (ConvertFormatDialog(hwnd
  1219. , pwd->pwfx
  1220. , pwd->cbdata
  1221. , pwd->pbdata
  1222. , pwfxNew
  1223. , &cbNew
  1224. , &pbNew
  1225. , 0
  1226. , NULL) == MMSYSERR_NOERROR)
  1227. {
  1228. GlobalFreePtr(pwd->pwfx);
  1229. if (pwd->pbdata)
  1230. GlobalFreePtr(pwd->pbdata);
  1231. pwd->pwfx = pwfxNew;
  1232. pwd->cbdata = cbNew;
  1233. pwd->pbdata = pbNew;
  1234. pwd->fChanged = TRUE;
  1235. if (pwd->lpv)
  1236. {
  1237. PSGLOBALS psg = (PSGLOBALS)pwd->lpv;
  1238. *psg->ppwfx = pwfxNew;
  1239. *psg->pcbwfx = sizeof(WAVEFORMATEX);
  1240. if (pwfxNew->wFormatTag != WAVE_FORMAT_PCM)
  1241. *psg->pcbwfx += pwfxNew->cbSize;
  1242. *psg->pcbdata = cbNew;
  1243. *psg->ppbdata = pwd->pbdata;
  1244. *psg->plSamples = wfBytesToSamples(pwfxNew, cbNew);
  1245. *psg->plSamplesValid = *psg->plSamples;
  1246. *psg->plWavePosition = 0;
  1247. UpdateDisplay(TRUE);
  1248. Properties_InitDocVars(hwnd, pwd);
  1249. }
  1250. EndWaveEdit(TRUE);
  1251. }
  1252. else
  1253. EndWaveEdit(FALSE);
  1254. }
  1255. return TRUE;
  1256. }
  1257. }
  1258. return FALSE;
  1259. }
  1260. /*
  1261. * Properties_Proc
  1262. */
  1263. INT_PTR CALLBACK
  1264. Properties_Proc(
  1265. HWND hdlg,
  1266. UINT umsg,
  1267. WPARAM wparam,
  1268. LPARAM lparam)
  1269. {
  1270. #ifdef CHICAGO
  1271. static const DWORD aHelpIds[] = {
  1272. IDC_DISPICON, IDH_SOUNDREC_ICON,
  1273. IDC_FILENAME, IDH_SOUNDREC_SNDTITLE,
  1274. IDC_TXT_COPYRIGHT, IDH_SOUNDREC_COPYRIGHT,
  1275. IDC_COPYRIGHT, IDH_SOUNDREC_COPYRIGHT,
  1276. IDC_TXT_FILELEN, IDH_SOUNDREC_LENGTH,
  1277. IDC_FILELEN, IDH_SOUNDREC_LENGTH,
  1278. IDC_TXT_DATASIZE, IDH_SOUNDREC_SIZE,
  1279. IDC_DATASIZE, IDH_SOUNDREC_SIZE,
  1280. IDC_TXT_AUDIOFORMAT, IDH_SOUNDREC_AUDIO,
  1281. IDC_AUDIOFORMAT, IDH_SOUNDREC_AUDIO,
  1282. IDC_CONVGROUP, IDH_SOUNDREC_COMM_GROUPBOX,
  1283. IDC_CONVERTCHOOSEFROM, IDH_SOUNDREC_CONVERT,
  1284. IDC_CONVERTTO, IDH_SOUNDREC_FORMAT,
  1285. 0, 0
  1286. };
  1287. #endif
  1288. switch (umsg)
  1289. {
  1290. #ifdef CHICAGO
  1291. case WM_CONTEXTMENU:
  1292. WinHelp((HWND)wparam, gachHelpFile, HELP_CONTEXTMENU,
  1293. (UINT_PTR)(LPSTR)aHelpIds);
  1294. return TRUE;
  1295. case WM_HELP:
  1296. {
  1297. LPHELPINFO lphi = (LPVOID) lparam;
  1298. WinHelp (lphi->hItemHandle, gachHelpFile, HELP_WM_HELP,
  1299. (UINT_PTR) (LPSTR) aHelpIds);
  1300. return TRUE;
  1301. }
  1302. #endif
  1303. case WM_INITDIALOG:
  1304. return HANDLE_WM_INITDIALOG(hdlg, wparam, lparam, Properties_OnInitDialog);
  1305. case WM_DESTROY:
  1306. HANDLE_WM_DESTROY(hdlg, wparam, lparam, Properties_OnDestroy);
  1307. break;
  1308. case WM_NOTIFY:
  1309. {
  1310. NMHDR *lpnm = (NMHDR FAR *)lparam;
  1311. switch(lpnm->code)
  1312. {
  1313. case PSN_KILLACTIVE:
  1314. FORWARD_WM_COMMAND(hdlg, IDOK, 0, 0, SendMessage);
  1315. break;
  1316. case PSN_APPLY:
  1317. FORWARD_WM_COMMAND(hdlg, ID_APPLY, 0, 0, SendMessage);
  1318. break;
  1319. case PSN_SETACTIVE:
  1320. FORWARD_WM_COMMAND(hdlg, ID_INIT, 0, 0, SendMessage);
  1321. break;
  1322. case PSN_RESET:
  1323. FORWARD_WM_COMMAND(hdlg, IDCANCEL, 0, 0, SendMessage);
  1324. break;
  1325. }
  1326. break;
  1327. }
  1328. case WM_COMMAND:
  1329. return HANDLE_WM_COMMAND(hdlg, wparam, lparam, Properties_OnCommand);
  1330. default:
  1331. {
  1332. #ifdef CHICAGO
  1333. extern DWORD aChooserHelpIds[];
  1334. extern UINT guChooserContextMenu;
  1335. extern UINT guChooserContextHelp;
  1336. //
  1337. // Handle context-sensitive help messages from acm dialog
  1338. //
  1339. if( umsg == guChooserContextMenu )
  1340. {
  1341. WinHelp( (HWND)wparam, NULL, HELP_CONTEXTMENU,
  1342. (UINT_PTR)(LPSTR)aChooserHelpIds );
  1343. }
  1344. else if( umsg == guChooserContextHelp )
  1345. {
  1346. WinHelp( ((LPHELPINFO)lparam)->hItemHandle, NULL,
  1347. HELP_WM_HELP, (UINT_PTR)(LPSTR)aChooserHelpIds );
  1348. }
  1349. #endif
  1350. break;
  1351. }
  1352. }
  1353. return FALSE;
  1354. }
  1355. /*
  1356. * Wave document property sheet.
  1357. * */
  1358. BOOL
  1359. SoundRec_Properties(
  1360. HWND hwnd,
  1361. HINSTANCE hinst,
  1362. PWAVEDOC pwd)
  1363. {
  1364. PROPSHEETPAGE psp;
  1365. PROPSHEETHEADER psh;
  1366. TCHAR szCaption[256], szCapFmt[64];
  1367. psp.dwSize = sizeof(PROPSHEETPAGE);
  1368. psp.dwFlags = PSP_DEFAULT;// | PSP_USETITLE;
  1369. psp.hInstance = hinst;
  1370. psp.pszTemplate = MAKEINTRESOURCE(IDD_PROPERTIES);
  1371. psp.pszIcon = NULL;
  1372. psp.pszTitle = NULL;
  1373. psp.pfnDlgProc = Properties_Proc;
  1374. psp.lParam = (LPARAM)(LPVOID)pwd;
  1375. psp.pfnCallback = NULL;
  1376. psp.pcRefParent = NULL;
  1377. psh.dwSize = sizeof(PROPSHEETHEADER);
  1378. psh.dwFlags = PSH_NOAPPLYNOW|PSH_PROPSHEETPAGE ;
  1379. psh.hwndParent = hwnd;
  1380. psh.hInstance = hinst;
  1381. psh.pszIcon = NULL;
  1382. if (LoadString(hinst, IDS_PROPERTIES, szCapFmt, SIZEOF(szCapFmt)))
  1383. {
  1384. wsprintf(szCaption, szCapFmt, pwd->pszFileName);
  1385. psh.pszCaption = szCaption;
  1386. }
  1387. else
  1388. psh.pszCaption = NULL;
  1389. psh.nPages = 1;
  1390. psh.nStartPage = 0;
  1391. psh.ppsp = &psp;
  1392. psh.pfnCallback = NULL;
  1393. PropertySheet(&psh);
  1394. return FALSE; // nothing changed?
  1395. }