根据钢琴音调频率对照表,使用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
截图7:测试用例
1.利用正弦波产生WAV文件
https://download.csdn.net/download/guo19910426/5697181
2.钢琴的音高与频率对照表
https://max.book118.com/html/2016/0314/37632175.shtm