home *** CD-ROM | disk | FTP | other *** search
- /* lowpass.c - WinMain() and dialog procedures for LOWPASS, along with
- * initialization and support code.
- *
- * LOWPASS is a sample application illustrating how to use the multimedia
- * file I/O services to read and write RIFF files.
- *
- * LOWPASS runs a simple low-pass filter over an 8-bit-per-sample
- * mono WAVE file. Note that this program does not copy unknown chunks
- * to the output file.
- *
- *
- * (C) Copyright Microsoft Corp. 1991. All rights reserved.
- *
- * You have a royalty-free right to use, modify, reproduce and
- * distribute the Sample Files (and/or any modified version) in
- * any way you find useful, provided that you agree that
- * Microsoft has no warranty obligations or liability for any
- * Sample Application Files which are modified.
- */
-
- #include <windows.h>
- #include <mmsystem.h>
- #include "lowpass.h"
-
-
- /* Globals
- */
- char gszAppName[] = "LowPass"; // for title bar, etc.
- HANDLE ghInst; // app's instance handle
-
-
- /* DoLowPass - Gets the name of the input and output WAVE files from
- * the dialog box; reads waveform data from the input file, performs
- * a simple low-pass filter by averaging adjacent samples, and writes
- * the filtered waveform data to the output WAVE file.
- *
- * Params: hWnd - Window handle for our dialog box.
- *
- * Returns:
- */
- void DoLowPass(HWND hWnd)
- {
- char achInFile[200]; // name of input file
- char achOutFile[200]; // name of output file
- HMMIO hmmioIn = NULL; // handle to open input WAVE file
- HMMIO hmmioOut = NULL; // handle to open output WAVE file
- MMCKINFO ckInRIFF; // chunk info. for input RIFF chunk
- MMCKINFO ckOutRIFF; // chunk info. for output RIFF chunk
- MMCKINFO ckIn; // info. for a chunk in input file
- MMCKINFO ckOut; // info. for a chunk in output file
- PCMWAVEFORMAT pcmWaveFormat; // contents of 'fmt' chunks
- MMIOINFO mmioinfoIn; // current status of <hmmioIn>
- MMIOINFO mmioinfoOut; // current status of <hmmioOut>
- long lSamples; // number of samples to filter
- BYTE abSamples[3]; // this, last, and before-last sample
-
- /* Read filenames from dialog box fields.
- */
- achInFile[0] == 0;
- GetDlgItemText(hWnd, ID_INPUTFILEEDIT, achInFile, sizeof(achInFile));
- achOutFile[0] == 0;
- GetDlgItemText(hWnd, ID_OUTPUTFILEEDIT, achOutFile, sizeof(achOutFile));
-
- /* Open the input file for reading using buffered I/O.
- */
- hmmioIn = mmioOpen(achInFile, NULL, MMIO_ALLOCBUF | MMIO_READ);
- if (hmmioIn == NULL)
- goto ERROR_CANNOT_READ; // cannot open WAVE file
-
- /* Open the output file for writing using buffered I/O. Note that
- * if the file exists, the MMIO_CREATE flag causes it to be truncated
- * to zero length.
- */
- hmmioOut = mmioOpen(achOutFile, NULL,
- MMIO_ALLOCBUF | MMIO_WRITE | MMIO_CREATE);
- if (hmmioOut == NULL)
- goto ERROR_CANNOT_WRITE; // cannot open WAVE file
-
- /* Descend the input file into the 'RIFF' chunk.
- */
- if (mmioDescend(hmmioIn, &ckInRIFF, NULL, 0) != 0)
- goto ERROR_CANNOT_READ; // end-of-file, probably
-
- /* Make sure the input file is a WAVE file.
- */
- if ((ckInRIFF.ckid != FOURCC_RIFF) ||
- (ckInRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E')))
- goto ERROR_BAD_FORMAT;
-
- /* Search the input file for for the 'fmt ' chunk.
- */
- ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
- if (mmioDescend(hmmioIn, &ckIn, &ckInRIFF, MMIO_FINDCHUNK) != 0)
- goto ERROR_BAD_FORMAT; // no 'fmt ' chunk
-
- /* Expect the 'fmt' chunk to be at least as large as <pcmWaveFormat>;
- * if there are extra parameters at the end, we'll ignore them
- */
- if (ckIn.cksize < (long) sizeof(pcmWaveFormat))
- goto ERROR_BAD_FORMAT; // 'fmt ' chunk too small
-
- /* Read the 'fmt ' chunk into <pcmWaveFormat>.
- */
- if (mmioRead(hmmioIn, (HPSTR) &pcmWaveFormat,
- (long) sizeof(pcmWaveFormat)) != (long) sizeof(pcmWaveFormat))
- goto ERROR_CANNOT_READ; // truncated file, probably
-
- /* Ascend the input file out of the 'fmt ' chunk.
- */
- if (mmioAscend(hmmioIn, &ckIn, 0) != 0)
- goto ERROR_CANNOT_READ; // truncated file, probably
-
- /* Make sure the input file is an 8-bit mono PCM WAVE file.
- */
- if ((pcmWaveFormat.wf.wFormatTag != WAVE_FORMAT_PCM) ||
- (pcmWaveFormat.wf.nChannels != 1) ||
- (pcmWaveFormat.wBitsPerSample != 8))
- goto ERROR_BAD_FORMAT; // bad input file format
-
- /* Search the input file for for the 'data' chunk.
- */
- ckIn.ckid = mmioFOURCC('d', 'a', 't', 'a');
- if (mmioDescend(hmmioIn, &ckIn, &ckInRIFF, MMIO_FINDCHUNK) != 0)
- goto ERROR_BAD_FORMAT; // no 'data' chunk
-
- /* Create the output file RIFF chunk of form type 'WAVE'.
- */
- ckOutRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E');
- if (mmioCreateChunk(hmmioOut, &ckOutRIFF, MMIO_CREATERIFF) != 0)
- goto ERROR_CANNOT_WRITE; // cannot write file, probably
-
- /* We are now descended into the 'RIFF' chunk we just created.
- * Now create the 'fmt ' chunk. Since we know the size of this chunk,
- * specify it in the MMCKINFO structure so MMIO doesn't have to seek
- * back and set the chunk size after ascending from the chunk.
- */
- ckOut.ckid = mmioFOURCC('f', 'm', 't', ' ');
- ckOut.cksize = sizeof(pcmWaveFormat); // we know the size of this ck.
- if (mmioCreateChunk(hmmioOut, &ckOut, 0) != 0)
- goto ERROR_CANNOT_WRITE; // cannot write file, probably
-
- /* Write the PCMWAVEFORMAT structure to the 'fmt ' chunk.
- */
- if (mmioWrite(hmmioOut, (HPSTR) &pcmWaveFormat, sizeof(pcmWaveFormat))
- != sizeof(pcmWaveFormat))
- goto ERROR_CANNOT_WRITE; // cannot write file, probably
-
- /* Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
- */
- if (mmioAscend(hmmioOut, &ckOut, 0) != 0)
- goto ERROR_CANNOT_WRITE; // cannot write file, probably
-
- /* Create the 'data' chunk that holds the waveform samples.
- */
- ckOut.ckid = mmioFOURCC('d', 'a', 't', 'a');
- if (mmioCreateChunk(hmmioOut, &ckOut, 0) != 0)
- goto ERROR_CANNOT_WRITE; // cannot write file, probably
-
- /* Read samples from the 'data' chunk of the input file, and write
- * samples to the 'data' chunk of the output file. Each sample in
- * the output file equals the average of the corresponding sample
- * in the input file and the previous two samples from the input file.
- * Access the I/O buffers of <hmmioIn> and <hmmioOut> directly,
- * since this is faster than calling mmioRead() and mmioWrite()
- * for each sample.
- */
- abSamples[0] = abSamples[1] = abSamples[2] = 128;
-
- /* Begin direct access of the I/O buffers.
- */
- if (mmioGetInfo(hmmioIn, &mmioinfoIn, 0) != 0)
- goto ERROR_UNKNOWN;
- if (mmioGetInfo(hmmioOut, &mmioinfoOut, 0) != 0)
- goto ERROR_UNKNOWN;
-
- /* For each input sample, compute and write the output sample.
- */
- for (lSamples = ckIn.cksize; lSamples > 0; lSamples--)
- {
- /* If we are at the end of the input file I/O buffer, fill it.
- * Test to see that we don't hit end of file while (lSamples > 0).
- */
- if (mmioinfoIn.pchNext == mmioinfoIn.pchEndRead)
- {
- if (mmioAdvance(hmmioIn, &mmioinfoIn, MMIO_READ) != 0)
- goto ERROR_CANNOT_READ;
-
- if (mmioinfoIn.pchNext == mmioinfoIn.pchEndRead)
- goto ERROR_CANNOT_READ;
- }
-
- /* If we are the end of the output file I/O buffer, flush it.
- */
- if (mmioinfoOut.pchNext == mmioinfoOut.pchEndWrite)
- {
- mmioinfoOut.dwFlags |= MMIO_DIRTY;
- if (mmioAdvance(hmmioOut, &mmioinfoOut, MMIO_WRITE) != 0)
- goto ERROR_CANNOT_WRITE;
- }
-
- /* Keep track of the last 3 samples so we can average.
- */
- abSamples[2] = abSamples[1]; // next-to-last sample
- abSamples[1] = abSamples[0]; // last sample
- abSamples[0] = *(mmioinfoIn.pchNext)++; // current sample
-
- /* The output file sample is the average of the last
- * 3 input file samples.
- */
- *(mmioinfoOut.pchNext)++ = (BYTE) (((int) abSamples[0]
- + (int) abSamples[1] + (int) abSamples[2]) / 3);
- }
-
- /* We are through processing samples, end direct access of
- * the I/O buffers. Set the MMIO_DIRTY flag for the output buffer
- * to flush it.
- */
- if (mmioSetInfo(hmmioIn, &mmioinfoIn, 0) != 0)
- goto ERROR_UNKNOWN;
- mmioinfoOut.dwFlags |= MMIO_DIRTY;
- if (mmioSetInfo(hmmioOut, &mmioinfoOut, 0) != 0)
- goto ERROR_CANNOT_WRITE; // cannot flush, probably
-
- /* Ascend the output file out of the 'data' chunk -- this will cause
- * the chunk size of the 'data' chunk to be written.
- */
- if (mmioAscend(hmmioOut, &ckOut, 0) != 0)
- goto ERROR_CANNOT_WRITE; // cannot write file, probably
-
- /* Ascend the output file out of the 'RIFF' chunk -- this will cause
- * the chunk size of the 'RIFF' chunk to be written.
- */
- if (mmioAscend(hmmioOut, &ckOutRIFF, 0) != 0)
- goto ERROR_CANNOT_WRITE; // cannot write file, probably
-
- /* We are done -- files are closed below.
- */
- goto EXIT_FUNCTION;
-
- ERROR_BAD_FORMAT:
-
- MessageBox(NULL, "Input file must be an 8-bit mono PCM WAVE file",
- gszAppName, MB_ICONEXCLAMATION | MB_OK);
- goto EXIT_FUNCTION;
-
- ERROR_CANNOT_READ:
-
- MessageBox(NULL, "Cannot read input WAVE file",
- gszAppName, MB_ICONEXCLAMATION | MB_OK);
- goto EXIT_FUNCTION;
-
- ERROR_CANNOT_WRITE:
-
- MessageBox(NULL, "Cannot write output WAVE file",
- gszAppName, MB_ICONEXCLAMATION | MB_OK);
- goto EXIT_FUNCTION;
-
- ERROR_UNKNOWN:
-
- MessageBox(NULL, "Unknown error",
- gszAppName, MB_ICONEXCLAMATION | MB_OK);
- goto EXIT_FUNCTION;
-
- EXIT_FUNCTION:
-
- /* Close the files (unless they weren't opened successfully).
- */
- if (hmmioIn != NULL)
- mmioClose(hmmioIn, 0);
- if (hmmioOut != NULL)
- mmioClose(hmmioOut, 0);
- }
-
-
- /* WinMain - Entry point for LowPass.
- */
- int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszCmdLine, int iCmdShow)
- {
- FARPROC fpfn;
-
- /* Save instance handle for dialog boxes.
- */
- ghInst = hInst;
-
- /* Display our dialog box.
- */
- fpfn = MakeProcInstance((FARPROC) LowPassDlgProc, ghInst);
- DialogBox(ghInst, "LOWPASSBOX", NULL, (DLGPROC)fpfn);
- FreeProcInstance(fpfn);
-
- return TRUE;
- }
-
-
- /* AboutDlgProc - Dialog procedure function for ABOUTBOX dialog box.
- */
- BOOL FAR PASCAL __export AboutDlgProc(HWND hWnd, unsigned wMsg, WORD wParam, LONG lParam)
- {
- switch (wMsg)
- {
- case WM_INITDIALOG:
- return TRUE;
-
- case WM_COMMAND:
- if (wParam == IDOK)
- EndDialog(hWnd, TRUE);
- break;
- }
- return FALSE;
- }
-
-
- /* LowPassDlgProc - Dialog procedure function for LOWPASSBOX dialog box.
- */
- BOOL FAR PASCAL __export LowPassDlgProc(HWND hWnd, unsigned wMsg, WORD wParam, LONG lParam)
- {
- FARPROC fpfn;
- HMENU hmenuSystem; // system menu
- HCURSOR ghcurSave; // previous cursor
-
- switch (wMsg)
- {
- case WM_INITDIALOG:
- /* Append "About" menu item to system menu.
- */
- hmenuSystem = GetSystemMenu(hWnd, FALSE);
- AppendMenu(hmenuSystem, MF_SEPARATOR, 0, NULL);
- AppendMenu(hmenuSystem, MF_STRING, IDM_ABOUT,
- "&About LowPass...");
- return TRUE;
-
- case WM_SYSCOMMAND:
- switch (wParam)
- {
- case IDM_ABOUT:
- /* Display "About" dialog box.
- */
- fpfn = MakeProcInstance((FARPROC) AboutDlgProc, ghInst);
- DialogBox(ghInst, "ABOUTBOX", hWnd, (DLGPROC)fpfn);
- FreeProcInstance(fpfn);
- break;
- }
- break;
-
- case WM_COMMAND:
- switch (wParam)
- {
- case IDOK: // "Begin"
- /* Set "busy" cursor, filter input file, restore cursor.
- */
- ghcurSave = SetCursor(LoadCursor(NULL, IDC_WAIT));
- DoLowPass(hWnd);
- SetCursor(ghcurSave);
- break;
-
- case IDCANCEL: // "Done"
- EndDialog(hWnd, TRUE);
- break;
- }
- break;
- }
- return FALSE;
- }
-