Annotation of q_a/samples/lowpass/lowpass.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.