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