Results 1 to 4 of 4
  1. #1
    Tekkn0logik's Avatar
    Join Date
    Sep 2010
    Gender
    male
    Posts
    37
    Reputation
    12
    Thanks
    52
    My Mood
    Amused

    Midi Keyboard Program

    Here's a program I wrote. It lets you play the piano (or any MIDI instrument really - there's a nice dropdown to select the instrument) using the first 2 rows of your computer keyboard.

    leet ascii diagram:
    Code:
     2 3   5 6 7   9 0
    q w e r t y u i o p
    It's ANSI C and should compile on anything. Oh, and I put a bunch of comments in, so read the source if you want.

    Not really game hacking related but I thought it was cool enough to post here.

    Code:
    /* A MIDI keyboard application for Windows. Controlled with the first 2 rows
       of the computer keyboard. Should compile on any Windows version down to 
       Windows 3.0 or 3.1. Doesn't use any fancy APIs. */
    #include <Windows.h>
    
    /* The keys used to control the keyboard. */
    static const char *keys = "Q2W3ER5T6Y7UI9O0P";
    /* Note value assigned to each key. */
    static unsigned char values[256];
    /* MIDI octave to play in. */
    static unsigned char octave = 5;
    /* Handle to the MIDI device. */
    static HMIDIOUT hMidi;
    /* Handle to the window. */
    static HWND hWnd;
    /* Handle to the drop-down list. */
    static HWND hDropDown;
    
    /* All the MIDI instruments. */
    static char *patches[] = {
    	"Acoustic Grand Piano",
    	"Bright Acoustic Piano",
    	"Electric Grand Piano",
    	"Honky-tonk Piano",
    	"Rhodes Piano",
    	"Chorused Piano",
    	"Harpsichord",
    	"Clavinet",
    	"Celesta",
    	"Glockenspiel",
    	"Music Box",
    	"Vibraphone",
    	"Marimba",
    	"Xylophone",
    	"Tubular Bells",
    	"Dulcimer",
    	"Hammond Organ",
    	"Percussive Organ",
    	"Rock Organ",
    	"Church Organ",
    	"Reed Organ",
    	"Accordion",
    	"Harmonica",
    	"Tango Accordion",
    	"Acoustic Guitar (nylon)",
    	"Acoustic Guitar (steel)",
    	"Electric Guitar (jazz)",
    	"Electric Guitar (clean)",
    	"Electric Guitar (muted)",
    	"Overdriven Guitar",
    	"Distortion Guitar",
    	"Guitar Harmonics",
    	"Acoustic Bass",
    	"Electric Bass (finger)",
    	"Electric Bass (pick)",
    	"Fretless Bass",
    	"Slap Bass 1",
    	"Slap Bass 2",
    	"Synth Bass 1",
    	"Synth Bass 2",
    	"Violin",
    	"Viola",
    	"Cello",
    	"Contrabass",
    	"Tremolo Strings",
    	"Pizzicato Strings",
    	"Orchestral Harp",
    	"Timpani",
    	"String Ensemble 1",
    	"String Ensemble 2",
    	"SynthStrings 1",
    	"SynthStrings 2",
    	"Choir Aahs",
    	"Voice Oohs",
    	"Synth Voice",
    	"Orchestra Hit",
    	"Trumpet",
    	"Trombone",
    	"Tuba",
    	"Muted Trumpet",
    	"French Horn",
    	"Brass Section",
    	"Synth Brass 1",
    	"Synth Brass 2",
    	"Soprano Sax",
    	"Alto Sax",
    	"Tenor Sax",
    	"Baritone Sax",
    	"Oboe",
    	"English Horn",
    	"Bassoon",
    	"Clarinet",
    	"Piccolo",
    	"Flute",
    	"Recorder",
    	"Pan Flute",
    	"Bottle Blow",
    	"Shakuhachi",
    	"Whistle",
    	"Ocarina",
    	"Lead 1 (square)",
    	"Lead 2 (sawtooth)",
    	"Lead 3 (calliope lead)",
    	"Lead 4 (chiff lead)",
    	"Lead 5 (charang)",
    	"Lead 6 (voice)",
    	"Lead 7 (fifths)",
    	"Lead 8 (bass + lead)",
    	"Pad 1 (new age)",
    	"Pad 2 (warm)",
    	"Pad 3 (polysynth)",
    	"Pad 4 (choir)",
    	"Pad 5 (bowed)",
    	"Pad 6 (metallic)",
    	"Pad 7 (halo)",
    	"Pad 8 (sweep)",
    	"FX 1 (rain)",
    	"FX 2 (soundtrack)",
    	"FX 3 (crystal)",
    	"FX 4 (atmosphere)",
    	"FX 5 (brightness)",
    	"FX 6 (goblins)",
    	"FX 7 (echoes)",
    	"FX 8 (sci-fi)",
    	"Sitar",
    	"Banjo",
    	"Shamisen",
    	"Koto",
    	"Kalimba",
    	"Bagpipe",
    	"Fiddle",
    	"Shanai",
    	"Tinkle Bell",
    	"Agogo",
    	"Steel Drums",
    	"Woodblock",
    	"Taiko Drum",
    	"Melodic Tom",
    	"Synth Drum",
    	"Reverse Cymbal",
    	"Guitar Fret Noise",
    	"Breath Noise",
    	"Seashore",
    	"Bird Tweet",
    	"Telephone Ring",
    	"Helicopter",
    	"Applause",
    	"Gunshot"
    };
    
    /* Sets the key notes based on the octave */
    void setKeyValues(void) {
    	int k, len = strlen(keys);
    	for(k = 0; k < len; k++) {
    		values[keys[k]] = k + (octave * 12);
    	}
    	/* Force a redraw of the window */
    	InvalidateRect(hWnd, NULL, FALSE);
    }
    
    void populateList(void)
    {
    	int k;
    
    	/* Add all the instruments to the list box. */
    	for(k = 0; k < 128; k++)
    		SendMessage(hDropDown, CB_ADDSTRING, (WPARAM) 0, (LPARAM) patches[k]);
    	/* Set the highlighted item to the first one. */
    	SendMessage(hDropDown, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
    }
    
    /* Sends a message to the MIDI output. */
    void sendMIDIMessage(int status, int channel, int data1, int data2)
    {
    	midiOutShortMsg(hMidi, (data2 << 16) | (data1 << 8) | status | channel);
    }
    
    /* Called when a key is pressed down */
    void onKeyDown(unsigned char key)
    {
    	if(key == VK_ESCAPE) { /* exit */
    		PostQuitMessage(0);
    	} else if(key == VK_OEM_COMMA) { /* octave down */
    		if(octave > 1) octave--;
    		setKeyValues();
    	} else if(key == VK_OEM_PERIOD) { /* octave up */
    		if(octave < 10) octave++;
    		setKeyValues();
    	} else if(values[key] != 0) { /* some note key */
    		sendMIDIMessage(0x90, 0, values[key], 127);
    		/* Force a redraw of the window */
    		InvalidateRect(hWnd, NULL, FALSE);
    	}
    }
    
    /* Called when a key is released */
    void onKeyUp(unsigned char key)
    {
    	if(values[key] != 0) { /* end the note by sending a velocity of 0 */
    		sendMIDIMessage(0x90, 0, values[key], 0);
    		/* Force a redraw of the window */
    		InvalidateRect(hWnd, NULL, FALSE);
    	}
    }
    
    /* Returns 1 if the key (0 to 11) is an accidental */
    int isAccidental(unsigned char key)
    {
    	int pos = key % 12;
    	return pos == 1 || pos == 3 || pos == 6 || pos == 8 || pos == 10;
    }
    
    /* Draws the keyboard on the window. */
    void drawKeyboard(HDC hdc)
    {
    	int k, x = 0, y, len = strlen(keys);
    
    	/* Draw the octave */
    	TextOut(hdc, 200, 165, "Octave: ", 8);
    	/* Small note: this next line uses a trick to convert an int to its char
    	   representation. It treats the string "0123456789" as an array of chars
    	   (since that's what strings are) and then uses the octave as an index
    	   into this array. Then, since the TextOut function wants a pointer to
    	   the text, it takes the address of that character. */
    	TextOut(hdc, 260, 165, &"0123456789"[octave - 1], 1);
    	TextOut(hdc, 280, 165, "(< and > to change)", 19);
    
    	for(k = 0; k < len; k++) {
    		if(GetAsyncKeyState(keys[k]) & 0x80000000) {
    			/* Set the background of the note to red */
    			SetDCBrushColor(hdc, RGB(255, 0, 0));
    			SelectObject(hdc, GetStockObject(DC_BRUSH));
    			/* Set the text foreground color to white */
    			SetTextColor(hdc, RGB(255, 255, 255));
    			/* Set the text background color to red */
    			SetBkColor(hdc, RGB(255, 0, 0));
    		} else if(isAccidental(k)) {
    			/* Set the background of the note to black */
    			SelectObject(hdc, GetStockObject(BLACK_BRUSH));
    			/* Set the text foreground color to white */
    			SetTextColor(hdc, RGB(255, 255, 255));
    			/* Set the text background color to black */
    			SetBkColor(hdc, RGB(0, 0, 0));
    		} else {
    			/* Set the background of the note to white */
    			SelectObject(hdc, GetStockObject(WHITE_BRUSH));
    			/* Set the text foreground color to black */
    			SetTextColor(hdc, RGB(0, 0, 0));
    			/* Set the text background color to white */
    			SetBkColor(hdc, RGB(255, 255, 255));
    		}
    
    		/* If the note is a white key, draw it lower */
    		if(!isAccidental(k))
    			y = 80;
    		else y = 0;
    
    		/* Draw the actual key */
    		Rectangle(hdc, x, y, x + 59, y + 79);
    		/* Set the text font to something less ugly than SYSTEM_FONT */
    		SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
    		/* Draw the letter which controls this key */
    		TextOut(hdc, x + 10, y + 10, &keys[k], 1);
    
    		/* Increment the position for the next key. If there are 2 white
    		   keys in a row (E to F or B to C), make the gap bigger so they
    		   don't run into each other, otherwise only offset a bit so the
    		   keys overlap. */
    		if(!isAccidental(k) && !isAccidental(k + 1))
    			x += 60;
    		else x += 30;
    	}
    }
    
    /* Called when the window receives a message */
    LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    	PAINTSTRUCT ps;
    
    	switch(msg) {
    		case WM_COMMAND:
    			if(HIWORD(wParam) == CBN_SELCHANGE) { /* New item selected from the listbox */
    				/* Send the MIDI message to change the instrument. The 'patch number'
    				   that the instrument is changed to is queried from the dropdown list. */
    				sendMIDIMessage(0xC0, 0, SendMessage(hDropDown, CB_GETCURSEL, 0, 0), 0);
    				/* Set the focus back to the main window so we can still get key events */
    				SetFocus(hWnd);
    			} else if(HIWORD(wParam) == CBN_SELENDCANCEL) {
    				/* The user clicked out of the combo box without selecting anything.
    				   Set the focus back to the main window so we can still get key events */
    				SetFocus(hWnd);
    			}
    			break;
    		case WM_DESTROY: /* Window is being closed */
    			PostQuitMessage(0);
    			break;
    		case WM_KEYDOWN: /* Key press */
    			/* Only call the function if it's not a 'held down' key event.
    			   Otherwise, the notes would repeat and it'd sound bad. */
    			if(((lParam >> 30) & 0x01) == 0)
    				onKeyDown((unsigned char) wParam);
    			break;
    		case WM_KEYUP: /* Key release */
    			onKeyUp((unsigned char) wParam);
    			break;
    		case WM_PAINT: /* Window is being redrawn */
    			BeginPaint(hWnd, &ps);
    			/* draw the keyboard */
    			drawKeyboard(ps.hdc);
    			EndPaint(hWnd, &ps);
    			break;
    		default:
    			/* Make Windows handle all messages that we don't. */
    			return DefWindowProc(hWnd, msg, wParam, lParam);
    	}
    
    	return 0;
    }
    
    /* Main entry point. */
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
    	LPSTR lpCmdLine, int nCmdShow)
    {
    	WNDCLASSEX wc;
    	MSG msg;
    	RECT rct;
    
    	/* Create and register the window type */
    	wc.cbSize = sizeof(WNDCLASSEX);
    	wc.style = 0;
    	wc.lpfnWndProc = WndProc;
    	wc.cbClsExtra = 0;
    	wc.cbWndExtra = 0;
    	wc.hInstance = hInstance;
    	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    	wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
    	wc.lpszMenuName = NULL;
    	wc.lpszClassName = "MidiKeyboard";
    	wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    
    	RegisterClassEx(&wc);
    
    	/* Calculate the width/height of the window based on the 
    	   width/height of the canvas area */
    	rct.left = 0;
    	rct.top = 0;
    	rct.right = 600;
    	rct.bottom = 185;
    	AdjustWindowRect(&rct, WS_OVERLAPPEDWINDOW, FALSE);
    
    	/* Actually create/show the window */
    	hWnd = CreateWindow("MidiKeyboard", "Keyboard", WS_OVERLAPPED | WS_CAPTION 
    		| WS_MINIMIZEBOX | WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, 
    		rct.right - rct.left, rct.bottom - rct.top, 0, 0, hInstance, 0);
    	hDropDown = CreateWindow("COMBOBOX", NULL, CBS_DROPDOWNLIST 
    		| WS_VISIBLE | WS_VSCROLL | WS_CHILD, 0, 160, 200, 200, hWnd, 0, hInstance, 0);
    	populateList();
    	ShowWindow(hWnd, nCmdShow);
    	UpdateWindow(hWnd);
    	
    	/* Set up the MIDI stuff */
    	midiOutOpen(&hMidi, MIDIMAPPER, 0, 0, 0);
    	setKeyValues();
    
    	/* Message loop */
    	while(GetMessage(&msg, NULL, 0, 0) > 0) {
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	}
    
    	/* Release the MIDI resources. */
    	midiOutClose(hMidi);
    
    	return msg.wParam;
    }
    Last edited by Tekkn0logik; 08-06-2011 at 04:36 PM.

  2. The Following 2 Users Say Thank You to Tekkn0logik For This Useful Post:

    tchdavid (09-19-2011),zhaoyun333 (08-07-2011)

  3. #2
    zhaoyun333's Avatar
    Join Date
    Apr 2009
    Gender
    male
    Posts
    396
    Reputation
    11
    Thanks
    1,125
    I just wasted an hour of my life playing with this xD
    There are five possible operations for any army. If you can fight, fight; if you cannot fight, defend; if you cannot defend, flee; if you cannot flee, surrender; if you cannot surrender, die." - Sima Yi

  4. #3
    tchdavid's Avatar
    Join Date
    Sep 2011
    Gender
    male
    Posts
    1
    Reputation
    10
    Thanks
    0
    I've tried this code, but it can't compile.
    Here are error messenges:

    main.c||In function 'onKeyDown':|
    main.c|185|error: 'VK_OEM_COMMA' undeclared (first use in this function)|
    main.c|185|error: (Each undeclared identifier is reported only once|
    main.c|185|error: for each function it appears in.)|
    main.c|188|error: 'VK_OEM_PERIOD' undeclared (first use in this function)|
    main.c||In function 'drawKeyboard':|
    main.c|234|error: 'DC_BRUSH' undeclared (first use in this function)|
    ||=== Build finished: 5 errors, 0 warnings ==

    I just open a new empty project and a new file "main.c" contain those codes.
    And I can't compile this file.

    Sorry that I'm new in midi program.
    Thank you.

  5. #4
    Jason's Avatar
    Join Date
    Apr 2010
    Gender
    male
    Location
    /dev/null
    Posts
    5,704
    Reputation
    918
    Thanks
    7,676
    My Mood
    Mellow
    Very nice! I had to manually pragma the winmm.lib to clear up some unresolved externals (thanks @Hell_Demon)

    Code:
    #pragma comment(lib, "winmm.lib")
    Other than than, this is awesome!

    I did find a small bug, if you hold down a note, then change the octave, the note is never released. It's quite cool for combining a variety of sounds though
    Last edited by Jason; 09-20-2011 at 09:39 AM.

    Quote Originally Posted by Jeremy S. Anderson
    There are only two things to come out of Berkley, Unix and LSD,
    and I don’t think this is a coincidence
    You can win the rat race,
    But you're still nothing but a fucking RAT.


    ++Latest Projects++
    [Open Source] Injection Library
    Simple PE Cipher
    FilthyHooker - Simple Hooking Class
    CLR Injector - Inject .NET dlls with ease
    Simple Injection - An in-depth look
    MPGH's .NET SDK
    eJect - Simple Injector
    Basic PE Explorer (BETA)

Similar Threads

  1. a good java program
    By snipelock in forum Java
    Replies: 18
    Last Post: 04-17-2009, 02:56 PM
  2. Runescape 2 auto programs
    By fabled in forum Hack Requests
    Replies: 19
    Last Post: 09-05-2007, 01:43 PM
  3. [Tutorial] Your first program
    By akimoko in forum C++/C Programming
    Replies: 10
    Last Post: 06-23-2007, 12:58 PM
  4. brainfuck Programming
    By sockopen in forum Programming
    Replies: 18
    Last Post: 07-05-2006, 05:15 AM
  5. Problem Wit Hacking Programs
    By f5awp in forum General Gaming
    Replies: 5
    Last Post: 01-10-2006, 05:44 AM