Windows_SDK编程--弹钢琴及自动弹琴辅助

记录Windows_SDK编程–弹钢琴项目及遇到的问题

首先是代码的前缀模板部分,均相同,故单独放置,使用时复制粘贴即可

#include <Windows.h>
#include <tchar.h>
#include <mmsystem.h>

#pragma comment(lib, "WINMM.LIB")
HINSTANCE g_hInstance = 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lPara);
int APIENTRY _tWinMain(
	HINSTANCE hInstance,   //本程序的实例句柄
	HINSTANCE hPreInstance,
	PTCHAR    pStr,
	int       nCmd
)
{
	g_hInstance = hInstance;
	//1  设计一个窗口类
	//UINT        style;
	//WNDPROC     lpfnWndProc;
	//int         cbClsExtra;
	//int         cbWndExtra;
	//HINSTANCE   hInstance;
	//HICON       hIcon;    图标
	//HCURSOR     hCursor;  光标
	//HBRUSH      hbrBackground;
	//LPCWSTR     lpszMenuName;
	//LPCWSTR     lpszClassName;
	WNDCLASS wnd = { 0 };
	wnd.style = CS_VREDRAW | CS_HREDRAW;//风格
	wnd.lpfnWndProc = WndProc;   //非常重要,消息处理回调函数的指针
	wnd.hInstance = hInstance;   //本程序的实例句柄,将窗口类注册到自己的程序中
	wnd.hbrBackground = (HBRUSH)COLOR_WINDOW;//背景颜色
	wnd.lpszClassName = _T("Piano");          //非常重要,窗口类名,是一个标识
	//---------------------------------------------------------------
	wnd.hCursor = 0;
	wnd.hIcon = 0;
	wnd.lpszMenuName = 0;
	//2  注册窗口类
	RegisterClass(&wnd);
	//3  创建窗口
	// 返回值,就是窗口的句柄
	// 我们要想操作窗口,API一定会要求我们提供句柄
	HWND hWnd = CreateWindow(
		_T("Piano"),        //窗口类名,必须和之前注册的一致
		_T("Piano"),//窗口名,随便起的名字
		WS_OVERLAPPEDWINDOW,//窗口风格,这里是重叠窗口(最常见的普通窗口)
		10, 10, 500, 300,   //窗口的左上角x,y坐标,宽度和高度
		NULL,               //父窗口句柄
		NULL,               //菜单的句柄
		hInstance,          //实例句柄,代表这个窗口属于本程序
		NULL                //传递WM_CREATE消息的时候,一个附加的参数
	);
	//4  更新显示窗口
	//窗口刚被创建的时候,是隐藏起来的,需要使用
	//ShowWindow显示出来
	ShowWindow(hWnd, SW_SHOW);
	//它会产生第一个WM_PAINT消息,让窗口有机会自我绘制
	UpdateWindow(hWnd);

	//5  消息循环(消息泵)
	MSG msg = {};
	//GetMessageW(
	//	_Out_ LPMSG lpMsg,
	//	_In_opt_ HWND hWnd,   我只接收某一个窗口的消息
	//	_In_ UINT wMsgFilterMin, 获取消息的最小值
	//	_In_ UINT wMsgFilterMax);获取消息的最大值

	//   5.1获取消息
	//当获取到WM_QUIT消息的时候,返回0
	//while结束整个程序结束
	while (GetMessage(&msg, 0, 0, 0))
	{
		//   5.2翻译消息
		TranslateMessage(&msg);
		//   5.3转发到消息回调函数
		DispatchMessage(&msg);
	}
	return 0;
}
LRESULT CALLBACK WndProc(
	HWND hWnd,    //哪一个窗口产生了消息
	UINT Message, //产生的消息是什么 
	WPARAM wParam,//消息的附加信息 
	LPARAM lParam //也是消息的附加信息
)
  • 第一次根据钢琴需求写出的代码为响应A~Z26个按键,播放对应按键的音效(很长,很LOW)
    case 0x(XX) 为16进制的A~Z
    (用PlaySound也可以)
    反正都是无效打工…
{
	switch (Message)
	{
	case WM_KEYDOWN:
		switch (wParam)
		{
		case 0x41:
			mciSendString(TEXT("close G://Sound_A.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_A.wav"), NULL, 0, NULL);
			break;
		case 0x42:
			mciSendString(TEXT("close G://Sound_B.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_B.wav"), NULL, 0, NULL);
			break;
		case 0x43:
			mciSendString(TEXT("close G://Sound_C.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_C.wav"), NULL, 0, NULL);
			break;
		case 0x44:
			mciSendString(TEXT("close G://Sound_D.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_D.wav"), NULL, 0, NULL);
			break;
		case 0x45:
			mciSendString(TEXT("close G://Sound_E.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_E.wav"), NULL, 0, NULL);
			break;
		case 0x46:
			mciSendString(TEXT("close G://Sound_F.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_F.wav"), NULL, 0, NULL);
			break;
		case 0x47:
			mciSendString(TEXT("close G://Sound_G.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_G.wav"), NULL, 0, NULL);
			break;
		case 0x48:
			mciSendString(TEXT("close G://Sound_H.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_H.wav"), NULL, 0, NULL);
			break;
		case 0x49:
			mciSendString(TEXT("close G://Sound_I.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_I.wav"), NULL, 0, NULL);
			break;
		case 0x4A:
			mciSendString(TEXT("close G://Sound_J.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_J.wav"), NULL, 0, NULL);
			break;
		case 0x4B:
			mciSendString(TEXT("close G://Sound_K.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_K.wav"), NULL, 0, NULL);
			break;
		case 0x4C:
			mciSendString(TEXT("close G://Sound_L.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_L.wav"), NULL, 0, NULL);
			break;
		case 0x4D:
			mciSendString(TEXT("close G://Sound_M.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_M.wav"), NULL, 0, NULL);
			break;
		case 0x4E:
			mciSendString(TEXT("close G://Sound_N.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_N.wav"), NULL, 0, NULL);
			break;
		case 0x4F:
			mciSendString(TEXT("close G://Sound_O.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_O.wav"), NULL, 0, NULL);
			break;
		case 0x50:
			mciSendString(TEXT("close G://Sound_P.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_P.wav"), NULL, 0, NULL);
			break;
		case 0x51:
			mciSendString(TEXT("close G://Sound_Q.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_Q.wav"), NULL, 0, NULL);
			break;
		case 0x52:
			mciSendString(TEXT("close G://Sound_R.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_R.wav"), NULL, 0, NULL);
			break;
		case 0x53:
			mciSendString(TEXT("close G://Sound_S.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_S.wav"), NULL, 0, NULL);
			break;
		case 0x54:
			mciSendString(TEXT("close G://Sound_T.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_T.wav"), NULL, 0, NULL);
			break;
		case 0x55:
			mciSendString(TEXT("close G://Sound_U.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_U.wav"), NULL, 0, NULL);
			break;
		case 0x56:
			mciSendString(TEXT("close G://Sound_V.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_V.wav"), NULL, 0, NULL);
			break;
		case 0x57:
			mciSendString(TEXT("close G://Sound_W.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_W.wav"), NULL, 0, NULL);
			break;
		case 0x58:
			mciSendString(TEXT("close G://Sound_X.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_X.wav"), NULL, 0, NULL);
			break;
		case 0x59:
			mciSendString(TEXT("close G://Sound_Y.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_Y.wav"), NULL, 0, NULL);
			break;
		case 0x5A:
			mciSendString(TEXT("close G://Sound_Z.wav"), NULL, 0, NULL);
			mciSendString(TEXT("play G://Sound_Z.wav"), NULL, 0, NULL);
			break;
		}
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	default:
		return DefWindowProc(hWnd, Message, wParam, lParam);
		break;
	}
	return 0;
	//所有不处理的消息,都可以由DefWindowProc默认处理
}

