序
在学习了小张同学的c语言midi编程钢琴演奏-CSDN博客后,我又突发奇想,既然我们能够使用midi音乐编程自己谱曲与演奏,那我们何不自己做一架钢琴出来呢?
于是乎,说干就干,小张同学根据已有知识,并查阅资料,很快就搓了一架自己的钢琴出来
一、开发工具
我们使用的是visual studio2022这款IDE。visual studio2022是由微软开发的一款集成开发环境(IDE),用于开发各种类型的软件应用程序。它提供了丰富的工具和功能,包括代码编辑器、调试器、编译器、版本控制等,能够帮助开发人员更高效地编写、调试和部署应用程序。VS支持多种编程语言,包括C++、C#、VB.NET、JavaScript等,适用于Windows平台上的应用程序开发。这里默认大家成功安装, 不再一一赘述。
二、项目创建
这里我们选择c++的空项目,并将项目扩展名.cpp重置为.c
三、引入头文件
这里我们使用的头文件有<stdio.h>、<conio.h> 、<mmsystem.h>、<windows.h>
还要引入动态链接库"winmm.lib"
#include <windows.h>
#include <mmsystem.h>
#include <stdio.h>
#include <conio.h>
#pragma comment(lib,"winmm.lib")
四、函数介绍
在开始之前,我们要先简单介绍一下midi音乐调用的一些函数
包括:
- HMIDIOUT函数
- midiOutOpen函数
- midiOutShortMsg函数
- midiOutClose函数
这四个函数是midi音乐编程里最主要的函数,详细介绍请参见 c语言midi编程钢琴演奏-CSDN博客
这里小张同学只带领大家使用,就不再一一介绍了,
五、项目规划
菜单栏
我们想让用户打开后进入菜单栏所以写入函数
void begin() {
system("cls");
printf("==========================================================\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("||\t\t\t1:选择乐器\t\t\t||\n");
printf("||\t\t 2:light show\t\t\t||\n");
printf("||\t\t\t3:使用说明\t\t\t||\n");
printf("||\t\t\t4:退出程序\t\t\t||\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("==========================================================\n");
int x;
x = _getch();
switch (x)
{
case '1':
break;
case '2':
begin();
break;
case '3':
begin();
break;
case '4':
break;
default:
begin();
break;
}
}
int main() {
begin();
system("cls");
return 0;
}
我们这里主要做后端,所以就不去引入图形库去做什么厉害的界面了(doge)
我们预先设定了三个功能:选择乐器、lightShow(灯光秀)、使用说明三个函数,下面我会一一讲解
选择乐器函数
再说选择乐器函数
void musicInstrument() {
system("cls");
printf("==========================================================\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("||\t\t\t1:钢琴\t\t\t\t||\n");
printf("||\t\t\t2:吉他\t\t\t\t||\n");
printf("||\t\t\t3:笛子\t\t\t\t||\n");
printf("||\t\t\t4:music\t\t\t\t||\n");
printf("||\t\t\t5:返回\t\t\t\t||\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("||\t\t\t\t\t\t\t||\n");
printf("==========================================================\n");
int x;
x = _getch();
switch (x)
{
case '1':
piano();
musicInstrument();
break;
case '2':
guitar();
musicInstrument();
break;
case '3':
flute();
musicInstrument();
break;
case '4':
music();
musicInstrument();
break;
case '5':
begin();
break;
default:
musicInstrument();
break;
}
}
这里我们设定四个函数,分别是:
- 钢琴piano
- 吉他guitar
- 笛子flute
- 音乐music
前三个分别对应三个不同的音色
而最后一个函数可以把自己谱好的曲子放进去以实现点歌功能
灯光秀函数(lightShow)
这里灯光秀并非传统意义上的灯光秀,只是通过改变控制台颜色来实现炫目的效果,我将代码放到下面,大家如果有想改进的可以自己设计
使用说明函数
大家可以将自己程序的使用说明用printf打印出来,以便游客理解。
亦可以改成创作日志函数,记录自己游戏的开发历程
这里不再过多赘述……
六、正式开始
lightShow函数
我们这里直接调用Windows系统库中的函数来改变控制台的背景颜色,然后再用Switch函数与_getch函数键盘操控颜色的改变:
int light() {
char a;
while (a = _getch()){
system("cls");
switch (a)
{
case '1':
system("color 10");
break;
case '2':
system("color 20");
break;
case '3':
system("color 30");
break;
case '4':
system("color 40");
break;
case '5':
system("color 50");
break;
case '6':
system("color 60");
break;
case '7':
system("color 70");
break;
case '8':
system("color 80");
break;
case '9':
system("color 90");
break;
case 'q':
case 'Q':
system("color a0");
break;
case 'w':
case 'W':
system("color b0");
break;
case 'e':
case 'E':
system("color c0");
break;
case 'r':
case 'R':
system("color d0");
break;
case 't':
case 'T':
system("color e0");
break;
case 'y':
case 'Y':
system("color f0");
break;
case 'u':
case 'U':
system("color 01");
break;
case '*':
system("color 07");
return 0;
break;
default:
system("color 07");
break;
}
}
}
只要狂按对应按键就可以做出晃眼的效果了(=゚ω゚)ノ ---===≡≡≡
钢琴函数
打开midi设备
首先我们打开midi设备并将主声道音色设置为钢琴
unsigned long result;
HMIDIOUT handle;
midiOutOpen(&handle, 0, 0, 0, CALLBACK_NULL);
midiOutShortMsg(handle, 0 << 8 | 0xC0); //设置通道0的乐器为 大钢琴
从键盘获取按键数据
通过while循环与switch选择语句来从键盘获取按键数据
char a
while (a = _getch()) {
//构造Note On消息
switch (a)
{
case'1':
note = 36;
velocity = 100;
break;
case'2':
note = 38;
velocity = 100;
break;
case'3':
note = 40;
velocity = 100;
break;
case'4':
note = 41;
velocity = 100;
break;
case'5':
note = 43;
velocity = 100;
break;
case'6':
note = 45;
velocity = 100;
break;
case'7':
note = 47;
velocity = 100;
break;
case'Q':
case'q':
note = 48;
velocity = 100;
break;
case'W':
case'w':
note = 50;
velocity = 100;
break;
case'E':
case'e':
note = 52;
velocity = 100;
break;
case'R':
case'r':
note = 53;
velocity = 100;
break;
case'T':
case't':
note = 55;
velocity = 100;
break;
case'Y':
case'y':
note = 57;
velocity = 100;
break;
case'U':
case'u':
note = 59;
velocity = 100;
break;
case'A':
case'a':
note = 60;
velocity = 100;
break;
case'S':
case's':
note = 62;
velocity = 100;
break;
case'D':
case'd':
note = 64;
velocity = 100;
break;
case'F':
case'f':
note = 65;
velocity = 100;
break;
case'G':
case'g':
note = 67;
velocity = 100;
break;
case'H':
case'h':
note = 69;
velocity = 100;
break;
case'J':
case'j':
note = 71;
velocity = 100;
break;
case'Z':
case'z':
note = 72;
velocity = 100;
break;
case'X':
case'x':
note = 74;
velocity = 100;
break;
case'C':
case'c':
note = 76;
velocity = 100;
break;
case'V':
case'v':
note = 77;
velocity = 100;
break;
case'B':
case'b':
note = 79;
velocity = 100;
break;
case'N':
case'n':
note = 81;
velocity = 100;
break;
case'M':
case'm':
note = 83;
velocity = 100;
break;
case'*':
midiOutClose(handle);
return 0;
break;
default:
break;
}
//打印所弹奏的音符
//发送MIDI消息
}
填充备注处
构造Note On消息
unsigned short note = 0; //音符编号
unsigned short velocity = 100; // 力度值,范围通常在0-127
unsigned char statusByte = 0x90 | (0 & 0x0F);//0为声道
打印所弹奏的音符
int h = note;
int x = (h - 24) % 12;
char y = 'C'; // 初始化为默认音名C
int z = (h - 12) / 12;
switch (x)
{
case 0:
y = 'C';
break;
case 2:
y = 'D';
break;
case 4:
y = 'E';
break;
case 5:
y = 'F';
break;
case 7:
y = 'G';
break;
case 9:
y = 'A';
break;
case 11:
y = 'B';
break;
default:
break;
}
if (z != (-1)) {
printf("\n您弹奏了%c%d音", y, z);
}
发送midi消息
// 组合3个字节的消息到一个DWORD值
unsigned long noteOnMsg = (((unsigned long)velocity << 16) | (((unsigned long)note) << 8) | (unsigned long)statusByte);
// 发送MIDI消息
midiOutShortMsg(handle, noteOnMsg);
将以上代码填充至备注处,我们的C语言钢琴便做好了数据结构部分。接下来,只需要在循环开始处printf一个带颜色的钢琴块,我们的C语言钢琴就基本完工了
写入琴键
system("cls");
printfcolor(" 1+ ,2+ ,3+ ,4+ ,5+ ,6+ ,7+ \n", 1, 2);
printfcolor(" 1 ,2 ,3 ,4 ,5 ,6 ,7 \n\n", 6, 2);
printfcolor(" 1 ,2 ,3 ,4 ,5 ,6 ,7 \n", 1, 3);
printfcolor(" Q ,W ,E ,R ,T ,Y ,U \n\n", 6, 3);
printfcolor(" 1- ,2- ,3- ,4- ,5- ,6- ,7- \n", 1, 4);
printfcolor("A ,S ,D ,F ,G ,H ,J \n\n", 6, 4);
printfcolor("1--,2--,3--,4--,5--,6--,7--\n", 1, 5);
printfcolor("Z ,X ,C ,V ,B ,N ,M \n\n", 6, 5);
printfcolor("按“*”键返回……", 7, 8);
这样,我们的钢琴就完成了。大家感兴趣的话快去尝试一下吧!