ITKeyword,专注技术干货聚合推荐

注册 | 登录

windows SDK模拟游戏钢琴的实现(一)

gaoxin1076 分享于 2012-01-01

推荐:windows SDK模拟游戏钢琴的实现(二)

       昨天晚上失眠了,于是一直在想实现GDI的一个效果:首先绘制10个相连的矩形,当鼠标移到某个矩形的时候,自动填充那个矩形的背景颜色为灰色,移开的时候恢

2019阿里云全部产品优惠券(新购或升级都可以使用,强烈推荐)
领取地址https://promotion.aliyun.com/ntms/yunparter/invite.html

最近想做一个模拟钢琴的小软件,想做个既有键盘接口又有鼠标接口的小软件。所涉及到的知识点如下:

1.有关键盘的知识

2.有关鼠标的知识

3.GDI的知识

4.媒体播放函数的有关知识

因为这几天也正好在看这些内容,所以理论结合实际是最好的学习方式

首先要找钢琴音阶,但是上网找了一圈也没有发现,最后在4399里面找到一个差不多类型的模拟钢琴游戏,而且音色不错,索性用Adobe Audition的录音功能将每个音阶都录下来做一些编辑,自己制作了20来个音阶,用mp3格式保存。 然后用的是mcisendstring函数实现mp3格式音乐的播放。 第一步首先做键盘接口,其实这一步还是比较简单的,在窗口过程里面处理对应的虚拟键码的消息就行了,这里遇到了一个小问题,找不到 <,

>.

这两个按键对应的虚拟键码了,找了一下虚拟键码表上面好像也没有写啊?先暂时搁下 成果做出来以后,发现一个比较严重的问题,就是使用mcisendstring这个宏的时候,不能同时打开某个音乐文件,这样比如我的la这个音阶有2秒的话,必须要等到2秒结束以后才能再次播放,这样显然影响了连续的效果,目前也没有什么好的解决方案。 第二步就要涉及到GDI和鼠标接口了,这一部分正在看,等到成品做出来以后在附上源码吧。 昨天晚上做梦的时候突然想到怎么实现可以几乎同时按一个键发出声音了,话说梦真是个神奇的东西啊。 既然不能同时打开同一个音乐文件,那么我在每次打开前关闭这个音乐文件不就实现这个效果了吗?想到了确实觉得挺简单的,但是昨天怎么就没想到呢?呵呵,下面先附上我键盘接口的代码: /*------------------------------------------------------------

a piano program

------------------------------------------------------------*/#include <windows.h>#include <mmsystem.h>#pragma comment(lib, "WINMM.LIB")LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow){

static TCHAR szAppName[] = TEXT ("HelloWin") ;

HWND

hwnd ;

MSG

msg ;

WNDCLASS

wndclass ;

wndclass.style

= CS_HREDRAW | CS_VREDRAW ;

wndclass.lpfnWndProc

= WndProc ;

wndclass.cbClsExtra

= 0 ;

wndclass.cbWndExtra

= 0 ;

wndclass.hInstance

= hInstance ;

wndclass.hIcon

= LoadIcon (NULL, IDI_APPLICATION) ;

wndclass.hCursor

= LoadCursor (NULL, IDC_ARROW) ;

wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;

wndclass.lpszMenuName

= NULL ;

wndclass.lpszClassName = szAppName ;

if (!RegisterClass (&wndclass))

{

MessageBox (NULL, TEXT ("This program requires Windows NT!"),

szAppName, MB_ICONERROR) ;

return 0 ;

}

hwnd = CreateWindow (szAppName,

// window class name

TEXT ("The Hello Program"), // window caption

WS_OVERLAPPEDWINDOW,

// window style

CW_USEDEFAULT,

// initial x position

CW_USEDEFAULT,

// initial y position

CW_USEDEFAULT,

// initial x size

CW_USEDEFAULT,

// initial y size

NULL,

// parent window handle

NULL,

// window menu handle

hInstance,

// program instance handle

NULL) ;

