📄 drum.c
字号:
// Convert mouse coordinates to grid coordinates
x = LOWORD (lParam) / cxChar - 40 ;
y = 2 * HIWORD (lParam) / cyChar - 2 ;
// Set a new number of beats of sequence
if (x > 0 && x <= 32 && y < 0)
{
SetTextColor (hdc, RGB (255, 255, 255)) ;
TextOut (hdc, (40 + drum.iNumBeats) * cxChar, 0, TEXT (":|"), 2);
SetTextColor (hdc, RGB (0, 0, 0)) ;
if (drum.iNumBeats % 4 == 0)
TextOut (hdc, (40 + drum.iNumBeats) * cxChar, 0,
TEXT ("."), 1) ;
drum.iNumBeats = x ;
TextOut (hdc, (40 + drum.iNumBeats) * cxChar, 0, TEXT (":|"), 2);
bNeedSave = TRUE ;
}
// Set or reset a percussion instrument beat
if (x >= 0 && x < 32 && y >= 0 && y < NUM_PERC)
{
if (message == WM_LBUTTONDOWN)
drum.dwSeqPerc[y] ^= (1 << x) ;
else
drum.dwSeqPian[y] ^= (1 << x) ;
DrawRectangle (hdc, x, y, drum.dwSeqPerc, drum.dwSeqPian) ;
bNeedSave = TRUE ;
}
ReleaseDC (hwnd, hdc) ;
DrumSetParams (&drum) ;
return 0 ;
case WM_HSCROLL:
// Change the note velocity
switch (LOWORD (wParam))
{
case SB_LINEUP: drum.iVelocity -= 1 ; break ;
case SB_LINEDOWN: drum.iVelocity += 1 ; break ;
case SB_PAGEUP: drum.iVelocity -= 8 ; break ;
case SB_PAGEDOWN: drum.iVelocity += 8 ; break ;
case SB_THUMBPOSITION:
drum.iVelocity = HIWORD (wParam) ;
break ;
default:
return 0 ;
}
drum.iVelocity = max (1, min (drum.iVelocity, 127)) ;
SetScrollPos (hwnd, SB_HORZ, drum.iVelocity, TRUE) ;
DrumSetParams (&drum) ;
bNeedSave = TRUE ;
return 0 ;
case WM_VSCROLL:
// Change the tempo
switch (LOWORD (wParam))
{
case SB_LINEUP: iTempo -= 1 ; break ;
case SB_LINEDOWN: iTempo += 1 ; break ;
case SB_PAGEUP: iTempo -= 10 ; break ;
case SB_PAGEDOWN: iTempo += 10 ; break ;
case SB_THUMBPOSITION:
iTempo = HIWORD (wParam) ;
break ;
default:
return 0 ;
}
iTempo = max (0, min (iTempo, 100)) ;
SetScrollPos (hwnd, SB_VERT, iTempo, TRUE) ;
drum.iMsecPerBeat = (WORD) (10 * pow (100, iTempo / 100.0)) ;
DrumSetParams (&drum) ;
bNeedSave = TRUE ;
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
SetTextAlign (hdc, TA_UPDATECP) ;
SetBkMode (hdc, TRANSPARENT) ;
// Draw the text strings and horizontal lines
for (i = 0 ; i < NUM_PERC ; i++)
{
MoveToEx (hdc, i & 1 ? 20 * cxChar : cxChar,
(2 * i + 3) * cyChar / 4, NULL) ;
TextOut (hdc, 0, 0, szPerc [i], lstrlen (szPerc [i])) ;
GetCurrentPositionEx (hdc, &point) ;
MoveToEx (hdc, point.x + cxChar, point.y + cyChar / 2, NULL) ;
LineTo (hdc, 39 * cxChar, point.y + cyChar / 2) ;
}
SetTextAlign (hdc, 0) ;
// Draw rectangular grid, repeat mark, and beat marks
for (x = 0 ; x < 32 ; x++)
{
for (y = 0 ; y < NUM_PERC ; y++)
DrawRectangle (hdc, x, y, drum.dwSeqPerc, drum.dwSeqPian) ;
SetTextColor (hdc, x == drum.iNumBeats - 1 ?
RGB (0, 0, 0) : RGB (255, 255, 255)) ;
TextOut (hdc, (41 + x) * cxChar, 0, TEXT (":|"), 2) ;
SetTextColor (hdc, RGB (0, 0, 0)) ;
if (x % 4 == 0)
TextOut (hdc, (40 + x) * cxChar, 0, TEXT ("."), 1) ;
}
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_USER_NOTIFY:
// Draw the "bouncing ball"
hdc = GetDC (hwnd) ;
SelectObject (hdc, GetStockObject (NULL_PEN)) ;
SelectObject (hdc, GetStockObject (WHITE_BRUSH)) ;
for (i = 0 ; i < 2 ; i++)
{
x = iIndexLast ;
y = NUM_PERC + 1 ;
Ellipse (hdc, (x + 40) * cxChar, (2 * y + 3) * cyChar / 4,
(x + 41) * cxChar, (2 * y + 5) * cyChar / 4);
iIndexLast = wParam ;
SelectObject (hdc, GetStockObject (BLACK_BRUSH)) ;
}
ReleaseDC (hwnd, hdc) ;
return 0 ;
case WM_USER_ERROR:
ErrorMessage (hwnd, TEXT ("Can't set timer event for tempo"),
szTitleName) ;
// fall through
case WM_USER_FINISHED:
DrumEndSequence (TRUE) ;
CheckMenuItem (hMenu, IDM_SEQUENCE_RUNNING, MF_UNCHECKED) ;
CheckMenuItem (hMenu, IDM_SEQUENCE_STOPPED, MF_CHECKED) ;
return 0 ;
case WM_CLOSE:
if (!bNeedSave || IDCANCEL != AskAboutSave (hwnd, szTitleName))
DestroyWindow (hwnd) ;
return 0 ;
case WM_QUERYENDSESSION:
if (!bNeedSave || IDCANCEL != AskAboutSave (hwnd, szTitleName))
return 1L ;
return 0 ;
case WM_DESTROY:
DrumEndSequence (TRUE) ;
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
BOOL CALLBACK AboutProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE ;
case WM_COMMAND:
switch (LOWORD (wParam))
{
case IDOK:
EndDialog (hDlg, 0) ;
return TRUE ;
}
break ;
}
return FALSE ;
}
void DrawRectangle (HDC hdc, int x, int y, DWORD * dwSeqPerc, DWORD * dwSeqPian)
{
int iBrush ;
if (dwSeqPerc [y] & dwSeqPian [y] & (1L << x))
iBrush = BLACK_BRUSH ;
else if (dwSeqPerc [y] & (1L << x))
iBrush = DKGRAY_BRUSH ;
else if (dwSeqPian [y] & (1L << x))
iBrush = LTGRAY_BRUSH ;
else
iBrush = WHITE_BRUSH ;
SelectObject (hdc, GetStockObject (iBrush)) ;
Rectangle (hdc, (x + 40) * cxChar , (2 * y + 4) * cyChar / 4,
(x + 41) * cxChar + 1, (2 * y + 6) * cyChar / 4 + 1) ;
}
void ErrorMessage (HWND hwnd, TCHAR * szError, TCHAR * szTitleName)
{
wsprintf (szBuffer, szError,
(LPSTR) (szTitleName [0] ? szTitleName : szUntitled)) ;
MessageBeep (MB_ICONEXCLAMATION) ;
MessageBox (hwnd, szBuffer, szAppName, MB_OK | MB_ICONEXCLAMATION) ;
}
void DoCaption (HWND hwnd, TCHAR * szTitleName)
{
wsprintf (szBuffer, TEXT ("MIDI Drum Machine - %s"),
(LPSTR) (szTitleName [0] ? szTitleName : szUntitled)) ;
SetWindowText (hwnd, szBuffer) ;
}
int AskAboutSave (HWND hwnd, TCHAR * szTitleName)
{
int iReturn ;
wsprintf (szBuffer, TEXT ("Save current changes in %s?"),
(LPSTR) (szTitleName [0] ? szTitleName : szUntitled)) ;
iReturn = MessageBox (hwnd, szBuffer, szAppName,
MB_YESNOCANCEL | MB_ICONQUESTION) ;
if (iReturn == IDYES)
if (!SendMessage (hwnd, WM_COMMAND, IDM_FILE_SAVE, 0))
iReturn = IDCANCEL ;
return iReturn ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -