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.

596 lines
18 KiB

  1. /* reverse.c - WinMain() and WndProc() for REVERSE, along with
  2. * initialization and support code.
  3. *
  4. * REVERSE is a Windows with Multimedia sample application that
  5. * illustrates how to use the low-level waveform playback services.
  6. * It also shows how to use the multimedia file I/O services to read
  7. * data from a WAVE file.
  8. *
  9. * REVERSE plays a WAVE waveform audio file backwards.
  10. *
  11. * (C) Copyright Microsoft Corp. 1991, 1992. All rights reserved.
  12. *
  13. * You have a royalty-free right to use, modify, reproduce and
  14. * distribute the Sample Files (and/or any modified version) in
  15. * any way you find useful, provided that you agree that
  16. * Microsoft has no warranty obligations or liability for any
  17. * Sample Application Files which are modified.
  18. *
  19. */
  20. #include <windows.h>
  21. #include <mmsystem.h>
  22. #include "reverse.h"
  23. #define MAX_FILENAME_SIZE 128
  24. /* Global variables.
  25. */
  26. char szAppName[] = "Reverse"; // application name
  27. HANDLE hInstApp = NULL; // instance handle
  28. HWND hwndApp = NULL; // main window handle
  29. HWND hwndName = NULL; // filename window handle
  30. HWND hwndPlay = NULL; // "Play" button window handle
  31. HWND hwndQuit = NULL; // "Exit" button window handle
  32. HWAVEOUT hWaveOut = NULL;
  33. LPWAVEHDR lpWaveHdr = NULL;
  34. VOID cleanup(LPWAVEINST lpWaveInst);
  35. /* WinMain - Entry point for Reverse.
  36. */
  37. int PASCAL WinMain(HANDLE hInst, HANDLE hPrev, LPSTR szCmdLine, int cmdShow)
  38. {
  39. MSG msg;
  40. WNDCLASS wc;
  41. hInstApp = hInst;
  42. /* Define and register a window class for the main window.
  43. */
  44. if (!hPrev)
  45. {
  46. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  47. wc.hIcon = LoadIcon(hInst, szAppName);
  48. wc.lpszMenuName = szAppName;
  49. wc.lpszClassName = szAppName;
  50. wc.hbrBackground = GetStockObject(LTGRAY_BRUSH);
  51. wc.hInstance = hInst;
  52. wc.style = 0;
  53. wc.lpfnWndProc = WndProc;
  54. wc.cbWndExtra = 0;
  55. wc.cbClsExtra = 0;
  56. if (!RegisterClass(&wc))
  57. return FALSE;
  58. }
  59. /* Create and show the main window.
  60. */
  61. hwndApp = CreateWindow (szAppName, // class name
  62. szAppName, // caption
  63. WS_OVERLAPPEDWINDOW, // style bits
  64. CW_USEDEFAULT, // x position
  65. CW_USEDEFAULT, // y position
  66. WMAIN_DX, // x size
  67. WMAIN_DY, // y size
  68. (HWND)NULL, // parent window
  69. (HMENU)NULL, // use class menu
  70. (HANDLE)hInst, // instance handle
  71. (LPSTR)NULL // no params to pass on
  72. );
  73. /* Create child windows for the "Play" and "Exit" buttons
  74. * and for an edit field to enter filenames.
  75. */
  76. hwndPlay = CreateWindow( "BUTTON", "Play",
  77. WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
  78. PLAY_X, PLAY_Y,
  79. PLAY_DX, PLAY_DY,
  80. hwndApp, (HMENU)IDB_PLAY, hInstApp, NULL );
  81. if( !hwndPlay )
  82. return( FALSE );
  83. hwndQuit = CreateWindow( "BUTTON", "Exit",
  84. WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
  85. QUIT_X, QUIT_Y,
  86. QUIT_DX, QUIT_DY,
  87. hwndApp, (HMENU)IDB_QUIT, hInstApp, NULL );
  88. if( !hwndQuit )
  89. return( FALSE );
  90. hwndName = CreateWindow("EDIT","",
  91. WS_CHILD|WS_VISIBLE|WS_BORDER|ES_AUTOHSCROLL,
  92. NAME_X, NAME_Y,
  93. NAME_DX, NAME_DY,
  94. hwndApp, (HMENU)IDE_NAME, hInstApp, NULL);
  95. if( !hwndName )
  96. return( FALSE );
  97. SendMessage(hwndName, EM_LIMITTEXT, MAX_FILENAME_SIZE - 1, 0);
  98. ShowWindow(hwndApp,cmdShow);
  99. /* Add about dialog to system menu.
  100. */
  101. AppendMenu(GetSystemMenu(hwndApp, 0),
  102. MF_STRING | MF_ENABLED, IDM_ABOUT, "About Reverse...");
  103. /* The main message processing loop. Nothing special here.
  104. */
  105. while (GetMessage(&msg,NULL,0,0))
  106. {
  107. TranslateMessage(&msg);
  108. DispatchMessage(&msg);
  109. }
  110. return msg.wParam;
  111. }
  112. /* WndProc - Main window procedure function.
  113. */
  114. LONG FAR PASCAL WndProc(HWND hWnd, unsigned msg, UINT wParam, LONG lParam)
  115. {
  116. FARPROC fpfn;
  117. LPWAVEINST lpWaveInst;
  118. switch (msg)
  119. {
  120. case WM_DESTROY:
  121. if (hWaveOut)
  122. {
  123. waveOutReset(hWaveOut);
  124. waveOutUnprepareHeader(hWaveOut, lpWaveHdr, sizeof(WAVEHDR) );
  125. lpWaveInst = (LPWAVEINST) lpWaveHdr->dwUser;
  126. cleanup(lpWaveInst);
  127. waveOutClose(hWaveOut);
  128. }
  129. PostQuitMessage(0);
  130. break;
  131. case WM_SYSCOMMAND:
  132. switch (LOWORD(wParam))
  133. {
  134. case IDM_ABOUT:
  135. /* Show ABOUTBOX dialog box.
  136. */
  137. fpfn = MakeProcInstance((FARPROC)AppAbout, hInstApp); // no op in 32 bit
  138. DialogBox(hInstApp, "ABOUTBOX", hWnd, (DLGPROC)fpfn);
  139. FreeProcInstance(fpfn);
  140. break;
  141. }
  142. break;
  143. /* Process messages sent by the child window controls.
  144. */
  145. case WM_SETFOCUS:
  146. SetFocus(hwndName);
  147. return 0;
  148. case WM_COMMAND:
  149. switch (LOWORD(wParam))
  150. {
  151. case IDE_NAME: // filename edit control
  152. return( 0L );
  153. case IDB_PLAY: // "Play" button
  154. if (HIWORD(wParam) == BN_CLICKED)
  155. ReversePlay();
  156. break;
  157. case IDB_QUIT: // "Exit" button
  158. if (HIWORD(wParam) == BN_CLICKED)
  159. PostQuitMessage(0);
  160. break;
  161. }
  162. return( 0L );
  163. case MM_WOM_DONE:
  164. /* This message indicates a waveform data block has
  165. * been played and can be freed. Clean up the preparation
  166. * done previously on the header.
  167. */
  168. waveOutUnprepareHeader( (HWAVEOUT) wParam,
  169. (LPWAVEHDR) lParam, sizeof(WAVEHDR) );
  170. /* Get a pointer to the instance data, then unlock and free
  171. * all memory associated with the data block, including the
  172. * memory for the instance data itself.
  173. */
  174. lpWaveInst = (LPWAVEINST) ((LPWAVEHDR)lParam)->dwUser;
  175. cleanup(lpWaveInst);
  176. /* Close the waveform output device.
  177. */
  178. waveOutClose( (HWAVEOUT) wParam );
  179. /* Reenable both button controls.
  180. */
  181. EnableWindow( hwndPlay, TRUE );
  182. EnableWindow( hwndQuit, TRUE );
  183. SetFocus(hwndName);
  184. break;
  185. }
  186. return DefWindowProc(hWnd,msg,wParam,lParam);
  187. }
  188. /* AppAbout -- Dialog procedure for ABOUTBOX dialog box.
  189. */
  190. BOOL FAR PASCAL AppAbout(HWND hDlg, unsigned msg, unsigned wParam, LONG lParam)
  191. {
  192. switch (msg)
  193. {
  194. case WM_COMMAND:
  195. if (LOWORD(wParam) == IDOK)
  196. EndDialog(hDlg,TRUE);
  197. break;
  198. case WM_INITDIALOG:
  199. return TRUE;
  200. }
  201. return FALSE;
  202. }
  203. /* ReversePlay - Gets a filename from the edit control, then uses
  204. * the multimedia file I/O services to read data from the requested
  205. * WAVE file. If the file is a proper WAVE file, ReversePlay() calls
  206. * the Interchange() function to reverse the order of the waveform
  207. * samples in the file. It then plays the reversed waveform data.
  208. *
  209. * Note that ReversePlay() only handles a single waveform data block.
  210. * If the requested WAVE file will not fit in a single data block, it
  211. * will not be played. The size of a single data block depends on the
  212. * amount of available system memory.
  213. *
  214. * Params: void
  215. *
  216. * Return: void
  217. */
  218. void ReversePlay()
  219. {
  220. HANDLE hWaveHdr;
  221. LPWAVEINST lpWaveInst;
  222. HMMIO hmmio;
  223. MMCKINFO mmckinfoParent;
  224. MMCKINFO mmckinfoSubchunk;
  225. DWORD dwFmtSize;
  226. char szFileName[ MAX_FILENAME_SIZE ];
  227. HANDLE hFormat;
  228. WAVEFORMAT *pFormat;
  229. DWORD dwDataSize;
  230. HPSTR hpch1, hpch2;
  231. WORD wBlockSize;
  232. HANDLE hWaveInst;
  233. HANDLE hData = NULL;
  234. HPSTR lpData = NULL;
  235. /* Get the filename from the edit control.
  236. */
  237. if (!GetWindowText( hwndName, (LPSTR)szFileName, MAX_FILENAME_SIZE))
  238. {
  239. MessageBox(hwndApp, "Failed to Get Filename",
  240. NULL, MB_OK | MB_ICONEXCLAMATION);
  241. return;
  242. }
  243. /* Open the given file for reading using buffered I/O.
  244. */
  245. if(!(hmmio = mmioOpen(szFileName, NULL, MMIO_READ | MMIO_ALLOCBUF)))
  246. {
  247. MessageBox(hwndApp, "Failed to open file.",
  248. NULL, MB_OK | MB_ICONEXCLAMATION);
  249. return;
  250. }
  251. /* Locate a 'RIFF' chunk with a 'WAVE' form type
  252. * to make sure it's a WAVE file.
  253. */
  254. mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
  255. if (mmioDescend(hmmio, (LPMMCKINFO) &mmckinfoParent, NULL, MMIO_FINDRIFF))
  256. {
  257. MessageBox(hwndApp, "This is not a WAVE file.",
  258. NULL, MB_OK | MB_ICONEXCLAMATION);
  259. mmioClose(hmmio, 0);
  260. return;
  261. }
  262. /* Now, find the format chunk (form type 'fmt '). It should be
  263. * a subchunk of the 'RIFF' parent chunk.
  264. */
  265. mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
  266. if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,
  267. MMIO_FINDCHUNK))
  268. {
  269. MessageBox(hwndApp, "WAVE file is corrupted.",
  270. NULL, MB_OK | MB_ICONEXCLAMATION);
  271. mmioClose(hmmio, 0);
  272. return;
  273. }
  274. /* Get the size of the format chunk, allocate and lock memory for it.
  275. */
  276. dwFmtSize = mmckinfoSubchunk.cksize;
  277. hFormat = LocalAlloc(LMEM_MOVEABLE, LOWORD(dwFmtSize));
  278. if (!hFormat)
  279. {
  280. MessageBox(hwndApp, "Out of memory.",
  281. NULL, MB_OK | MB_ICONEXCLAMATION);
  282. mmioClose(hmmio, 0);
  283. return;
  284. }
  285. pFormat = (WAVEFORMAT *) LocalLock(hFormat);
  286. if (!pFormat)
  287. {
  288. MessageBox(hwndApp, "Failed to lock memory for format chunk.",
  289. NULL, MB_OK | MB_ICONEXCLAMATION);
  290. LocalFree( hFormat );
  291. mmioClose(hmmio, 0);
  292. return;
  293. }
  294. /* Read the format chunk.
  295. */
  296. if (mmioRead(hmmio, (HPSTR) pFormat, dwFmtSize) != (LONG) dwFmtSize)
  297. {
  298. MessageBox(hwndApp, "Failed to read format chunk.",
  299. NULL, MB_OK | MB_ICONEXCLAMATION);
  300. LocalUnlock( hFormat );
  301. LocalFree( hFormat );
  302. mmioClose(hmmio, 0);
  303. return;
  304. }
  305. /* Make sure it's a PCM file.
  306. */
  307. if (pFormat->wFormatTag != WAVE_FORMAT_PCM)
  308. {
  309. LocalUnlock( hFormat );
  310. LocalFree( hFormat );
  311. mmioClose(hmmio, 0);
  312. MessageBox(hwndApp, "The file is not a PCM file.",
  313. NULL, MB_OK | MB_ICONEXCLAMATION);
  314. return;
  315. }
  316. /* Make sure a waveform output device supports this format.
  317. */
  318. if (waveOutOpen(&hWaveOut, WAVE_MAPPER, (LPWAVEFORMAT)pFormat, 0L, 0L,
  319. WAVE_FORMAT_QUERY))
  320. {
  321. LocalUnlock( hFormat );
  322. LocalFree( hFormat );
  323. mmioClose(hmmio, 0);
  324. MessageBox(hwndApp, "The waveform device can't play this format.",
  325. NULL, MB_OK | MB_ICONEXCLAMATION);
  326. return;
  327. }
  328. /* Ascend out of the format subchunk.
  329. */
  330. mmioAscend(hmmio, &mmckinfoSubchunk, 0);
  331. /* Find the data subchunk.
  332. */
  333. mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
  334. if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,
  335. MMIO_FINDCHUNK))
  336. {
  337. MessageBox(hwndApp, "WAVE file has no data chunk.",
  338. NULL, MB_OK | MB_ICONEXCLAMATION);
  339. LocalUnlock( hFormat );
  340. LocalFree( hFormat );
  341. mmioClose(hmmio, 0);
  342. return;
  343. }
  344. /* Get the size of the data subchunk.
  345. */
  346. dwDataSize = mmckinfoSubchunk.cksize;
  347. if (dwDataSize == 0L)
  348. {
  349. MessageBox(hwndApp, "The data chunk has no data.",
  350. NULL, MB_OK | MB_ICONEXCLAMATION);
  351. LocalUnlock( hFormat );
  352. LocalFree( hFormat );
  353. mmioClose(hmmio, 0);
  354. return;
  355. }
  356. /* Open a waveform output device.
  357. */
  358. if (waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER,
  359. (LPWAVEFORMAT)pFormat, (UINT)hwndApp, 0L, CALLBACK_WINDOW))
  360. {
  361. MessageBox(hwndApp, "Failed to open waveform output device.",
  362. NULL, MB_OK | MB_ICONEXCLAMATION);
  363. LocalUnlock( hFormat );
  364. LocalFree( hFormat );
  365. mmioClose(hmmio, 0);
  366. return;
  367. }
  368. /* Save block alignment info for later use.
  369. */
  370. wBlockSize = pFormat->nBlockAlign;
  371. /* We're done with the format header, free it.
  372. */
  373. LocalUnlock( hFormat );
  374. LocalFree( hFormat );
  375. /* Allocate and lock memory for the waveform data.
  376. */
  377. hData = GlobalAlloc(GMEM_MOVEABLE , dwDataSize );
  378. /* GMEM_SHARE is not needed on 32 bits */
  379. if (!hData)
  380. {
  381. MessageBox(hwndApp, "Out of memory.",
  382. NULL, MB_OK | MB_ICONEXCLAMATION);
  383. mmioClose(hmmio, 0);
  384. return;
  385. }
  386. lpData = GlobalLock(hData);
  387. if (!lpData)
  388. {
  389. MessageBox(hwndApp, "Failed to lock memory for data chunk.",
  390. NULL, MB_OK | MB_ICONEXCLAMATION);
  391. GlobalFree( hData );
  392. mmioClose(hmmio, 0);
  393. return;
  394. }
  395. /* Read the waveform data subchunk.
  396. */
  397. if(mmioRead(hmmio, (HPSTR) lpData, dwDataSize) != (LONG) dwDataSize)
  398. {
  399. MessageBox(hwndApp, "Failed to read data chunk.",
  400. NULL, MB_OK | MB_ICONEXCLAMATION);
  401. GlobalUnlock( hData );
  402. GlobalFree( hData );
  403. mmioClose(hmmio, 0);
  404. return;
  405. }
  406. /* We're done with the file, close it.
  407. */
  408. mmioClose(hmmio, 0);
  409. /* Reverse the sound for playing.
  410. */
  411. hpch1 = lpData;
  412. hpch2 = lpData + dwDataSize - 1;
  413. while (hpch1 < hpch2)
  414. {
  415. Interchange( hpch1, hpch2, wBlockSize );
  416. hpch1 += wBlockSize;
  417. hpch2 -= wBlockSize;
  418. }
  419. /* Allocate a waveform data header. The WAVEHDR must be
  420. * globally allocated and locked.
  421. */
  422. hWaveHdr = GlobalAlloc(GMEM_MOVEABLE, (DWORD) sizeof(WAVEHDR));
  423. if (!hWaveHdr)
  424. {
  425. GlobalUnlock( hData );
  426. GlobalFree( hData );
  427. MessageBox(hwndApp, "Not enough memory for header.",
  428. NULL, MB_OK | MB_ICONEXCLAMATION);
  429. return;
  430. }
  431. lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr);
  432. if (!lpWaveHdr)
  433. {
  434. GlobalUnlock( hData );
  435. GlobalFree( hData );
  436. GlobalFree( hWaveHdr );
  437. MessageBox(hwndApp, "Failed to lock memory for header.",
  438. NULL, MB_OK | MB_ICONEXCLAMATION);
  439. return;
  440. }
  441. /* Allocate and set up instance data for waveform data block.
  442. * This information is needed by the routine that frees the
  443. * data block after it has been played.
  444. */
  445. hWaveInst = GlobalAlloc(GMEM_MOVEABLE, (DWORD) sizeof(WAVEHDR));
  446. if (!hWaveInst)
  447. {
  448. GlobalUnlock( hData );
  449. GlobalFree( hData );
  450. GlobalUnlock( hWaveHdr );
  451. GlobalFree( hWaveHdr );
  452. MessageBox(hwndApp, "Not enough memory for instance data.",
  453. NULL, MB_OK | MB_ICONEXCLAMATION);
  454. return;
  455. }
  456. lpWaveInst = (LPWAVEINST) GlobalLock(hWaveInst);
  457. if (!lpWaveInst)
  458. {
  459. GlobalUnlock( hData );
  460. GlobalFree( hData );
  461. GlobalUnlock( hWaveHdr );
  462. GlobalFree( hWaveHdr );
  463. GlobalFree( hWaveInst );
  464. MessageBox(hwndApp, "Failed to lock memory for instance data.",
  465. NULL, MB_OK | MB_ICONEXCLAMATION);
  466. return;
  467. }
  468. lpWaveInst->hWaveInst = hWaveInst;
  469. lpWaveInst->hWaveHdr = hWaveHdr;
  470. lpWaveInst->hWaveData = hData;
  471. /* Set up WAVEHDR structure and prepare it to be written to wave device.
  472. */
  473. lpWaveHdr->lpData = lpData;
  474. lpWaveHdr->dwBufferLength = dwDataSize;
  475. lpWaveHdr->dwFlags = 0L;
  476. lpWaveHdr->dwLoops = 0L;
  477. lpWaveHdr->dwUser = (DWORD) lpWaveInst;
  478. if(waveOutPrepareHeader(hWaveOut, lpWaveHdr, sizeof(WAVEHDR)))
  479. {
  480. GlobalUnlock( hData );
  481. GlobalFree( hData );
  482. GlobalUnlock( hWaveHdr );
  483. GlobalFree( hWaveHdr );
  484. GlobalUnlock( hWaveInst );
  485. GlobalFree( hWaveInst );
  486. MessageBox(hwndApp, "Unable to prepare wave header.",
  487. NULL, MB_OK | MB_ICONEXCLAMATION);
  488. return;
  489. }
  490. /* Then the data block can be sent to the output device.
  491. */
  492. { MMRESULT mmResult;
  493. mmResult = waveOutWrite(hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
  494. if (mmResult != 0)
  495. {
  496. waveOutUnprepareHeader( hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
  497. GlobalUnlock( hData );
  498. GlobalFree( hData );
  499. MessageBox(hwndApp, "Failed to write block to device",
  500. NULL, MB_OK | MB_ICONEXCLAMATION);
  501. return;
  502. }
  503. }
  504. /* Disable input to the button controls.
  505. */
  506. EnableWindow(hwndPlay, FALSE);
  507. EnableWindow(hwndQuit, FALSE);
  508. }
  509. /* Interchange - Interchanges two samples at the given positions.
  510. *
  511. * Params: hpchPos1 - Points to one sample.
  512. * hpchPos2 - Points to the other sample.
  513. * wLength - The length of a sample in bytes.
  514. *
  515. * Return: void
  516. */
  517. void Interchange(HPSTR hpchPos1, HPSTR hpchPos2, unsigned uLength)
  518. {
  519. unsigned uPlace;
  520. BYTE bTemp;
  521. for (uPlace = 0; uPlace < uLength; uPlace++)
  522. {
  523. bTemp = hpchPos1[uPlace];
  524. hpchPos1[uPlace] = hpchPos2[uPlace];
  525. hpchPos2[uPlace] = bTemp;
  526. }
  527. }
  528. VOID cleanup(LPWAVEINST lpWaveInst)
  529. {
  530. GlobalUnlock( lpWaveInst->hWaveData );
  531. GlobalFree( lpWaveInst->hWaveData );
  532. GlobalUnlock( lpWaveInst->hWaveHdr );
  533. GlobalFree( lpWaveInst->hWaveHdr );
  534. GlobalUnlock( lpWaveInst->hWaveInst );
  535. GlobalFree( lpWaveInst->hWaveInst );
  536. }