// creation parameters

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){

HDC

hdc;

PAINTSTRUCT ps ;

RECT

rect;

switch (message)

{

case WM_CREATE:

return 0 ;

case WM_PAINT:

hdc = BeginPaint (hwnd, &ps);

GetClientRect (hwnd, &rect);

DrawText (hdc, TEXT ("an intersting piano game^_^

just use keyboard" ), -1, &rect,

DT_SINGLELINE | DT_CENTER | DT_VCENTER);

EndPaint (hwnd, &ps) ;

return 0 ;

case WM_KEYDOWN:

switch(wParam)

{

case 0x31:

mciSendString(TEXT("close c://1.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://1.mp3"), NULL, 0, NULL);

//0-9键盘接口

break;

case 0x32:

mciSendString(TEXT("close c://2.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://2.mp3"), NULL, 0, NULL);

break;

case 0x33:

mciSendString(TEXT("close c://3.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://3.mp3"), NULL, 0, NULL);

break;

case 0x34:

mciSendString(TEXT("close c://4.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://4.mp3"), NULL, 0, NULL);

break;

case 0x35:

mciSendString(TEXT("close c://5.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://5.mp3"), NULL, 0, NULL);

break;

case 0x36:

mciSendString(TEXT("close c://6.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://6.mp3"), NULL, 0, NULL);

break;

case 0x37:

mciSendString(TEXT("close c://7.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://7.mp3"), NULL, 0, NULL);

break;

case 0x38:

mciSendString(TEXT("close c://8.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://8.mp3"), NULL, 0, NULL);

break;

case 0x39:

mciSendString(TEXT("close c://9.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://9.mp3"), NULL, 0, NULL);

break;

case 0x30:

mciSendString(TEXT("close c://10.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://10.mp3"), NULL, 0, NULL);

break;

case 65:

//字母键盘接口

mciSendString(TEXT("close c://1.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://1.mp3"), NULL, 0, NULL);

break;

case 90:

mciSendString(TEXT("close c://2.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://2.mp3"), NULL, 0, NULL);

break;

case 83:

mciSendString(TEXT("close c://3.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://3.mp3"), NULL, 0, NULL);

break;

case 88:

mciSendString(TEXT("close c://4.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://4.mp3"), NULL, 0, NULL);

break;

case 68:

mciSendString(TEXT("close c://5.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://5.mp3"), NULL, 0, NULL);

break;

case 67:

mciSendString(TEXT("close c://6.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://6.mp3"), NULL, 0, NULL);

break;

case 70:

mciSendString(TEXT("close c://7.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://7.mp3"), NULL, 0, NULL);

break;

case 86:

mciSendString(TEXT("close c://8.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://8.mp3"), NULL, 0, NULL);

break;

case 71:

mciSendString(TEXT("close c://9.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://9.mp3"), NULL, 0, NULL);

break;

case 66:

mciSendString(TEXT("close c://10.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://10.mp3"), NULL, 0, NULL);

break;

case 72:

mciSendString(TEXT("close c://11.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://11.mp3"), NULL, 0, NULL);

break;

case 78:

mciSendString(TEXT("close c://12.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://12.mp3"), NULL, 0, NULL);

break;

case 74:

mciSendString(TEXT("close c://13.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://13.mp3"), NULL, 0, NULL);

break;

case 77:

mciSendString(TEXT("close c://14.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://14.mp3"), NULL, 0, NULL);

break;

case 75:

mciSendString(TEXT("close c://15.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://15.mp3"), NULL, 0, NULL);

break;

case VK_OEM_8:

mciSendString(TEXT("close c://16.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://16.mp3"), NULL, 0, NULL);

break;

case 76:

mciSendString(TEXT("close c://17.mp3"), NULL, 0, NULL);

mciSendString(TEXT("play c://17.mp3"), NULL, 0, NULL);

break;

}

return 0;

case WM_DESTROY:

PostQuitMessage (0) ;

return 0 ;

}

return DefWindowProc (hwnd, message, wParam, lParam) ;} 中间有很多东西都是重复的,只是简单地完成了一个音乐播放的功能,而且也没有加上资源,加上GDI等东西。 这几天偶尔在书上看到了类似的一个程序,集合了菜单,资源等很多功能,是用MIDI来控制音乐播放的,所以有很多选项可以选择,下面附上代码: /*---------------------------------------

KBMIDI.C -- Keyboard MIDI Player

(c) Charles Petzold, 1998

---------------------------------------*/#include <windows.h>// Defines for Menu IDs// --------------------#define IDM_OPEN

0x100#define IDM_CLOSE

0x101#define IDM_DEVICE

0x200#define IDM_CHANNEL 0x300#define IDM_VOICE

0x400LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);TCHAR

szAppName [] = TEXT ("KBMidi") ;HMIDIOUT hMidiOut ;int

iDevice = MIDIMAPPER, iChannel = 0, iVoice = 0, iVelocity = 64 ;int

cxCaps, cyChar, xOffset, yOffset ;

// Structures and data for showing families and instruments on menu

// ----------------------------------------------------------------typedef struct{

TCHAR * szInst ;

int

