📄 drum.c
字号:
/*-------------------------------------
DRUM.C -- MIDI Drum Machine
(c) Charles Petzold, 1998
-------------------------------------*/
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "drumtime.h"
#include "drumfile.h"
#include "resource.h"
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
BOOL CALLBACK AboutProc (HWND, UINT, WPARAM, LPARAM) ;
void DrawRectangle (HDC, int, int, DWORD *, DWORD *) ;
void ErrorMessage (HWND, TCHAR *, TCHAR *) ;
void DoCaption (HWND, TCHAR *) ;
int AskAboutSave (HWND, TCHAR *) ;
TCHAR * szPerc [NUM_PERC] =
{
TEXT ("Acoustic Bass Drum"), TEXT ("Bass Drum 1"),
TEXT ("Side Stick"), TEXT ("Acoustic Snare"),
TEXT ("Hand Clap"), TEXT ("Electric Snare"),
TEXT ("Low Floor Tom"), TEXT ("Closed High Hat"),
TEXT ("High Floor Tom"), TEXT ("Pedal High Hat"),
TEXT ("Low Tom"), TEXT ("Open High Hat"),
TEXT ("Low-Mid Tom"), TEXT ("High-Mid Tom"),
TEXT ("Crash Cymbal 1"), TEXT ("High Tom"),
TEXT ("Ride Cymbal 1"), TEXT ("Chinese Cymbal"),
TEXT ("Ride Bell"), TEXT ("Tambourine"),
TEXT ("Splash Cymbal"), TEXT ("Cowbell"),
TEXT ("Crash Cymbal 2"), TEXT ("Vibraslap"),
TEXT ("Ride Cymbal 2"), TEXT ("High Bongo"),
TEXT ("Low Bongo"), TEXT ("Mute High Conga"),
TEXT ("Open High Conga"), TEXT ("Low Conga"),
TEXT ("High Timbale"), TEXT ("Low Timbale"),
TEXT ("High Agogo"), TEXT ("Low Agogo"),
TEXT ("Cabasa"), TEXT ("Maracas"),
TEXT ("Short Whistle"), TEXT ("Long Whistle"),
TEXT ("Short Guiro"), TEXT ("Long Guiro"),
TEXT ("Claves"), TEXT ("High Wood Block"),
TEXT ("Low Wood Block"), TEXT ("Mute Cuica"),
TEXT ("Open Cuica"), TEXT ("Mute Triangle"),
TEXT ("Open Triangle")
} ;
TCHAR szAppName [] = TEXT ("Drum") ;
TCHAR szUntitled [] = TEXT ("(Untitled)") ;
TCHAR szBuffer [80 + MAX_PATH] ;
HANDLE hInst ;
int cxChar, cyChar ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
hInst = hInstance ;
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 ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, NULL,
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
WS_MINIMIZEBOX | WS_HSCROLL | WS_VSCROLL,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, szCmdLine) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL bNeedSave ;
static DRUM drum ;
static HMENU hMenu ;
static int iTempo = 50, iIndexLast ;
static TCHAR szFileName [MAX_PATH], szTitleName [MAX_PATH] ;
HDC hdc ;
int i, x, y ;
PAINTSTRUCT ps ;
POINT point ;
RECT rect ;
TCHAR * szError ;
switch (message)
{
case WM_CREATE:
// Initialize DRUM structure
drum.iMsecPerBeat = 100 ;
drum.iVelocity = 64 ;
drum.iNumBeats = 32 ;
DrumSetParams (&drum) ;
// Other initialization
cxChar = LOWORD (GetDialogBaseUnits ()) ;
cyChar = HIWORD (GetDialogBaseUnits ()) ;
GetWindowRect (hwnd, &rect) ;
MoveWindow (hwnd, rect.left, rect.top,
77 * cxChar, 29 * cyChar, FALSE) ;
hMenu = GetMenu (hwnd) ;
// Initialize "Volume" scroll bar
SetScrollRange (hwnd, SB_HORZ, 1, 127, FALSE) ;
SetScrollPos (hwnd, SB_HORZ, drum.iVelocity, TRUE) ;
// Initialize "Tempo" scroll bar
SetScrollRange (hwnd, SB_VERT, 0, 100, FALSE) ;
SetScrollPos (hwnd, SB_VERT, iTempo, TRUE) ;
DoCaption (hwnd, szTitleName) ;
return 0 ;
case WM_COMMAND:
switch (LOWORD (wParam))
{
case IDM_FILE_NEW:
if (bNeedSave && IDCANCEL == AskAboutSave (hwnd, szTitleName))
return 0 ;
// Clear drum pattern
for (i = 0 ; i < NUM_PERC ; i++)
{
drum.dwSeqPerc [i] = 0 ;
drum.dwSeqPian [i] = 0 ;
}
InvalidateRect (hwnd, NULL, FALSE) ;
DrumSetParams (&drum) ;
bNeedSave = FALSE ;
return 0 ;
case IDM_FILE_OPEN:
// Save previous file
if (bNeedSave && IDCANCEL ==
AskAboutSave (hwnd, szTitleName))
return 0 ;
// Open the selected file
if (DrumFileOpenDlg (hwnd, szFileName, szTitleName))
{
szError = DrumFileRead (&drum, szFileName) ;
if (szError != NULL)
{
ErrorMessage (hwnd, szError, szTitleName) ;
szTitleName [0] = '\0' ;
}
else
{
// Set new parameters
iTempo = (int) (50 *
(log10 (drum.iMsecPerBeat) - 1)) ;
SetScrollPos (hwnd, SB_VERT, iTempo, TRUE) ;
SetScrollPos (hwnd, SB_HORZ, drum.iVelocity, TRUE) ;
DrumSetParams (&drum) ;
InvalidateRect (hwnd, NULL, FALSE) ;
bNeedSave = FALSE ;
}
DoCaption (hwnd, szTitleName) ;
}
return 0 ;
case IDM_FILE_SAVE:
case IDM_FILE_SAVE_AS:
// Save the selected file
if ((LOWORD (wParam) == IDM_FILE_SAVE && szTitleName [0]) ||
DrumFileSaveDlg (hwnd, szFileName, szTitleName))
{
szError = DrumFileWrite (&drum, szFileName) ;
if (szError != NULL)
{
ErrorMessage (hwnd, szError, szTitleName) ;
szTitleName [0] = '\0' ;
}
else
bNeedSave = FALSE ;
DoCaption (hwnd, szTitleName) ;
}
return 0 ;
case IDM_APP_EXIT:
SendMessage (hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L) ;
return 0 ;
case IDM_SEQUENCE_RUNNING:
// Begin sequence
if (!DrumBeginSequence (hwnd))
{
ErrorMessage (hwnd,
TEXT ("Could not start MIDI sequence -- ")
TEXT ("MIDI Mapper device is unavailable!"),
szTitleName) ;
}
else
{
CheckMenuItem (hMenu, IDM_SEQUENCE_RUNNING, MF_CHECKED) ;
CheckMenuItem (hMenu, IDM_SEQUENCE_STOPPED, MF_UNCHECKED) ;
}
return 0 ;
case IDM_SEQUENCE_STOPPED:
// Finish at end of sequence
DrumEndSequence (FALSE) ;
return 0 ;
case IDM_APP_ABOUT:
DialogBox (hInst, TEXT ("AboutBox"), hwnd, AboutProc) ;
return 0 ;
}
return 0 ;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
hdc = GetDC (hwnd) ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -