用C/C++写一个简易的钢琴小程序

您所在的位置:网站首页 演奏钢琴游戏 用C/C++写一个简易的钢琴小程序

用C/C++写一个简易的钢琴小程序

2024-07-16 15:18:15| 来源: 网络整理| 查看: 265

0.缘由

C语言课期末大作业。由于是开放性的作业,随便写着玩的,就写了这么一个玩意。虽然高中的时候接触过一些音乐或者音频软件,像Au,FLstudio,Minecraft之类的,但实际上对音乐方面的还算是一窍不通,其原因是不同于许多同龄人,在小的时候并没有被父母逼着去学一门乐器,也就没有接受过正规的乐理方面的教育。如果本文或文中代码里出现一些低级的音乐常识方面的错误,还请不吝赐教。当然,作为半年前刚刚接触代码的大一新生,代码部分存在很多漏洞,不规范之处和可优化的地方,也希望能够给予谅解并多多指教。

1.环境

Win10系统

Micosoft cl编译器,msvc开发者工具包

VS2019白嫖版附赠的cl编译器,为什么用这个后文会讲

Visual Studio Code编辑器,coderunner插件,C/C++拓展插件

vscode里的tasks.json文件。不要问我任务名为什么既是build又是test,问就是脑子抽了

vscode里的launch.json文件,此次不需要用到下面那个g++

引用头文件或类:iostream, thread, string.h, windows.h, conio.h, mmsystem.h, stdlib.h

链接的库:winmm.lib

计算机配置:

家贫,买不起好机子

2.思路

思考编写过程中可能会出现的问题和需要特别关照的点:

2.1如何在程序内播放声音?

上网查了一下,似乎是在mmsystem.h头文件中,提供了一个windows本身的api函数mciSendString,可以播放媒体文件。但不幸的是,使用这个函数需要链接一个动态库,而我一直以来使用的g++编译器不仅链接起来十分麻烦,g++自带的那些库中还找不到这个库。many shoes?查了一下,大概是说gcc和g++属于linux系的编译器,因此其提供的很多api函数都是对接linux的。无奈,只好下载了微软家的VS2019白嫖版(理论上来说visual c++之流应该也可以)。在调整了一些环境变量之后,用cl编译了一次,发现可以播放声音了。

2.2钢琴上每个键的声音从哪来?

这个算是一个比较简单的问题,观察一下网上一些在线钢琴:

图片原网址:https://virtualpiano.net/

发现在打开网页的时候服务器会发送一系列MP3文件过来。不用说,就是每个键对应的音。那么接下来就好办了,遂设计爬虫爬取之:

import requests jianlist=['C','Cs','D',"Ds","E","F","Fs","G","Gs","A","As","B"] jielist=[str(x) for x in range(7)] for jian in jianlist: for jie in jielist: url = "https://cdn.jsdelivr.net/gh/warpprism/cdn@latest/au\ topiano/static/samples/bright_piano/"+jian+jie+".mp3" path = 你所需要的路径+jian+jie+".mp3" headers = { "User-Agent":"Mozilla/5.0 (Windows NT 6.3; Win64; x64) Apple\ WebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36" } respones = requests.get(url,headers=headers) with open(path,mode="wb") as f: f.write(respones.content) print(path+" done") print("end")

当时写这个爬虫是用来爬https://www.autopiano.cn/这个网站的(非常感谢autopiano.cn对本程序编写过程中提供的借鉴和启发意义,以及非常抱歉用爬虫消耗了一部分服务器资源,真心非常抱歉),但截至发稿时间该网站已更换了底层源码(应该是叫这个吧?),打开网页和更换音色的时候服务器不会再发送一系列的MP3文件过来了,而是会发送一个js文件。具体的工作原理我也不是很懂,有待以后进一步探究。

2.3如何实现短时间内播放多个声音?

钢琴上一个音可以持续3秒,甚至更多。但两个音之间的间隔远远小于3秒。如何在使用mciSendString函数播放声音的同时,使程序不停止在该函数处,而是继续运行并播放下一个音? 答案是多线程。 但由于将之前的g++编译器换成了cl编译器,而微软的开发者工具包中没有pthread.h,手动引入pthread.h又比较复杂(太懒),所以本程序使用的是c++11引入的、功能远没有pthread.h丰富的、但是是由微软的开发者工具包中自带的、使用起来非常简便的、与windows系统有天然适应性(大概)的thread类。 (好像有个process.h也能多线程编程?但是用起来有点麻烦。本程序涉及的多线程方面的东西都比较浅显,所以是越简单越好)

2.4如何实现键盘按键与声音的对应?

由于爬下来的声音文件名是对应的音名(当时是这样的),肯定不能直接输入音名来播放。方法之一是将每个音的文件名改成对应按键的名字,但这样手动操作量较大。我的想法是使用一个decode函数进行解码(?),通过一定的规律将按键映射成相应的音名。

2.5如何实现按下对应键后立马播放对应的声音?

平常使用的getchar函数、scanf函数以及cin方法等都需要按下回车后才能被程序所接收,这些函数显然不符合需求。经过网上查询后得知,conio.h中的getch函数和_getch函数有这样的效果。

2.6如何实现不断地接收输入并播放对应声音?

死循环,while(True)…

2.7如何实现自动按输入的简谱演奏?

可以设置将简谱写在一个文件中,播放时读取这个文件。原本的想法是直接将简谱的数字写在文件中,用*代表升8度,用.代表降8度,音符之间以空格间隔,一次用%s读取一个音符,然后再通过另一个decode函数解码为对应音名。但最终发现简谱实在过于复杂,应由人工将简谱上的音符转换为应该按下的按键,再直接将按键输入文件中,相当于是将stdin重定向为某一文件流之后的手动模式。

2.8如何存储人肉解码好的谱子?

如图: 图为在vscode中打开的样子(乐曲为平凡之路) 对照一下原乐谱: 来源:http://www.doc88.com/p-7794828256780.html

3.结构

首先这个程序初步确定有两个模式:自动和手动。两个模式的界面应该是不同的。所以根据结构化编程思想,一个函数负责一个模式,分别是automode()和manualmode()。既然有两个模式,那么肯定要有一个选择模式的开始界面,设为beginmode()。又开始必有结束,还要有一个endmode()。Mode之间的跳转可以放在main里,用一个int来存放跳到哪一个mode的信息。 所以main的伪代码大概为:(注意接下来都是伪代码)

Int main(){ Int mode=0; While(true): If mode==0: Mode = Beginmode() If mode==1: Mode = manualmode() If mode==2: Mode = automode() If mode==3: Mode = endmode() Break //这个地方好像用switch语句也可以 System.cls; Return 0; }

而beginmode应该是这样:

Int beginmode(){ Cout


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