home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pcmagazi
/
1992
/
19
/
midfil.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-15
|
30KB
|
887 lines
/*-----------------------------------------------------
MIDFIL.C -- MIDI Recorder and Player with File Save
(c) Charles Petzold, 1992
-----------------------------------------------------*/
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <commdlg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "midbuf.h"
#include "midfil.h"
#define BUFFER_SIZE 4096 // Should be multiple of 8
long FAR PASCAL _export WndProc (HWND, UINT, UINT, LONG) ;
BOOL FAR PASCAL _export DlgProc (HWND, UINT, UINT, LONG) ;
char szAppName [] = "MidFil" ;
HANDLE hInst ;
HWND hDlg ;
int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdParam, int nCmdShow)
{
HWND hwnd ;
int xWin, yWin ;
MSG msg ;
WNDCLASS wndclass ;
hInst = hInstance ;
if (!hPrevInstance)
{
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (hInstance, szAppName) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = szAppName ;
wndclass.lpszClassName = szAppName ;
RegisterClass (&wndclass) ;
}
xWin = DLG_WIDTH * LOWORD (GetDialogBaseUnits ()) / 4 +
2 * GetSystemMetrics (SM_CXBORDER) ;
yWin = DLG_HEIGHT * HIWORD (GetDialogBaseUnits ()) / 8 +
2 * GetSystemMetrics (SM_CYBORDER) +
GetSystemMetrics (SM_CYCAPTION) +
GetSystemMetrics (SM_CYMENU) ;
hwnd = CreateWindow (szAppName, "Midi File Saver",
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
WS_BORDER | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, xWin, yWin,
NULL, NULL, hInstance, lpszCmdParam) ;
ShowWindow (hwnd, nCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
if (hDlg != NULL || !IsDialogMessage (hDlg, &msg))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
}
return msg.wParam ;
}
// Functions to allocate and free MIDIHDR structures and buffers
// -------------------------------------------------------------
LPMIDIHDR AllocMidiHeader (HANDLE hMidi, LPMIDIHDR pmhRoot)
{
LPMIDIHDR pmhNew, pmhNext ;
// Allocate memory for the new MIDIHDR
pmhNew = (LPMIDIHDR) GlobalAllocPtr (GHND | GMEM_SHARE, sizeof (MIDIHDR));
if (pmhNew == NULL)
return NULL ;
// Allocate memory for the buffer
pmhNew->lpData = (LPSTR) GlobalAllocPtr (GHND | GMEM_SHARE, BUFFER_SIZE) ;
if (pmhNew->lpData == NULL)
{
GlobalFreePtr (pmhNew) ;
return NULL ;
}
pmhNew->dwBufferLength = BUFFER_SIZE ;
// Prepare the header
if (midiInPrepareHeader (hMidi, pmhNew, sizeof (MIDIHDR)))
{
GlobalFreePtr (pmhNew->lpData) ;
GlobalFreePtr (pmhNew) ;
return NULL ;
}
// Attach new header to end of chain
if (pmhRoot != NULL)
{
pmhNext = pmhRoot ;
while (pmhNext->dwUser != NULL)
pmhNext = (LPMIDIHDR) pmhNext->dwUser ;
pmhNext->dwUser = (DWORD) pmhNew ;
}
return pmhNew ;
}
LPMIDIHDR CleanUpMidiHeaderChain (HANDLE hMidi, LPMIDIHDR pmhRoot)
{
LPMIDIHDR pmhCurr, pmhLast, pmhNext, pmhRetn ;
pmhRetn = pmhRoot ;
pmhCurr = pmhRoot ;
pmhLast = NULL ;
while (pmhCurr != NULL)
{
pmhNext = (LPMIDIHDR) pmhCurr->dwUser ;
if (pmhCurr->dwBytesRecorded == 0)
{
midiInUnprepareHeader (hMidi, pmhCurr, sizeof (MIDIHDR)) ;
GlobalFreePtr (pmhCurr->lpData) ;
GlobalFreePtr (pmhCurr) ;
if (pmhCurr == pmhRoot)
pmhRetn = NULL ;
if (pmhLast != NULL)
pmhLast->dwUser = (DWORD) pmhNext ;
pmhCurr = pmhLast ;
}
else if (pmhCurr->dwBytesRecorded < BUFFER_SIZE)
{
midiInUnprepareHeader (hMidi, pmhCurr, sizeof (MIDIHDR)) ;
GlobalReAllocPtr (pmhCurr->lpData,
pmhCurr->dwBytesRecorded, 0) ;
midiInPrepareHeader (hMidi, pmhCurr, sizeof (MIDIHDR)) ;
pmhCurr->dwBufferLength = pmhCurr->dwBytesRecorded ;
}
pmhLast = pmhCurr ;
pmhCurr = pmhNext ;
}
return pmhRetn ;
}
VOID FreeMidiHeaderChain (HANDLE hMidi, LPMIDIHDR pmhRoot)
{
LPMIDIHDR pmhNext, pmhTemp ;
pmhNext = pmhRoot ;
while (pmhNext != NULL)
{
pmhTemp = (LPMIDIHDR) pmhNext->dwUser ;
midiInUnprepareHeader (hMidi, pmhNext, sizeof (MIDIHDR)) ;
GlobalFreePtr (pmhNext->lpData) ;
GlobalFreePtr (pmhNext) ;
pmhNext = pmhTemp ;
}
}
// Add MIDI device lists to the program's menu
// -------------------------------------------
WORD AddDevicesToMenu (HWND hwnd, int iNumInpDevs, int iNumOutDevs)
{
HMENU hMenu, hMenuInp, hMenuMon, hMenuOut ;
int i ;
MIDIINCAPS mic ;
MIDIOUTCAPS moc ;
WORD wDefaultOut ;
hMenu = GetMenu (hwnd) ;
// Create "Input" popup menu
hMenuInp = CreateMenu () ;
for (i = 0 ; i < iNumInpDevs ; i++)
{
midiInGetDevCaps (i, &mic, sizeof (MIDIINCAPS)) ;
AppendMenu (hMenuInp, MF_STRING, ID_DEV_INP + i, mic.szPname) ;
}
CheckMenuItem (hMenuInp, 0, MF_BYPOSITION | MF_CHECKED) ;
ModifyMenu (hMenu, ID_DEV_INP, MF_POPUP, hMenuInp, "&Input") ;
// Create "Monitor" and "Output" popup menus
hMenuMon = CreateMenu () ;
hMenuOut = CreateMenu () ;
AppendMenu (hMenuMon, MF_STRING, ID_DEV_MON, "&None") ;
if (!midiOutGetDevCaps (MIDIMAPPER, &moc, sizeof (moc)))
{
AppendMenu (hMenuMon, MF_STRING, ID_DEV_MON + 1, moc.szPname) ;
AppendMenu (hMenuOut, MF_STRING, ID_DEV_OUT , moc.szPname) ;
wDefaultOut = 0 ;
}
else
wDefaultOut = 1 ;
// Add the rest of the MIDI devices
for (i = 0 ; i < iNumOutDevs ; i++)
{
midiOutGetDevCaps (i, &moc, sizeof (moc)) ;
AppendMenu (hMenuMon, MF_STRING, ID_DEV_MON + i + 2, moc.szPname) ;
AppendMenu (hMenuOut, MF_STRING, ID_DEV_OUT + i + 1, moc.szPname) ;
}
CheckMenuItem (hMenuMon, 0, MF_BYPOSITION | MF_CHECKED) ;
CheckMenuItem (hMenuOut, 0, MF_BYPOSITION | MF_CHECKED) ;
ModifyMenu (hMenu, ID_DEV_MON, MF_POPUP, hMenuMon, "&Monitor") ;
ModifyMenu (hMenu, ID_DEV_OUT, MF_POPUP, hMenuOut, "&Output") ;
return wDefaultOut ;
}
// Functions to save the MIDI data buffers as a .MID file
// ------------------------------------------------------
int VarLenNumOut (BYTE * pOut, int iOut, long lAbsTime)
{
long lVarTime ;
lVarTime = lAbsTime & 0x7F ;
while ((lAbsTime >>= 7) > 0)
{
lVarTime <<= 8 ;
lVarTime |= 0x80 ;
lVarTime += lAbsTime & 0x7F ;
}
while (TRUE)
{
pOut[iOut++] = (char) lVarTime ;
if (lVarTime & 0x80)
lVarTime >>= 8 ;
else
break ;
}
return iOut ;
}
long IntelToMotorolaLong (long lIn)
{
long lOut ;
* ((char *) & lOut + 0) = * ((char *) & lIn + 3) ;
* ((char *) & lOut + 1) = * ((char *) & lIn + 2) ;
* ((char *) & lOut + 2) = * ((char *) & lIn + 1) ;
* ((char *) & lOut + 3) = * ((char *) & lIn + 0) ;
return lOut ;
}
BOOL SaveMidiFile (char * szFileName, LPMIDIHDR pMidiHdrRoot)
{
static BYTE pBufOut [2 * BUFFER_SIZE] ;
static BYTE pHeader [] = { 'M', 'T', 'h', 'd', 0, 0, 0, 6,
0, 0, 0, 1, -25, 40,
'M', 'T', 'r', 'k', 0, 0, 0, 0 } ;
static BYTE pEndTrk [] = { 0, 0xFF, 0x2F, 0x00 } ;
BYTE bStatus, bChannel, bData1, bData2 ;
DWORD dwTime, dwMidiMsg ;
int hFile, iLenIn, iIn, iOut ;
long lTotLen ;
LPMIDIHDR pMidiHdr ;
LPDWORD pdwBufIn ;
// Attempt to open the file
if (-1 == (hFile = _lcreat (szFileName, 0)))
return FALSE ;
// Write out the header chunk and some of the track chunk
_lwrite (hFile, pHeader, sizeof (pHeader)) ;
// Loop through the MIDIHDR chain
pMidiHdr = pMidiHdrRoot ;
lTotLen = 0 ;
while (pMidiHdr != NULL)
{
iLenIn = (int) pMidiHdr->dwBufferLength / 4 ;
pdwBufIn = (LPDWORD) pMidiHdr->lpData ;
iOut = 0 ;
// Loop through the DWORDs in the buffer
for (iIn = 0 ; iIn < iLenIn ; iIn += 2)
{
// Get the delta time in milliseconds
dwTime = pdwBufIn [iIn] ;
// If it's the very first, set it to zero
if (pMidiHdr == pMidiHdrRoot && iIn == 0)
dwTime = 0 ;
// Store it as a variable length number
iOut = VarLenNumOut (pBufOut, iOut, dwTime) ;
// Get the MIDI message
dwMidiMsg = pdwBufIn [iIn + 1] ;
bStatus = LOBYTE (LOWORD (dwMidiMsg)) ;
bData1 = HIBYTE (LOWORD (dwMidiMsg)) ;
bData2 = LOBYTE (HIWORD (dwMidiMsg)) ;
// Forget about system messages
if (bStatus >= 0xF0)
continue ;
// Store the status byte and first data byte
pBufOut[iOut++] = bStatus ;
pBufOut[iOut++] = bData1 ;
// For three-byte messages, store the second data byte
if (bStatus < 0xC0 || bStatus >= 0xE0)
pBufOut [iOut++] = bData2 ;
// Get the channel number
bChannel = bStatus & 0x0F ;
// If it's not mappable, continue with next loop
if ((bChannel > 2 && bChannel < 9) ||
(bChannel > 9 && bChannel < 12))
continue ;
// Map the channel and create a new status byte
if (bChannel < 3)
bChannel += 12 ;
else if (bChannel == 9)
bChannel = 15 ;
else if (bChannel == 15)
bChannel = 9 ;
else if (bChannel > 11)
bChannel -= 12 ;
bStatus = (bStatus & 0xF0) | bChannel ;
// Store a delta time of zero
pBufOut[iOut++] = 0 ;
// Store the MIDI message as above
pBufOut[iOut++] = bStatus ;
pBufOut[iOut++] = bData1 ;
if (bStatus < 0xC0 || bStatus >= 0xE0)
pBufOut [iOut++] = bData2 ;
}
// Write out the buffer
if (iOut != (int) _lwrite (hFile, pBufOut, iOut))
{
_lclose (hFile) ;
unlink (szFileName) ;
return FALSE ;
}
// Increment the total track size
lTotLen += iOut ;
// Get next MIDIHDR structure in chain
pMidiHdr = (LPMIDIHDR) pMidiHdr->dwUser ;
}
// Store an "end of track" meta-message
_lwrite (hFile, pEndTrk, sizeof (pEndTrk)) ;
lTotLen += sizeof (pEndTrk) ;
// Convert track length to Motorola format and store it
// in the size field of the track chunk
lTotLen = IntelToMotorolaLong (lTotLen) ;
_llseek (hFile, 18, 0) ;
_lwrite (hFile, &lTotLen, sizeof (long)) ;
// Close the file
_lclose (hFile) ;
return TRUE ;
}
long FAR PASCAL _export WndProc (HWND hwnd, UINT message, UINT wParam,
LONG lParam)
{
static BOOL bRecording, bPlaying, bEnding, bPaused, bTerminating ;
static char szInpError[] = { "Error opening MIDI input port!" } ;
static char szOutError[] = { "Error opening MIDI output port!" } ;
static char szMonError[] = { "Error opening MIDI output port "
"for monitoring input! Continuing." } ;
static char szMemError[] = { "Error allocating memory!" } ;
static char szFilError[] = { "Error save file!" } ;
static char szFileName [_MAX_PATH],
szFileTitle [_MAX_FNAME | _MAX_EXT] ;
static HMIDIIN hMidiIn ;
static HMIDIOUT hMidiOut ;
static int iNumInpDevs, iNumOutDevs ;
static LPMIDIHDR pMidiHdrRoot, pMidiHdrNext, pMidiHdr ;
static OPENFILENAME ofn ;
static char * szFilter[] = { "Midi Files (*.MID)", "*.mid",
"" } ;
static WORD wDeviceInp, wDeviceMon, wDeviceOut ;
FARPROC lpDlgProc ;
HMENU hMenu ;
int i ;
switch (message)
{
case WM_CREATE:
if (0 == (iNumInpDevs = midiInGetNumDevs ()))
{
MessageBox (hwnd, "No MIDI Input Devices!", szAppName,
MB_ICONEXCLAMATION | MB_OK) ;
DestroyWindow (hwnd) ;
}
if (0 == (iNumOutDevs = midiOutGetNumDevs ()))
{
MessageBox (hwnd, "No MIDI Output Devices!", szAppName,
MB_ICONEXCLAMATION | MB_OK) ;
DestroyWindow (hwnd) ;
}
wDeviceOut = AddDevicesToMenu (hwnd, iNumInpDevs, iNumOutDevs) ;
lpDlgProc = MakeProcInstance ((FARPROC) DlgProc, hInst) ;
hDlg = CreateDialog (hInst, szAppName, hwnd, lpDlgProc) ;
return 0 ;
case WM_COMMAND:
hMenu = GetMenu (hwnd) ;
switch (wParam)
{
case ID_RECORD_BEG:
// Open MIDI In port for recording
if (midiInOpen (&hMidiIn, wDeviceInp, hwnd, 0L,
CALLBACK_WINDOW))
{
MessageBox (hwnd, szInpError, szAppName,
MB_ICONEXCLAMATION | MB_OK) ;
return 0 ;
}
// Open MIDI Out port for monitoring
// (continue if unable to open it)
if (wDeviceMon > 0)
{
if (midiOutOpen (&hMidiOut, wDeviceMon - 2,
0L, 0L, 0L))
{
hMidiOut = NULL ;
MessageBox (hwnd, szMonError, szAppName,
MB_ICONEXCLAMATION | MB_OK) ;
}
}
else
hMidiOut = NULL ;
return 0 ;
case ID_RECORD_END:
// Reset and close input
bEnding = TRUE ;
midiInReset (hMidiIn) ;
midiInClose (hMidiIn) ;
return 0 ;
case ID_FILE_SAVE:
ofn.lStructSize = sizeof (OPENFILENAME) ;
ofn.hwndOwner = hwnd ;
ofn.lpstrFilter = szFilter [0] ;
ofn.lpstrFile = szFileName ;
ofn.nMaxFile = _MAX_PATH ;
ofn.lpstrFileTitle = szFileTitle ;
ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT ;
ofn.Flags = OFN_OVERWRITEPROMPT ;
ofn.lpstrDefExt = "mid" ;
if (!GetSaveFileName (&ofn))
return 0 ;
if (!SaveMidiFile (szFileName, pMidiHdrRoot))
MessageBox (hwnd, szFilError, szAppName,
MB_ICONEXCLAMATION | MB_OK) ;
SetFocus (GetDlgItem (hDlg, ID_RECORD_BEG)) ;
return 0 ;
case ID_PLAY_BEG:
// Open MIDI Out port for playing
if (midiOutOpen (&hMidiOut, wDeviceOut - 1,
hwnd, 0L, CALLBACK_WINDOW))
{
MessageBox (hwnd, szOutError, szAppName,
MB_ICONEXCLAMATION | MB_OK) ;
}
return 0 ;
case ID_PLAY_PAUSE:
// Pause or restart output
if (!bPaused)
{
midiOutPause (hMidiOut) ;
// All Notes Off message
for (i = 0 ; i < 16 ; i++)
midiOutShortMsg (hMidiOut, 0x7BB0 + i) ;
SetDlgItemText (hwnd, ID_PLAY_PAUSE, "Resume") ;
bPaused = TRUE ;
}
else
{
midiOutRestart (hMidiOut) ;
SetDlgItemText (hwnd, ID_PLAY_PAUSE, "Pause") ;
bPaused = FALSE ;
}
return 0 ;
case ID_PLAY_END:
// Reset the port and close it
bEnding = TRUE ;
midiOutReset (hMidiOut) ;
midiOutClose (hMidiOut) ;
return 0 ;
default:
break ;
}
if (wParam >= ID_DEV_INP & wParam < ID_DEV_MON)
{
CheckMenuItem (hMenu, wDeviceInp + ID_DEV_INP,
MF_UNCHECKED) ;
wDeviceInp = wParam - ID_DEV_INP ;
CheckMenuItem (hMenu, wDeviceInp + ID_DEV_INP,
MF_CHECKED) ;
return 0 ;
}
else if (wParam >= ID_DEV_MON & wParam < ID_DEV_OUT)
{
CheckMenuItem (hMenu, wDeviceMon + ID_DEV_MON,
MF_UNCHECKED) ;
wDeviceMon = wParam - ID_DEV_MON ;
CheckMenuItem (hMenu, wDeviceMon + ID_DEV_MON,
MF_CHECKED) ;
return 0 ;
}
if (wParam >= ID_DEV_OUT)
{
CheckMenuItem (hMenu, wDeviceOut + ID_DEV_OUT,
MF_UNCHECKED) ;
wDeviceOut = wParam - ID_DEV_OUT ;
CheckMenuItem (hMenu, wDeviceOut + ID_DEV_OUT,
MF_CHECKED) ;
return 0 ;
}
break ;
case MM_MIM_OPEN:
hMidiIn = wParam ;
// Free existing headers
FreeMidiHeaderChain (hMidiIn, pMidiHdrRoot) ;
// Allocate root header
if (NULL == (pMidiHdrRoot = AllocMidiHeader (hMidiIn, NULL)))
{
midiInClose (hMidiIn) ;
MessageBox (hwnd, szMemError, szAppName,
MB_ICONEXCLAMATION | MB_OK) ;
return 0 ;
}
// Allocate next header
if (NULL == (pMidiHdrNext = AllocMidiHeader (hMidiIn,
pMidiHdrRoot)))
{
FreeMidiHeaderChain (hMidiIn, pMidiHdrRoot) ;
midiInClose (hMidiIn) ;
MessageBox (hwnd, szMemError, szAppName,
MB_ICONEXCLAMATION | MB_OK) ;
return 0 ;
}
// Enable and disable buttons
EnableWindow (GetDlgItem (hDlg, ID_RECORD_BEG), FALSE) ;
EnableWindow (GetDlgItem (hDlg, ID_RECORD_END), TRUE) ;
EnableWindow (GetDlgItem (hDlg, ID_FILE_SAVE), FALSE) ;
EnableWindow (GetDlgItem (hDlg, ID_PLAY_BEG), FALSE) ;
EnableWindow (GetDlgItem (hDlg, ID_PLAY_PAUSE), FALSE) ;
EnableWindow (GetDlgItem (hDlg, ID_PLAY_END), FALSE) ;
SetFocus (GetDlgItem (hDlg, ID_RECORD_END)) ;
// Submit the buffers for receiving data
midiInShortBuffer (hMidiIn, pMidiHdrRoot, sizeof (MIDIHDR)) ;
midiInShortBuffer (hMidiIn, pMidiHdrNext, sizeof (MIDIHDR)) ;
// Begin recording
midiInStart (hMidiIn) ;
bRecording = TRUE ;
bEnding = FALSE ;
return 0 ;
case MM_MIM_DATA:
if (hMidiOut)
{
midiOutShortMsg (hMidiOut, lParam) ;
}
return 0 ;
case MM_MIM_LONGDATA:
if (bEnding)
return 0 ;
pMidiHdrNext = AllocMidiHeader (hMidiIn, pMidiHdrRoot) ;
if (pMidiHdrNext == NULL)
{
midiInReset (hMidiIn) ;
midiInClose (hMidiIn) ;
MessageBox (hwnd, szMemError, szAppName,
MB_ICONEXCLAMATION | MB_OK) ;
return 0 ;
}
midiInShortBuffer (hMidiIn, pMidiHdrNext, sizeof (MIDIHDR));
return 0 ;
case MM_MIM_CLOSE:
// Close the monitoring output port
if (hMidiOut)
{
midiOutReset (hMidiOut) ;
midiOutClose (hMidiOut) ;
}
// Enable and Disable Buttons
EnableWindow (GetDlgItem (hDlg, ID_RECORD_BEG), TRUE) ;
EnableWindow (GetDlgItem (hDlg, ID_RECORD_END), FALSE) ;
SetFocus (GetDlgItem (hDlg, ID_RECORD_BEG)) ;
pMidiHdrRoot = CleanUpMidiHeaderChain (hMidiIn, pMidiHdrRoot) ;
if (pMidiHdrRoot != NULL)
{
EnableWindow (GetDlgItem (hDlg, ID_FILE_SAVE), TRUE) ;
EnableWindow (GetDlgItem (hDlg, ID_PLAY_BEG), TRUE) ;
EnableWindow (GetDlgItem (hDlg, ID_PLAY_PAUSE), FALSE) ;
EnableWindow (GetDlgItem (hDlg, ID_PLAY_END), FALSE) ;
SetFocus (GetDlgItem (hDlg, ID_PLAY_BEG)) ;
}
bRecording = FALSE ;
if (bTerminating)
{
FreeMidiHeaderChain (hMidiIn, pMidiHdrRoot) ;
SendMessage (hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L) ;
}
return 0 ;
case MM_MOM_OPEN:
hMidiOut = wParam ;
// Enable and Disable Buttons
EnableWindow (GetDlgItem (hDlg, ID_RECORD_BEG), FALSE) ;
EnableWindow (GetDlgItem (hDlg, ID_RECORD_END), FALSE) ;
EnableWindow (GetDlgItem (hDlg, ID_PLAY_BEG), FALSE) ;
EnableWindow (GetDlgItem (hDlg, ID_PLAY_PAUSE), TRUE) ;
EnableWindow (GetDlgItem (hDlg, ID_PLAY_END), TRUE) ;
SetFocus (GetDlgItem (hDlg, ID_PLAY_END)) ;
// Submit the root buffer to begin playing
midiOutShortBuffer (hMidiOut, pMidiHdrRoot, sizeof (MIDIHDR)) ;
// If there's a second buffer, submit that also
if (NULL != (pMidiHdr = (LPMIDIHDR) pMidiHdrRoot->dwUser))
midiOutShortBuffer (hMidiOut, pMidiHdr, sizeof (MIDIHDR)) ;
bEnding = FALSE ;
bPlaying = TRUE ;
return 0 ;
case MM_MOM_DONE:
// If stopping playback, just return
if (bEnding)
return 0 ;
// Get header of buffer just finished playing
pMidiHdr = (LPMIDIHDR) lParam ;
// Get header of next buffer (already submitted)
pMidiHdr = (LPMIDIHDR) pMidiHdr->dwUser ;
// Get header of next buffer to submit now
if (pMidiHdr != NULL)
pMidiHdr = (LPMIDIHDR) pMidiHdr->dwUser ;
if (pMidiHdr != NULL)
midiOutShortBuffer (hMidiOut, pMidiHdr, sizeof (MIDIHDR)) ;
else
{
midiOutReset (hMidiOut) ;
midiOutClose (hMidiOut) ;
}
return 0 ;
case MM_MOM_CLOSE:
// Enable and Disable Buttons
EnableWindow (GetDlgItem (hDlg, ID_RECORD_BEG), TRUE) ;
EnableWindow (GetDlgItem (hDlg, ID_RECORD_END), TRUE) ;
EnableWindow (GetDlgItem (hDlg, ID_PLAY_BEG), TRUE) ;
EnableWindow (GetDlgItem (hDlg, ID_PLAY_PAUSE), FALSE) ;
EnableWindow (GetDlgItem (hDlg, ID_PLAY_END), FALSE) ;
SetFocus (GetDlgItem (hDlg, ID_PLAY_BEG)) ;
SetDlgItemText (hwnd, ID_PLAY_PAUSE, "Pause") ;
bPaused = FALSE ;
bPlaying = FALSE ;
if (bTerminating)
{
FreeMidiHeaderChain (hMidiIn, pMidiHdrRoot) ;
SendMessage (hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L) ;
}
return 0 ;
case WM_CLOSE:
if (bRecording)
{
bTerminating = TRUE ;
bEnding = TRUE ;
midiInReset (hMidiIn) ;
midiInClose (hMidiIn) ;
}
if (bPlaying)
{
bTerminating = TRUE ;
bEnding = TRUE ;
midiOutReset (hMidiOut) ;
midiOutClose (hMidiOut) ;
}
break ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
BOOL FAR PASCAL _export DlgProc (HWND hwnd, UINT message, UINT wParam,
LONG lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE ;
case WM_COMMAND:
SendMessage (GetParent (hwnd), WM_COMMAND, wParam, lParam) ;
return TRUE ;
}
return FALSE ;
}