home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pcmagazi
/
1992
/
17
/
midplay
/
midpla.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-06-07
|
24KB
|
628 lines
/*---------------------------------------
MIDPLA.C -- MIDI File Player
(c) Charles Petzold, 1992
---------------------------------------*/
#include <windows.h>
#include <mmsystem.h>
#include <commdlg.h>
#include <stdlib.h>
#include <string.h>
#include "midpla.h"
#define ID_TIMER 1
#define MIN_TEMPO_BPS 20
#define MAX_TEMPO_BPS 480
#define MIN_TEMPO_SMPTE 5
#define MAX_TEMPO_SMPTE 120
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define EnableDlgWindow(hwnd, wID, bEnable) \
(EnableWindow (GetDlgItem ((hwnd), (wID)), (bEnable)))
BOOL FAR PASCAL _export DlgProc (HWND, UINT, UINT, LONG) ;
static char szAppName [] = "MidPla" ;
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 ;
}
/*----------------------------------------------
mciSendCommand with an error message display
----------------------------------------------*/
BOOL MciSend (UINT wDeviceID, UINT wMessage, DWORD dwParam1, DWORD dwParam2)
{
static char szBuffer [256] ;
DWORD dwError ;
HWND hwnd ;
dwError = mciSendCommand (wDeviceID, wMessage, dwParam1, dwParam2) ;
if (dwError)
{
hwnd = (HWND) ((LPMCI_GENERIC_PARMS) dwParam2)->dwCallback ;
if (!mciGetErrorString (dwError, szBuffer, sizeof (szBuffer)))
strcpy (szBuffer, "Error not known") ;
MessageBox (hwnd, szBuffer, szAppName, MB_OK | MB_ICONEXCLAMATION) ;
}
return dwError == 0 ;
}
/*---------------
Open function
---------------*/
UINT MciMidiOpen (HWND hwnd, char * szFileName, DWORD dwFlags)
{
BOOL bSuccess ;
MCI_OPEN_PARMS open ;
open.dwCallback = (DWORD) hwnd ;
open.lpstrDeviceType = "sequencer" ;
open.lpstrElementName = szFileName ;
open.lpstrAlias = NULL ;
bSuccess = MciSend (0, MCI_OPEN,
MCI_OPEN_ELEMENT | MCI_OPEN_TYPE | dwFlags,
(DWORD) (LPMCI_OPEN_PARMS) &open) ;
return bSuccess ? open.wDeviceID : 0 ;
}
/*-----------------------------------------------------------------
Functions and macros for operations using the generic structure
-----------------------------------------------------------------*/
BOOL MciMidiGeneric (UINT wDeviceID, HWND hwnd, UINT wMessage, DWORD dwFlags)
{
MCI_GENERIC_PARMS generic ;
generic.dwCallback = (DWORD) hwnd ;
return MciSend (wDeviceID, wMessage, dwFlags,
(DWORD) (LPMCI_GENERIC_PARMS) &generic) ;
}
#define MciMidiClose(wDeviceID, hwnd, dwFlags) \
(MciMidiGeneric ((wDeviceID), (hwnd), MCI_CLOSE, (dwFlags)))
#define MciMidiPause(wDeviceID, hwnd, dwFlags) \
(MciMidiGeneric ((wDeviceID), (hwnd), MCI_PAUSE, (dwFlags)))
#define MciMidiStop(wDeviceID, hwnd, dwFlags) \
(MciMidiGeneric ((wDeviceID), (hwnd), MCI_STOP, (dwFlags)))
/*------------------------------
MIDI Play and Seek functions
------------------------------*/
BOOL MciMidiPlay (UINT wDeviceID, HWND hwnd, DWORD dwFlags, DWORD dwFrom,
DWORD dwTo)
{
MCI_PLAY_PARMS play ;
play.dwCallback = (DWORD) hwnd ;
play.dwFrom = dwFrom ;
play.dwTo = dwTo ;
return MciSend (wDeviceID, MCI_PLAY, dwFlags,
(DWORD) (LPMCI_PLAY_PARMS) &play) ;
}
BOOL MciMidiSeek (UINT wDeviceID, HWND hwnd, DWORD dwFlags, DWORD dwTo)
{
MCI_SEEK_PARMS seek ;
seek.dwCallback = (DWORD) hwnd ;
seek.dwTo = dwTo ;
return MciSend (wDeviceID, MCI_SEEK, dwFlags,
(DWORD) (LPMCI_SEEK_PARMS) &seek) ;
}
/*---------------------------------------------------
Functions and macros to obtain status information
---------------------------------------------------*/
DWORD MciMidiGet (UINT wDeviceID, HWND hwnd, DWORD dwFlags, DWORD dwItem)
{
BOOL bSuccess ;
MCI_STATUS_PARMS status ;
status.dwCallback = (HWND) hwnd ;
status.dwItem = dwItem ;
bSuccess = MciSend (wDeviceID, MCI_STATUS, dwFlags | MCI_STATUS_ITEM,
(DWORD) (LPMCI_STATUS_PARMS) & status) ;
return bSuccess ? status.dwReturn : 0 ;
}
#define MciMidiGetMode(wDeviceID, hwnd, dwFlags) \
MciMidiGet ((wDeviceID), (hwnd), (dwFlags), MCI_STATUS_MODE)
#define MciMidiGetDivType(wDeviceID, hwnd, dwFlags) \
MciMidiGet ((wDeviceID), (hwnd), (dwFlags), MCI_SEQ_STATUS_DIVTYPE)
#define MciMidiGetFormat(wDeviceID, hwnd, dwFlags) \
MciMidiGet ((wDeviceID), (hwnd), (dwFlags), MCI_STATUS_TIME_FORMAT)
#define MciMidiGetLength(wDeviceID, hwnd, dwFlags) \
MciMidiGet ((wDeviceID), (hwnd), (dwFlags), MCI_STATUS_LENGTH)
#define MciMidiGetPosition(wDeviceID, hwnd, dwFlags) \
MciMidiGet ((wDeviceID), (hwnd), (dwFlags), MCI_STATUS_POSITION)
#define MciMidiGetTempo(wDeviceID, hwnd, dwFlags) \
MciMidiGet ((wDeviceID), (hwnd), (dwFlags), MCI_SEQ_STATUS_TEMPO)
/*----------------------------------------
Functions to set time format and tempo
----------------------------------------*/
BOOL MciMidiSetFormat (UINT wDeviceID, HWND hwnd, DWORD dwFlags, DWORD dwFormat)
{
MCI_SEQ_SET_PARMS set ;
set.dwCallback = (HWND) hwnd ;
set.dwTimeFormat = dwFormat ;
return MciSend (wDeviceID, MCI_SET, dwFlags | MCI_SET_TIME_FORMAT,
(DWORD) (LPMCI_SEQ_SET_PARMS) & set) ;
}
BOOL MciMidiSetTempo (UINT wDeviceID, HWND hwnd, DWORD dwFlags, DWORD dwTempo)
{
MCI_SEQ_SET_PARMS set ;
set.dwCallback = (HWND) hwnd ;
set.dwTempo = dwTempo ;
return MciSend (wDeviceID, MCI_SET, dwFlags | MCI_SEQ_SET_TEMPO,
(DWORD) (LPMCI_SEQ_SET_PARMS) & set) ;
}
/*---------------------------------
Update the labels on the window
---------------------------------*/
void UpdateLabels (UINT wDeviceID, HWND hwnd)
{
char szPosBeg [16], szPosEnd [16], szPosition [40], szTempo [40] ;
DWORD dwDivType, dwFormat, dwLength, dwPosition, dwTempo ;
UINT iPosition, iTempo ;
// Get information
dwDivType = MciMidiGetDivType (wDeviceID, hwnd, MCI_WAIT) ;
dwFormat = MciMidiGetFormat (wDeviceID, hwnd, MCI_WAIT) ;
dwLength = MciMidiGetLength (wDeviceID, hwnd, MCI_WAIT) ;
dwPosition = MciMidiGetPosition (wDeviceID, hwnd, MCI_WAIT) ;
dwTempo = MciMidiGetTempo (wDeviceID, hwnd, MCI_WAIT) ;
// Format the length and position values, calculate position scroll
if (dwFormat == MCI_FORMAT_MILLISECONDS ||
dwFormat == MCI_SEQ_FORMAT_SONGPTR)
{
wsprintf (szPosBeg, "0") ;
wsprintf (szPosEnd, "%ld", dwLength) ;
wsprintf (szPosition, "Position: %ld %s", dwPosition,
(LPSTR) (dwFormat == MCI_FORMAT_MILLISECONDS ?
"milliseconds" : "sixteenth notes")) ;
iPosition = (UINT) (1000 * dwPosition / dwLength) ;
}
else
{
wsprintf (szPosBeg, "00:00:00:00") ;
wsprintf (szPosEnd, "%02d:%02d:%02d:%02d",
LOBYTE (LOWORD (dwLength)), HIBYTE (LOWORD (dwLength)),
LOBYTE (HIWORD (dwLength)), HIBYTE (HIWORD (dwLength))) ;
wsprintf (szPosition, "Position: %02d:%02d:%02d:%02d",
LOBYTE (LOWORD (dwPosition)), HIBYTE (LOWORD (dwPosition)),
LOBYTE (HIWORD (dwPosition)), HIBYTE (HIWORD (dwPosition))) ;
// (switch to millisecond format for scroll bar calc)
MciMidiSetFormat (wDeviceID, hwnd,
MCI_WAIT, MCI_FORMAT_MILLISECONDS) ;
iPosition = (UINT) (1000 *
MciMidiGetPosition (wDeviceID, hwnd, MCI_WAIT) /
MciMidiGetLength (wDeviceID, hwnd, MCI_WAIT)) ;
MciMidiSetFormat (wDeviceID, hwnd, MCI_WAIT, dwFormat) ;
}
// Format the tempo, calculate tempo scroll
if (dwDivType == MCI_SEQ_DIV_PPQN)
{
wsprintf (szTempo, "Tempo: %ld quarter notes per minute", dwTempo) ;
iTempo = (UINT) (max (MIN_TEMPO_BPS, min (dwTempo, MAX_TEMPO_BPS))) ;
}
else
{
wsprintf (szTempo, "Tempo: %ld frames per second", dwTempo) ;
iTempo = (UINT) (max (MIN_TEMPO_SMPTE,
min (dwTempo, MAX_TEMPO_SMPTE))) ;
}
// Set text and scroll bar positions
SetDlgItemText (hwnd, ID_POSBEG, szPosBeg) ;
SetDlgItemText (hwnd, ID_POSEND, szPosEnd) ;
SetDlgItemText (hwnd, ID_POSTEXT, szPosition) ;
SetDlgItemText (hwnd, ID_TMPTEXT, szTempo) ;
SetScrollPos (GetDlgItem (hwnd, ID_POSITION), SB_CTL, iPosition, TRUE) ;
SetScrollPos (GetDlgItem (hwnd, ID_TEMPO), SB_CTL, iTempo, TRUE) ;
}
/*---------------------------
Main dialog box procedure
---------------------------*/
BOOL FAR PASCAL _export DlgProc (HWND hwnd, UINT message, UINT wParam,
LONG lParam)
{
static char szFileName [_MAX_PATH],
szTitleName [_MAX_FNAME + _MAX_EXT] ;
static char * szFilter[] = { "MIDI Sequencer (*.mid;*.rmi)",
"*.mid;*.rmi", "" } ;
static DWORD dwFormats [] = { MCI_FORMAT_MILLISECONDS,
MCI_SEQ_FORMAT_SONGPTR,
MCI_FORMAT_SMPTE_24,
MCI_FORMAT_SMPTE_25,
MCI_FORMAT_SMPTE_30,
MCI_FORMAT_SMPTE_30DROP } ;
static OPENFILENAME ofn = { sizeof (OPENFILENAME) } ;
static UINT wDeviceID ;
int i, iPosition, iTempo, iMin, iMax ;
DWORD dwDivType, dwFormat, dwMode ;
switch (message)
{
case WM_INITDIALOG:
// Initialize OPENFILENAME structure
ofn.hwndOwner = hwnd ;
ofn.lpstrFilter = szFilter [0] ;
ofn.lpstrFile = szFileName ;
ofn.nMaxFile = sizeof (szFileName) ;
ofn.lpstrFileTitle = szTitleName ;
ofn.nMaxFileTitle = sizeof (szTitleName) ;
ofn.Flags = OFN_FILEMUSTEXIST |
OFN_PATHMUSTEXIST ;
ofn.lpstrDefExt = "mid" ;
// Initialize position scroll bar
SetScrollRange (GetDlgItem (hwnd, ID_POSITION),
SB_CTL, 0, 1000, FALSE) ;
SetScrollPos (GetDlgItem (hwnd, ID_POSITION),
SB_CTL, 0, FALSE) ;
return TRUE ;
case WM_COMMAND:
switch (wParam)
{
case ID_OPEN:
// Display open-file dialog box
if (!GetOpenFileName (&ofn))
return TRUE ;
// Open the file
wDeviceID = MciMidiOpen (hwnd, szFileName, MCI_WAIT) ;
if (0 == wDeviceID)
return TRUE ;
// Possibly disable song pointer button
dwDivType = MciMidiGetDivType (wDeviceID, hwnd,
MCI_WAIT) ;
EnableDlgWindow (hwnd, ID_SONGPTR,
dwDivType == MCI_SEQ_DIV_PPQN) ;
// Set the tempo scroll bar range
if (dwDivType == MCI_SEQ_DIV_PPQN)
{
SetScrollRange (GetDlgItem (hwnd, ID_TEMPO),
SB_CTL, MIN_TEMPO_BPS, MAX_TEMPO_BPS, TRUE) ;
SetDlgItemInt (hwnd, ID_TMPMIN, MIN_TEMPO_BPS,
FALSE) ;
SetDlgItemInt (hwnd, ID_TMPMAX, MAX_TEMPO_BPS,
FALSE) ;
}
else
{
SetScrollRange (GetDlgItem (hwnd, ID_TEMPO),
SB_CTL, MIN_TEMPO_SMPTE, MAX_TEMPO_SMPTE,
TRUE) ;
SetDlgItemInt (hwnd, ID_TMPMIN, MIN_TEMPO_SMPTE,
FALSE) ;
SetDlgItemInt (hwnd, ID_TMPMAX, MAX_TEMPO_SMPTE,
FALSE) ;
}
// Find the default time format
dwFormat = MciMidiGetFormat (wDeviceID, hwnd,
MCI_WAIT) ;
for (i = 0 ; i < 6 ; i++)
if (dwFormat == dwFormats [i])
break ;
CheckRadioButton (hwnd, ID_MILLISECS,
ID_SMPTE30DF, ID_MILLISECS + i) ;
// Display labels
iPosition = 0 ;
UpdateLabels (wDeviceID, hwnd) ;
// Ready to play
EnableDlgWindow (hwnd, ID_OPEN, FALSE) ;
EnableDlgWindow (hwnd, ID_PLAY, TRUE) ;
EnableDlgWindow (hwnd, ID_CLOSE, TRUE) ;
SetFocus (GetDlgItem (hwnd, ID_PLAY)) ;
return TRUE ;
case ID_PLAY:
if (MciMidiPlay (wDeviceID, hwnd, MCI_NOTIFY, 0, 0))
{
EnableDlgWindow (hwnd, ID_PLAY, FALSE) ;
EnableDlgWindow (hwnd, ID_PAUSE, TRUE) ;
EnableDlgWindow (hwnd, ID_STOP, TRUE) ;
EnableDlgWindow (hwnd, ID_CLOSE, FALSE) ;
SetFocus (GetDlgItem (hwnd, ID_STOP)) ;
SetTimer (hwnd, 1, 250, NULL) ;
}
return TRUE ;
case ID_PAUSE:
if (MciMidiPause (wDeviceID, hwnd, MCI_WAIT))
{
EnableDlgWindow (hwnd, ID_PLAY, TRUE) ;
EnableDlgWindow (hwnd, ID_PAUSE, FALSE) ;
SetFocus (GetDlgItem (hwnd, ID_PLAY)) ;
KillTimer (hwnd, 1) ;
UpdateLabels (wDeviceID, hwnd) ;
}
return TRUE ;
case ID_STOP:
if (MciMidiStop (wDeviceID, hwnd, MCI_WAIT))
{
EnableDlgWindow (hwnd, ID_PLAY, TRUE) ;
EnableDlgWindow (hwnd, ID_PAUSE, FALSE) ;
EnableDlgWindow (hwnd, ID_STOP, FALSE) ;
EnableDlgWindow (hwnd, ID_CLOSE, TRUE) ;
SetFocus (GetDlgItem (hwnd, ID_PLAY)) ;
KillTimer (hwnd, 1) ;
UpdateLabels (wDeviceID, hwnd) ;
}
return 0 ;
case ID_CLOSE:
if (MciMidiClose (wDeviceID, hwnd, MCI_WAIT))
{
EnableDlgWindow (hwnd, ID_OPEN, TRUE) ;
EnableDlgWindow (hwnd, ID_PLAY, FALSE) ;
EnableDlgWindow (hwnd, ID_CLOSE, FALSE) ;
SetFocus (GetDlgItem (hwnd, ID_OPEN)) ;
wDeviceID = 0 ;
}
return TRUE ;
case ID_MILLISECS:
case ID_SONGPTR:
case ID_SMPTE24:
case ID_SMPTE25:
case ID_SMPTE30:
case ID_SMPTE30DF:
dwFormat = wParam - ID_MILLISECS ;
if (MciMidiSetFormat (wDeviceID, hwnd, MCI_WAIT,
dwFormats [dwFormat]))
{
CheckRadioButton (hwnd, ID_MILLISECS,
ID_SMPTE30DF, wParam) ;
UpdateLabels (wDeviceID, hwnd) ;
}
return TRUE ;
default:
break ;
}
return TRUE ;
case WM_HSCROLL:
switch (GetDlgCtrlID (HIWORD (lParam)))
{
case ID_POSITION:
iPosition = GetScrollPos (
GetDlgItem (hwnd, ID_POSITION), SB_CTL) ;
switch (wParam)
{
case SB_LEFT: iPosition = 0 ; break ;
case SB_LINELEFT: iPosition -= 10 ; break ;
case SB_PAGELEFT: iPosition -= 100 ; break ;
case SB_PAGERIGHT: iPosition += 100 ; break ;
case SB_LINERIGHT: iPosition += 10 ; break ;
case SB_RIGHT: iPosition = 1000 ; break ;
case SB_THUMBPOSITION:
iPosition = LOWORD (lParam) ;
break ;
default:
return TRUE ;
}
iPosition = max (0, min (iPosition, 1000)) ;
SetScrollPos (GetDlgItem (hwnd, ID_POSITION),
SB_CTL, iPosition, FALSE) ;
if (wDeviceID)
{
// Save existing time format
dwFormat = MciMidiGetFormat (wDeviceID, hwnd,
MCI_WAIT) ;
// Set time format to milliseconds
MciMidiSetFormat (wDeviceID, hwnd, MCI_WAIT,
MCI_FORMAT_MILLISECONDS) ;
// Find out if we're currently playing
dwMode = MciMidiGetMode (wDeviceID, hwnd,
MCI_WAIT) ;
// Perform a seek
MciMidiSeek (wDeviceID, hwnd, MCI_WAIT | MCI_TO,
iPosition * MciMidiGetLength (wDeviceID,
hwnd, MCI_WAIT) / 1000) ;
// Reset the time format
MciMidiSetFormat (wDeviceID, hwnd,
MCI_WAIT, dwFormat) ;
// Update the scroll bar labels
UpdateLabels (wDeviceID, hwnd) ;
// Continue playing
if (dwMode == MCI_MODE_PLAY)
SendMessage (hwnd, WM_COMMAND, ID_PLAY, 0L) ;
}
return TRUE ;
case ID_TEMPO:
iTempo = GetScrollPos (
GetDlgItem (hwnd, ID_TEMPO), SB_CTL) ;
GetScrollRange (GetDlgItem (hwnd, ID_TEMPO), SB_CTL,
&iMin, &iMax) ;
switch (wParam)
{
case SB_LEFT: iTempo = iMin ; break ;
case SB_LINELEFT: iTempo -= 1 ; break ;
case SB_PAGELEFT: iTempo -= 10 ; break ;
case SB_PAGERIGHT: iTempo += 10 ; break ;
case SB_LINERIGHT: iTempo += 1 ; break ;
case SB_RIGHT: iTempo = iMax ; break ;
case SB_THUMBPOSITION:
iTempo = LOWORD (lParam) ;
break ;
default:
return TRUE ;
}
iTempo = max (iMin, min (iTempo, iMax)) ;
SetScrollPos (GetDlgItem (hwnd, ID_TEMPO),
SB_CTL, iTempo, FALSE) ;
if (wDeviceID)
{
// Set the new tempo
MciMidiSetTempo (wDeviceID, hwnd,
MCI_WAIT, iTempo) ;
// Update the scroll bar labels
UpdateLabels (wDeviceID, hwnd) ;
}
return TRUE ;
}
return TRUE ;
case WM_TIMER:
UpdateLabels (wDeviceID, hwnd) ;
return TRUE ;
case MM_MCINOTIFY:
if (wParam == MCI_NOTIFY_SUCCESSFUL)
SendMessage (hwnd, WM_COMMAND, ID_STOP, 0L) ;
return TRUE ;
case WM_SYSCOMMAND:
switch (wParam)
{
case SC_CLOSE:
if (wDeviceID)
SendMessage (hwnd, WM_COMMAND, ID_CLOSE, 0L) ;
EndDialog (hwnd, 0) ;
return TRUE ;
}
break ;
}
return FALSE ;
}