www.pudn.com > instruments.zip > instruments.cpp


// instruments.cpp : Defines the entry point for the application. 
// 
#include "stdafx.h" 
#include "instruments.h" 
#include  
#include  
#include  
#include  
#include  
 
#define MAX_LOADSTRING 100 
#define NOTENUM 12 
 
struct { 
	int nOctave; 
	int nNote; 
	char cChar; 
} notes[] = { 
	5,  0,  'C',     //  16     q    5    C 
	5,  2,  'D',     //  17     w    5    D 
	5,  4,  'E',     //  18     e    5    E 
	5,  5,  'F',     //  19     r    5    F 
	5,  7,  'G',     //  20     t    5    G 
	5,  9,  'A',     //  21     y    5    A 
	5, 11,  'B',     //  22     u    5    B 
	6,  0,  'C',     //  23     i    6    C 
	6,  2,  'D',     //  24     o    6    D 
	6,  4,  'E',     //  25     p    6    E 
	6,  5,  'F',     //  26     [    6    F 
	6,  7,  'G',     //  27     ]    6    G 
}; 
 
// Global Variables: 
HINSTANCE hInst;								// current instance 
TCHAR szTitle[MAX_LOADSTRING];					// The title bar text 
TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name 
 
// Forward declarations of functions included in this code module: 
ATOM				MyRegisterClass(HINSTANCE hInstance); 
BOOL				InitInstance(HINSTANCE, int); 
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM); 
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM); 
 
// Helper functions 
DWORD myMidiOutMessage (HMIDIOUT hMidi, int iStatus, int iChannel, 
    int iData1,  int iData2) 
{ 
    DWORD dwMessage ; 
 
    dwMessage = iStatus | iChannel | (iData1 << 8) | (iData2 << 16) ; 
 
    return midiOutShortMsg (hMidi, dwMessage) ; 
} 
 
DWORD myMidiNoteOff (HMIDIOUT hMidi, int iChannel, int iOct, int iNote, int iVel) 
{ 
	return myMidiOutMessage (hMidi, 0x080, iChannel, 12 * iOct + iNote, iVel) ; 
} 
 
DWORD myMidiNoteOn (HMIDIOUT hMidi, int iChannel, int iOct, int iNote, int iVel) 
{ 
	return myMidiOutMessage (hMidi, 0x090, iChannel, 12 * iOct + iNote, iVel) ; 
} 
 
DWORD myMidiSetPatch (HMIDIOUT hMidi, int iChannel, int iVoice) 
{ 
	return myMidiOutMessage (hMidi, 0x0C0, iChannel, iVoice, 0) ; 
} 
 
void drawKey( HDC hDc, int x, int y, int width, int height ){ 
	MoveToEx( hDc, x, y, NULL ); 
	LineTo( hDc, x+width, y ); 
	LineTo( hDc, x+width, y+height ); 
	MoveToEx( hDc, x, y+height, NULL ); 
	LineTo( hDc, x, y ); 
} 
 
 
int APIENTRY _tWinMain(HINSTANCE hInstance, 
                     HINSTANCE hPrevInstance, 
                     LPTSTR    lpCmdLine, 
                     int       nCmdShow) 
{ 
	UNREFERENCED_PARAMETER(hPrevInstance); 
	UNREFERENCED_PARAMETER(lpCmdLine); 
 
 	// TODO: Place code here. 
	MSG msg; 
	HACCEL hAccelTable; 
 
	// Initialize global strings 
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 
	LoadString(hInstance, IDC_INSTRUMENTS, szWindowClass, MAX_LOADSTRING); 
	MyRegisterClass(hInstance); 
 
	// Perform application initialization: 
	if (!InitInstance (hInstance, nCmdShow)) 
	{ 
		return FALSE; 
	} 
 
	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_INSTRUMENTS)); 
 
	// Main message loop: 
	while (GetMessage(&msg, NULL, 0, 0)) 
	{ 
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
		{ 
			TranslateMessage(&msg); 
			DispatchMessage(&msg); 
		} 
	} 
 
	return (int) msg.wParam; 
} 
 
 
 
// 
//  FUNCTION: MyRegisterClass() 
// 
//  PURPOSE: Registers the window class. 
// 
//  COMMENTS: 
// 
//    This function and its usage are only necessary if you want this code 
//    to be compatible with Win32 systems prior to the 'RegisterClassEx' 
//    function that was added to Windows 95. It is important to call this function 
//    so that the application will get 'well formed' small icons associated 
//    with it. 
// 
ATOM MyRegisterClass(HINSTANCE hInstance) 
{ 
	WNDCLASSEX wcex; 
 
	wcex.cbSize = sizeof(WNDCLASSEX); 
 
	wcex.style			= CS_HREDRAW | CS_VREDRAW; 
	wcex.lpfnWndProc	= WndProc; 
	wcex.cbClsExtra		= 0; 
	wcex.cbWndExtra		= 0; 
	wcex.hInstance		= hInstance; 
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_INSTRUMENTS)); 
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW); 
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1); 
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_INSTRUMENTS); 
	wcex.lpszClassName	= szWindowClass; 
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); 
 
	return RegisterClassEx(&wcex); 
} 
 
