|
|
1.1 ! root 1: /* lowpass.c - WinMain() and dialog procedures for LOWPASS, along with ! 2: * initialization and support code. ! 3: * ! 4: * LOWPASS is a sample application illustrating how to use the multimedia ! 5: * file I/O services to read and write RIFF files. ! 6: * ! 7: * LOWPASS runs a simple low-pass filter over an 8-bit-per-sample ! 8: * mono WAVE file. Note that this program does not copy unknown chunks ! 9: * to the output file. ! 10: * ! 11: * ! 12: * (C) Copyright Microsoft Corp. 1991. All rights reserved. ! 13: * ! 14: * You have a royalty-free right to use, modify, reproduce and ! 15: * distribute the Sample Files (and/or any modified version) in ! 16: * any way you find useful, provided that you agree that ! 17: * Microsoft has no warranty obligations or liability for any ! 18: * Sample Application Files which are modified. ! 19: */ ! 20: ! 21: #include <windows.h> ! 22: #include <mmsystem.h> ! 23: #include "lowpass.h" ! 24: ! 25: ! 26: /* Globals ! 27: */ ! 28: char gszAppName[] = "LowPass"; // for title bar, etc. ! 29: HANDLE ghInst; // app's instance handle ! 30: ! 31: ! 32: /* DoLowPass - Gets the name of the input and output WAVE files from ! 33: * the dialog box; reads waveform data from the input file, performs ! 34: * a simple low-pass filter by averaging adjacent samples, and writes ! 35: * the filtered waveform data to the output WAVE file. ! 36: * ! 37: * Params: hWnd - Window handle for our dialog box. ! 38: * ! 39: * Returns: ! 40: */ ! 41: void DoLowPass(HWND hWnd) ! 42: { ! 43: char achInFile[200]; // name of input file ! 44: char achOutFile[200]; // name of output file ! 45: HMMIO hmmioIn = NULL; // handle to open input WAVE file ! 46: HMMIO hmmioOut = NULL; // handle to open output WAVE file ! 47: MMCKINFO ckInRIFF; // chunk info. for input RIFF chunk ! 48: MMCKINFO ckOutRIFF; // chunk info. for output RIFF chunk ! 49: MMCKINFO ckIn; // info. for a chunk in input file ! 50: MMCKINFO ckOut; // info. for a chunk in output file ! 51: PCMWAVEFORMAT pcmWaveFormat; // contents of 'fmt' chunks ! 52: MMIOINFO mmioinfoIn; // current status of <hmmioIn> ! 53: MMIOINFO mmioinfoOut; // current status of <hmmioOut> ! 54: long lSamples; // number of samples to filter ! 55: BYTE abSamples[3]; // this, last, and before-last sample ! 56: ! 57: /* Read filenames from dialog box fields. ! 58: */ ! 59: achInFile[0] == 0; ! 60: GetDlgItemText(hWnd, ID_INPUTFILEEDIT, achInFile, sizeof(achInFile)); ! 61: achOutFile[0] == 0; ! 62: GetDlgItemText(hWnd, ID_OUTPUTFILEEDIT, achOutFile, sizeof(achOutFile)); ! 63: ! 64: /* Open the input file for reading using buffered I/O. ! 65: */ ! 66: hmmioIn = mmioOpen(achInFile, NULL, MMIO_ALLOCBUF | MMIO_READ); ! 67: if (hmmioIn == NULL) ! 68: goto ERROR_CANNOT_READ; // cannot open WAVE file ! 69: ! 70: /* Open the output file for writing using buffered I/O. Note that ! 71: * if the file exists, the MMIO_CREATE flag causes it to be truncated ! 72: * to zero length. ! 73: */ ! 74: hmmioOut = mmioOpen(achOutFile, NULL, ! 75: MMIO_ALLOCBUF | MMIO_WRITE | MMIO_CREATE); ! 76: if (hmmioOut == NULL) ! 77: goto ERROR_CANNOT_WRITE; // cannot open WAVE file ! 78: ! 79: /* Descend the input file into the 'RIFF' chunk. ! 80: */ ! 81: if (mmioDescend(hmmioIn, &ckInRIFF, NULL, 0) != 0) ! 82: goto ERROR_CANNOT_READ; // end-of-file, probably ! 83: ! 84: /* Make sure the input file is a WAVE file. ! 85: */ ! 86: if ((ckInRIFF.ckid != FOURCC_RIFF) || ! 87: (ckInRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) ! 88: goto ERROR_FORMAT_BAD; ! 89: ! 90: /* Search the input file for for the 'fmt ' chunk. ! 91: */ ! 92: ckIn.ckid = mmioFOURCC('f', 'm', 't', ' '); ! 93: if (mmioDescend(hmmioIn, &ckIn, &ckInRIFF, MMIO_FINDCHUNK) != 0) ! 94: goto ERROR_FORMAT_BAD; // no 'fmt ' chunk ! 95: ! 96: /* Expect the 'fmt' chunk to be at least as large as <pcmWaveFormat>; ! 97: * if there are extra parameters at the end, we'll ignore them ! 98: */ ! 99: if (ckIn.cksize < (long) sizeof(pcmWaveFormat)) ! 100: goto ERROR_FORMAT_BAD; // 'fmt ' chunk too small ! 101: ! 102: /* Read the 'fmt ' chunk into <pcmWaveFormat>. ! 103: */ ! 104: if (mmioRead(hmmioIn, (HPSTR) &pcmWaveFormat, ! 105: (long) sizeof(pcmWaveFormat)) != (long) sizeof(pcmWaveFormat)) ! 106: goto ERROR_CANNOT_READ; // truncated file, probably ! 107: ! 108: /* Ascend the input file out of the 'fmt ' chunk. ! 109: */ ! 110: if (mmioAscend(hmmioIn, &ckIn, 0) != 0) ! 111: goto ERROR_CANNOT_READ; // truncated file, probably ! 112: ! 113: /* Make sure the input file is an 8-bit mono PCM WAVE file. ! 114: */ ! 115: if ((pcmWaveFormat.wf.wFormatTag != WAVE_FORMAT_PCM) || ! 116: (pcmWaveFormat.wf.nChannels != 1) || ! 117: (pcmWaveFormat.wBitsPerSample != 8)) ! 118: goto ERROR_FORMAT_BAD; // bad input file format ! 119: ! 120: /* Search the input file for for the 'data' chunk. ! 121: */ ! 122: ckIn.ckid = mmioFOURCC('d', 'a', 't', 'a'); ! 123: if (mmioDescend(hmmioIn, &ckIn, &ckInRIFF, MMIO_FINDCHUNK) != 0) ! 124: goto ERROR_FORMAT_BAD; // no 'data' chunk ! 125: ! 126: /* Create the output file RIFF chunk of form type 'WAVE'. ! 127: */ ! 128: ckOutRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E'); ! 129: if (mmioCreateChunk(hmmioOut, &ckOutRIFF, MMIO_CREATERIFF) != 0) ! 130: goto ERROR_CANNOT_WRITE; // cannot write file, probably ! 131: ! 132: /* We are now descended into the 'RIFF' chunk we just created. ! 133: * Now create the 'fmt ' chunk. Since we know the size of this chunk, ! 134: * specify it in the MMCKINFO structure so MMIO doesn't have to seek ! 135: * back and set the chunk size after ascending from the chunk. ! 136: */ ! 137: ckOut.ckid = mmioFOURCC('f', 'm', 't', ' '); ! 138: ckOut.cksize = sizeof(pcmWaveFormat); // we know the size of this ck. ! 139: if (mmioCreateChunk(hmmioOut, &ckOut, 0) != 0) ! 140: goto ERROR_CANNOT_WRITE; // cannot write file, probably ! 141: ! 142: /* Write the PCMWAVEFORMAT structure to the 'fmt ' chunk. ! 143: */ ! 144: if (mmioWrite(hmmioOut, (HPSTR) &pcmWaveFormat, sizeof(pcmWaveFormat)) ! 145: != sizeof(pcmWaveFormat)) ! 146: goto ERROR_CANNOT_WRITE; // cannot write file, probably ! 147: ! 148: /* Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk. ! 149: */ ! 150: if (mmioAscend(hmmioOut, &ckOut, 0) != 0) ! 151: goto ERROR_CANNOT_WRITE; // cannot write file, probably ! 152: ! 153: /* Create the 'data' chunk that holds the waveform samples. ! 154: */ ! 155: ckOut.ckid = mmioFOURCC('d', 'a', 't', 'a'); ! 156: if (mmioCreateChunk(hmmioOut, &ckOut, 0) != 0) ! 157: goto ERROR_CANNOT_WRITE; // cannot write file, probably ! 158: ! 159: /* Read samples from the 'data' chunk of the input file, and write ! 160: * samples to the 'data' chunk of the output file. Each sample in ! 161: * the output file equals the average of the corresponding sample ! 162: * in the input file and the previous two samples from the input file. ! 163: * Access the I/O buffers of <hmmioIn> and <hmmioOut> directly, ! 164: * since this is faster than calling mmioRead() and mmioWrite() ! 165: * for each sample. ! 166: */ ! 167: abSamples[0] = abSamples[1] = abSamples[2] = 128; ! 168: ! 169: /* Begin direct access of the I/O buffers. ! 170: */ ! 171: if (mmioGetInfo(hmmioIn, &mmioinfoIn, 0) != 0) ! 172: goto ERROR_UNKNOWN; ! 173: if (mmioGetInfo(hmmioOut, &mmioinfoOut, 0) != 0) ! 174: goto ERROR_UNKNOWN; ! 175: ! 176: /* For each input sample, compute and write the output sample. ! 177: */ ! 178: for (lSamples = ckIn.cksize; lSamples > 0; lSamples--) ! 179: { ! 180: /* If we are at the end of the input file I/O buffer, fill it. ! 181: * Test to see that we don't hit end of file while (lSamples > 0). ! 182: */ ! 183: if (mmioinfoIn.pchNext == mmioinfoIn.pchEndRead) ! 184: { ! 185: if (mmioAdvance(hmmioIn, &mmioinfoIn, MMIO_READ) != 0) ! 186: goto ERROR_CANNOT_READ; ! 187: ! 188: if (mmioinfoIn.pchNext == mmioinfoIn.pchEndRead) ! 189: goto ERROR_CANNOT_READ; ! 190: } ! 191: ! 192: /* If we are the end of the output file I/O buffer, flush it. ! 193: */ ! 194: if (mmioinfoOut.pchNext == mmioinfoOut.pchEndWrite) ! 195: { ! 196: mmioinfoOut.dwFlags |= MMIO_DIRTY; ! 197: if (mmioAdvance(hmmioOut, &mmioinfoOut, MMIO_WRITE) != 0) ! 198: goto ERROR_CANNOT_WRITE; ! 199: } ! 200: ! 201: /* Keep track of the last 3 samples so we can average. ! 202: */ ! 203: abSamples[2] = abSamples[1]; // next-to-last sample ! 204: abSamples[1] = abSamples[0]; // last sample ! 205: abSamples[0] = *(mmioinfoIn.pchNext)++; // current sample ! 206: ! 207: /* The output file sample is the average of the last ! 208: * 3 input file samples. ! 209: */ ! 210: *(mmioinfoOut.pchNext)++ = (BYTE) (((int) abSamples[0] ! 211: + (int) abSamples[1] + (int) abSamples[2]) / 3); ! 212: } ! 213: ! 214: /* We are through processing samples, end direct access of ! 215: * the I/O buffers. Set the MMIO_DIRTY flag for the output buffer ! 216: * to flush it. ! 217: */ ! 218: if (mmioSetInfo(hmmioIn, &mmioinfoIn, 0) != 0) ! 219: goto ERROR_UNKNOWN; ! 220: mmioinfoOut.dwFlags |= MMIO_DIRTY; ! 221: if (mmioSetInfo(hmmioOut, &mmioinfoOut, 0) != 0) ! 222: goto ERROR_CANNOT_WRITE; // cannot flush, probably ! 223: ! 224: /* Ascend the output file out of the 'data' chunk -- this will cause ! 225: * the chunk size of the 'data' chunk to be written. ! 226: */ ! 227: if (mmioAscend(hmmioOut, &ckOut, 0) != 0) ! 228: goto ERROR_CANNOT_WRITE; // cannot write file, probably ! 229: ! 230: /* Ascend the output file out of the 'RIFF' chunk -- this will cause ! 231: * the chunk size of the 'RIFF' chunk to be written. ! 232: */ ! 233: if (mmioAscend(hmmioOut, &ckOutRIFF, 0) != 0) ! 234: goto ERROR_CANNOT_WRITE; // cannot write file, probably ! 235: ! 236: /* We are done -- files are closed below. ! 237: */ ! 238: goto EXIT_FUNCTION; ! 239: ! 240: ERROR_FORMAT_BAD: ! 241: ! 242: MessageBox(NULL, "Input file must be an 8-bit mono PCM WAVE file", ! 243: gszAppName, MB_ICONEXCLAMATION | MB_OK); ! 244: goto EXIT_FUNCTION; ! 245: ! 246: ERROR_CANNOT_READ: ! 247: ! 248: MessageBox(NULL, "Cannot read input WAVE file", ! 249: gszAppName, MB_ICONEXCLAMATION | MB_OK); ! 250: goto EXIT_FUNCTION; ! 251: ! 252: ERROR_CANNOT_WRITE: ! 253: ! 254: MessageBox(NULL, "Cannot write output WAVE file", ! 255: gszAppName, MB_ICONEXCLAMATION | MB_OK); ! 256: goto EXIT_FUNCTION; ! 257: ! 258: ERROR_UNKNOWN: ! 259: ! 260: MessageBox(NULL, "Unknown error", ! 261: gszAppName, MB_ICONEXCLAMATION | MB_OK); ! 262: goto EXIT_FUNCTION; ! 263: ! 264: EXIT_FUNCTION: ! 265: ! 266: /* Close the files (unless they weren't opened successfully). ! 267: */ ! 268: if (hmmioIn != NULL) ! 269: mmioClose(hmmioIn, 0); ! 270: if (hmmioOut != NULL) ! 271: mmioClose(hmmioOut, 0); ! 272: } ! 273: ! 274: ! 275: /* WinMain - Entry point for LowPass. ! 276: */ ! 277: int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszCmdLine, int iCmdShow) ! 278: { ! 279: FARPROC fpfn; ! 280: ! 281: /* Save instance handle for dialog boxes. ! 282: */ ! 283: ghInst = hInst; ! 284: ! 285: /* Display our dialog box. ! 286: */ ! 287: fpfn = MakeProcInstance((FARPROC) LowPassDlgProc, ghInst); ! 288: DialogBox(ghInst, "LOWPASSBOX", NULL, (DLGPROC)fpfn); ! 289: FreeProcInstance(fpfn); ! 290: ! 291: return TRUE; ! 292: } ! 293: ! 294: ! 295: /* AboutDlgProc - Dialog procedure function for ABOUTBOX dialog box. ! 296: */ ! 297: BOOL FAR PASCAL ! 298: AboutDlgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) ! 299: { ! 300: switch (wMsg) ! 301: { ! 302: case WM_INITDIALOG: ! 303: return TRUE; ! 304: ! 305: case WM_COMMAND: ! 306: if (LOWORD(wParam) == IDOK) ! 307: EndDialog(hWnd, TRUE); ! 308: break; ! 309: } ! 310: return FALSE; ! 311: } ! 312: ! 313: ! 314: /* LowPassDlgProc - Dialog procedure function for LOWPASSBOX dialog box. ! 315: */ ! 316: BOOL FAR PASCAL ! 317: LowPassDlgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) ! 318: { ! 319: FARPROC fpfn; ! 320: HMENU hmenuSystem; // system menu ! 321: HCURSOR ghcurSave; // previous cursor ! 322: ! 323: switch (wMsg) ! 324: { ! 325: case WM_INITDIALOG: ! 326: /* Append "About" menu item to system menu. ! 327: */ ! 328: hmenuSystem = GetSystemMenu(hWnd, FALSE); ! 329: AppendMenu(hmenuSystem, MF_SEPARATOR, 0, NULL); ! 330: AppendMenu(hmenuSystem, MF_STRING, IDM_ABOUT, ! 331: "&About LowPass..."); ! 332: return TRUE; ! 333: ! 334: case WM_SYSCOMMAND: ! 335: switch (wParam) ! 336: { ! 337: case IDM_ABOUT: ! 338: /* Display "About" dialog box. ! 339: */ ! 340: fpfn = MakeProcInstance((FARPROC) AboutDlgProc, ghInst); ! 341: DialogBox(ghInst, "ABOUTBOX", hWnd, (DLGPROC)fpfn); ! 342: FreeProcInstance(fpfn); ! 343: break; ! 344: } ! 345: break; ! 346: ! 347: case WM_COMMAND: ! 348: switch (LOWORD(wParam)) ! 349: { ! 350: case IDOK: // "Begin" ! 351: /* Set "busy" cursor, filter input file, restore cursor. ! 352: */ ! 353: ghcurSave = SetCursor(LoadCursor(NULL, IDC_WAIT)); ! 354: DoLowPass(hWnd); ! 355: SetCursor(ghcurSave); ! 356: break; ! 357: ! 358: case IDCANCEL: // "Done" ! 359: EndDialog(hWnd, TRUE); ! 360: break; ! 361: } ! 362: break; ! 363: } ! 364: return FALSE; ! 365: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.