Category : Files from Magazines
Archive   : VOL11N19.ZIP
Filename : MIDFIL.C
MIDFIL.C -- MIDI Recorder and Player with File Save
(c) Charles Petzold, 1992
-----------------------------------------------------*/
#include
#include
#include
#include
#include
#include
#include
#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 ;
}
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/