// 
//   FUNCTION: InitInstance(HINSTANCE, int) 
// 
//   PURPOSE: Saves instance handle and creates main window 
// 
//   COMMENTS: 
// 
//        In this function, we save the instance handle in a global variable and 
//        create and display the main program window. 
// 
BOOL InitInstance( HINSTANCE hInstance, int nCmdShow ) 
{ 
   HWND hWnd; 
 
   hInst = hInstance; // Store instance handle in our global variable 
 
   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, 
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); 
 
   if (!hWnd) 
   { 
      return FALSE; 
   } 
 
   ShowWindow(hWnd, nCmdShow); 
   UpdateWindow(hWnd); 
 
   return TRUE; 
} 
 
// 
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) 
// 
//  PURPOSE:  Processes messages for the main window. 
// 
//  WM_COMMAND	- process the application menu 
//  WM_PAINT	- Paint the main window 
//  WM_DESTROY	- post a quit message and return 
// 
// 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
	int wmId, wmEvent; 
	PAINTSTRUCT ps; 
	HDC hdc; 
	static HMIDIOUT hMidiOut; 
	static bool isOpened = false; 
	static int nVelocity = 65; 
	static int nVoice = 0; // Acoustic grand piano 
	static int nChannel = 0; // Only one channel 
	static int xOffset, yOffset; 
	static int cxKeyWidth; 
	static int cyKeyHeight; 
	static int height, width; 
	 
	HMENU hMenu; 
	RECT rect; 
 
	switch (message) 
	{ 
	case WM_SIZE: 
		height = HIWORD( lParam ); 
		width = LOWORD( lParam ); 
		yOffset = height/2; 
 
		cyKeyHeight = height/2; 
		// Calculate key width 
		cxKeyWidth = ( width-100 )/12; 
		if( cxKeyWidth < 20 ) 
			cxKeyWidth = 20; 
		if( cxKeyWidth > 50 ) 
			cxKeyWidth = 50; 
 
		xOffset = width/2 - 6*cxKeyWidth; 
		 
		break; 
	case WM_COMMAND: 
		wmId    = LOWORD(wParam); 
		wmEvent = HIWORD(wParam); 
		// Parse the menu selections: 
		switch (wmId) 
		{ 
		case IDM_RUN: 
			if( isOpened == false ){ 
 
				// Open the deivice 
				if( midiOutOpen( &hMidiOut, 0, (DWORD_PTR)hWnd, 0, CALLBACK_WINDOW ) != MMSYSERR_NOERROR ){ 
					MessageBox( hWnd, "Can't open midi device!", "Eorror", MB_ICONEXCLAMATION|MB_OK ); 
					break; 
				} 
				isOpened = true; 
 
				// Set the voice in the channel 
				myMidiSetPatch( hMidiOut, nChannel, nVoice );						 
 
				// Check menu item 
				hMenu = GetMenu( hWnd ); 
				CheckMenuItem( hMenu, IDM_RUN, MF_CHECKED ); 
			}else{ 
				 
				midiOutReset( hMidiOut ); 
				midiOutClose( hMidiOut ); 
				isOpened = false; 
 
				hMenu = GetMenu( hWnd ); 
				CheckMenuItem( hMenu, IDM_RUN, MF_UNCHECKED ); 
			} 
			InvalidateRect(hWnd, NULL, TRUE); 
			 
			break; 
		case IDM_ABOUT: 
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); 
			break; 
		case IDM_EXIT: 
			DestroyWindow(hWnd); 
			break; 
		default: 
			return DefWindowProc(hWnd, message, wParam, lParam); 
		} 
		break; 
	 
	case WM_KEYDOWN: 
	case WM_KEYUP: 
 
		// If device is not opened, nothing will happen 
		if( isOpened == false ) 
			break; 
 
		int nScanCode; 
		int nOctave, nNote; 
		HBRUSH hBrush; 
 
		// Get scan code 
		nScanCode = HIWORD( lParam )&0xff; 
		 
		// If the scan code falls in the range 16-27 
		if( ( nScanCode >= 16 ) && ( nScanCode <= 27 ) ){ 
			nScanCode -= 16; 
			nOctave = notes[nScanCode].nOctave; 
			nNote = notes[nScanCode].nNote; 
		}else{ 
			break; 
		} 
 
		if( message == WM_KEYDOWN ){ 
			// ignore typematics 
			if (0x40000000 & lParam)	 
				break; 
			myMidiNoteOn( hMidiOut, nChannel, nOctave, nNote, nVelocity ); 
			hBrush = (HBRUSH)GetStockObject( BLACK_BRUSH ); 
		}else{ 
			myMidiNoteOff( hMidiOut, nChannel, nOctave, nNote, nVelocity ); 
			hBrush = (HBRUSH)GetStockObject( WHITE_BRUSH ); 
		} 
 
		// Get gdi object 
		hdc = GetDC( hWnd ); 
 
		rect.bottom = yOffset + cyKeyHeight; 
		rect.top = yOffset; 
		rect.left = xOffset + nScanCode*cxKeyWidth; 
		rect.right = rect.left + cxKeyWidth; 
		// Carefull for the key block frame 
		rect.left += 1; 
		rect.top += 1; 
		// Paint the key block that user just hit 
		FillRect( hdc, &rect, hBrush );  
 
		ReleaseDC( hWnd, hdc ); 
		break; 
 
	case WM_PAINT: 
		hdc = BeginPaint(hWnd, &ps); 
		// TODO: Add any drawing code here... 
		int i; 
		char buffer[2]; 
		for( i=0; i