iVoice ;}INSTRUMENT ;typedef struct{

TCHAR

* szFam ;

INSTRUMENT

inst [8] ;}FAMILY ;FAMILY fam [16] = {

TEXT ("Piano"),

TEXT ("Acoustic Grand Piano"),

0,

TEXT ("Bright Acoustic Piano"),

1,

TEXT ("Electric Grand Piano"),

2,

TEXT ("Honky-tonk Piano"),

3,

TEXT ("Rhodes Piano"),

4,

TEXT ("Chorused Piano"),

5,

TEXT ("Harpsichord"),

6,

TEXT ("Clavinet"),

7,

TEXT ("Chromatic Percussion"),

TEXT ("Celesta"),

8,

TEXT ("Glockenspiel"),

9,

TEXT ("Music Box"),

10,

TEXT ("Vibraphone"),

11,

TEXT ("Marimba"),

12,

TEXT ("Xylophone"),

13,

TEXT ("Tubular Bells"),

14,

TEXT ("Dulcimer"),

15,

TEXT ("Organ"),

TEXT ("Hammond Organ"),

16,

TEXT ("Percussive Organ"),

17,

TEXT ("Rock Organ"),

18,

TEXT ("Church Organ"),

19,

TEXT ("Reed Organ"),

20,

TEXT ("Accordian"),

21,

TEXT ("Harmonica"),

22,

TEXT ("Tango Accordian"),

23,

TEXT ("Guitar"),

TEXT ("Acoustic Guitar (nylon)"),

24,

TEXT ("Acoustic Guitar (steel)"),

25,

TEXT ("Electric Guitar (jazz)"),

26,

TEXT ("Electric Guitar (clean)"),

27,

TEXT ("Electric Guitar (muted)"),

28,

TEXT ("Overdriven Guitar"),

29,

TEXT ("Distortion Guitar"),

30,

TEXT ("Guitar Harmonics"),

31,

TEXT ("Bass"),

TEXT ("Acoustic Bass"),

32,

TEXT ("Electric Bass (finger)"),

33,

TEXT ("Electric Bass (pick)"),

34,

TEXT ("Fretless Bass"),

35,

TEXT ("Slap Bass 1"),

36,

TEXT ("Slap Bass 2"),

37,

TEXT ("Synth Bass 1"),

38,

TEXT ("Synth Bass 2"),

39,

TEXT ("Strings"),

TEXT ("Violin"),

40,

TEXT ("Viola"),

41,

TEXT ("Cello"),

42,

TEXT ("Contrabass"),

43,

TEXT ("Tremolo Strings"),

44,

TEXT ("Pizzicato Strings"),

45,

TEXT ("Orchestral Harp"),

46,

TEXT ("Timpani"),

47,

TEXT ("Ensemble"),

TEXT ("String Ensemble 1"),

48,

TEXT ("String Ensemble 2"),

49,

TEXT ("Synth Strings 1"),

50,

TEXT ("Synth Strings 2"),

51,

TEXT ("Choir Aahs"),

52,

TEXT ("Voice Oohs"),

53,

TEXT ("Synth Voice"),

54,

TEXT ("Orchestra Hit"),

55,

TEXT ("Brass"),

TEXT ("Trumpet"),

56,

TEXT ("Trombone"),

57,

TEXT ("Tuba"),

58,

TEXT ("Muted Trumpet"),

59,

TEXT ("French Horn"),

60,

TEXT ("Brass Section"),

61,

TEXT ("Synth Brass 1"),

62,

TEXT ("Synth Brass 2"),

63,

TEXT ("Reed"),

TEXT ("Soprano Sax"),

64,

TEXT ("Alto Sax"),

65,

TEXT ("Tenor Sax"),

66,

TEXT ("Baritone Sax"),

67,

TEXT ("Oboe"),

68,

TEXT ("English Horn"),

69,

TEXT ("Bassoon"),

70,

TEXT ("Clarinet"),

71,

TEXT ("Pipe"),

TEXT ("Piccolo"),

72,

TEXT ("Flute"),

73,

TEXT ("Recorder"),

74,

TEXT ("Pan Flute"),

75,

TEXT ("Bottle Blow"),

76,

TEXT ("Shakuhachi"),

77,

TEXT ("Whistle"),

78,

TEXT ("Ocarina"),

79,

TEXT ("Synth Lead"),

TEXT ("Lead 1 (square)"),

80,

TEXT ("Lead 2 (sawtooth)"),

81,

TEXT ("Lead 3 (caliope lead)"),

82,

TEXT ("Lead 4 (chiff lead)"),

83,

TEXT ("Lead 5 (charang)"),

84,

TEXT ("Lead 6 (voice)"),

85,

TEXT ("Lead 7 (fifths)"),

86,

TEXT ("Lead 8 (brass + lead)"),

87,

TEXT ("Synth Pad"),

TEXT ("Pad 1 (new age)"),

88,

TEXT ("Pad 2 (warm)"),

89,

TEXT ("Pad 3 (polysynth)"),

90,

TEXT ("Pad 4 (choir)"),

91,

TEXT ("Pad 5 (bowed)"),

92,

TEXT ("Pad 6 (metallic)"),

93,

TEXT ("Pad 7 (halo)"),

94,

TEXT ("Pad 8 (sweep)"),

95,

TEXT ("Synth Effects"),

TEXT ("FX 1 (rain)"),

96,

TEXT ("FX 2 (soundtrack)"),

97,

TEXT ("FX 3 (crystal)"),

98,

TEXT ("FX 4 (atmosphere)"),

99,

TEXT ("FX 5 (brightness)"),

100,

TEXT ("FX 6 (goblins)"),

101,

TEXT ("FX 7 (echoes)"),

102,

TEXT ("FX 8 (sci-fi)"),

103,

TEXT ("Ethnic"),

TEXT ("Sitar"),

104,

TEXT ("Banjo"),

105,

TEXT ("Shamisen"),

106,

TEXT ("Koto"),

107,

TEXT ("Kalimba"),

108,

TEXT ("Bagpipe"),

109,

TEXT ("Fiddle"),

110,

TEXT ("Shanai"),

111,

TEXT ("Percussive"),

TEXT ("Tinkle Bell"),

112,

TEXT ("Agogo"),

113,

TEXT ("Steel Drums"),

114,

TEXT ("Woodblock"),

115,

TEXT ("Taiko Drum"),

116,

TEXT ("Melodic Tom"),

117,

TEXT ("Synth Drum"),

118,

TEXT ("Reverse Cymbal"),

119,

TEXT ("Sound Effects"),

TEXT ("Guitar Fret Noise"),

120,

TEXT ("Breath Noise"),

121,

TEXT ("Seashore"),

122,

TEXT ("Bird Tweet"),

123,

TEXT ("Telephone Ring"),

124,

TEXT ("Helicopter"),

125,

TEXT ("Applause"),

126,

TEXT ("Gunshot"),

127 } ;

