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

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