大一也能看懂的原神风物之诗自动演奏程序

更新时间:2023-07-09 06:16:55 阅读: 评论:0

⼤⼀也能看懂的原神风物之诗⾃动演奏程序
前⾔
应朋友之邀,写⼀篇分析原神风物之诗⾃动弹奏原理的博客,并附带⼀个样例程序。
朋友的要求是:只⽤⼤⼀的C语⾔知识,写⼀个类似C语⾔⼤项⽬的程序,来实现原神风物之诗⾃动弹奏的功能。
注1:阅读本⽂需具有前置知识:C语⾔数组、⽂件、指针的知识。
注2:样例程序对编译器⽆限制,虽然dev-c++也能编译,但建议使⽤Visual Studio。
注3:本类程序使⽤C并不是最优解,相⽐来说,java更适合本类程序。
注4:⽂中的分析与注释基于初学者的C语⾔⽔平,实现简单,⽤语⽩话,程序结构没有进⾏精简。
正⽂
先来分析⼀下常见的风物之诗⾃动弹奏程序(pc端)。
(图源⽹络,侵权必删)
不难看出,这些程序本质上都由配置、选择乐谱、进⾏播放这⼏部分组成。再拆分⼀下进⾏模块化,我们将程序⼤体分为以下⼏个模块:主菜单模块menu(),调节曲速模块adjust(),集成⽂件选择与乐谱播放的读谱演奏模块play()。
第⼀部分是menu模块,功能是列出程序功能并提供相应跳转。本部分涉及对输⼊的处理操作。menu模块演⽰如下:
habe
第⼆部分是adjust模块,模块功能是修改程序中的⼀个变量(⾳间间隔变量cd)。本部分涉及指针操作。adjust模块演⽰如下:
第三部分是play模块,模块主要提供两个功能。第⼀个功能是遍历特定⽂件夹⾥的特定乐谱⽂件,列出乐谱⽂件供⽤户选择。本部分涉及⼀维、⼆维数组操作和⽂件操作。
第⼆个功能是根据⽤户选择的乐谱进⾏读谱弹奏。本部分涉及数组、⽂件以及模拟按键操作。
代码实现
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <windows.h>
4
5int cd=300; //⾳间间隔
6char temp; //1号临时变量
7int temp2; //2号临时变量
8int *p= &cd;//指向⾳间间隔的指针,需要对⼤⼀朋友强调的是,⼀定要有初始化指针的习惯,以免出现野指针
9
10//play函数内的变量
11char c;//临时变量,储存模拟按下的键的键名
12int tempcd;// tempcd为临时的⾳间间隔,⽅便调整。
13char musicPath[20]="乐谱\\*.txt"; //乐谱⽂件的地址的通⽤格式
14 WIN32_FIND_DATA findFileData;//⽂件操作常⽤的⼀种数据结构
15 HANDLE hFind;//句柄
16char str[50];//记录乐谱名字的字符串, 歌名最长50字符,汉字占两个
17char path[55][50]; //记录乐谱名字的字符串数组,⽤⼆维数组实现,最多55⾸歌
18
19void adjust(int *p);//调节曲速(⾳间间隔)功能
20void menu();//主菜单
21void play();//弹奏乐谱功能
22void me();//项⽬背景
esperanza spalding23void bye();//退出菜单
24
25void menu()//主菜单
26 {
27    printf("\n --------------功能菜单--------------\n");
28    printf(" |                                  |\n");
29    printf(" |          1、调节曲速            |\n");
30    printf(" |          2、读谱演奏            |\n");
31    printf(" |          3、项⽬相关            |\n");
32    printf(" |          4、退出程序            |\n");发音技巧
33    printf(" |                                  |\n");
34    printf(" ------------------------------------\n");
35    temp =  getch();//getch会读取下⼀个键⼊的字符,⽆需回车
36if(temp<'1' || temp>'4')//规范输⼊
37    {
38        printf("  请输⼊1-4之间的整数  \n\n");
39        menu();
40    }
41if(temp == '1')//页⾯跳转
42    {
43        adjust(&cd);
44    }
45if(temp == '2')
46    {
prosperous的名词
47        play();
48    }
49if(temp == '3')
50    {
51        me();
52    }
53if(temp == '4')
54    {
55        bye();
56    }
57 }
58
59void adjust(int *p)//使⽤指针可以将在函数内部改变的⾳间间隔传递出函数,当然,也可以⽤返回值解决这个问题
60 {
61    printf("\n--------------调节曲速--------------\n");
62    printf("|                                  |\n");
63    printf("| 这⾥的曲速指两个⾳之间的时间间隔 |\n");
64    printf("| 当前值%3ld,单位ms,值越⼩演奏越快  |\n",cd);
65    printf("| 将新曲速调节为: __________ ms    |\n");
66    printf("|                                  |\n");
67    printf("------------------------------------\n  ");
68    scanf("%d",&temp2);//将新曲速赋给临时变量temp2
69while('\n'!=getchar());    //对可能残留在输⼊流中的数据进⾏清理。
70if(temp2>0 && temp2<5000)//将新曲速限制在0~5s
71    {
72        *p = temp2;//符合要求则将新曲速赋给⾳间间隔cd
73        printf("  新曲速( %d ms)设置成功        \n\n",cd);
74        menu();//跳转
75    }el
76    {
77        printf("  请输⼊1-5000之间的整数        \n",cd);
78        printf("  单位 ms ,1000 ms = 1 s        \n\n",cd);
79        adjust(&cd); //规范输⼊
80    }
81  }
82
83void play()//遍历乐谱⽂件夹,列出乐谱,使⽤者选择后,读相应乐谱,然后模拟按键弹奏。此部分可进⼀步模块化
84 {
85int i=0;//记录乐谱序号
86int j=0;//记录选择的乐谱的序号的临时变量
87char str[50] = "乐谱/";//初始化乐谱地址字符串,初始化为乐谱地址的⽬录
88char path[55][50]={};//初始化乐谱名字符串数组,初始化为空
89    hFind=FindFirstFile(musicPath,&findFileData);//找到⽬录下第⼀个格式为 musicPath(即乐谱\\*.txt)的⽂件
90if(hFind==INVALID_HANDLE_VALUE) //如果⽬录下没有(第⼀个)⽂件
91    {
92        printf("乐谱⽂件夹中没有⽂件,请将txt格式的乐谱放⼊乐谱⽂件夹中!\n");
93        menu();
94    }
95el//如果⽬录下存在(第⼀个)⽂件
96    {
97        printf("当前可演奏的乐谱有:\n");
98while(1)//开始遍历乐谱,并将每个乐谱的地址放进path数组中。
99        {
100if(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
101            {//优化搜索结果,可以注释掉这个ifel看看
102            }
103el//输出符合结果⽂件名
104            {
105char str[50] = "乐谱/";//新⼀轮循坏开始的时候重置str
106                memcpy(str+5, findFileData.cFileName, strlen(findFileData.cFileName));//补全乐谱名字符串str,添加⽬录后的乐谱名,memcpy会据参数进⾏字符串覆盖,详情可107//百度,第⼀个参数+5值覆盖的内容从str的第六个字符开始,⽬的是保留"乐谱/"
108                sprintf(path[i],str);//将得到的乐谱名str放⼊乐谱名数组path,也可以⽤memcpy(path[i], str, strlen(str))。path[i]可以看作path[i][]的数组名
109                i++;//数组下标从0开始,供⽤户选择的乐谱序号从1开始,所以i++放到这个位置
110                printf("%3d : %s\n",i,findFileData.cFileName); //输出序号和与其对应的乐谱名
111            }
112if(!FindNextFile(hFind,&findFileData)) //没有下⼀个⽂件了就退出遍历
113            {
114break;
115            }
116        }FindClo(hFind); //关掉句柄
117        printf(" 输⼊乐谱前序号开始演奏:\n");
118        scanf(" %d",&j);//读者可以⾃⾏对⽐这⾥的读取输⼊与主菜单的读取输⼊的区别
119while('\n'!=getchar());    //对可能残留在输⼊流中的数据进⾏清理。
120if(j<1 || j>i)
121        {covid 19英文全称怎么读
122            printf("  请输⼊1-4之间的整数  \n\n");
123            play();
124        }el
125        {
126            FILE *p = fopen(path[j-1], "r");//打开⽂件流,因为给⽤户看的序号⽐数组的下标⼤1,所以这⾥j-1
127if(p == NULL)
128            {
129                printf(" 乐谱 %s 打开失败!\n",path[j-1]);
130                play();
131            }
132            printf(" 5秒后开始演奏 %s ,请切到原神风物之诗界⾯...\n\n",path[j-1]);
133                Sleep(5000);//暂停5秒
134            tempcd=cd;//tempcd为临时的⾳间间隔。
135            printf(" 演奏开始...\n");
136            printf(" ...\n");
137//while((c = fgetc(p)) != EOF)
dumbass
138// while(fscanf(p, "%c,%d", &c, &a) != EOF)//可以对⽐⼀下不同循环的区别
139for(;fscanf(p, "%c%d", &c, &tempcd) != EOF;tempcd=cd)//第⼆个参数:格式化读取到⽂件结束;第三个参数:没有指定⾳间间隔的使⽤默认⾳间间隔tempcd 140            {
141if(c>='a'&&c<='z') c-=32;//⼩写转⼤写
142if(c>='A'&&c<='Z')
143                {
144                    keybd_event(c, 0, 0, 0); //模拟按下键盘
145                    keybd_event(c, 0, 2, 0); //模拟松开键盘
146                }
147                Sleep(tempcd);//等待指定时间:⾳间间隔tempcd毫秒。放到if外⾯,这样⽂档中打','来分隔的话也会延时默认⾳间间隔
148//printf(" %c\n %d\n",c,tempcd);//可以解除注释观察读⽂件过程
149            }
150            fclo(p);//关闭⽂件流
151            printf("\n %s 演奏完毕!\n\n",path[j-1]);
152        }
153    }
154    printf(" -----------------------\n");
155    printf(" |                    |\n");
猪的英文156    printf(" |    现在你可以:    |\n");
157    printf(" |    1、继续演奏    |\n");
158    printf(" |    2、返回⾸页    |\n");
159    printf(" |    3、退出程序    |\n");
160    printf(" |                    |\n");
161    printf(" -----------------------\n");
162    j = 0;//重置临时变量
163    scanf(" %d",&j);
164while('\n'!=getchar());    //对可能残留在输⼊流中的数据进⾏清理。
165if(j<1 || j>3)
166    {
167        printf("  请输⼊1-3之间的整数  \n\n");
168        play();
169    }
170if(j == 1)//跳转
171        play();
172if(j == 2)
173        menu();
174if(j == 3)
175        bye();
176 }
177
mba统考
178void me()
179 {
180    printf("\n");
181    FILE *file = fopen("项⽬相关.txt", "r");
182if(file == NULL)
183        printf("⽂件缺失!\n");
184char b;
185while((b = fgetc(file)) != EOF)
186        printf("%c", b);
187    fclo(file);
188    printf("\n");
189    menu();
190 }
191
192void bye()
193 {
194    printf("\n                                    \n");
195    printf("        ----------------------      \n");
196    printf("        | 我们都有光明的未来 |      \n");
197    printf("        ----------------------      \n");
198    printf("                                    \n");
199    printf("  ------                      ------ \n");
200    printf("  | 我 |          /\\          | 你 |\n");
201    printf("  | 单 |        /福\\        | ⼗ |\n");
202    printf("  | 抽 |      /福福福\\      | 连 |\n");
203    printf("  | 奇 |    <;福福福福福>    | 七 | \n");
gc
204    printf("  | 迹 |      \\福福福/      | ⾦ |\n");
205    printf("  | ⼀ |        \\福/        | 从 |\n");
206    printf("  | ⾝ |          \\/          | 未 |\n");
207    printf("  | 欧 |                      | 保 | \n");
208    printf("  | ⽓ |                      | 底 | \n");
209    printf("  ------                      ------ \n");
210    printf("                                    \n");
211    printf("                                    \n");
212    printf("    希望你喜欢这个不完善的⼩程序  \n");
213    printf("    再见啦        /派蒙挥⼿.gif  \n\n");
214    system("pau");
215 }
216
217void main()
218 {
219    menu();
shinewrite220  }
原理讲解到此就差不多了,如果有没讲清楚的地⽅欢迎提出。另外,程序的具体的使⽤⽅法我会和源码、乐谱库⼀起放到百度云中,有需要的朋友⾃取。
补充
如果你觉得程序太简陋(确实太简陋了),那么可改进的地⽅还有很多,⽐如使⽤变长数组,再增加暂停、录谱、和⾳等功能;或者改进程序使之不仅能读键盘谱,还能读数字谱,并增加数据库操作来处理两种谱;也可以使⽤图形化api来写个窗⼝程序,同时让程序⾃动获得管理员权限等。难度逐渐上升,但都是⼤⼀经过不复杂的学习或百度就能实现的功能,但是像分析⾳频⽂件⾃动⽣成乐谱⽂件等功能这⾥就不推荐了,因为这种功能往往涉及⽅向特化的知识,有兴趣的朋友可以⾃⾏实现。
最后,我的UID是116752259,我的世界还蛮⼤的,资源都可以随便拿,欢迎你来我家玩。

本文发布于:2023-07-09 06:16:55,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/78/1086846.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:乐谱   程序   间隔   模块   功能   部分
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图