一、乐理准备
十二平均律(12-equal temperament)又称十二等程律。
一个八度分成12份,八个八度的十二平均音率对应的频率如下(从33Hz到7902Hz)。
相邻两个音之间的倍数是2^(1/12),约等于1.0594630943592952645618252949463)。这样一来,高八度的do频率是低八度do的两倍。
频率与钢琴上的按键是对应的:
C | C# | D | D# | E | F | F# | G | G# | A | A# | B | C | C# | D | D# | E | F | F# | G | G# | A | A# | B | C | C# | D | D# | E | F | F# | G | G# | A | A# | B | C | C# | D | D# | E | F | F# | G | G# | A | A# | B | C | C# | D | D# | E | F | F# | G | G# | A | A# | B | C | C# | D | D# | E | F | F# | G | G# | A | A# | B | ||||||||||||||||||||||||
33 | 35 | 37 | 39 | 41 | 44 | 46 | 49 | 52 | 55 | 58 | 62 | 65 | 69 | 73 | 78 | 82 | 87 | 92 | 98 | 104 | 110 | 117 | 123 | 131 | 139 | 147 | 156 | 165 | 175 | 185 | 196 | 208 | 220 | 233 | 247 | 262 | 277 | 294 | 311 | 330 | 349 | 370 | 392 | 415 | 440 | 466 | 494 | 523 | 554 | 587 | 622 | 659 | 698 | 740 | 784 | 831 | 880 | 932 | 988 | 1047 | 1109 | 1175 | 1245 | 1319 | 1397 | 1480 | 1568 | 1661 | 1760 | 1865 | 1976 | 2093 | 2217 | 2349 | 2489 | 2637 | 2794 | 2960 | 3135 | 3322 | 3520 | 3729 | 3951 | 4186 | 4435 | 4699 | 4978 | 5274 | 5588 | 5920 | 6272 | 6645 | 7040 | 7459 | 7902 |
我们把频率440赫兹作为中央C ,C调的歌就是把频率440赫兹当作do,乐谱中写作:1=C。
相邻的两个音之间的差一个半音,12345671之间的间隔分别是“全全半全全全半”。
D调的歌就是把从440后面第二个音494赫兹当作do,乐谱中写作1=D。
对应的频率就是:(0代表停顿)
831 | 740 | 622 | 740 | 988 | 831 | 740 | 831 | 0 | 0 | |
622 | 740 | 831 | 740 | 622 | 494 | 440 | 740 | 622 | 554 | 0 |
554 | 622 | 740 | 740 | 831 | 622 | 554 | 494 | 0 | 0 | |
740 | 622 | 554 | 494 | 440 | 494 | 392 | 0 | 0 |
加上每个音的时长:
{831,0.3}, | {740,0.3}, | {622,0.3}, | {740,0.3}, | {988,0.3}, | {831,0.15}, | {740,0.15}, | {831,0.4}, | {0,0.3}, | {0,0.3}, | |
{622,0.3}, | {740,0.3}, | {831,0.3}, | {740,0.3}, | {622,0.3}, | {494,0.15}, | {440,0.15}, | {740,0.15}, | {622,0.15}, | {554,0.4}, | {0,0.3}, |
{554,0.3}, | {622,0.3}, | {740,0.3}, | {740,0.3}, | {831,0.3}, | {622,0.15}, | {554,0.15}, | {494,0.4}, | {0,0.3}, | {0,0.3}, | |
{740,0.3}, | {622,0.3}, | {554,0.15}, | {494,0.15}, | {440,0.15}, | {494,0.15}, | {392,0.5}, | {0,0.3}, | {0,0.3}, |
二、代码实现
用的ESP32 WROOM开发板。
struct YINFU{ //定义音符
int freq;
float Duration;
};
struct YINFU YUEPU[128]={//乐谱就是由音符结构体组成的数组
{831,0.3}, {740,0.3}, {622,0.3}, {740,0.3}, {988,0.3}, {831,0.15}, {740,0.15}, {831,0.4}, {0,0.3}, {0,0.3},
{622,0.3}, {740,0.3}, {831,0.3}, {740,0.3}, {622,0.3}, {494,0.15}, {440,0.15}, {740,0.15}, {622,0.15}, {554,0.4}, {0,0.3},
{554,0.3}, {622,0.3}, {740,0.3}, {740,0.3}, {831,0.3}, {622,0.15}, {554,0.15}, {494,0.4}, {0,0.3}, {0,0.3},
{740,0.3}, {622,0.3}, {554,0.15}, {494,0.15}, {440,0.15}, {494,0.15}, {392,0.5}, {0,0.3}, {0,0.3},
};
完整代码如下:
//定义蜂鸣器控制管脚
#define beep_pin 25 //连无源喇叭
// float k=1.0594631;
struct YINFU{ //定义音符
int freq;
float Duration;
};
struct YINFU YUEPU[128]={
{831,0.3}, {740,0.3}, {622,0.3}, {740,0.3}, {988,0.3}, {831,0.15}, {740,0.15}, {831,0.4}, {0,0.3}, {0,0.3},
{622,0.3}, {740,0.3}, {831,0.3}, {740,0.3}, {622,0.3}, {494,0.15}, {440,0.15}, {740,0.15}, {622,0.15}, {554,0.4}, {0,0.3},
{554,0.3}, {622,0.3}, {740,0.3}, {740,0.3}, {831,0.3}, {622,0.15}, {554,0.15}, {494,0.4}, {0,0.3}, {0,0.3},
{740,0.3}, {622,0.3}, {554,0.15}, {494,0.15}, {440,0.15}, {494,0.15}, {392,0.5}, {0,0.3}, {0,0.3},
};
void setup() {
pinMode(beep_pin, OUTPUT); //设置引脚为输出模式
}
void loop(){
for(int k=0;k<128;k++){ //顺序演奏128音符
float d=YUEPU[k].Duration;
for(int D=0;D<int(d*YUEPU[k].freq);D++){ //演奏YUEPU[k].freq的音符,时长=d
if(YUEPU[k].freq != 0){ //演奏音符
//频率转化为时间间隔,1秒=500000微秒*2。一半高电平,一半低电平,所以用500000/音符频率。
int freq_to_us=int(500000/YUEPU[k].freq);
digitalWrite(beep_pin,HIGH); //一半高电平
delayMicroseconds(freq_to_us);
digitalWrite(beep_pin,LOW); //一半低电平
delayMicroseconds(freq_to_us);
}
else{ //停顿
digitalWrite(beep_pin,LOW); //低电平,不发声
delayMicroseconds(1000);
}
}
}
}