当 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(下) 在之前的两篇文章中,基本上介绍了如何录制脚本和生成并发用户,同时还对测试报告中的几个图表做了简单的说明.今天这篇文章做为这个系列的最后一篇,将会介绍 ...
随机推荐
- shiro使用redis作为缓存,出现要清除缓存时报错 java.lang.Exception: Failed to deserialize at org.crazycake.shiro.SerializeUtils.deserialize(SerializeUtils.java:41) ~[shiro-redis-2.4.2.1-RELEASE.jar:na]
shiro使用redis作为缓存,出现要清除缓存时报错 java.lang.Exception: Failed to deserialize at org.crazycake.shiro.Serial ...
- [ROS]激光驱动安装
参考资料: https://blog.csdn.net/hongliang2009/article/details/73302986 https://blog.csdn.net/bohaijun_12 ...
- JDK丨WIN10配置JDK1.8 (解决javac不是内部或外部命令,也不是可运行的程序或批处理文件)
1.下载JDK,安装. 2.配置JDK. (右键我的电脑 - 属性 - 高级系统设置 - 环境变量.) 2.1 添加系统变量JAVA_HOME 变量名:JAVA_HOME 变量值:C:\Program ...
- 灵雀云获邀加入CDF(持续交付基金会),成为中国区三大创始成员之一
3月12日,在加州Half Moon Bay举行的开源领导者峰会(Open Leadership Summit 2019 )上,CDF(Continuous Delivery Foundation ) ...
- linux下tomcat的https访问
1.安装JDK(省略…) 2.安装tomcat(省略…) 3.配置SSL 进入JDK的安装目录 # cd /usr/java/jdk1..0_03/bin # ./keytool -genkey -a ...
- IDEA 创建Web项目
1,创建Project:依次点击File–new Project: 创建.png 2,选择Empty Project项目,点击Next: 下一步 3,输入项目名称,选择项目路径: Past ...
- get_class __class__ get_called_class 分析记录
首先看代码: class A { use T { T::say as aTsay; } public function say() { echo 'a__class__:' . __CLASS__ . ...
- Linux替换文件内容sed命令
sed -e 4a\newline testfile //在第四行后添加一行,并将结果输出到标准输出.-e,以指定脚本处理文本文件:a,新增. nl /etc/passwd | sed '2,5d' ...
- Tensorflow object detection API 搭建属于自己的物体识别模型
一.下载Tensorflow object detection API工程源码 网址:https://github.com/tensorflow/models,可通过Git下载,打开Git Bash, ...
- ROS之坑
我使用ROS建图的时候,用的是Kinect的深度信息转换成laser scan,Rviz仿真环境调用出laser scan信息的时候显示如下错误: Transform [sender=unknown_ ...