好友
阅读权限10
听众
最后登录1970-1-1
|
本帖最后由 hudaoyuan163 于 2022-8-23 08:35 编辑
钢琴买不起,可以自己码一个。
来个C++ Piano,码砖累了还可以即兴演奏一首。
主要用到SDK知识,文件流,字符转,程序之间消息传送,window运行程序遍历等
音源和乐谱在压缩包中,一并奉上,望大佬多多指教
1.实现播放本地音乐:
-
在项目中添加音乐文件,如果在vs中运行即以main数所在文件夹为当前文件夹,如果运行的是exe文件,则是以exe文件所在的文件夹为当前文件夹。
-
导入Windows.h头文件,#pragma comment(lib,"winmm.lib"),需要使用micString(),该函数用于将mci(媒体控制设备)有关指令发送到设备上。该函数有两种版本A版和W版,是否可以使用通用版?函数如果成功返回0失败则返回其他。
-
MCIERROR mciSendString(
LPCTSTR lpszCommand, //发送给MCI的指令
LPTSTR lpszReturnString, //返回的结果
UINT cchReturn, //返回结果大小
HANDLE hwndCallback //如果在命令字符串中指定了“通知”标志,则返回回调窗口的hwndCallback句柄
);
-
新建一个loadmusic函数导入所有音乐并设置别名mciSendStringA(("open sound\start.mp3 alias START"), temp, 255, 0);这里alias是别名指令,将start.mp3打开为别名START。
-
新建一个PlayMusic函数用于播放已经打开的音乐,mciSendStringA("seek START to start", NULL, 0, 0);mciSendStringA("play START", NULL, 0, 0);
2.实现窗口对按键的反应
- 在窗口的回调函数中判断 Msg 如果是WM_CHAR消息,则获取wParam的值,以该值作为索引找出对应的音乐。
- 按下不同的按键就会打开对应音乐。
3.实现外挂读取文件
- 包含windows,使用GetDesktopWindow()得到桌面句柄,使用GetWindow得到屏幕上第一个子窗口句柄,通过while循环和GetNextWindow遍历所有窗口,找到Piano程序,得到其句柄。
- 创建SendOpern函数发送曲谱,参数为句柄,第一步打开文件获取数据,使用ofstream读取文本文件。(无法读取空格)
- 将读取到的字符通过sendmessage发送给Pinao窗口,第一个参数为句柄,第二个参数为发送消息类型,第三个参数为wParam,第四个参数为lParam。 SendMessage( hd,WM_CHAR,k, 0)。
贴上源代码
Piano
#include<Windows.h>
#include<tchar.h>//为通用提供映射
#include< conio.h >
#include<stdio.h>
//该链接库用于音乐播放
#pragma comment(lib,"winmm.lib")
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void LoadMusic();
int APIENTRY _tWinMain(
HINSTANCE hinstance, //实例句柄
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, //命令行参数
int nCmdShow //显示方式
)
{
//1.设计窗口类
WNDCLASS ws = {};
//窗口类名
ws.lpszClassName = _T("Music");
//窗口回调函数
ws.lpfnWndProc = WndProc;
//背景颜色
ws.hbrBackground = CreateSolidBrush(RGB(255, 180, 255));
//光标图标菜单,
ws.hInstance = hinstance;
//2.注册窗口类
RegisterClass(&ws);
//3.创建窗口
HWND hWnd = CreateWindow(
_T("Music"), //窗口类名
_T("Piano"), //窗口名
WS_OVERLAPPEDWINDOW,//窗口风格
100, 100, //窗口左上角的位置,以屏幕左上角为参考点
600, 800, //窗口的宽度和高度
NULL, //父窗口句柄
NULL, //菜单句柄
hinstance, //实例句柄
NULL //附加参数
);
//4.更新显示窗口
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
LoadMusic();
//5.消息循环
MSG msg = {};
//GetMessage
//第一个是消息结构体
//第二个是窗口句柄,如果填0就是所有窗口的消息
//第三个是最小消息数量
//第四个是最大消息数量
while (GetMessage(&msg, 0, 0, 0))
{
//将消息分发给回调函数
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam,
LPARAM lParam)
{
switch (Msg)
{
case WM_CHAR:
{
char szBuf[100] = { 0 };
char szBuf1[100] = { 0 };
sprintf_s(szBuf, sizeof(szBuf), "seek %c to start", wParam);
sprintf_s(szBuf1, sizeof(szBuf1), "play %c", wParam);
mciSendStringA(szBuf, NULL, 0, 0);
mciSendStringA(szBuf1, NULL, 0, 0);
}break;
case WM_KEYDOWN:
{
//MessageBox(0, buff, 0, 0);
}break;
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
break;
}
//如果不想要处理的消息类型,就让他返回默认的处理函数
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
void LoadMusic()
{
char A = 'A';
for (int i = 1; i < 26; i++)
{
char szBuf[100] = { 0 };
sprintf_s(szBuf, sizeof(szBuf), "open sound\\Sound_%c.wav alias %c", A, A);//写入
A++;
mciSendStringA(szBuf, NULL, 0, 0);
}
}
辅助,读取琴谱自动演奏
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#include <string.h>
#include <iostream>
#include<fstream>
void SendOpern(HWND hd);
void SendOpern2(HWND hd);
using namespace std;
int main()
{
HWND hd = GetDesktopWindow(); //得到桌面窗口
hd = GetWindow(hd, GW_CHILD); //得到屏幕上第一个子窗口
char s[200] = {0};
int num = 1;
while (hd != NULL) //循环得到所有的子窗口
{
//memset(s, 0,200);
GetWindowTextA(hd, s, 200);
//cout << num++ << ": " << s <<sizeof(s) << endl;
//由于字符串数组之间无法比较,所以需要转换为字符串
std::string a(&s[0], &s[strlen(s)]);
if (a == "Piano") {
SendOpern2(hd);
printf("演奏成功");
break;
}
hd = GetNextWindow(hd, GW_HWNDNEXT);
}
SendOpern(hd);
getchar();
return 0;
}
void SendOpern(HWND hd)
{
ifstream Opern;
Opern.open("Sound.txt", ios::in);
char k;
while (Opern >> k) {
Sleep(800);
//此处空格和"\n"都被>>吃掉了
SendMessage(
hd,
WM_CHAR,
k, 0
);
printf("%c\n", k);
}
}
void SendOpern2(HWND hd)
{
ifstream Opern;
Opern.open("Sound.txt", ios::in);
string k;
while (Opern >> k) {
for (auto ele : k) {
Sleep(1000);
SendMessage(
hd,
WM_CHAR,
ele, 0
);
printf("%c\n", ele);
}
Sleep(1000);
}
}
|
免费评分
-
查看全部评分
|