反正就…通俗易懂…
在这里插入图片描述

--------------------------------------------------------------------------------------------------------------------------------------------------------

  • 因为按键音频的wav文件都是大致一致的Sound_(X).wav格式,故修改为如下版本(从这里有点小坑,导致后面做自动弹琴的辅助时出现问题)
{
	switch (Message)
	{
	case WM_KEYDOWN:
	{
		TCHAR szFullPath[MAX_PATH];
		_stprintf_s(szFullPath, MAX_PATH, _T("G://Sound_%C.wav"), wParam);
		PlaySound(szFullPath, NULL, SND_ASYNC | SND_NOWAIT);//PlaySound不支持混音
	}break;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	default:
		return DefWindowProc(hWnd, Message, wParam, lParam);
		break;
	}
	return 0;
	//所有不处理的消息,都可以由DefWindowProc默认处理
}

(到这里其实不考虑自动弹琴辅助的问题是可以正常使用的)

  • 接下来是自动弹琴辅助
    读取曲谱文件,并输出打印即可
#include<stdio.h>
#include<Windows.h>

void GetDate(char*& data, int& len)
{
	FILE* fp;
	fopen_s(&fp, "G:\\Sound.txt", "r");
	fseek(fp, 0, SEEK_END);
	len = ftell(fp);
	data = new char[len];
	fseek(fp, 0, SEEK_SET);
	fread(data, len, 1, fp);
	fclose(fp);
}

int main()
{
	HWND hWnd = FindWindow(NULL, L"Piano");
	char* data = NULL;
	int len = 0;
	GetDate(data, len);
	for (int i = 0; i < len; i++)
	{
		printf(" %c", data[i]);
		if (data[i] != '\n' && data[i] != ' ')
		{
			SendMessage(hWnd, WM_CHAR, data[i], 0);
			Sleep(400);
		}
	}
	return 0;
}

然后这里就出现问题了,程序倒是跑起来了,自嗨模拟按键也感觉妥妥的,但是就是没有声音…
实现了吗?实现了。有影响吗?没有影响。有人在乎吗?没有人在乎。
在这里插入图片描述
其实就是之前自己挖的小坑…
之前想的是钢琴,那就是我按下按键,你发出声音,逻辑没毛病,单独看也没毛病,但放在一起就不行了。
这里也很好解决,其实就是把WM_KEYDOWN换成WM_CHAR就可以了,再贴一遍代码,毕竟我看别人代码也看不懂。

{
	switch (Message)
	{
	//case WM_KEYDOWN:
	case WM_CHAR:
	{
		TCHAR szFullPath[MAX_PATH];
		_stprintf_s(szFullPath, MAX_PATH, _T("G:\\Sound_%C.wav"), wParam);
		PlaySound(szFullPath, NULL, SND_ASYNC | SND_NOWAIT);//PlaySound不支持混音
	}break;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	default:
		return DefWindowProc(hWnd, Message, wParam, lParam);
		break;
	}
	return 0;
	//所有不处理的消息,都可以由DefWindowProc默认处理
}

:WM_CHAR消息是俘获某一个字符的消息,WM_KEYDOWN消息是俘获某一个键按下的消息

如果光是弹琴可以是获取字符消息也可以是获取按键消息,但是由于自动弹琴是通过读取字符实现的,故此处需使用WM_CHAR。

  • 最后先运行钢琴程序,再运行自动弹琴辅助程序就可以实现自动弹琴了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值