当 C++ 遇上音乐
前几天在洛谷日报征文中看到了这样一篇文章:C++不止能做题。作为原来校管弦乐队的一名成员,而后因为信息完全放弃了管弦乐队,我看完是又激动又怀念。于是我自行去研究了一下:C++ 如何让蜂鸣器叫出乐曲。
由于本人乐理只有五线谱D2-2级,数学成绩中游,信息也只有普及组水平。如果有哪里写错了,望大家指正、轻 D。
首先需要知道两个函数:
#include <windows.h>
Beep( f, t );
Sleep( t );
Beep() 函数可以让蜂鸣器发出频率为 \(f\) 赫兹,音长大约为 \(2t\) 毫秒的音。(注意是 \(2t\))
Sleep() 函数可以当做休止符用。它可以让程序停止运行 \(t\) 毫秒的时间。
如果想知道每个音对应的频率,可以自行百度十二平均律频率表。以下是三个最常用的八度的频率:
// _在前表示低音, 在后表示高音
// o表示升
const int _oC = 277, _oD = 311, _oF = 370, _oG = 415, _oA = 466;
const int _C = 262, _D = 294, _E = 330, _F = 349, _G = 392, _A = 440, _B = 494;
const int oC = 554, oD = 622, oF = 740, oG = 831, oA = 932;
const int C = 523, D = 578, E = 659, F = 698, G = 784, A = 880, B = 988;
const int C_ = 1047, D_ = 1175, E_ = 1319, F_ = 1397, G_ = 1568, A_ = 1760, B_ = 1976;
const int oC_ = 1109, oD_ = 1245, oF_ = 1480, oG_ = 1661, oA_ = 1865;
(为了偷懒方便,这当中我统一把降音变成了升音……比如降 \(\text{B}\) 我就用升 \(\text{A}\) 代替。)
接下来考虑如何计算 \(t\)。在编程中,我们可以设置一个常量 \(T\) 表示单拍子的时长的一半(因为 Beep 函数中调用的 \(t\) 就是时长的一半)。这样,如果一个音符占半拍,那么它的时长 \(t = \frac{T}{2}\);如果一个音符占两拍,那么它的时长 \(t = 2T\);如果一个休止符占一拍,那么它的时长 \(t = 2T\)(请特别注意 Sleep 函数与 Beep 函数中 \(t\) 的区别)。另外,在乐曲结尾经常有无限延长记号。无限延长记号一般是延长到 \(6\) 到 \(8\) 拍,最好不要超过 \(10\) 拍。
那么如何计算这个常量 \(T\) 呢?在一般谱子的左上角,都会有 ♩ = 76、♩ = 84 之类的符号,这意味着该曲以四分音符为一拍,每分钟 76 / 84 拍(取决于等号后面的数字)。
接下来就是小学数学题了。以 ♩ = 76 为例。每分钟 \(60000\) 毫秒,每分钟 \(76\) 拍,那么每拍占 \(\frac{60000}{76}\) 毫秒,可以近似取到 \(800\)。又因为 \(T\) 是时长的一半,所以 \(T\) 就应该取 \(\frac{800}{2}\),也就是 \(400\)。
知道了这些以后,我们看一个例子(小星星):
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <windows.h>
using namespace std;
// _在前表示低音, 在后表示高音
// o表示升
const int _oC = 277, _oD = 311, _oF = 370, _oG = 415, _oA = 466;
const int _C = 262, _D = 294, _E = 330, _F = 349, _G = 392, _A = 440, _B = 494;
const int oC = 554, oD = 622, oF = 740, oG = 831, oA = 932;
const int C = 523, D = 578, E = 659, F = 698, G = 784, A = 880, B = 988;
const int C_ = 1047, D_ = 1175, E_ = 1319, F_ = 1397, G_ = 1568, A_ = 1760, B_ = 1976;
const int oC_ = 1109, oD_ = 1245, oF_ = 1480, oG_ = 1661, oA_ = 1865;
const int T = 400; //一拍的长度
const int Stop = 800; //一拍休止符的长度
int main()
{
Beep( C, T );
Beep( C, T );
Beep( G, T );
Beep( G, T );
Beep( A, T );
Beep( A, T );
Beep( G, T * 2 );
Beep( F, T );
Beep( F, T );
Beep( E, T );
Beep( E, T );
Beep( D, T );
Beep( D, T );
Beep( C, T * 2 );
Beep( G, T );
Beep( G, T );
Beep( F, T );
Beep( F, T );
Beep( E, T );
Beep( E, T );
Beep( D, T * 2 );
Beep( G, T );
Beep( G, T );
Beep( F, T );
Beep( F, T );
Beep( E, T );
Beep( E, T );
Beep( D, T * 2 );
Beep( C, T );
Beep( C, T );
Beep( G, T );
Beep( G, T );
Beep( A, T );
Beep( A, T );
Beep( G, T * 2 );
Beep( F, T );
Beep( F, T );
Beep( E, T );
Beep( E, T );
Beep( D, T );
Beep( D, T );
Beep( C, T * 4 );
return 0;
}
这里面多了一个常量 \(Stop\),用于表示休止符的一拍,这样书写起来可以方便许多,调用 Sleep 函数的时候不需要一直换算。
我还无聊地打了另外几首歌。
《团结就是力量》
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <windows.h>
using namespace std;
// _在前表示低音, 在后表示高音
// o表示升
const int _oC = 277, _oD = 311, _oF = 370, _oG = 415, _oA = 466;
const int _C = 262, _D = 294, _E = 330, _F = 349, _G = 392, _A = 440, _B = 494;
const int oC = 554, oD = 622, oF = 740, oG = 831, oA = 932;
const int C = 523, D = 578, E = 659, F = 698, G = 784, A = 880, B = 988;
const int C_ = 1047, D_ = 1175, E_ = 1319, F_ = 1397, G_ = 1568, A_ = 1760, B_ = 1976;
const int oC_ = 1109, oD_ = 1245, oF_ = 1480, oG_ = 1661, oA_ = 1865;
const int T = 400;
const int Stop = 800;
int main()
{
Beep( C_, T * 2 );
Beep( G, T );
Beep( E, T / 4 * 3 );
Beep( D, T / 4 );
Beep( C, T );
Beep( G, T );
Beep( E, T );
Sleep( Stop );
Beep( C_, T * 2 );
Beep( G, T );
Beep( E, T / 4 * 3 );
Beep( D, T / 4 );
Beep( C, T );
Beep( A, T );
Beep( G, T );
Sleep( Stop / 2 );
Beep( G, T / 2 );
Beep( C_, T );
Beep( A, T / 2 );
Beep( G, T / 2 );
Beep( C_, T );
Sleep( Stop / 2 );
Beep( G, T / 2 );
Beep( C_, T );
Beep( A, T / 2 );
Beep( G, T / 2 );
Beep( A, T );
Sleep( Stop / 2 );
Beep( E, T / 2 );
Beep( C_, T / 2 * 3 );
Beep( A, T / 2 );
Beep( G, T );
Beep( E, T );
Beep( C_, T / 2 * 3 );
Beep( A, T / 2 );
Beep( C_, T );
Sleep( Stop );
Beep( C_, T );
Beep( G, T );
Beep( E, T / 2 );
Beep( A, T / 2 );
Beep( G, T / 2 );
Beep( E, T / 2 );
Beep( D, T / 2 * 3 );
Beep( C, T / 2 );
Beep( E, T );
Sleep( Stop / 2 );
Beep( G, T / 2 );
Beep( C_, T );
Beep( G, T );
Beep( A, T / 2 );
Beep( C_, T / 2 );
Beep( A, T / 2 );
Beep( G, T / 2 );
Beep( E, T );
Beep( E, T / 2 );
Beep( C, T / 2 );
Beep( A, T * 2 );
Beep( A, T );
Sleep( Stop );
Beep( C_, T / 4 * 3 );
Beep( C_, T / 4 );
Beep( G, T / 2 );
Beep( G, T / 2 );
Beep( D, T / 4 * 3 );
Beep( E, T / 4 );
Beep( G, T / 2 );
Beep( G, T / 2 );
Beep( A, T / 2 * 3 );
Beep( G, T / 2 );
Beep( A, T );
Beep( D_, T );
Beep( C_, T );
Beep( A, T / 2 );
Beep( G, T / 2 );
Beep( C_, T );
Beep( A, T / 2 );
Beep( G, T / 2 );
Beep( E, T * 2 );
Beep( C_, T );
Sleep( Stop );
return 0;
}
可以明显听出,当节奏快起来的时候,蜂鸣器发音的速度就有点赶不上了。所以这种方法局限性还是很强的,只适合打小夜曲之类的……
最后附上我们学校的校歌(原曲是 G 大调的,但是我太弱了不知道怎么弄……于是降成 C 大调写了)。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <windows.h>
using namespace std;
// _在前表示低音, 在后表示高音
// o表示升
const int _oC = 277, _oD = 311, _oF = 370, _oG = 415, _oA = 466;
const int _C = 262, _D = 294, _E = 330, _F = 349, _G = 392, _A = 440, _B = 494;
const int oC = 554, oD = 622, oF = 740, oG = 831, oA = 932;
const int C = 523, D = 578, E = 659, F = 698, G = 784, A = 880, B = 988;
const int C_ = 1047, D_ = 1175, E_ = 1319, F_ = 1397, G_ = 1568, A_ = 1760, B_ = 1976;
const int oC_ = 1109, oD_ = 1245, oF_ = 1480, oG_ = 1661, oA_ = 1865;
const int T = 400;
const int Stop = 800;
int main()
{
Beep( C, T );
Beep( A, T * 2 );
Beep( A, T );
Beep( F, T );
Beep( C, T );
Beep( C, T );
Beep( F, T * 2 );
Beep( E, T );
Beep( D, T * 3 );
Beep( _B, T / 2 );
Beep( _B, T / 2 );
Beep( _A, T );
Beep( E, T );
Beep( D, T * 2 );
Beep( _A, T );
Beep( _B, T );
Beep( C, T * 3 );
Beep( _E, T );
Beep( _A, T / 2 );
Beep( _B, T / 2 );
Beep( C, T / 2 );
Beep( D, T / 2 );
for ( int i = 1; i <= 2; ++i ) {
Beep( E, T );
Beep( E, T );
Beep( E, T );
Beep( D, T / 2 * 3 );
Beep( E, T / 2 );
Beep( C, T );
Beep( _B, T * 2 );
Beep( _A, T / 2 );
Beep( _G, T / 2 );
Beep( _A, T * 5 );
Beep( _A, T );
Beep( _G, T );
Beep( C, T );
Beep( E, T );
Beep( G, T * 2 );
Beep( E, T );
Beep( F, T / 2 * 3 );
Beep( E, T / 2 );
Beep( D, T / 2 );
Beep( _A, T / 2 );
Beep( D, T * 6 );
Beep( E, T );
Beep( E, T );
Beep( E, T );
Beep( D, T / 2 * 3 );
Beep( E, T / 2 );
Beep( C, T );
Beep( _B, T );
Beep( _B, T / 2 );
Beep( _B, T / 2 );
Beep( _A, T / 2 );
Beep( _G, T / 2 );
Beep( _A, T * 2 );
Beep( _A, T );
Beep( _G, T );
Beep( C, T );
Beep( E, T );
Beep( G, T * 3 );
Beep( F, T * 2 );
Beep( F, T );
Beep( E, T / 2 * 3 );
Beep( E, T / 2 );
Beep( D, T / 4 * 3 );
Beep( E, T / 4 );
Beep( C, T * 5 );
Beep( C, T / 2 );
Beep( C, T / 2 );
Beep( A, T );
Beep( A, T );
Beep( A, T );
Beep( G, T );
Beep( F, T );
Beep( E, T );
Beep( D, T * 2 );
Beep( C, T );
Beep( G, T * 3 );
Beep( F, T / 2 );
Beep( E, T / 2 );
Beep( D, T );
Beep( _A, T / 2 );
Beep( _B, T / 2 * 3 );
Beep( _A, T / 2 );
Beep( _B, T / 2 );
Beep( C, T / 2 );
Beep( D, T * 5 );
Beep( C, T / 2 );
Beep( C, T / 2 );
Beep( A, T );
Beep( A, T );
Beep( A, T );
Beep( G, T );
Beep( F, T );
Beep( E, T );
Beep( D, T * 2 );
Beep( E, T );
Beep( _A, T * 3 );
Beep( _B, T / 2 );
Beep( _B, T / 2 );
Beep( _A, T );
Beep( E, T );
Beep( D, T / 2 * 3 );
Sleep( Stop / 2 );
Beep( _A, T / 2 );
Beep( _B, T / 2 );
Beep( C, T * 6 );
}
Beep( G, T * 3 );
Beep( G, T * 3 );
Beep( C_, T * 10 );
Sleep( Stop * 2 );
return 0;
}
当 C++ 遇上音乐的更多相关文章
- 当c++遇上音乐
运用到的函数 #include <windows.h> Beep( f, t ); Sleep( t ); eep() 函数可以让蜂鸣器发出频率为f赫兹,音长大约为 2t 毫秒的音.(注意 ...
- MVC遇上bootstrap后的ajax表单模型验证
MVC遇上bootstrap后的ajax表单验证 使用bootstrap后他由他自带的样式has-error,想要使用它就会比较麻烦,往常使用jqueyr.validate的话只有使用他自己的样式了, ...
- 敏捷遇上UML-需求分析及软件设计最佳实践(郑州站 2014-6-7)
邀请函: 尊敬的阁下:我们将在郑州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实 ...
- 敏捷遇上UML—软创基地马年大会(广州站 2014-4-19)
我们将在广州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战技巧. 时间:2 ...
- 敏捷遇上UML——软创基地马年大会(深圳站 2014-3-15)
邀请函: 尊敬的阁下: 我们将在深圳为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战 ...
- 初识genymotion安装遇上的VirtualBox问题
想必做过Android开发的都讨厌那慢如蜗牛的 eclipse原生Android模拟器吧! 光是启动这个模拟器都得花上两三分钟,慢慢的用起来手机来调试,但那毕竟不是长久之计,也确实不方便,后来知道了g ...
- SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败解决方案
SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败的问题,可作如下尝试: 更新失败后,在windows的[事件查看器→应用程序]中找到来源为MsiInstaller,事件ID为1 ...
- 当创业遇上O2O,新一批死亡名单,看完震惊了!
当创业遇上O2O,故事就开始了,总投入1.6亿.半年开7家便利店.会员猛增至10万……2015半年过去后,很多故事在后面变成了一场创业“事故”,是模式错误还是烧钱过度?这些项目的失败能给国内创业者带来 ...
- LoadRunner - 当DiscuzNT遇上了Loadrunner(下) (转发)
当DiscuzNT遇上了Loadrunner(下) 在之前的两篇文章中,基本上介绍了如何录制脚本和生成并发用户,同时还对测试报告中的几个图表做了简单的说明.今天这篇文章做为这个系列的最后一篇,将会介绍 ...
随机推荐
- sudoers权限管理
该/etc/sudoers文件的权限管理很完善,覆盖了linux中的各种命令,各种shell.编辑器等等,在此留作以后作为参考. # This file MUST be edited with the ...
- MyBatis基本使用
MyBatis是轻量级的数据库访问API,封装了JDBC操作,可以实现对实体对象的CRUD操作. MyBatis体系结构主要组成部分: 配置文件:SqlMapConfig.xml 主配置文件 ...
- pydemo_testMaopuSpider
import json from multiprocessing import Pool import requests from requests.exceptions import Request ...
- python 练习1(流控制)
#!/usr/bin/python #_*_ coding:utf-8 _*_ #练习题 #1.使用while循环输入 1 2 3 4 5 6 8 9 10 #a.定义一个变量存放数字 #b.用whi ...
- caffe程序中出现的db.cpp:#line(行号) unknown database backend问题
报错原因:lmdb不可用 解决方法:Makefile.config将此处更改 CPU_ONLY := 1 #如果只使用CPU的话就改这个,使用GPU的不需要改 USE_OPENCV := 1 #有安装 ...
- c#之AES加密解密
.Net已封装好算法,直接调用即可,代码如下: 转载请注明出处:https://www.cnblogs.com/jietian331/p/9707771.html using System; usin ...
- hdu4780 最小费用最大流
提交 题意: 给了M个机器,N个糖果要被生产,每个糖果有一个Si和Ti的时间,只能在Si或者在Si<=t<Ti的时间开始生产 每个机器进行转化生产产品的时候都会产生一个代价,然后求最小的代 ...
- tab切换的效果——仿照今日头条APP的切换效果
说点废话;不知道是哪一版本起头条的tab切换效果就变了,一直琢磨着这个事,去度娘那里也没有什么结果:正好这两天有空就尝试做了一下:用前端的技术来实现: 先看效果吧:上面的tab随着slide滑动,上面 ...
- 哨兵2 NDVI
shp从国外网站下载的,不是很准确了 数据:COPERNICUS/S2 交流合作请联系:ab000c@163.com
- 问题 1923: [蓝桥杯][算法提高VIP]学霸的迷宫 (BFS)
题目链接:https://www.dotcpp.com/oj/problem1923.html 题目描述 学霸抢走了大家的作业,班长为了帮同学们找回作业,决定去找学霸决斗.但学霸为了不要别人打扰,住在 ...