如何使用 MicroPython 在树莓派 Pico 上通过有源蜂鸣器播放音频。

目录

————————

前言

我的树莓派 Pico 早在过年时就到手了,但是一直没有时间玩,最近闲到开始生一种叫做 senioritis 的病,才开始捣鼓起来。

买的时候贪方便,直接购入了已焊接的板子,如下图所示:

创乐博MAKEROBO PicoBlock扩展板,已焊接树莓派Pico主板、面包板、LED灯、方向按键、有源蜂鸣器、传感器等套件

不过本文内容专注于 MicroPython,所以不会细讲硬件部分。如何配置树莓派 Pico 和安装 IDE 等基础内容也不会讲,可以自行搜索。

  • 本文使用的 IDE 为 Thonny
  • 本文乐谱均来自于 Online Sequencer 这个网站
————————

准备

导入库

1
2
import time
from machine import PWM, Pin
  • time 库自不用多说,是用来延时的
  • machine 库则包含了和特定电路板上的硬件有关的方法,例如我们刚刚导入的 PWMPin。详细的内容可以参考 MicroPython 官方文档

音符与频率

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
tones = {
'C0': 16, 'C#0': 17, 'D0': 18, 'D#0': 19, 'E0': 21, 'F0': 22,
'F#0': 23, 'G0': 24, 'G#0': 26, 'A0': 28, 'A#0': 29, 'B0': 31,
'C1': 33, 'C#1': 35, 'D1': 37, 'D#1': 39, 'E1': 41, 'F1': 44,
'F#1': 46, 'G1': 49, 'G#1': 52, 'A1': 55, 'A#1': 58, 'B1': 62,
'C2': 65, 'C#2': 69, 'D2': 73, 'D#2': 78, 'E2': 82, 'F2': 87,
'F#2': 92, 'G2': 98, 'G#2': 104, 'A2': 110, 'A#2': 117, 'B2': 123,
'C3': 131, 'C#3': 139, 'D3': 147, 'D#3': 156, 'E3': 165, 'F3': 175,
'F#3': 185, 'G3': 196, 'G#3': 208, 'A3': 220, 'A#3': 233, 'B3': 247,
'C4': 262, 'C#4': 277, 'D4': 294, 'D#4': 311, 'E4': 330, 'F4': 349,
'F#4': 370, 'G4': 392, 'G#4': 415, 'A4': 440, 'A#4': 466, 'B4': 494,
'C5': 523, 'C#5': 554, 'D5': 587, 'D#5': 622, 'E5': 659, 'F5': 698,
'F#5': 740, 'G5': 784, 'G#5': 831, 'A5': 880, 'A#5': 932, 'B5': 988,
'C6': 1047, 'C#6': 1109, 'D6': 1175, 'D#6': 1245, 'E6': 1319, 'F6': 1397,
'F#6': 1480, 'G6': 1568, 'G#6': 1661, 'A6': 1760, 'A#6': 1865, 'B6': 1976,
'C7': 2093, 'C#7': 2217, 'D7': 2349, 'D#7': 2489, 'E7': 2637, 'F7': 2794,
'F#7': 2960, 'G7': 3136, 'G#7': 3322, 'A7': 3520, 'A#7': 3729, 'B7': 3951,
'C8': 4186, 'C#8': 4435, 'D8': 4699, 'D#8': 4978, 'E8': 5274, 'F8': 5588,
'F#8': 5920, 'G8': 6272, 'G#8': 6645, 'A8': 7040, 'A#8': 7459, 'B8': 7902,
'C9': 8372, 'C#9': 8870, 'D9': 9397, 'D#9': 9956, 'E9': 10548, 'F9': 11175,
'F#9': 11840, 'G9': 12544, 'G#9': 13290, 'A9': 14080, 'A#9': 14917, 'B9': 15804
}

这个字典包含了从 C0 到 B9 的所有音符的频率,单位为 Hz。这些频率之后会被用来设置 PWM 的频率。

题外话

