home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pcmagazi
/
1992
/
15
/
midrec.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-04
|
21KB
|
601 lines
/*---------------------------------------
MIDREC.C -- MIDI Recorder and Player
(c) Charles Petzold, 1992
---------------------------------------*/
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <string.h>
#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 ;
}