【小程序】C语言实现简易钢琴-利用sin函数构造不同频率波形模拟各琴键发音

根据钢琴音调频率对照表,使用sin函数构造对应频率正弦波数据模拟各琴键声音,实现简易钢琴效果,结果写入wav文件中。

目录

  • 程序效果
  • 实现过程
  • 样例代码
  • 测试用例
  • 参考资料

程序效果

截图1:键位图 钢琴键盘结构,包含3组Do Re Mi Fa So La Xi以及空格静音代表的空拍,使用字符'z'结束。

截图2:使用效果-欢乐颂 输入音符后,使用'z'回车即可结束录入,生成的文件位于D盘根目录下,播放即可。

实现过程

截图3:流程图

主要流程如上,需要注意的细节有以下几处:

0.每秒44100采样时,一个音符想要延续0.5秒左右就需要一个长度为22050的数组构造正弦波,不现实,采用s[1000]数组构造正弦波,使用for循环重复至30000左右。

1.使用有限长度数组构造正弦波,由于Π为无理数,在实际计算数值时,很难取到完整周期的分界点。

截图4:不连续现象

分界点选取间隔不大时,人耳听不出明显的噪音。

2.每个音符末尾需要插入一小段短暂静音,否则连续2各相同音会听成一个长音。

截图5:单音末尾静音

3.空拍使用完整静音

截图6:空拍的静音

样例代码

1.共享链接:C语言实现简易钢琴-利用sin函数构造不同频率波形模拟各琴键发音

https://download.csdn.net/download/u013025955/11174606

2.关键代码

//钢琴键盘结构,包含3组Do Re Mi Fa So La Xi以及空格静音代表的空拍
struct MusicNote
{
    char noteName; //音符名称
    int frequence; //音符频率,根据钢琴音高频率对照表定义
    DWORD noteLength; //在使用sin函数构造正弦波信号的单个音实际字节长度,用于计算总长度,填写在wav文件头部,同时该长度让每个音能延续0.5秒左右,由nearZero*4*2*40算出,可以自定义时长,只要是nearZero的整数倍都行
    DWORD nearZero; //在使用sin函数构造正弦波信号时,不同频率采样值最接近完整周期的数据点,避免取不到完整周期导致杂音出现
}note[NOTENUM] = {
    {'a', 130, 108800, 680}, {'q', 261, 81600,  170}, {'1', 523, 80960, 253},
    {'s', 146, 72640,  908}, {'w', 293, 60320,  754}, {'2', 587, 84320, 527},
    {'d', 164, 86400,  270}, {'e', 329, 75200,  940}, {'3', 659, 69680, 871},
    {'f', 174, 40460,  508}, {'r', 349, 101280, 633}, {'4', 698, 55680, 696},
    {'g', 195, 72480,  906}, {'t', 391, 90400,  565}, {'5', 784, 72320, 226},
    {'h', 220, 64320,  402}, {'y', 440, 64320,  402}, {'6', 880, 68240, 853},
    {'j', 246, 86240,  539}, {'u', 493, 78800,  985}, {'7', 988, 78720, 492},
    {' ', 0, 80000, 1000}
};

//正弦波生成函数
void sin_sound(WORD *p, int n, int f)
{
    int i;
    double x, temp1;

    x = 2*PI*f/44100; //2Πf即可获得对应频率波形,44100为音频文件头定义的采样率,也需要考虑进去

    for (i=0; i<n; i++) //n的值通过本地测试21次,分别确定的,确定方法为查看正弦函数值从负数变成整数,经过x轴时最接近0的点,即最接近完整周期的点
    {
        temp1 = 5000 * sin(x*i);
        p[i] = (WORD)temp1;
    }
}

测试用例

截图7:测试用例

参考资料

1.利用正弦波产生WAV文件

https://download.csdn.net/download/guo19910426/5697181

2.钢琴的音高与频率对照表

https://max.book118.com/html/2016/0314/37632175.shtm

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值