如果不懂音符,但又想要照着现实中的乐谱来弹奏,那该怎么办?(当然,如果你懂的话,可以直接跳到这个位置

先来看看一个简单的乐谱长什么样子。有请我们的主角——《小星星》:

小星星乐谱

首先,乐谱每一行都有数个小节,被竖线隔开。

每一行的最左边都有一个数字,代表了这一行的拍子。例如这个乐谱的拍子是 4/4 拍,也就是说每一小节有四拍,每一拍是一个四分音符。

那什么又是四分音符?这又要从音符的时值说起了。

音符的时值分为全音符、二分音符、四分音符、八分音符、十六分音符、三十二分音符等等。为了直接分辨,上图:

圆圈,全音符,时值为4拍,简谱符号为1---;圆圈插一个天线,二分音符,时值为2拍,简谱符号为1-;黑圆圈插一个天线,四分音符,时值为1拍,简谱符号为1;黑圆圈插一个挂了旗子的天线,八分音符,时值为1/2拍,简谱符号为1.;黑圆圈插一个挂了俩旗子的天线,十六分音符,时值为1/4拍,简谱符号为1..;黑圆圈插一个挂了仨旗子的天线,三十二分音符,时值为1/8拍,简谱符号为1...;所有的.代表下划线

现在回到《小星星》的乐谱上,我们可以看到,第一小节正好有四个四分音符,而第二小节则有两个四分音符和一个二分音符:

小星星简谱的第1小节和第2小节

那么在实际演奏中,这两个小节的区别是什么呢?

四个四分音符实际演奏:啊 啊 啊 啊;
两个四分音符 & 一个二分音符实际演奏:啊 啊 啊——。

也就是说,在这个谱子里一个二分音符相当于把两个四分音符融合在一起,拉了个长音。

说完时值,现在来看五线谱中各个音符所处的位置。想必你也发现了,有些音符在线上、有些音符在线下、有些音符在中间、有些音符在上下两个线之间……这是为什么呢?

这又要说到音符的音高了。这里要注意一点,《小星星》的乐谱中标记了 1=C,也就是 C 大调。C 大调由 C、D、E、F、G、A、B 七个音组成,况且还是唯一一个没有升降号的大调。

钢琴上不是有白键和黑键吗?白键总体分为 C、D、E、F、G、A、B 七个音,而黑键总体分为 C#、D#、F#、G#、A# 五个音。
#符号代表了升号,也就是把这个音调提高半个音阶。比如 C# 是 C 的升半音,也是 C 和 D 之间的音。
还有一个名为b的符号,代表了降号。和#符号相反,b符号是把这个音调降低半个音阶。Db 是 D 的降半音,是 C 和 D 之间的音,也是 C#。

我们说了这么多 C、D、E、F、G、A、B,但是在《小星星》里,我们只看到了数字。这是因为在简谱中,用以表示音的高低的符号是阿拉伯数字。1 代表了 C,2 代表了 D,3 代表了 E,以此类推。

而在现实生活中,我们最常使用的还是唱名,由 do、re、mi、fa、so、la、si 来表示音的高低。do 代表了 C,re 代表了 D,mi 代表了 E,以此类推。

阿拉伯数字、唱名、汉字的对照表

我们已经知道了如何用阿拉伯数字辨认音的高低,但是这仅能在简谱中使用。我们依旧还是要学会如何看五线谱。C 大调的音阶是这样的:

C大调的音阶

来看《小星星》的第一小节。不需要看阿拉伯数字,这次也可以参照上一张图判断出这是 CCGG 了:

小星星的第一小节,1155

但是在我们先前的音符对频率字典里,C、D、E、F、G、A、B 后面还跟了多个数字。比如 C4、C5、C6……这些数字代表了这个音的频率,也就是音的高低。C4 通常被认为是中央 C,C5 是高一个八度的 C,C6 是再高一个八度的 C,以此类推。

八度指的是音的高低,在频率上是 2 倍的关系。比如 C4 的频率是 261.63Hz,C5 的频率是 523.25Hz,C6 的频率是 1046.50Hz,以此类推。
不过我们不需要那么详细的小数,只要四舍五入到整数即可。

为了方便,我们直接使用中央 C 作为基准,也就是 C4。这样,我们就可以把《小星星》的乐谱和音符结合起来了:

1
2
3
C4 C4 G4 G4 A4 A4 G4- F4 F4 E4 E4 D4 D4 C4- 
G4 G4 F4 F4 E4 E4 D4- G4 G4 F4 F4 E4 E4 D4-
C4 C4 G4 G4 A4 A4 G4- F4 F4 E4 E4 D4 D4 C4-
这不是最终我们会使用的乐谱,只是为了方便理解而已。

设置蜂鸣器

来设置蜂鸣器的引脚。我习惯使用 GP15(参考先前的图片,GP15 引脚已经和蜂鸣器连接好了)。你自然也可以根据自己的需要更改引脚:

1
2
3
buzzer = PWM(Pin(15))
buzzer.freq(50000)
buzzer.duty_u16(int(65536 * 0.2))

我们先创建了一个 PWM 对象,然后设置了 PWM 周期的频率为 50000Hz(不发出任何声音),最后设置了占空比为 20%。

————————

编写代码

获取乐谱

我选择用超级马里奥的经典曲子来演示。Online Sequencer 的乐谱可以直接复制粘贴,如下:

1
Online Sequencer:616413:0 F#5 1 7;0 E6 1 7;2 F#5 1 7;2 E6 1 7;6 F#5 1 7;6 E6 1 7;10 F#5 1 7;10 C6 1 7;12 F#5 1 7;12 E6 1 7;16 G5 1 7;16 B5 1 7;16 G6 1 7;24 G5 1 7;32 E5 1 7;32 C6 1 7;38 C5 1 7;38 G5 1 7;44 G4 1 7;44 E5 1 7;50 C5 1 7;50 A5 1 7;54 D5 1 7;54 B5 1 7;58 C#5 1 7;58 A#5 1 7;60 C5 1 7;60 A5 1 7;64 C5 1 7;64 G5 1 7;66 G5 1 7;66 E6 1 7;69 B5 1 7;69 G6 1 7;72 C6 1 7;72 A6 1 7;76 A5 1 7;76 F6 1 7;78 B5 1 7;78 G6 1 7;82 A5 1 7;82 E6 1 7;86 E5 1 7;86 C6 1 7;88 F5 1 7;88 D6 1 7;90 D5 1 7;90 B5 1 7;96 E5 1 7;96 C6 1 7;102 C5 1 7;102 G5 1 7;108 G4 1 7;108 E5 1 7;114 C5 1 7;114 A5 1 7;118 D5 1 7;118 B5 1 7;122 C#5 1 7;122 A#5 1 7;124 C5 1 7;124 A5 1 7;128 C5 1 7;128 G5 1 7;130 G5 1 7;130 E6 1 7;133 B5 1 7;133 G6 1 7;136 C6 1 7;136 A6 1 7;140 A5 1 7;140 F6 1 7;142 B5 1 7;142 G6 1 7;146 A5 1 7;146 E6 1 7;150 E5 1 7;150 C6 1 7;152 F5 1 7;152 D6 1 7;154 D5 1 7;154 B5 1 7;164 E6 1 7;164 G6 1 7;166 D#6 1 7;166 F#6 1 7;168 D6 1 7;168 F6 1 7;170 B5 1 7;170 D#6 1 7;174 C6 1 7;174 E6 1 7;178 E5 1 7;178 G#5 1 7;180 F5 1 7;180 A5 1 7;182 G5 1 7;182 C6 1 7;186 C5 1 7;186 A5 1 7;188 E5 1 7;188 C6 1 7;190 F5 1 7;190 D6 1 7;196 E6 1 7;196 G6 1 7;198 D#6 1 7;198 F#6 1 7;200 D6 1 7;200 F6 1 7;202 B5 1 7;202 D#6 1 7;206 C6 1 7;206 E6 1 7;210 F6 1 7;210 G6 1 7;210 C7 1 7;214 F6 1 7;214 G6 1 7;214 C7 1 7;216 F6 1 7;216 G6 1 7;216 C7 1 7;228 E6 1 7;228 G6 1 7;230 D#6 1 7;230 F#6 1 7;232 D6 1 7;232 F6 1 7;234 B5 1 7;234 D#6 1 7;238 C6 1 7;238 E6 1 7;242 E5 1 7;242 G#5 1 7;244 F5 1 7;244 A5 1 7;246 G5 1 7;246 C6 1 7;250 C5 1 7;250 A5 1 7;252 E5 1 7;252 C6 1 7;254 F5 1 7;254 D6 1 7;260 G#5 1 7;260 D#6 1 7;266 F5 1 7;266 D6 1 7;272 C5 1 7;272 E5 1 7;272 C6 1 7;292 E6 1 7;292 G6 1 7;294 D#6 1 7;294 F#6 1 7;296 D6 1 7;296 F6 1 7;298 B5 1 7;298 D#6 1 7;302 C6 1 7;302 E6 1 7;306 E5 1 7;306 G#5 1 7;308 F5 1 7;308 A5 1 7;310 G5 1 7;310 C6 1 7;314 C5 1 7;314 A5 1 7;316 E5 1 7;316 C6 1 7;318 F5 1 7;318 D6 1 7;324 E6 1 7;324 G6 1 7;326 D#6 1 7;326 F#6 1 7;328 D6 1 7;328 F6 1 7;330 B5 1 7;330 D#6 1 7;334 C6 1 7;334 E6 1 7;338 F6 1 7;338 G6 1 7;338 C7 1 7;342 F6 1 7;342 G6 1 7;342 C7 1 7;344 F6 1 7;344 G6 1 7;344 C7 1 7;356 E6 1 7;356 G6 1 7;358 D#6 1 7;358 F#6 1 7;360 D6 1 7;360 F6 1 7;362 B5 1 7;362 D#6 1 7;366 C6 1 7;366 E6 1 7;370 E5 1 7;370 G#5 1 7;372 F5 1 7;372 A5 1 7;374 G5 1 7;374 C6 1 7;378 C5 1 7;378 A5 1 7;380 E5 1 7;380 C6 1 7;382 F5 1 7;382 D6 1 7;388 G#5 1 7;388 D#6 1 7;394 F5 1 7;394 D6 1 7;400 E5 1 7;400 C6 1 7;416 G#5 1 7;416 C6 1 7;418 G#5 1 7;418 C6 1 7;422 G#5 1 7;422 C6 1 7;426 G#5 1 7;426 C6 1 7;428 A#5 1 7;428 D6 1 7;432 G5 1 7;432 E6 1 7;434 E5 1 7;434 C6 1 7;438 E5 1 7;438 A5 1 7;440 C5 1 7;440 G5 1 7;448 G#5 1 7;448 C6 1 7;450 G#5 1 7;450 C6 1 7;454 G#5 1 7;454 C6 1 7;458 G#5 1 7;458 C6 1 7;460 A#5 1 7;460 D6 1 7;462 G5 1 7;462 E6 1 7;480 G#5 1 7;480 C6 1 7;482 G#5 1 7;482 C6 1 7;486 G#5 1 7;486 C6 1 7;490 G#5 1 7;490 C6 1 7;492 A#5 1 7;492 D6 1 7;496 G5 1 7;496 E6 1 7;498 E5 1 7;498 C6 1 7;502 E5 1 7;502 A5 1 7;504 C5 1 7;504 G5 1 7;512 F#5 1 7;512 E6 1 7;514 F#5 1 7;514 E6 1 7;518 F#5 1 7;518 E6 1 7;522 F#5 1 7;522 C6 1 7;524 F#5 1 7;524 E6 1 7;528 G5 1 7;528 B5 1 7;528 G6 1 7;536 G5 1 7;544 E5 1 7;544 C6 1 7;550 C5 1 7;550 G5 1 7;556 G4 1 7;556 E5 1 7;562 C5 1 7;562 A5 1 7;566 D5 1 7;566 B5 1 7;570 C#5 1 7;570 A#5 1 7;572 C5 1 7;572 A5 1 7;576 C5 1 7;576 G5 1 7;578 G5 1 7;578 E6 1 7;581 B5 1 7;581 G6 1 7;584 C6 1 7;584 A6 1 7;588 A5 1 7;588 F6 1 7;590 B5 1 7;590 G6 1 7;594 A5 1 7;594 E6 1 7;598 E5 1 7;598 C6 1 7;600 F5 1 7;600 D6 1 7;602 D5 1 7;602 B5 1 7;608 E5 1 7;608 C6 1 7;614 C5 1 7;614 G5 1 7;620 G4 1 7;620 E5 1 7;626 C5 1 7;626 A5 1 7;630 D5 1 7;630 B5 1 7;634 C#5 1 7;634 A#5 1 7;636 C5 1 7;636 A5 1 7;640 C5 1 7;640 G5 1 7;642 G5 1 7;642 E6 1 7;645 B5 1 7;645 G6 1 7;648 C6 1 7;648 A6 1 7;652 A5 1 7;652 F6 1 7;654 B5 1 7;654 G6 1 7;658 A5 1 7;658 E6 1 7;662 E5 1 7;662 C6 1 7;664 F5 1 7;664 D6 1 7;666 D5 1 7;666 B5 1 7;672 C6 1 7;672 E6 1 7;674 A5 1 7;674 C6 1 7;678 E5 1 7;678 G5 1 7;684 E5 1 7;684 G#5 1 7;688 F5 1 7;688 A5 1 7;690 C6 1 7;690 F6 1 7;694 C6 1 7;694 F6 1 7;696 F5 1 7;696 A5 1 7;704 G5 1 7;704 B5 1 7;706 F6 1 7;706 A6 1 7;709 F6 1 7;709 A6 1 7;712 F6 1 7;712 A6 1 7;714 E6 1 7;714 G6 1 7;717 D6 1 7;717 F6 1 7;720 C6 1 7;720 E6 1 7;722 A5 1 7;722 C6 1 7;726 F5 1 7;726 A5 1 7;728 E5 1 7;728 G5 1 7;736 C6 1 7;736 E6 1 7;738 A5 1 7;738 C6 1 7;742 E5 1 7;742 G5 1 7;748 E5 1 7;748 G#5 1 7;752 F5 1 7;752 A5 1 7;754 C6 1 7;754 F6 1 7;758 C6 1 7;758 F6 1 7;760 F5 1 7;760 A5 1 7;768 G5 1 7;768 B5 1 7;770 D6 1 7;770 F6 1 7;774 D6 1 7;774 F6 1 7;776 D6 1 7;776 F6 1 7;778 C6 1 7;778 E6 1 7;781 B5 1 7;781 D6 1 7;784 G5 1 7;784 C6 1 7;786 E5 1 7;790 E5 1 7;792 C5 1 7;800 C6 1 7;800 E6 1 7;802 A5 1 7;802 C6 1 7;806 E5 1 7;806 G5 1 7;812 E5 1 7;812 G#5 1 7;816 F5 1 7;816 A5 1 7;818 C6 1 7;818 F6 1 7;822 C6 1 7;822 F6 1 7;824 F5 1 7;824 A5 1 7;832 G5 1 7;832 B5 1 7;834 F6 1 7;834 A6 1 7;837 F6 1 7;837 A6 1 7;840 F6 1 7;840 A6 1 7;842 E6 1 7;842 G6 1 7;845 D6 1 7;845 F6 1 7;848 C6 1 7;848 E6 1 7;850 A5 1 7;850 C6 1 7;854 F5 1 7;854 A5 1 7;856 E5 1 7;856 G5 1 7;864 C6 1 7;864 E6 1 7;866 A5 1 7;866 C6 1 7;870 E5 1 7;870 G5 1 7;876 E5 1 7;876 G#5 1 7;880 F5 1 7;880 A5 1 7;882 C6 1 7;882 F6 1 7;886 C6 1 7;886 F6 1 7;888 F5 1 7;888 A5 1 7;896 G5 1 7;896 B5 1 7;898 D6 1 7;898 F6 1 7;902 D6 1 7;902 F6 1 7;904 D6 1 7;904 F6 1 7;906 C6 1 7;906 E6 1 7;909 B5 1 7;909 D6 1 7;912 G5 1 7;912 C6 1 7;914 E5 1 7;918 E5 1 7;920 C5 1 7;928 G#5 1 7;928 C6 1 7;930 G#5 1 7;930 C6 1 7;934 G#5 1 7;934 C6 1 7;938 G#5 1 7;938 C6 1 7;940 A#5 1 7;940 D6 1 7;944 G5 1 7;944 E6 1 7;946 E5 1 7;946 C6 1 7;950 E5 1 7;950 A5 1 7;952 C5 1 7;952 G5 1 7;960 G#5 1 7;960 C6 1 7;962 G#5 1 7;962 C6 1 7;966 G#5 1 7;966 C6 1 7;970 G#5 1 7;970 C6 1 7;972 A#5 1 7;972 D6 1 7;974 G5 1 7;974 E6 1 7;992 G#5 1 7;992 C6 1 7;994 G#5 1 7;994 C6 1 7;998 G#5 1 7;998 C6 1 7;1002 G#5 1 7;1002 C6 1 7;1004 A#5 1 7;1004 D6 1 7;1008 G5 1 7;1008 E6 1 7;1010 E5 1 7;1010 C6 1 7;1014 E5 1 7;1014 A5 1 7;1016 C5 1 7;1016 G5 1 7;1024 F#5 1 7;1024 E6 1 7;1026 F#5 1 7;1026 E6 1 7;1030 F#5 1 7;1030 E6 1 7;1034 F#5 1 7;1034 C6 1 7;1036 F#5 1 7;1036 E6 1 7;1040 G5 1 7;1040 B5 1 7;1040 G6 1 7;1048 G5 1 7;1056 C6 1 7;1056 E6 1 7;1058 A5 1 7;1058 C6 1 7;1062 E5 1 7;1062 G5 1 7;1068 E5 1 7;1068 G#5 1 7;1072 F5 1 7;1072 A5 1 7;1074 C6 1 7;1074 F6 1 7;1078 C6 1 7;1078 F6 1 7;1080 F5 1 7;1080 A5 1 7;1088 G5 1 7;1088 B5 1 7;1090 F6 1 7;1090 A6 1 7;1093 F6 1 7;1093 A6 1 7;1096 F6 1 7;1096 A6 1 7;1098 E6 1 7;1098 G6 1 7;1101 D6 1 7;1101 F6 1 7;1104 C6 1 7;1104 E6 1 7;1106 A5 1 7;1106 C6 1 7;1110 F5 1 7;1110 A5 1 7;1112 E5 1 7;1112 G5 1 7;1120 C6 1 7;1120 E6 1 7;1122 A5 1 7;1122 C6 1 7;1126 E5 1 7;1126 G5 1 7;1132 E5 1 7;1132 G#5 1 7;1136 F5 1 7;1136 A5 1 7;1138 C6 1 7;1138 F6 1 7;1142 C6 1 7;1142 F6 1 7;1144 F5 1 7;1144 A5 1 7;1152 G5 1 7;1152 B5 1 7;1154 D6 1 7;1154 F6 1 7;1158 D6 1 7;1158 F6 1 7;1160 D6 1 7;1160 F6 1 7;1162 C6 1 7;1162 E6 1 7;1165 B5 1 7;1165 D6 1 7;1168 G5 1 7;1168 C6 1 7;1170 E5 1 7;1174 E5 1 7;1176 C5 1 7;0 D4 1 7;2 D4 1 7;6 D4 1 7;10 D4 1 7;12 D4 1 7;24 G4 1 7;32 G4 1 7;38 E4 1 7;44 C4 1 7;50 F4 1 7;54 G4 1 7;58 F#4 1 7;60 F4 1 7;64 E4 1 7;66 C5 1 7;69 E5 1 7;72 F5 1 7;76 D5 1 7;78 E5 1 7;82 C5 1 7;86 A4 1 7;88 B4 1 7;90 G4 1 7;96 G4 1 7;102 E4 1 7;108 C4 1 7;114 F4 1 7;118 G4 1 7;122 F#4 1 7;124 F4 1 7;128 E4 1 7;130 C5 1 7;133 E5 1 7;136 F5 1 7;140 D5 1 7;142 E5 1 7;146 C5 1 7;150 A4 1 7;152 B4 1 7;154 G4 1 7;160 C4 1 7;166 G4 1 7;172 C5 1 7;176 F4 1 7;182 C5 1 7;184 C5 1 7;188 F4 1 7;192 C4 1 7;198 E4 1 7;204 G4 1 7;206 C5 1 7;220 G4 1 7;224 C4 1 7;230 G4 1 7;236 C5 1 7;240 F4 1 7;246 C5 1 7;248 C5 1 7;252 F4 1 7;256 C4 1 7;260 G#4 1 7;266 A#4 1 7;278 G4 1 7;280 G4 1 7;284 C4 1 7;288 C4 1 7;294 G4 1 7;300 C5 1 7;304 F4 1 7;310 C5 1 7;312 C5 1 7;316 F4 1 7;320 C4 1 7;326 E4 1 7;332 G4 1 7;334 C5 1 7;348 G4 1 7;352 C4 1 7;358 G4 1 7;364 C5 1 7;368 F4 1 7;374 C5 1 7;376 C5 1 7;380 F4 1 7;384 C4 1 7;388 G#4 1 7;394 A#4 1 7;400 C5 1 7;406 G4 1 7;408 G4 1 7;412 C4 1 7;416 G#3 1 7;422 D#4 1 7;428 G#4 1 7;432 G4 1 7;438 C4 1 7;444 G3 1 7;448 G#3 1 7;454 D#4 1 7;460 G#4 1 7;464 G4 1 7;470 C4 1 7;476 G3 1 7;480 G#3 1 7;486 D#4 1 7;492 G#4 1 7;496 G4 1 7;502 C4 1 7;508 G3 1 7;512 D4 1 7;514 D4 1 7;518 D4 1 7;522 D4 1 7;524 D4 1 7;536 G4 1 7;544 G4 1 7;550 E4 1 7;556 C4 1 7;562 F4 1 7;566 G4 1 7;570 F#4 1 7;572 F4 1 7;576 E4 1 7;578 C5 1 7;581 E5 1 7;584 F5 1 7;588 D5 1 7;590 E5 1 7;594 C5 1 7;598 A4 1 7;600 B4 1 7;602 G4 1 7;608 G4 1 7;614 E4 1 7;620 C4 1 7;626 F4 1 7;630 G4 1 7;634 F#4 1 7;636 F4 1 7;640 E4 1 7;642 C5 1 7;645 E5 1 7;648 F5 1 7;652 D5 1 7;654 E5 1 7;658 C5 1 7;662 A4 1 7;664 B4 1 7;666 G4 1 7;672 C4 1 7;678 F#4 1 7;680 G4 1 7;684 C5 1 7;688 F4 1 7;692 F4 1 7;696 C5 1 7;698 C5 1 7;700 F4 1 7;704 D4 1 7;710 F4 1 7;712 G4 1 7;716 B4 1 7;720 G4 1 7;724 G4 1 7;728 C5 1 7;730 C5 1 7;732 G4 1 7;736 C4 1 7;742 F#4 1 7;744 G4 1 7;748 C5 1 7;752 F4 1 7;756 F4 1 7;760 C5 1 7;762 C5 1 7;764 F4 1 7;768 G4 1 7;774 G4 1 7;776 G4 1 7;778 A4 1 7;781 B4 1 7;784 C5 1 7;788 G4 1 7;792 C4 1 7;800 C4 1 7;806 F#4 1 7;808 G4 1 7;812 C5 1 7;816 F4 1 7;820 F4 1 7;824 C5 1 7;826 C5 1 7;828 F4 1 7;832 D4 1 7;838 F4 1 7;840 G4 1 7;844 B4 1 7;848 G4 1 7;852 G4 1 7;856 C5 1 7;858 C5 1 7;860 G4 1 7;864 C4 1 7;870 F#4 1 7;872 G4 1 7;876 C5 1 7;880 F4 1 7;884 F4 1 7;888 C5 1 7;890 C5 1 7;892 F4 1 7;896 G4 1 7;902 G4 1 7;904 G4 1 7;906 A4 1 7;909 B4 1 7;912 C5 1 7;916 G4 1 7;920 C4 1 7;928 G#3 1 7;934 D#4 1 7;940 G#4 1 7;944 G4 1 7;950 C4 1 7;956 G3 1 7;960 G#3 1 7;966 D#4 1 7;972 G#4 1 7;976 G4 1 7;982 C4 1 7;988 G3 1 7;992 G#3 1 7;998 D#4 1 7;1004 G#4 1 7;1008 G4 1 7;1014 C4 1 7;1020 G3 1 7;1024 D4 1 7;1026 D4 1 7;1030 D4 1 7;1034 D4 1 7;1036 D4 1 7;1048 G4 1 7;1056 C4 1 7;1062 F#4 1 7;1064 G4 1 7;1068 C5 1 7;1072 F4 1 7;1076 F4 1 7;1080 C5 1 7;1082 C5 1 7;1084 F4 1 7;1088 D4 1 7;1094 F4 1 7;1096 G4 1 7;1100 B4 1 7;1104 G4 1 7;1108 G4 1 7;1112 C5 1 7;1114 C5 1 7;1116 G4 1 7;1120 C4 1 7;1126 F#4 1 7;1128 G4 1 7;1132 C5 1 7;1136 F4 1 7;1140 F4 1 7;1144 C5 1 7;1146 C5 1 7;1148 F4 1 7;1152 G4 1 7;1158 G4 1 7;1160 G4 1 7;1162 A4 1 7;1165 B4 1 7;1168 C5 1 7;1172 G4 1 7;1176 C4 1 7;:

真是一大串呢~

稍微分析一下 Online Sequencer 乐谱的格式:

  1. Online Sequencer:616413: 没有什么用,要被除掉
  2. 0 F#5 1 7; 才是重点。0 是音符所处的时间位置,F#5 是音符的音高,1 是音符的持续时间,7 是播放用的乐器类型。Online Sequencer 乐谱中每个音符都是这样的格式,用分号隔开
  3. 还要注意最后有一个 :,这个也要除掉

那么来编写一下将 Online Sequencer 乐谱转换为 Python 字典的代码吧。

先将 Online Sequencer 乐谱中需要被去除的部分去除掉,然后将乐谱中的音符部分根据 ; 分割开来:

1
2
song = song_file.split(":")[2]
notes_list = song.split(";")[:-1]

接着把音符的时间位置提取出来,设为字典的键,音符的音高、持续时间和乐器类型设为字典的值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
notes_dict = {}
for note in notes_list:
note_parts = note.split()
beat = float(note_parts[0])

# 如果该时间位置是初次被添加到字典当中
if beat not in notes_dict:
# 添加该音符的信息到字典里
notes_dict[beat] = note_parts[1:]
# 如果该时间位置并不是第一次被添加到字典当中
else:
# 如果该音符的音高比字典中已有的音符的音高更高
if tones[note_parts[1]] > tones[notes_dict[beat][0]]:
# 将该音符的信息覆盖到字典里
notes_dict[beat] = note_parts[1:]

由于是单个蜂鸣器播放,所以无法同时播放多个音符。当同个时间位置有多个音符时,我们只能选择音高最高的音符来播放。

至此,我们已经有了一个 Python 字典作为我们的乐谱。

播放音频

想要让蜂鸣器发出声音来很简单,代码如下:

1
2
buzzer.freq(tones[tone])
time.sleep(duration)

buzzer.freq() 会设置蜂鸣器的频率,time.sleep() 会让程序暂停一段时间(在我们这个例子中,就是用来拉长音的)。

播放乐谱

结合上面两个部分,我们可以让字典中的音符一个一个地播放出来。但在这之前,还需要设置乐谱的播放速度。

1
2
3
bpm = 199  # 每分钟节拍数
time_signature = [4, 4] # 拍号
beat_duration = (60 / bpm) / time_signature[0] # 每拍的持续时间

乐谱知识时说到过,拍号决定了每一小节有多少拍,什么音符的时值是一拍。从我们拿来马里奥曲子的网站里能看到,马里奥曲子的 bpm 是 199、拍号是 4/4。

进行一小些计算,算出每一拍的持续时间为 (60 / 199) / 4

继续编写播放乐谱的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 从第0拍开始播放
current_beat = float(0)

# 播放到乐谱中最后一个音符的时间位置
while current_beat <= max(notes_dict.keys()):
# 取出当前时间位置的音符的持续时间(持续了多少拍),乘以每拍的持续时间,得到音符的持续时间(持续了多少秒)
note_duration = float(notes_dict[current_beat][1]) * beat_duration

# 如果当前时间位置有音符,就播放
if current_beat in notes_dict:
note_name = notes_dict[current_beat][0]

print("第" + str(current_beat) + "拍:播放音符 " + note_name + " 中,持续时间为 " + str(note_duration) + " 秒。")
buzzer.freq(tones[note_name])
time.sleep(note_duration)

current_beat += float(notes_dict[current_beat][1])
buzzer.freq(50000)

# 如果当前时间位置没有音符,就暂停
else:
print("第" + str(current_beat) + "拍:暂停,持续时间为" + str(note_duration) + " 秒。")
buzzer.freq(50000)
time.sleep(beat_duration)
current_beat += 1

print("播放结束。")
buzzer.freq(50000)

一个简单的播放乐谱的程序便完成了。

最终代码可以在这个仓库里找到。

————————

最终效果

该视频实际上并未是最终版本的效果,但没有差别多少。