// Data for translating scan codes to octaves and notes

// ----------------------------------------------------#define NUMSCANS

(sizeof key / sizeof key[0])struct{

int

iOctave ;

int

iNote ;

int

yPos ;

int

xPos ;

TCHAR * szKey ;}key [] ={

// Scan

Char

Oct

Note

// ----

----

---

----

-1, -1, -1, -1, NULL,

//

0

None

-1, -1, -1, -1, NULL,

//

1

Esc

-1, -1,

0,

0, TEXT (""),

//

2

1

5,

1,

0,

2, TEXT ("C#"),

//

3

2

5

C#

5,

3,

0,

4, TEXT ("D#"),

//

4

3

5

D#

-1, -1,

0,

6, TEXT (""),

//

5

4

5,

6,

0,

8, TEXT ("F#"),

//

6

5

5

F#

5,

8,

0, 10, TEXT ("G#"),

//

7

6

5

G#

5, 10,

0, 12, TEXT ("A#"),

//

8

7

5

A#

-1, -1,

0, 14, TEXT (""),

//

9

8

6,

1,

0, 16, TEXT ("C#"),

//

10

9

6

C#

6,

3,

0, 18, TEXT ("D#"),

//

11

0

6

D#

-1, -1,

0, 20, TEXT (""),

//

12

-

6,

6,

0, 22, TEXT ("F#"),

//

13

=

6

F#

-1, -1, -1, -1, NULL,

//

14

Back

-1, -1, -1, -1, NULL,

//

15

Tab

5,

0,

1,

1, TEXT ("C"),

//

16

q

5

C

5,

2,

1,

3, TEXT ("D"),

//

17

w

5

D

5,

4,

1,

5, TEXT ("E"),

//

18

e

5

E

5,

5,

1,

7, TEXT ("F"),

//

19

r

5

F

5,

7,

1,

9, TEXT ("G"),

//

20

t

5

G

5,

9,

1, 11, TEXT ("A"),

//

21

y

5

A

5, 11,

1, 13, TEXT ("B"),

//

22

u

5

B

6,

0,

1, 15, TEXT ("C"),

//

23

i

6

C

6,

2,

1, 17, TEXT ("D"),

//

24

o

6

D

6,

4,

1, 19, TEXT ("E"),

//

25

p

6

E

6,

5,

1, 21, TEXT ("F"),

//

26

[

6

F

6,

7,

1, 23, TEXT ("G"),

//

27

]

6

G

-1, -1, -1, -1, NULL,

//

28

Ent

-1, -1, -1, -1, NULL,

//

29

Ctrl

3,

8,

2,

2, TEXT ("G#"),

//

30

a

3

G#

3, 10,

2,

4, TEXT ("A#"),

//

31

s

3

A#

-1, -1,

2,

6, TEXT (""),

//

32

d

4,

1,

2,

8, TEXT ("C#"),

//

33

f

4

C#

4,

3,

2, 10, TEXT ("D#"),

//

34

g

4

D#

-1, -1,

2, 12, TEXT (""),

//

35

h

4,

6,

2, 14, TEXT ("F#"),

//

36

j

4

F#

4,

8,

2, 16, TEXT ("G#"),

//

37

k

4

G#

4, 10,

2, 18, TEXT ("A#"),

//

38

l

4

A#

-1, -1,

2, 20, TEXT (""),

//

39

;

5,

1,

2, 22, TEXT ("C#"),

//

40

'

5

C#

-1, -1, -1, -1, NULL,

//

41

`

-1, -1, -1, -1, NULL,

//

42

Shift

-1, -1, -1, -1, NULL,

//

43

\

(not line continuation)

3,

9,

3,

3, TEXT ("A"),

//

44

z

3

A

3, 11,

3,

5, TEXT ("B"),

//

45

x

3

B

4,

0,

3,

7, TEXT ("C"),

//

46

c

4

C

4,

2,

3,

9, TEXT ("D"),

//

47

v

4

D

4,

4,

3, 11, TEXT ("E"),

//

48

b

4

E

4,

5,

3, 13, TEXT ("F"),

//

49

n

4

F

4,

7,

3, 15, TEXT ("G"),

//

50

m

4

G

4,

9,

3, 17, TEXT ("A"),

//

51

,

4

A

4, 11,

3, 19, TEXT ("B"),

//

52

.

4

B

5,

0,

3, 21, TEXT ("C")

//

53

/

5

C} ;int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow){

MSG

msg;

HWND

hwnd ;

WNDCLASS wndclass ;

wndclass.style

= CS_HREDRAW | CS_VREDRAW ;

wndclass.lpfnWndProc

= WndProc ;

wndclass.cbClsExtra

= 0 ;

wndclass.cbWndExtra

= 0 ;

wndclass.hInstance

= hInstance ;

wndclass.hIcon

= LoadIcon (NULL, IDI_APPLICATION) ;

wndclass.hCursor

= LoadCursor (NULL, IDC_ARROW) ;

wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;

wndclass.lpszMenuName

= NULL ;

wndclass.lpszClassName = szAppName ;

if (!RegisterClass (&wndclass))

{

MessageBox (NULL, TEXT ("This program requires Windows NT!"),

szAppName, MB_ICONERROR) ;

return 0 ;

}

hwnd = CreateWindow (szAppName, TEXT ("Keyboard MIDI Player"),

WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL) ;

if (!hwnd)

return 0 ;

ShowWindow (hwnd, iCmdShow) ;

UpdateWindow (hwnd);

while (GetMessage (&msg, NULL, 0, 0))

{

TranslateMessage (&msg) ;

DispatchMessage (&msg) ;

}

return msg.wParam ;}// Create the program's menu (called from WndProc, WM_CREATE)// ----------------------------------------------------------HMENU CreateTheMenu (int iNumDevs){

TCHAR

szBuffer [32] ;

HMENU

hMenu, hMenuPopup, hMenuSubPopup ;

int

i, iFam, iIns ;

MIDIOUTCAPS moc ;

hMenu = CreateMenu () ;

// Create "On/Off" popup menu

hMenuPopup = CreateMenu () ;

AppendMenu (hMenuPopup, MF_STRING, IDM_OPEN, TEXT ("&Open")) ;

AppendMenu (hMenuPopup, MF_STRING | MF_CHECKED, IDM_CLOSE,

TEXT ("&Closed")) ;

AppendMenu (hMenu, MF_STRING | MF_POPUP, (UINT) hMenuPopup,

TEXT ("&Status")) ;

// Create "Device" popup menu

hMenuPopup = CreateMenu () ;

// Put MIDI Mapper on menu if it's installed

if (!midiOutGetDevCaps (MIDIMAPPER, &moc, sizeof (moc)))

AppendMenu (hMenuPopup, MF_STRING, IDM_DEVICE + (int) MIDIMAPPER,

moc.szPname) ;

else

iDevice = 0 ;

// Add the rest of the MIDI devices

for (i = 0 ; i < iNumDevs ; i++)

{

midiOutGetDevCaps (i, &moc, sizeof (moc)) ;

AppendMenu (hMenuPopup, MF_STRING, IDM_DEVICE + i, moc.szPname) ;

}

CheckMenuItem (hMenuPopup, 0, MF_BYPOSITION | MF_CHECKED) ;

AppendMenu (hMenu, MF_STRING | MF_POPUP, (UINT) hMenuPopup,

TEXT ("&Device")) ;

// Create "Channel" popup menu

hMenuPopup = CreateMenu () ;

for (i = 0 ; i < 16 ; i++)

{

wsprintf (szBuffer, TEXT ("%d"), i + 1) ;

AppendMenu (hMenuPopup, MF_STRING | (i ? MF_UNCHECKED : MF_CHECKED),

IDM_CHANNEL + i, szBuffer) ;

}

AppendMenu (hMenu, MF_STRING | MF_POPUP, (UINT) hMenuPopup,

TEXT ("&Channel")) ;

// Create "Voice" popup menu

hMenuPopup = CreateMenu () ;

for (iFam = 0 ; iFam < 16 ; iFam++)

{

hMenuSubPopup = CreateMenu () ;

for (iIns = 0 ; iIns < 8 ; iIns++)

{

wsprintf (szBuffer, TEXT ("&%d.\t%s"), iIns + 1,

fam[iFam].inst[iIns].szInst) ;

AppendMenu (hMenuSubPopup,

MF_STRING | (fam[iFam].inst[iIns].iVoice ?

MF_UNCHECKED : MF_CHECKED),

fam[iFam].inst[iIns].iVoice + IDM_VOICE,

szBuffer) ;

}

wsprintf (szBuffer, TEXT ("&%c.\t%s"), 'A' + iFam,

fam[iFam].szFam) ;

AppendMenu (hMenuPopup, MF_STRING | MF_POPUP, (UINT) hMenuSubPopup,

szBuffer) ;

}

AppendMenu (hMenu, MF_STRING | MF_POPUP, (UINT) hMenuPopup,

TEXT ("&Voice")) ;

return hMenu ;}// Routines for simplifying MIDI output// ------------------------------------DWORD MidiOutMessage (HMIDIOUT hMidi, int iStatus, int iChannel,

int iData1,

int iData2){

DWORD dwMessage ;

dwMessage = iStatus | iChannel | (iData1 << 8) | (iData2 << 16) ;

return midiOutShortMsg (hMidi, dwMessage) ;}DWORD MidiNoteOff (HMIDIOUT hMidi, int iChannel, int iOct, int iNote, int iVel){

return MidiOutMessage (hMidi, 0x080, iChannel, 12 * iOct + iNote, iVel) ;}DWORD MidiNoteOn (HMIDIOUT hMidi, int iChannel, int iOct, int iNote, int iVel){

return MidiOutMessage (hMidi, 0x090, iChannel, 12 * iOct + iNote, iVel) ;}DWORD MidiSetPatch (HMIDIOUT hMidi, int iChannel, int iVoice){

return MidiOutMessage (hMidi, 0x0C0, iChannel, iVoice, 0) ;}DWORD MidiPitchBend (HMIDIOUT hMidi, int iChannel, int iBend){

return MidiOutMessage (hMidi, 0x0E0, iChannel, iBend & 0x7F, iBend >> 7) ;}// Draw a single key on window// ---------------------------VOID DrawKey (HDC hdc, int iScanCode, BOOL fInvert){

RECT rc ;

rc.left

= 3 * cxCaps * key[iScanCode].xPos / 2 + xOffset ;

rc.top

= 3 * cyChar * key[iScanCode].yPos / 2 + yOffset ;

rc.right

= rc.left + 3 * cxCaps ;

rc.bottom = rc.top

+ 3 * cyChar / 2 ;

SetTextColor (hdc, fInvert ? 0x00FFFFFFul : 0x00000000ul) ;

SetBkColor

(hdc, fInvert ? 0x00000000ul : 0x00FFFFFFul) ;

FillRect (hdc, &rc, GetStockObject (fInvert ? BLACK_BRUSH : WHITE_BRUSH)) ;

DrawText (hdc, key[iScanCode].szKey, -1, &rc,

DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;

FrameRect (hdc, &rc, GetStockObject (BLACK_BRUSH)) ;}// Process a Key Up or Key Down message// ------------------------------------VOID ProcessKey (HDC hdc, UINT message, LPARAM lParam){

int iScanCode, iOctave, iNote ;

iScanCode = 0x0FF & HIWORD (lParam) ;

if (iScanCode >= NUMSCANS)

// No scan codes over 53

return ;

if ((iOctave = key[iScanCode].iOctave) == -1)

// Non-music key

return ;

if (GetKeyState (VK_SHIFT) < 0)

iOctave += 0x20000000 & lParam ? 2 : 1 ;

if (GetKeyState (VK_CONTROL) < 0)

iOctave -= 0x20000000 & lParam ? 2 : 1 ;

iNote = key[iScanCode].iNote ;

if (message == WM_KEYUP)

// For key up

{

MidiNoteOff (hMidiOut, iChannel, iOctave, iNote, 0) ;

// Note off

DrawKey (hdc, iScanCode, FALSE) ;

return ;

}

if (0x40000000 & lParam)

// ignore typematics

return ;

MidiNoteOn (hMidiOut, iChannel, iOctave, iNote, iVelocity) ; // Note on

DrawKey (hdc, iScanCode, TRUE) ;

// Draw the inverted key}// Window Procedure// ----------------LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){

static BOOL bOpened = FALSE ;

HDC

hdc ;

HMENU

hMenu ;

int

i, iNumDevs, iPitchBend, cxClient, cyClient ;

MIDIOUTCAPS moc ;

PAINTSTRUCT ps ;

SIZE

size ;

TCHAR

szBuffer [16] ;

switch (message)

{

case WM_CREATE:

// Get size of capital letters in system font

hdc = GetDC (hwnd) ;

GetTextExtentPoint (hdc, TEXT ("M"), 1, &size) ;

cxCaps = size.cx ;

cyChar = size.cy ;

ReleaseDC (hwnd, hdc) ;

// Initialize "Volume" scroll bar

SetScrollRange (hwnd, SB_HORZ, 1, 127, FALSE) ;

SetScrollPos

(hwnd, SB_HORZ, iVelocity, TRUE) ;

// Initialize "Pitch Bend" scroll bar

SetScrollRange (hwnd, SB_VERT, 0, 16383, FALSE) ;

SetScrollPos

(hwnd, SB_VERT, 8192, TRUE) ;

// Get number of MIDI output devices and set up menu

if (0 == (iNumDevs = midiOutGetNumDevs ()))

{

MessageBeep (MB_ICONSTOP) ;

MessageBox (hwnd, TEXT ("No MIDI output devices!"),

szAppName, MB_OK | MB_ICONSTOP) ;

return -1 ;

}

SetMenu (hwnd, CreateTheMenu (iNumDevs)) ;

return 0 ;

case WM_SIZE:

cxClient = LOWORD (lParam) ;

cyClient = HIWORD (lParam) ;

xOffset = (cxClient - 25 * 3 * cxCaps / 2) / 2 ;

yOffset = (cyClient - 11 * cyChar) / 2 + 5 * cyChar ;

return 0 ;

case WM_COMMAND:

hMenu = GetMenu (hwnd) ;

// "Open" menu command

if (LOWORD (wParam) == IDM_OPEN && !bOpened)

{

if (midiOutOpen (&hMidiOut, iDevice, 0, 0, 0))

{

MessageBeep (MB_ICONEXCLAMATION) ;

MessageBox (hwnd, TEXT ("Cannot open MIDI device"),

szAppName, MB_OK | MB_ICONEXCLAMATION) ;

}

else

{

CheckMenuItem (hMenu, IDM_OPEN,

MF_CHECKED) ;

CheckMenuItem (hMenu, IDM_CLOSE, MF_UNCHECKED) ;

MidiSetPatch (hMidiOut, iChannel, iVoice) ;

bOpened = TRUE ;

}

}

// "Close" menu command

else if (LOWORD (wParam) == IDM_CLOSE && bOpened)

{

CheckMenuItem (hMenu, IDM_OPEN,

MF_UNCHECKED) ;

CheckMenuItem (hMenu, IDM_CLOSE, MF_CHECKED) ;

// Turn all keys off and close device

for (i = 0 ; i < 16 ; i++)

MidiOutMessage (hMidiOut, 0xB0, i, 123, 0) ;

midiOutClose (hMidiOut) ;

bOpened = FALSE ;

}

// Change MIDI "Device" menu command

else if (LOWORD (wParam) >= IDM_DEVICE - 1 &&

LOWORD (wParam) <

IDM_CHANNEL)

{

CheckMenuItem (hMenu, IDM_DEVICE + iDevice, MF_UNCHECKED) ;

iDevice = LOWORD (wParam) - IDM_DEVICE ;

CheckMenuItem (hMenu, IDM_DEVICE + iDevice, MF_CHECKED) ;

// Close and reopen MIDI device

if (bOpened)

{

SendMessage (hwnd, WM_COMMAND, IDM_CLOSE, 0L) ;

SendMessage (hwnd, WM_COMMAND, IDM_OPEN,

0L) ;

}

}

// Change MIDI "Channel" menu command

else if (LOWORD (wParam) >= IDM_CHANNEL &&

LOWORD (wParam) <

IDM_VOICE)

{

CheckMenuItem (hMenu, IDM_CHANNEL + iChannel, MF_UNCHECKED);

iChannel = LOWORD (wParam) - IDM_CHANNEL ;

CheckMenuItem (hMenu, IDM_CHANNEL + iChannel, MF_CHECKED) ;

if (bOpened)

MidiSetPatch (hMidiOut, iChannel, iVoice) ;

}

// Change MIDI "Voice" menu command

else if (LOWORD (wParam) >= IDM_VOICE)

{

CheckMenuItem (hMenu, IDM_VOICE + iVoice, MF_UNCHECKED) ;

iVoice = LOWORD (wParam) - IDM_VOICE ;

CheckMenuItem (hMenu, IDM_VOICE + iVoice, MF_CHECKED) ;

if (bOpened)

MidiSetPatch (hMidiOut, iChannel, iVoice) ;

}

InvalidateRect (hwnd, NULL, TRUE) ;

return 0 ;

// Process a Key Up or Key Down message

case WM_KEYUP:

case WM_KEYDOWN:

hdc = GetDC (hwnd) ;

if (bOpened)

ProcessKey (hdc, message, lParam) ;

ReleaseDC (hwnd, hdc) ;

return 0 ;

// For Escape, turn off all notes and repaint

case WM_CHAR:

if (bOpened && wParam == 27)

{

for (i = 0 ; i < 16 ; i++)

MidiOutMessage (hMidiOut, 0xB0, i, 123, 0) ;

InvalidateRect (hwnd, NULL, TRUE) ;

}

return 0 ;

// Horizontal scroll: Velocity

case WM_HSCROLL:

switch (LOWORD (wParam))

{

case SB_LINEUP:

iVelocity -= 1 ;

break ;

case SB_LINEDOWN:

iVelocity += 1 ;

break ;

case SB_PAGEUP:

iVelocity -= 8 ;

break ;

case SB_PAGEDOWN:

iVelocity += 8 ;

break ;

case SB_THUMBPOSITION:

iVelocity = HIWORD (wParam) ;

break ;

default:

return 0 ;

}

iVelocity = max (1, min (iVelocity, 127)) ;

SetScrollPos (hwnd, SB_HORZ, iVelocity, TRUE) ;

return 0 ;

// Vertical scroll:

Pitch Bend

case WM_VSCROLL:

switch (LOWORD (wParam))

{

case SB_THUMBTRACK:

iPitchBend = 16383 - HIWORD (wParam) ;

break ;

case SB_THUMBPOSITION: iPitchBend = 8191 ;

break ;

default:

return 0 ;

}

iPitchBend = max (0, min (iPitchBend, 16383)) ;

SetScrollPos (hwnd, SB_VERT, 16383 - iPitchBend, TRUE) ;

if (bOpened)

MidiPitchBend (hMidiOut, iChannel, iPitchBend) ;

return 0 ;

case WM_PAINT:

hdc = BeginPaint (hwnd, &ps) ;

for (i = 0 ; i < NUMSCANS ; i++)

if (key[i].xPos != -1)

DrawKey (hdc, i, FALSE) ;

midiOutGetDevCaps (iDevice, &moc, sizeof (MIDIOUTCAPS)) ;

wsprintf (szBuffer, TEXT ("Channel %i"), iChannel + 1) ;

TextOut (hdc, cxCaps, 1 * cyChar,

bOpened ? TEXT ("Open") : TEXT ("Closed"),

bOpened ? 4 : 6) ;

TextOut (hdc, cxCaps, 2 * cyChar, moc.szPname,

lstrlen (moc.szPname)) ;

TextOut (hdc, cxCaps, 3 * cyChar, szBuffer, lstrlen (szBuffer)) ;

TextOut (hdc, cxCaps, 4 * cyChar,

fam[iVoice / 8].inst[iVoice % 8].szInst,

lstrlen (fam[iVoice / 8].inst[iVoice % 8].szInst)) ;

EndPaint (hwnd, &ps) ;

return 0 ;

case WM_DESTROY :

SendMessage (hwnd, WM_COMMAND, IDM_CLOSE, 0L) ;

PostQuitMessage (0) ;

return 0 ;

}

return DefWindowProc (hwnd, message, wParam, lParam) ;} 程序虽然有点长,自己现在也没有学得很好,所以还不能完全看懂。希望以后能写一下关于这个程序的解释。

  最近想做一个模拟钢琴的小软件,想做个既有键盘接口又有鼠标接口的小软件。所涉及到的知识点如下:   1.有关键盘的知识   2.有关鼠标的知识   3.GDI的知识   4.媒体播放函数的有关知识   因为

相关阅读排行


用户评论

游客

相关内容推荐

最新文章

×

×

请激活账号

为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。

您的注册邮箱: 修改

重新发送激活邮件 进入我的邮箱

如果您没有收到激活邮件,请注意检查垃圾箱。