zoukankan      html  css  js  c++  java
  • 当 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;
    

    (为了偷懒方便,这当中我统一把降音变成了升音……比如降 ( ext{B}) 我就用升 ( ext{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++ Primer 笔记——标准库类型string
    Windows文件系统
    c++数组
    B+树
    简单搭建FastDFS分布式文件系统(简单易懂)
    什么是分布式系统(通俗易懂)
    对List中每个对象元素按时间顺序排序
    java23种设计模式之一: 策略模式
    微信app支付java后台流程、原理分析及nei网穿透
    quartz多任务调度+spring 实现
  • 原文地址:https://www.cnblogs.com/tweetuzki/p/9564382.html
Copyright © 2011-2022 走看看