Category : Files from Magazines
Archive   : VOL11N15.ZIP
Filename : MIDREC.C

 
Output of file : MIDREC.C contained in archive : VOL11N15.ZIP
/*---------------------------------------
MIDREC.C -- MIDI Recorder and Player
(c) Charles Petzold, 1992
---------------------------------------*/

#include
#include
#include
#include
#include "midbuf.h"
#include "midrec.h"

#define BUFFER_SIZE 4096 // Should be multiple of 8

BOOL FAR PASCAL _export DlgProc (HWND, UINT, UINT, LONG) ;

static char szAppName [] = "MidRec" ;

int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
FARPROC lpDlgProc ;

lpDlgProc = MakeProcInstance ((FARPROC) DlgProc, hInstance) ;
DialogBox (hInstance, szAppName, NULL, lpDlgProc) ;
FreeProcInstance (lpDlgProc) ;

return 0 ;
}

// 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 ;
}

BOOL FAR PASCAL _export DlgProc (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 HMIDIIN hMidiIn ;
static HMIDIOUT hMidiOut ;
static int iNumInpDevs, iNumOutDevs ;
static LPMIDIHDR pMidiHdrRoot, pMidiHdrNext, pMidiHdr ;
static WORD wDeviceInp, wDeviceMon, wDeviceOut ;
HMENU hMenu ;
int i ;

switch (message)
{
case WM_INITDIALOG:

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) ;

return TRUE ;

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 TRUE ;
}

// 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 TRUE ;

case ID_RECORD_END:
// Reset and close input

bEnding = TRUE ;

midiInReset (hMidiIn) ;
midiInClose (hMidiIn) ;

return TRUE ;

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 TRUE ;

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 TRUE ;

case ID_PLAY_END:
// Reset the port and close it

bEnding = TRUE ;
midiOutReset (hMidiOut) ;
midiOutClose (hMidiOut) ;
return TRUE ;

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 TRUE ;
}

// Allocate next header

if (NULL == (pMidiHdrNext = AllocMidiHeader (hMidiIn,
pMidiHdrRoot)))
{
FreeMidiHeaderChain (hMidiIn, pMidiHdrRoot) ;
midiInClose (hMidiIn) ;
MessageBox (hwnd, szMemError, szAppName,
MB_ICONEXCLAMATION | MB_OK) ;

return TRUE ;
}
// Enable and disable buttons

EnableWindow (GetDlgItem (hwnd, ID_RECORD_BEG), FALSE) ;
EnableWindow (GetDlgItem (hwnd, ID_RECORD_END), TRUE) ;
EnableWindow (GetDlgItem (hwnd, ID_PLAY_BEG), FALSE) ;
EnableWindow (GetDlgItem (hwnd, ID_PLAY_PAUSE), FALSE) ;
EnableWindow (GetDlgItem (hwnd, ID_PLAY_END), FALSE) ;
SetFocus (GetDlgItem (hwnd, 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 TRUE ;

case MM_MIM_DATA:
if (hMidiOut)
{
midiOutShortMsg (hMidiOut, lParam) ;
}

return TRUE ;

case MM_MIM_LONGDATA:

if (bEnding)
return TRUE ;

pMidiHdrNext = AllocMidiHeader (hMidiIn, pMidiHdrRoot) ;

if (pMidiHdrNext == NULL)
{
midiInReset (hMidiIn) ;
midiInClose (hMidiIn) ;
MessageBox (hwnd, szMemError, szAppName,
MB_ICONEXCLAMATION | MB_OK) ;

return TRUE ;
}

midiInShortBuffer (hMidiIn, pMidiHdrNext, sizeof (MIDIHDR));

return TRUE ;

case MM_MIM_CLOSE:
// Close the monitoring output port

if (hMidiOut)
{
midiOutReset (hMidiOut) ;
midiOutClose (hMidiOut) ;
}

// Enable and Disable Buttons

EnableWindow (GetDlgItem (hwnd, ID_RECORD_BEG), TRUE) ;
EnableWindow (GetDlgItem (hwnd, ID_RECORD_END), FALSE) ;
SetFocus (GetDlgItem (hwnd, ID_RECORD_BEG)) ;

pMidiHdrRoot = CleanUpMidiHeaderChain (hMidiIn, pMidiHdrRoot) ;

if (pMidiHdrRoot != NULL)
{
EnableWindow (GetDlgItem (hwnd, ID_PLAY_BEG), TRUE) ;
EnableWindow (GetDlgItem (hwnd, ID_PLAY_PAUSE), FALSE) ;
EnableWindow (GetDlgItem (hwnd, ID_PLAY_END), FALSE) ;
SetFocus (GetDlgItem (hwnd, ID_PLAY_BEG)) ;
}

bRecording = FALSE ;

if (bTerminating)
{
FreeMidiHeaderChain (hMidiIn, pMidiHdrRoot) ;
SendMessage (hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L) ;
}

return TRUE ;

case MM_MOM_OPEN:
hMidiOut = wParam ;

// Enable and Disable Buttons

EnableWindow (GetDlgItem (hwnd, ID_RECORD_BEG), FALSE) ;
EnableWindow (GetDlgItem (hwnd, ID_RECORD_END), FALSE) ;
EnableWindow (GetDlgItem (hwnd, ID_PLAY_BEG), FALSE) ;
EnableWindow (GetDlgItem (hwnd, ID_PLAY_PAUSE), TRUE) ;
EnableWindow (GetDlgItem (hwnd, ID_PLAY_END), TRUE) ;
SetFocus (GetDlgItem (hwnd, 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 TRUE ;

case MM_MOM_DONE:

// If stopping playback, just return

if (bEnding)
return TRUE ;

// 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 TRUE ;

case MM_MOM_CLOSE:

// Enable and Disable Buttons

EnableWindow (GetDlgItem (hwnd, ID_RECORD_BEG), TRUE) ;
EnableWindow (GetDlgItem (hwnd, ID_RECORD_END), TRUE) ;
EnableWindow (GetDlgItem (hwnd, ID_PLAY_BEG), TRUE) ;
EnableWindow (GetDlgItem (hwnd, ID_PLAY_PAUSE), FALSE) ;
EnableWindow (GetDlgItem (hwnd, ID_PLAY_END), FALSE) ;
SetFocus (GetDlgItem (hwnd, 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 TRUE ;

case WM_SYSCOMMAND:
switch (wParam)
{
case SC_CLOSE:
if (bRecording)
{
bTerminating = TRUE ;
bEnding = TRUE ;
midiInReset (hMidiIn) ;
midiInClose (hMidiIn) ;
return TRUE ;
}

if (bPlaying)
{
bTerminating = TRUE ;
bEnding = TRUE ;
midiOutReset (hMidiOut) ;
midiOutClose (hMidiOut) ;
return TRUE ;
}

EndDialog (hwnd, 0) ;
return TRUE ;
}
break ;
}
return FALSE ;
}


  3 Responses to “Category : Files from Magazines
Archive   : VOL11N15.ZIP
Filename : MIDREC.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. 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/