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