REVERSE is a Windows with Multimedia sample application that illustrates how to use the low-level waveform playback services. It also shows how to use the multimedia file I/O services to read data from a WAVE file.
reverse.h:
#define IDE_NAME 200
#define IDB_PLAY 201
#define IDB_QUIT 202
#define WMAIN_DX 207
#define WMAIN_DY 120
#define NAME_DX 180
#define NAME_DY 30
#define NAME_X 10
#define NAME_Y 10
#define PLAY_DX 85
#define PLAY_DY 35
#define PLAY_X 10
#define PLAY_Y 50
#define QUIT_DX 85
#define QUIT_DY 35
#define QUIT_X 105
#define QUIT_Y 50
#define IDM_ABOUT 0x101
typedef struct waveInst
{
HANDLE hWaveInst;
HANDLE hWaveHdr;
HANDLE hWaveData;
} WAVEINST;
typedef WAVEINST FAR *LPWAVEINST;
BOOL FAR PASCAL AppAbout(HWND, unsigned, UINT, LONG);
LONG FAR PASCAL WndProc(HWND, unsigned, UINT, LONG);
void Interchange(HPSTR, HPSTR, unsigned);
void ReversePlay(void);
reverse.cpp:
#include <windows.h>
#include <mmsystem.h>
#include "reverse.h"
#define MAX_FILENAME_SIZE 128
char szAppName[] = "Reverse"; HANDLE hInstApp = NULL; HWND hwndApp = NULL; HWND hwndName = NULL; HWND hwndPlay = NULL; HWND hwndQuit = NULL; HWAVEOUT hWaveOut = NULL;
LPWAVEHDR lpWaveHdr = NULL;
VOID cleanup(LPWAVEINST lpWaveInst);
int PASCAL WinMain(HANDLE hInst, HANDLE hPrev, LPSTR szCmdLine, int cmdShow)
{
MSG msg;
WNDCLASS wc;
hInstApp = hInst;
if (!hPrev)
{
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(hInst, szAppName);
wc.lpszMenuName = szAppName;
wc.lpszClassName = szAppName;
wc.hbrBackground = GetStockObject(LTGRAY_BRUSH);
wc.hInstance = hInst;
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbWndExtra = 0;
wc.cbClsExtra = 0;
if (!RegisterClass(&wc))
return FALSE;
}
hwndApp = CreateWindow(szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WMAIN_DX, WMAIN_DY, (HWND)NULL, (HMENU)NULL, (HANDLE)hInst, (LPSTR)NULL );
hwndPlay = CreateWindow("BUTTON", "Play", WS_CHILD | WS_VISIBLE |
BS_PUSHBUTTON, PLAY_X, PLAY_Y, PLAY_DX, PLAY_DY, hwndApp, (HMENU)IDB_PLAY,
hInstApp, NULL);
if (!hwndPlay)
return (FALSE);
hwndQuit = CreateWindow("BUTTON", "Exit", WS_CHILD | WS_VISIBLE |
BS_PUSHBUTTON, QUIT_X, QUIT_Y, QUIT_DX, QUIT_DY, hwndApp, (HMENU)IDB_QUIT,
hInstApp, NULL);
if (!hwndQuit)
return (FALSE);
hwndName = CreateWindow("EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER |
ES_AUTOHSCROLL, NAME_X, NAME_Y, NAME_DX, NAME_DY, hwndApp, (HMENU)IDE_NAME,
hInstApp, NULL);
if (!hwndName)
return (FALSE);
SendMessage(hwndName, EM_LIMITTEXT, MAX_FILENAME_SIZE - 1, 0);
ShowWindow(hwndApp, cmdShow);
AppendMenu(GetSystemMenu(hwndApp, 0), MF_STRING | MF_ENABLED, IDM_ABOUT,
"About Reverse...");
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LONG FAR PASCAL WndProc(HWND hWnd, unsigned msg, UINT wParam, LONG lParam)
{
FARPROC fpfn;
LPWAVEINST lpWaveInst;
switch (msg)
{
case WM_DESTROY:
if (hWaveOut)
{
waveOutReset(hWaveOut);
waveOutUnprepareHeader(hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
lpWaveInst = (LPWAVEINST)lpWaveHdr->dwUser;
cleanup(lpWaveInst);
waveOutClose(hWaveOut);
}
PostQuitMessage(0);
break;
case WM_SYSCOMMAND:
switch (LOWORD(wParam))
{
case IDM_ABOUT:
fpfn = MakeProcInstance((FARPROC)AppAbout, hInstApp); DialogBox(hInstApp, "ABOUTBOX", hWnd, (DLGPROC)fpfn);
FreeProcInstance(fpfn);
break;
}
break;
case WM_SETFOCUS:
SetFocus(hwndName);
return 0;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDE_NAME:
return (0L);
case IDB_PLAY:
if (HIWORD(wParam) == BN_CLICKED)
ReversePlay();
break;
case IDB_QUIT:
if (HIWORD(wParam) == BN_CLICKED)
PostQuitMessage(0);
break;
}
return (0L);
case MM_WOM_DONE:
waveOutUnprepareHeader((HWAVEOUT)wParam, (LPWAVEHDR)lParam, sizeof
(WAVEHDR));
lpWaveInst = (LPWAVEINST)((LPWAVEHDR)lParam)->dwUser;
cleanup(lpWaveInst);
waveOutClose((HWAVEOUT)wParam);
EnableWindow(hwndPlay, TRUE);
EnableWindow(hwndQuit, TRUE);
SetFocus(hwndName);
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
BOOL FAR PASCAL AppAbout(HWND hDlg, unsigned msg, unsigned wParam, LONG lParam)
{
switch (msg)
{
case WM_COMMAND:
if (LOWORD(wParam) == IDOK)
EndDialog(hDlg, TRUE);
break;
case WM_INITDIALOG:
return TRUE;
}
return FALSE;
}
void ReversePlay()
{
HANDLE hWaveHdr;
LPWAVEINST lpWaveInst;
HMMIO hmmio;
MMCKINFO mmckinfoParent;
MMCKINFO mmckinfoSubchunk;
DWORD dwFmtSize;
char szFileName[MAX_FILENAME_SIZE];
HANDLE hFormat;
WAVEFORMAT *pFormat;
DWORD dwDataSize;
HPSTR hpch1, hpch2;
WORD wBlockSize;
HANDLE hWaveInst;
HANDLE hData = NULL;
HPSTR lpData = NULL;
if (!GetWindowText(hwndName, (LPSTR)szFileName, MAX_FILENAME_SIZE))
{
MessageBox(hwndApp, "Failed to Get Filename", NULL, MB_OK |
MB_ICONEXCLAMATION);
return ;
}
if (!(hmmio = mmioOpen(szFileName, NULL, MMIO_READ | MMIO_ALLOCBUF)))
{
MessageBox(hwndApp, "Failed to open file.", NULL, MB_OK |
MB_ICONEXCLAMATION);
return ;
}
mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
if (mmioDescend(hmmio, (LPMMCKINFO) &mmckinfoParent, NULL, MMIO_FINDRIFF))
{
MessageBox(hwndApp, "This is not a WAVE file.", NULL, MB_OK |
MB_ICONEXCLAMATION);
mmioClose(hmmio, 0);
return ;
}
mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK))
{
MessageBox(hwndApp, "WAVE file is corrupted.", NULL, MB_OK |
MB_ICONEXCLAMATION);
mmioClose(hmmio, 0);
return ;
}
dwFmtSize = mmckinfoSubchunk.cksize;
hFormat = LocalAlloc(LMEM_MOVEABLE, LOWORD(dwFmtSize));
if (!hFormat)
{
MessageBox(hwndApp, "Out of memory.", NULL, MB_OK | MB_ICONEXCLAMATION);
mmioClose(hmmio, 0);
return ;
}
pFormat = (WAVEFORMAT*)LocalLock(hFormat);
if (!pFormat)
{
MessageBox(hwndApp, "Failed to lock memory for format chunk.", NULL, MB_OK
| MB_ICONEXCLAMATION);
LocalFree(hFormat);
mmioClose(hmmio, 0);
return ;
}
if (mmioRead(hmmio, (HPSTR)pFormat, dwFmtSize) != (LONG)dwFmtSize)
{
MessageBox(hwndApp, "Failed to read format chunk.", NULL, MB_OK |
MB_ICONEXCLAMATION);
LocalUnlock(hFormat);
LocalFree(hFormat);
mmioClose(hmmio, 0);
return ;
}
if (pFormat->wFormatTag != WAVE_FORMAT_PCM)
{
LocalUnlock(hFormat);
LocalFree(hFormat);
mmioClose(hmmio, 0);
MessageBox(hwndApp, "The file is not a PCM file.", NULL, MB_OK |
MB_ICONEXCLAMATION);
return ;
}
if (waveOutOpen(&hWaveOut, WAVE_MAPPER, (LPWAVEFORMAT)pFormat, 0L, 0L,
WAVE_FORMAT_QUERY))
{
LocalUnlock(hFormat);
LocalFree(hFormat);
mmioClose(hmmio, 0);
MessageBox(hwndApp, "The waveform device can't play this format.", NULL,
MB_OK | MB_ICONEXCLAMATION);
return ;
}
mmioAscend(hmmio, &mmckinfoSubchunk, 0);
mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK))
{
MessageBox(hwndApp, "WAVE file has no data chunk.", NULL, MB_OK |
MB_ICONEXCLAMATION);
LocalUnlock(hFormat);
LocalFree(hFormat);
mmioClose(hmmio, 0);
return ;
}
dwDataSize = mmckinfoSubchunk.cksize;
if (dwDataSize == 0L)
{
MessageBox(hwndApp, "The data chunk has no data.", NULL, MB_OK |
MB_ICONEXCLAMATION);
LocalUnlock(hFormat);
LocalFree(hFormat);
mmioClose(hmmio, 0);
return ;
}
if (waveOutOpen((LPHWAVEOUT) &hWaveOut, WAVE_MAPPER, (LPWAVEFORMAT)pFormat,
(UINT)hwndApp, 0L, CALLBACK_WINDOW))
{
MessageBox(hwndApp, "Failed to open waveform output device.", NULL, MB_OK |
MB_ICONEXCLAMATION);
LocalUnlock(hFormat);
LocalFree(hFormat);
mmioClose(hmmio, 0);
return ;
}
wBlockSize = pFormat->nBlockAlign;
LocalUnlock(hFormat);
LocalFree(hFormat);
hData = GlobalAlloc(GMEM_MOVEABLE, dwDataSize);
if (!hData)
{
MessageBox(hwndApp, "Out of memory.", NULL, MB_OK | MB_ICONEXCLAMATION);
mmioClose(hmmio, 0);
return ;
}
lpData = GlobalLock(hData);
if (!lpData)
{
MessageBox(hwndApp, "Failed to lock memory for data chunk.", NULL, MB_OK |
MB_ICONEXCLAMATION);
GlobalFree(hData);
mmioClose(hmmio, 0);
return ;
}
if (mmioRead(hmmio, (HPSTR)lpData, dwDataSize) != (LONG)dwDataSize)
{
MessageBox(hwndApp, "Failed to read data chunk.", NULL, MB_OK |
MB_ICONEXCLAMATION);
GlobalUnlock(hData);
GlobalFree(hData);
mmioClose(hmmio, 0);
return ;
}
mmioClose(hmmio, 0);
hpch1 = lpData;
hpch2 = lpData + dwDataSize - 1;
while (hpch1 < hpch2)
{
Interchange(hpch1, hpch2, wBlockSize);
hpch1 += wBlockSize;
hpch2 -= wBlockSize;
}
hWaveHdr = GlobalAlloc(GMEM_MOVEABLE, (DWORD)sizeof(WAVEHDR));
if (!hWaveHdr)
{
GlobalUnlock(hData);
GlobalFree(hData);
MessageBox(hwndApp, "Not enough memory for header.", NULL, MB_OK |
MB_ICONEXCLAMATION);
return ;
}
lpWaveHdr = (LPWAVEHDR)GlobalLock(hWaveHdr);
if (!lpWaveHdr)
{
GlobalUnlock(hData);
GlobalFree(hData);
GlobalFree(hWaveHdr);
MessageBox(hwndApp, "Failed to lock memory for header.", NULL, MB_OK |
MB_ICONEXCLAMATION);
return ;
}
hWaveInst = GlobalAlloc(GMEM_MOVEABLE, (DWORD)sizeof(WAVEHDR));
if (!hWaveInst)
{
GlobalUnlock(hData);
GlobalFree(hData);
GlobalUnlock(hWaveHdr);
GlobalFree(hWaveHdr);
MessageBox(hwndApp, "Not enough memory for instance data.", NULL, MB_OK |
MB_ICONEXCLAMATION);
return ;
}
lpWaveInst = (LPWAVEINST)GlobalLock(hWaveInst);
if (!lpWaveInst)
{
GlobalUnlock(hData);
GlobalFree(hData);
GlobalUnlock(hWaveHdr);
GlobalFree(hWaveHdr);
GlobalFree(hWaveInst);
MessageBox(hwndApp, "Failed to lock memory for instance data.", NULL, MB_OK
| MB_ICONEXCLAMATION);
return ;
}
lpWaveInst->hWaveInst = hWaveInst;
lpWaveInst->hWaveHdr = hWaveHdr;
lpWaveInst->hWaveData = hData;
lpWaveHdr->lpData = lpData;
lpWaveHdr->dwBufferLength = dwDataSize;
lpWaveHdr->dwFlags = 0L;
lpWaveHdr->dwLoops = 0L;
lpWaveHdr->dwUser = (DWORD)lpWaveInst;
if (waveOutPrepareHeader(hWaveOut, lpWaveHdr, sizeof(WAVEHDR)))
{
GlobalUnlock(hData);
GlobalFree(hData);
GlobalUnlock(hWaveHdr);
GlobalFree(hWaveHdr);
GlobalUnlock(hWaveInst);
GlobalFree(hWaveInst);
MessageBox(hwndApp, "Unable to prepare wave header.", NULL, MB_OK |
MB_ICONEXCLAMATION);
return ;
}
{
MMRESULT mmResult;
mmResult = waveOutWrite(hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
if (mmResult != 0)
{
waveOutUnprepareHeader(hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
GlobalUnlock(hData);
GlobalFree(hData);
MessageBox(hwndApp, "Failed to write block to device", NULL, MB_OK |
MB_ICONEXCLAMATION);
return ;
}
}
EnableWindow(hwndPlay, FALSE);
EnableWindow(hwndQuit, FALSE);
}
void Interchange(HPSTR hpchPos1, HPSTR hpchPos2, unsigned uLength)
{
unsigned uPlace;
BYTE bTemp;
for (uPlace = 0; uPlace < uLength; uPlace++)
{
bTemp = hpchPos1[uPlace];
hpchPos1[uPlace] = hpchPos2[uPlace];
hpchPos2[uPlace] = bTemp;
}
}
VOID cleanup(LPWAVEINST lpWaveInst)
{
GlobalUnlock(lpWaveInst->hWaveData);
GlobalFree(lpWaveInst->hWaveData);
GlobalUnlock(lpWaveInst->hWaveHdr);
GlobalFree(lpWaveInst->hWaveHdr);
GlobalUnlock(lpWaveInst->hWaveInst);
GlobalFree(lpWaveInst->hWaveInst);
}
Read more...