~cytrogen/blog-public

blog-public/posts/ba6a.html -rw-r--r-- 57.5 KiB
88eebf3dCytrogen Deploy 2026-02-19 08:34:27 4 days ago
                                                                                
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
<!DOCTYPE html><html lang="zh" data-theme="dark"><head><meta charset="utf-8"><meta name="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>树莓派 Pico 通过有源蜂鸣器播放音频 · Cytrogen 的个人博客</title><meta name="description" content="本文是一篇使用 MicroPython 在树莓派 Pico 上通过有源蜂鸣器播放音乐的详细教程。文章以《超级马里奥》主题曲为例,从零开始指导你如何将在线乐谱(来自 Online Sequencer)解析为程序可用的数据结构,并利用 MicroPython 的 PWM 功能精确控制蜂鸣器的频率和发声时长。内容不仅涵盖了代码实现,还为不熟悉乐理的读者科普了音符、节拍等基础知识,非常适合 Pico 入门玩家和对硬件音乐项目感兴趣的朋友。"><link rel="icon" href="../favicon.png"><link rel="canonical" href="https://cytrogen.icu/posts/ba6a.html"><link rel="webmention" href="https://webmention.io/cytrogen.icu/webmention"><link rel="me" href="https://m.otter.homes/@Cytrogen"><link rel="me" href="https://github.com/cytrogen"><meta name="fediverse:creator" content="@Cytrogen@m.otter.homes"><link rel="preload" href="../fonts/opensans-regular-latin.woff2" as="font" type="font/woff2" crossorigin="anonymous"><style>@font-face {
  font-family: 'Open Sans';
  src: url('../fonts/opensans-regular-latin.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  size-adjust: 107%;
  ascent-override: 97%;
  descent-override: 25%;
  line-gap-override: 0%;
}
</style><script>(function() {
  try {
    // 优先级:用户选择 > 系统偏好 > 默认浅色
    const saved = localStorage.getItem('theme');
    const theme = saved || 
      (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
    
    document.documentElement.setAttribute('data-theme', theme);
    document.documentElement.style.colorScheme = theme;
  } catch (error) {
    // 失败时使用默认主题,不阻塞渲染
    document.documentElement.setAttribute('data-theme', 'light');
  }
})();
</script><link rel="stylesheet" href="../css/ares.css"><script data-netlify-skip-bundle="true">(function() {
  document.addEventListener('DOMContentLoaded', function() {
    const theme = document.documentElement.getAttribute('data-theme');
    const pageWrapper = document.getElementById('page-wrapper');
    if (pageWrapper && theme) {
      pageWrapper.setAttribute('data-theme', theme);
    }
  });
})();

</script><!-- hexo injector head_end start -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css">

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hexo-math@4.0.0/dist/style.css">
<!-- hexo injector head_end end --><meta name="generator" content="Hexo 8.1.1"><link rel="alternate" href="atom.xml" title="Cytrogen 的个人博客" type="application/atom+xml">
</head><body><div id="page-wrapper"><a class="skip-link" href="#main-content">跳到主要内容</a><div class="wrap"><header><a class="logo-link" href="../index.html"><img src="../favicon.png" alt="logo"></a><div class="h-card visually-hidden"><img class="u-photo" src="https://cytrogen.icu/favicon.png" alt="Cytrogen"><a class="p-name u-url u-uid" href="https://cytrogen.icu">Cytrogen</a><p class="p-note">Cytrogen 的个人博客,Cytrogen's Blog</p><a class="u-url" rel="me noopener" target="_blank" href="https://m.otter.homes/@Cytrogen">Mastodon</a><a class="u-url" rel="me noopener" target="_blank" href="https://github.com/cytrogen">GitHub</a></div><nav class="site-nav"><div class="nav-main"><div class="nav-primary"><ul class="nav-list hidden-mobile"><li class="nav-item"><a class="nav-link" href="../index.html">首页</a></li></ul><div class="nav-tools"><div class="language-menu"><button class="language-toggle" type="button"><svg class="icon icon-globe" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855A7.97 7.97 0 0 0 5.145 4H7.5V1.077zM4.09 4a9.267 9.267 0 0 1 .64-1.539 6.7 6.7 0 0 1 .597-.933A7.025 7.025 0 0 0 2.255 4H4.09zm-.582 3.5c.03-.877.138-1.718.312-2.5H1.674a6.958 6.958 0 0 0-.656 2.5h2.49zM4.847 5a12.5 12.5 0 0 0-.338 2.5H7.5V5H4.847zM8.5 5v2.5h2.99a12.495 12.495 0 0 0-.337-2.5H8.5zM4.51 8.5a12.5 12.5 0 0 0 .337 2.5H7.5V8.5H4.51zm3.99 0V11h2.653c.187-.765.306-1.608.338-2.5H8.5zM5.145 12c.138.386.295.744.468 1.068.552 1.035 1.218 1.65 1.887 1.855V12H5.145zm.182 2.472a6.696 6.696 0 0 1-.597-.933A9.268 9.268 0 0 1 4.09 12H2.255a7.024 7.024 0 0 0 3.072 2.472zM3.82 11a13.652 13.652 0 0 1-.312-2.5h-2.49c.062.89.291 1.733.656 2.5H3.82zm6.853 3.472A7.024 7.024 0 0 0 13.745 12H11.91a9.27 9.27 0 0 1-.64 1.539 6.688 6.688 0 0 1-.597.933zM8.5 12v2.923c.67-.204 1.335-.82 1.887-1.855A7.97 7.97 0 0 0 10.855 12H8.5zm3.68-1h2.146c.365-.767.594-1.61.656-2.5h-2.49a13.65 13.65 0 0 1-.312 2.5zm2.802-3.5a6.959 6.959 0 0 0-.656-2.5H12.18c.174.782.282 1.623.312 2.5h2.49zM11.27 2.461c.247.464.462.98.64 1.539h1.835a7.024 7.024 0 0 0-3.072-2.472c.218.284.418.598.597.933zM10.855 4a7.966 7.966 0 0 0-.468-1.068C9.835 1.897 9.17 1.282 8.5 1.077V4h2.355z"></path></svg><span>中文</span></button><div class="language-dropdown"></div></div></div><div class="nav-controls"><div class="more-menu hidden-mobile"><button class="more-toggle" type="button"><span>更多</span><svg class="icon icon-chevron-down" width="12" height="12" viewBox="0 0 12 12" fill="currentColor" aria-hidden="true" focusable="false"><path d="M6 8.825c-.2 0-.4-.1-.5-.2l-3.3-3.3c-.3-.3-.3-.8 0-1.1s.8-.3 1.1 0l2.7 2.7 2.7-2.7c.3-.3.8-.3 1.1 0s.3.8 0 1.1l-3.3 3.3c-.1.1-.3.2-.5.2z"></path></svg></button><div class="more-dropdown"><ul class="dropdown-list"><li class="dropdown-item"><a class="nav-link" href="../archives/index.html">归档</a></li><li class="dropdown-item"><a class="nav-link" href="../categories/index.html">分类</a></li><li class="dropdown-item"><a class="nav-link" href="../tags/index.html">标签</a></li><li class="dropdown-item"><a class="nav-link" href="../about/index.html">关于</a></li><li class="dropdown-item"><a class="nav-link" href="../sitemap/index.html">领地地图</a></li></ul></div></div><div class="theme-switcher"><button class="theme-toggle" type="button" role="switch" aria-pressed="false" aria-label="切换主题"><div class="theme-icon moon-icon"><svg class="icon icon-moon" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278z"></path></svg></div><div class="theme-icon sun-icon"><svg class="icon icon-sun" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M8 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0 1a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z"></path></svg></div></button></div><details class="mobile-menu-details hidden-desktop"><summary class="hamburger-menu" aria-label="nav.menu"><svg class="icon icon-bars" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z"></path></svg><span class="menu-text">nav.menu</span></summary><div class="mobile-menu-dropdown"><ul class="mobile-nav-list"><li class="mobile-nav-item"><a class="mobile-nav-link" href="../index.html">首页</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../archives/index.html">归档</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../categories/index.html">分类</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../tags/index.html">标签</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../about/index.html">关于</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../sitemap/index.html">领地地图</a></li></ul></div></details></div></div></div></nav></header><main class="container" id="main-content" tabindex="-1"><div class="post"><article class="post-block h-entry"><div class="post-meta p-author h-card visually-hidden"><img class="author-avatar u-photo" src="../favicon.png" alt="Cytrogen"><span class="p-name">Cytrogen</span><a class="u-url" href="https://cytrogen.icu">https://cytrogen.icu</a></div><a class="post-permalink u-url u-uid visually-hidden" href="https://cytrogen.icu/posts/ba6a.html">永久链接</a><div class="p-summary visually-hidden"><p>如何使用 MicroPython 在树莓派 Pico 上通过有源蜂鸣器播放音频。</p></div><div class="visually-hidden"><a class="p-category" href="../categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/">编程笔记</a><a class="p-category" href="../tags/Python/">Python</a><a class="p-category" href="../tags/%E6%A0%91%E8%8E%93%E6%B4%BE/">树莓派</a></div><h1 class="post-title p-name">树莓派 Pico 通过有源蜂鸣器播放音频</h1><div class="post-info"><time class="post-date dt-published" datetime="2023-05-15T22:49:48.000Z">5/15/2023</time><time class="dt-updated visually-hidden" datetime="2026-02-09T17:16:55.401Z"></time></div><div class="post-content e-content"><html><head></head><body><p>如何使用 MicroPython 在树莓派 Pico 上通过有源蜂鸣器播放音频。</p>
<span id="more"></span>
<h1 id="目录"><a class="markdownIt-Anchor" href="#目录"></a> 目录</h1>
<ul>
<li><a href="#%E7%9B%AE%E5%BD%95">目录</a></li>
<li><a href="#%E5%89%8D%E8%A8%80">前言</a></li>
<li><a href="#%E5%87%86%E5%A4%87">准备</a>
<ul>
<li><a href="#%E5%AF%BC%E5%85%A5%E5%BA%93">导入库</a></li>
<li><a href="#%E9%9F%B3%E7%AC%A6%E4%B8%8E%E9%A2%91%E7%8E%87">音符与频率</a>
<ul>
<li><a href="#%E9%A2%98%E5%A4%96%E8%AF%9D">题外话</a></li>
</ul>
</li>
<li><a href="#%E8%AE%BE%E7%BD%AE%E8%9C%82%E9%B8%A3%E5%99%A8">设置蜂鸣器</a></li>
</ul>
</li>
<li><a href="#%E7%BC%96%E5%86%99%E4%BB%A3%E7%A0%81">编写代码</a>
<ul>
<li><a href="#%E8%8E%B7%E5%8F%96%E4%B9%90%E8%B0%B1">获取乐谱</a></li>
<li><a href="#%E6%92%AD%E6%94%BE%E9%9F%B3%E9%A2%91">播放音频</a></li>
<li><a href="#%E6%92%AD%E6%94%BE%E4%B9%90%E8%B0%B1">播放乐谱</a></li>
</ul>
</li>
<li><a href="#%E6%9C%80%E7%BB%88%E6%95%88%E6%9E%9C">最终效果</a></li>
</ul>
<center> ————————</center>
<h1 id="前言"><a class="markdownIt-Anchor" href="#前言"></a> 前言</h1>
<p>我的树莓派 Pico 早在过年时就到手了,但是一直没有时间玩,最近闲到开始生一种叫做 senioritis 的病,才开始捣鼓起来。</p>
<p>买的时候贪方便,直接购入了已焊接的板子,如下图所示:</p>
<img src="/posts/ba6a/1.jpeg" alt="创乐博MAKEROBO PicoBlock扩展板,已焊接树莓派Pico主板、面包板、LED灯、方向按键、有源蜂鸣器、传感器等套件">
<p>不过本文内容专注于 MicroPython,所以不会细讲硬件部分。如何配置树莓派 Pico 和安装 IDE 等基础内容也不会讲,可以自行搜索。</p>
<div class="danger">
<ul>
<li>本文使用的 IDE 为 Thonny</li>
<li>本文乐谱均来自于 <a target="_blank" rel="noopener" href="https://onlinesequencer.net/">Online Sequencer</a> 这个网站</li>
</ul>
</div>
<center>————————</center>
<h1 id="准备"><a class="markdownIt-Anchor" href="#准备"></a> 准备</h1>
<h2 id="导入库"><a class="markdownIt-Anchor" href="#导入库"></a> 导入库</h2>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">from</span> machine <span class="keyword">import</span> PWM, Pin</span><br></pre></td></tr></tbody></table></figure>
<ul>
<li><code>time</code> 库自不用多说,是用来延时的</li>
<li><code>machine</code> 库则包含了和特定电路板上的硬件有关的方法,例如我们刚刚导入的 <code>PWM</code><code>Pin</code>。详细的内容可以参考 <a target="_blank" rel="noopener" href="https://docs.micropython.org/en/latest/library/machine.html">MicroPython 官方文档</a></li>
</ul>
<h2 id="音符与频率"><a class="markdownIt-Anchor" href="#音符与频率"></a> 音符与频率</h2>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">tones = {</span><br><span class="line">    <span class="string">'C0'</span>: <span class="number">16</span>, <span class="string">'C#0'</span>: <span class="number">17</span>, <span class="string">'D0'</span>: <span class="number">18</span>, <span class="string">'D#0'</span>: <span class="number">19</span>, <span class="string">'E0'</span>: <span class="number">21</span>, <span class="string">'F0'</span>: <span class="number">22</span>,</span><br><span class="line">    <span class="string">'F#0'</span>: <span class="number">23</span>, <span class="string">'G0'</span>: <span class="number">24</span>, <span class="string">'G#0'</span>: <span class="number">26</span>, <span class="string">'A0'</span>: <span class="number">28</span>, <span class="string">'A#0'</span>: <span class="number">29</span>, <span class="string">'B0'</span>: <span class="number">31</span>,</span><br><span class="line">    <span class="string">'C1'</span>: <span class="number">33</span>, <span class="string">'C#1'</span>: <span class="number">35</span>, <span class="string">'D1'</span>: <span class="number">37</span>, <span class="string">'D#1'</span>: <span class="number">39</span>, <span class="string">'E1'</span>: <span class="number">41</span>, <span class="string">'F1'</span>: <span class="number">44</span>,</span><br><span class="line">    <span class="string">'F#1'</span>: <span class="number">46</span>, <span class="string">'G1'</span>: <span class="number">49</span>, <span class="string">'G#1'</span>: <span class="number">52</span>, <span class="string">'A1'</span>: <span class="number">55</span>, <span class="string">'A#1'</span>: <span class="number">58</span>, <span class="string">'B1'</span>: <span class="number">62</span>,</span><br><span class="line">    <span class="string">'C2'</span>: <span class="number">65</span>, <span class="string">'C#2'</span>: <span class="number">69</span>, <span class="string">'D2'</span>: <span class="number">73</span>, <span class="string">'D#2'</span>: <span class="number">78</span>, <span class="string">'E2'</span>: <span class="number">82</span>, <span class="string">'F2'</span>: <span class="number">87</span>,</span><br><span class="line">    <span class="string">'F#2'</span>: <span class="number">92</span>, <span class="string">'G2'</span>: <span class="number">98</span>, <span class="string">'G#2'</span>: <span class="number">104</span>, <span class="string">'A2'</span>: <span class="number">110</span>, <span class="string">'A#2'</span>: <span class="number">117</span>, <span class="string">'B2'</span>: <span class="number">123</span>,</span><br><span class="line">    <span class="string">'C3'</span>: <span class="number">131</span>, <span class="string">'C#3'</span>: <span class="number">139</span>, <span class="string">'D3'</span>: <span class="number">147</span>, <span class="string">'D#3'</span>: <span class="number">156</span>, <span class="string">'E3'</span>: <span class="number">165</span>, <span class="string">'F3'</span>: <span class="number">175</span>,</span><br><span class="line">    <span class="string">'F#3'</span>: <span class="number">185</span>, <span class="string">'G3'</span>: <span class="number">196</span>, <span class="string">'G#3'</span>: <span class="number">208</span>, <span class="string">'A3'</span>: <span class="number">220</span>, <span class="string">'A#3'</span>: <span class="number">233</span>, <span class="string">'B3'</span>: <span class="number">247</span>,</span><br><span class="line">    <span class="string">'C4'</span>: <span class="number">262</span>, <span class="string">'C#4'</span>: <span class="number">277</span>, <span class="string">'D4'</span>: <span class="number">294</span>, <span class="string">'D#4'</span>: <span class="number">311</span>, <span class="string">'E4'</span>: <span class="number">330</span>, <span class="string">'F4'</span>: <span class="number">349</span>,</span><br><span class="line">    <span class="string">'F#4'</span>: <span class="number">370</span>, <span class="string">'G4'</span>: <span class="number">392</span>, <span class="string">'G#4'</span>: <span class="number">415</span>, <span class="string">'A4'</span>: <span class="number">440</span>, <span class="string">'A#4'</span>: <span class="number">466</span>, <span class="string">'B4'</span>: <span class="number">494</span>,</span><br><span class="line">    <span class="string">'C5'</span>: <span class="number">523</span>, <span class="string">'C#5'</span>: <span class="number">554</span>, <span class="string">'D5'</span>: <span class="number">587</span>, <span class="string">'D#5'</span>: <span class="number">622</span>, <span class="string">'E5'</span>: <span class="number">659</span>, <span class="string">'F5'</span>: <span class="number">698</span>,</span><br><span class="line">    <span class="string">'F#5'</span>: <span class="number">740</span>, <span class="string">'G5'</span>: <span class="number">784</span>, <span class="string">'G#5'</span>: <span class="number">831</span>, <span class="string">'A5'</span>: <span class="number">880</span>, <span class="string">'A#5'</span>: <span class="number">932</span>, <span class="string">'B5'</span>: <span class="number">988</span>,</span><br><span class="line">    <span class="string">'C6'</span>: <span class="number">1047</span>, <span class="string">'C#6'</span>: <span class="number">1109</span>, <span class="string">'D6'</span>: <span class="number">1175</span>, <span class="string">'D#6'</span>: <span class="number">1245</span>, <span class="string">'E6'</span>: <span class="number">1319</span>, <span class="string">'F6'</span>: <span class="number">1397</span>,</span><br><span class="line">    <span class="string">'F#6'</span>: <span class="number">1480</span>, <span class="string">'G6'</span>: <span class="number">1568</span>, <span class="string">'G#6'</span>: <span class="number">1661</span>, <span class="string">'A6'</span>: <span class="number">1760</span>, <span class="string">'A#6'</span>: <span class="number">1865</span>, <span class="string">'B6'</span>: <span class="number">1976</span>,</span><br><span class="line">    <span class="string">'C7'</span>: <span class="number">2093</span>, <span class="string">'C#7'</span>: <span class="number">2217</span>, <span class="string">'D7'</span>: <span class="number">2349</span>, <span class="string">'D#7'</span>: <span class="number">2489</span>, <span class="string">'E7'</span>: <span class="number">2637</span>, <span class="string">'F7'</span>: <span class="number">2794</span>,</span><br><span class="line">    <span class="string">'F#7'</span>: <span class="number">2960</span>, <span class="string">'G7'</span>: <span class="number">3136</span>, <span class="string">'G#7'</span>: <span class="number">3322</span>, <span class="string">'A7'</span>: <span class="number">3520</span>, <span class="string">'A#7'</span>: <span class="number">3729</span>, <span class="string">'B7'</span>: <span class="number">3951</span>,</span><br><span class="line">    <span class="string">'C8'</span>: <span class="number">4186</span>, <span class="string">'C#8'</span>: <span class="number">4435</span>, <span class="string">'D8'</span>: <span class="number">4699</span>, <span class="string">'D#8'</span>: <span class="number">4978</span>, <span class="string">'E8'</span>: <span class="number">5274</span>, <span class="string">'F8'</span>: <span class="number">5588</span>,</span><br><span class="line">    <span class="string">'F#8'</span>: <span class="number">5920</span>, <span class="string">'G8'</span>: <span class="number">6272</span>, <span class="string">'G#8'</span>: <span class="number">6645</span>, <span class="string">'A8'</span>: <span class="number">7040</span>, <span class="string">'A#8'</span>: <span class="number">7459</span>, <span class="string">'B8'</span>: <span class="number">7902</span>,</span><br><span class="line">    <span class="string">'C9'</span>: <span class="number">8372</span>, <span class="string">'C#9'</span>: <span class="number">8870</span>, <span class="string">'D9'</span>: <span class="number">9397</span>, <span class="string">'D#9'</span>: <span class="number">9956</span>, <span class="string">'E9'</span>: <span class="number">10548</span>, <span class="string">'F9'</span>: <span class="number">11175</span>,</span><br><span class="line">    <span class="string">'F#9'</span>: <span class="number">11840</span>, <span class="string">'G9'</span>: <span class="number">12544</span>, <span class="string">'G#9'</span>: <span class="number">13290</span>, <span class="string">'A9'</span>: <span class="number">14080</span>, <span class="string">'A#9'</span>: <span class="number">14917</span>, <span class="string">'B9'</span>: <span class="number">15804</span></span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>这个字典包含了从 C0 到 B9 的所有音符的频率,单位为 Hz。这些频率之后会被用来设置 PWM 的频率。</p>
<h4 id="题外话"><a class="markdownIt-Anchor" href="#题外话"></a> 题外话</h4>
<p>如果不懂音符,但又想要照着现实中的乐谱来弹奏,那该怎么办?(当然,如果你懂的话,可以直接跳到 <a href="#%E8%AE%BE%E7%BD%AE%E8%9C%82%E9%B8%A3%E5%99%A8">这个位置</a></p>
<p>先来看看一个简单的乐谱长什么样子。有请我们的主角 ——《小星星》:</p>
<img src="/posts/ba6a/2.jpg" alt="小星星乐谱">
<p>首先,乐谱每一行都有数个小节,被竖线隔开。</p>
<p>每一行的最左边都有一个数字,代表了这一行的拍子。例如这个乐谱的拍子是 4 / 4 拍,也就是说每一小节有四拍,每一拍是一个四分音符。</p>
<p>那什么又是四分音符?这又要从音符的时值说起了。</p>
<p>音符的时值分为全音符、二分音符、四分音符、八分音符、十六分音符、三十二分音符等等。为了直接分辨,上图:</p>
<img src="/posts/ba6a/3.png" alt="圆圈,全音符,时值为4拍,简谱符号为1---;圆圈插一个天线,二分音符,时值为2拍,简谱符号为1-;黑圆圈插一个天线,四分音符,时值为1拍,简谱符号为1;黑圆圈插一个挂了旗子的天线,八分音符,时值为1/2拍,简谱符号为1.;黑圆圈插一个挂了俩旗子的天线,十六分音符,时值为1/4拍,简谱符号为1..;黑圆圈插一个挂了仨旗子的天线,三十二分音符,时值为1/8拍,简谱符号为1...;所有的.代表下划线">
<p>现在回到《小星星》的乐谱上,我们可以看到,第一小节正好有四个四分音符,而第二小节则有两个四分音符和一个二分音符:</p>
<img src="/posts/ba6a/4.jpg" alt="小星星简谱的第1小节和第2小节">
<p>那么在实际演奏中,这两个小节的区别是什么呢?</p>
<p>四个四分音符实际演奏:啊 啊 啊 啊;<br>
两个四分音符 &amp; 一个二分音符实际演奏:啊 啊 啊 ——。</p>
<p>也就是说,在这个谱子里一个二分音符相当于把两个四分音符融合在一起,拉了个长音。</p>
<p>说完时值,现在来看五线谱中各个音符所处的位置。想必你也发现了,有些音符在线上、有些音符在线下、有些音符在中间、有些音符在上下两个线之间…… 这是为什么呢?</p>
<p>这又要说到音符的音高了。这里要注意一点,《小星星》的乐谱中标记了 1 = C,也就是 C 大调。C 大调由 C、D、E、F、G、A、B 七个音组成,况且还是唯一一个没有升降号的大调。</p>
<blockquote>
<p>钢琴上不是有白键和黑键吗?白键总体分为 C、D、E、F、G、A、B 七个音,而黑键总体分为 C#、D#、F#、G#、A# 五个音。<br>
# 符号代表了升号,也就是把这个音调提高半个音阶。比如 C# 是 C 的升半音,也是 C 和 D 之间的音。<br>
还有一个名为 b 的符号,代表了降号。和 #符号相反,b 符号是把这个音调降低半个音阶。Db 是 D 的降半音,是 C 和 D 之间的音,也是 C#。</p>
</blockquote>
<p>我们说了这么多 C、D、E、F、G、A、B,但是在《小星星》里,我们只看到了数字。这是因为在简谱中,用以表示音的高低的符号是阿拉伯数字。1 代表了 C,2 代表了 D,3 代表了 E,以此类推。</p>
<blockquote>
<p>而在现实生活中,我们最常使用的还是唱名,由 do、re、mi、fa、so、la、si 来表示音的高低。do 代表了 C,re 代表了 D,mi 代表了 E,以此类推。</p>
</blockquote>
<img src="/posts/ba6a/6.jpg" alt="阿拉伯数字、唱名、汉字的对照表">
<p>我们已经知道了如何用阿拉伯数字辨认音的高低,但是这仅能在简谱中使用。我们依旧还是要学会如何看五线谱。C 大调的音阶是这样的:</p>
<img src="/posts/ba6a/7.png" alt="C大调的音阶">
<p>来看《小星星》的第一小节。不需要看阿拉伯数字,这次也可以参照上一张图判断出这是 CCGG 了:</p>
<img src="/posts/ba6a/5.jpg" alt="小星星的第一小节,1155">
<p>但是在我们先前的 <a href="#%E9%9F%B3%E7%AC%A6%E4%B8%8E%E9%A2%91%E7%8E%87">音符对频率字典</a> 里,C、D、E、F、G、A、B 后面还跟了多个数字。比如 C4、C5、C6…… 这些数字代表了这个音的频率,也就是音的高低。C4 通常被认为是中央 C,C5 是高一个八度的 C,C6 是再高一个八度的 C,以此类推。</p>
<blockquote>
<p>八度指的是音的高低,在频率上是 2 倍的关系。比如 C4 的频率是 261.63Hz,C5 的频率是 523.25Hz,C6 的频率是 1046.50Hz,以此类推。<br>
不过我们不需要那么详细的小数,只要四舍五入到整数即可。</p>
</blockquote>
<p>为了方便,我们直接使用中央 C 作为基准,也就是 C4。这样,我们就可以把《小星星》的乐谱和音符结合起来了:</p>
<figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">C4 C4 G4 G4 A4 A4 G4- F4 F4 E4 E4 D4 D4 C4- </span><br><span class="line">G4 G4 F4 F4 E4 E4 D4- G4 G4 F4 F4 E4 E4 D4- </span><br><span class="line">C4 C4 G4 G4 A4 A4 G4- F4 F4 E4 E4 D4 D4 C4-</span><br></pre></td></tr></tbody></table></figure>
<div class="danger">
这不是最终我们会使用的乐谱,只是为了方便理解而已。
</div>
<h2 id="设置蜂鸣器"><a class="markdownIt-Anchor" href="#设置蜂鸣器"></a> 设置蜂鸣器</h2>
<p>来设置蜂鸣器的引脚。我习惯使用 GP15(参考 <a href="#%E5%89%8D%E8%A8%80">先前的图片</a>,GP15 引脚已经和蜂鸣器连接好了)。你自然也可以根据自己的需要更改引脚:</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">buzzer = PWM(Pin(<span class="number">15</span>))</span><br><span class="line">buzzer.freq(<span class="number">50000</span>)</span><br><span class="line">buzzer.duty_u16(<span class="built_in">int</span>(<span class="number">65536</span> * <span class="number">0.2</span>))</span><br></pre></td></tr></tbody></table></figure>
<p>我们先创建了一个 PWM 对象,然后设置了 PWM 周期的频率为 50000Hz(不发出任何声音),最后设置了占空比为 20%。</p>
<center>————————</center>
<h1 id="编写代码"><a class="markdownIt-Anchor" href="#编写代码"></a> 编写代码</h1>
<h2 id="获取乐谱"><a class="markdownIt-Anchor" href="#获取乐谱"></a> 获取乐谱</h2>
<p>我选择用超级马里奥的 <a target="_blank" rel="noopener" href="https://onlinesequencer.net/25966">经典曲子</a> 来演示。Online Sequencer 的乐谱可以直接复制粘贴,如下:</p>
<figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">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;:</span><br></pre></td></tr></tbody></table></figure>
<p>真是一大串呢~</p>
<p>稍微分析一下 Online Sequencer 乐谱的格式:</p>
<ol>
<li><code>Online Sequencer:616413:</code> 没有什么用,要被除掉</li>
<li><code>0 F#5 1 7;</code> 才是重点。<code>0</code> 是音符所处的时间位置,<code>F#5</code> 是音符的音高,<code>1</code> 是音符的持续时间,<code>7</code> 是播放用的乐器类型。Online Sequencer 乐谱中每个音符都是这样的格式,用分号隔开</li>
<li>还要注意最后有一个 <code>:</code>,这个也要除掉</li>
</ol>
<p>那么来编写一下将 Online Sequencer 乐谱转换为 Python 字典的代码吧。</p>
<p>先将 Online Sequencer 乐谱中需要被去除的部分去除掉,然后将乐谱中的音符部分根据 <code>;</code> 分割开来:</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">song = song_file.split(<span class="string">":"</span>)[<span class="number">2</span>]</span><br><span class="line">notes_list = song.split(<span class="string">";"</span>)[:-<span class="number">1</span>]</span><br></pre></td></tr></tbody></table></figure>
<p>接着把音符的时间位置提取出来,设为字典的键,音符的音高、持续时间和乐器类型设为字典的值:</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">notes_dict = {}</span><br><span class="line"><span class="keyword">for</span> note <span class="keyword">in</span> notes_list:</span><br><span class="line">    note_parts = note.split()</span><br><span class="line">    beat = <span class="built_in">float</span>(note_parts[<span class="number">0</span>])</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 如果该时间位置是初次被添加到字典当中</span></span><br><span class="line">    <span class="keyword">if</span> beat <span class="keyword">not</span> <span class="keyword">in</span> notes_dict:</span><br><span class="line">        <span class="comment"># 添加该音符的信息到字典里</span></span><br><span class="line">        notes_dict[beat] = note_parts[<span class="number">1</span>:]</span><br><span class="line">    <span class="comment"># 如果该时间位置并不是第一次被添加到字典当中</span></span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="comment"># 如果该音符的音高比字典中已有的音符的音高更高</span></span><br><span class="line">        <span class="keyword">if</span> tones[note_parts[<span class="number">1</span>]] &gt; tones[notes_dict[beat][<span class="number">0</span>]]:</span><br><span class="line">            <span class="comment"># 将该音符的信息覆盖到字典里</span></span><br><span class="line">            notes_dict[beat] = note_parts[<span class="number">1</span>:]</span><br></pre></td></tr></tbody></table></figure>
<p>由于是单个蜂鸣器播放,所以无法同时播放多个音符。当同个时间位置有多个音符时,我们只能选择音高最高的音符来播放。</p>
<p>至此,我们已经有了一个 Python 字典作为我们的乐谱。</p>
<h2 id="播放音频"><a class="markdownIt-Anchor" href="#播放音频"></a> 播放音频</h2>
<p>想要让蜂鸣器发出声音来很简单,代码如下:</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">buzzer.freq(tones[tone])</span><br><span class="line">time.sleep(duration)</span><br></pre></td></tr></tbody></table></figure>
<p><code>buzzer.freq()</code> 会设置蜂鸣器的频率,<code>time.sleep()</code> 会让程序暂停一段时间(在我们这个例子中,就是用来拉长音的)。</p>
<h2 id="播放乐谱"><a class="markdownIt-Anchor" href="#播放乐谱"></a> 播放乐谱</h2>
<p>结合上面两个部分,我们可以让字典中的音符一个一个地播放出来。但在这之前,还需要设置乐谱的播放速度。</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">bpm = <span class="number">199</span>  <span class="comment"># 每分钟节拍数</span></span><br><span class="line">time_signature = [<span class="number">4</span>, <span class="number">4</span>]  <span class="comment"># 拍号</span></span><br><span class="line">beat_duration = (<span class="number">60</span> / bpm) / time_signature[<span class="number">0</span>]  <span class="comment"># 每拍的持续时间</span></span><br></pre></td></tr></tbody></table></figure>
<p><a href="#%E9%A2%98%E5%A4%96%E8%AF%9D">乐谱知识</a> 时说到过,拍号决定了每一小节有多少拍,什么音符的时值是一拍。从我们拿来马里奥曲子的 <a target="_blank" rel="noopener" href="https://onlinesequencer.net/25966">网站</a> 里能看到,马里奥曲子的 bpm 是 199、拍号是 4 / 4。</p>
<p>进行一小些计算,算出每一拍的持续时间为 <code>(60 / 199) / 4</code></p>
<p>继续编写播放乐谱的代码:</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 从第0拍开始播放</span></span><br><span class="line">current_beat = <span class="built_in">float</span>(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 播放到乐谱中最后一个音符的时间位置</span></span><br><span class="line"><span class="keyword">while</span> current_beat &lt;= <span class="built_in">max</span>(notes_dict.keys()):   </span><br><span class="line">    <span class="comment"># 取出当前时间位置的音符的持续时间(持续了多少拍),乘以每拍的持续时间,得到音符的持续时间(持续了多少秒)</span></span><br><span class="line">    note_duration = <span class="built_in">float</span>(notes_dict[current_beat][<span class="number">1</span>]) * beat_duration</span><br><span class="line"> </span><br><span class="line">    <span class="comment"># 如果当前时间位置有音符,就播放</span></span><br><span class="line">    <span class="keyword">if</span> current_beat <span class="keyword">in</span> notes_dict:</span><br><span class="line">        note_name = notes_dict[current_beat][<span class="number">0</span>]</span><br><span class="line">        </span><br><span class="line">        <span class="built_in">print</span>(<span class="string">"第"</span> + <span class="built_in">str</span>(current_beat) + <span class="string">"拍:播放音符 "</span> + note_name + <span class="string">" 中,持续时间为 "</span> + <span class="built_in">str</span>(note_duration) + <span class="string">" 秒。"</span>)</span><br><span class="line">        buzzer.freq(tones[note_name])</span><br><span class="line">        time.sleep(note_duration)</span><br><span class="line"></span><br><span class="line">        current_beat += <span class="built_in">float</span>(notes_dict[current_beat][<span class="number">1</span>])</span><br><span class="line">        buzzer.freq(<span class="number">50000</span>)</span><br><span class="line">    </span><br><span class="line">    <span class="comment"># 如果当前时间位置没有音符,就暂停</span></span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">"第"</span> + <span class="built_in">str</span>(current_beat) + <span class="string">"拍:暂停,持续时间为"</span> + <span class="built_in">str</span>(note_duration) + <span class="string">" 秒。"</span>)</span><br><span class="line">        buzzer.freq(<span class="number">50000</span>)</span><br><span class="line">        time.sleep(beat_duration)</span><br><span class="line">        current_beat += <span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">"播放结束。"</span>)</span><br><span class="line">buzzer.freq(<span class="number">50000</span>)</span><br></pre></td></tr></tbody></table></figure>
<p>一个简单的播放乐谱的程序便完成了。</p>
<p>最终代码可以在 <a target="_blank" rel="noopener" href="https://github.com/Cytrogen/Music_Player_Pico">这个仓库</a> 里找到。</p>
<center>————————</center>
<h1 id="最终效果"><a class="markdownIt-Anchor" href="#最终效果"></a> 最终效果</h1>
<div class="danger">
该视频实际上并未是最终版本的效果,但没有差别多少。
</div>
<video id="video" controls="" height="420">
    <source id="mp4" src="ba6a/8.mp4" type="video/mp4">
</video></body></html></div></article></div></main><footer><div class="paginator"><a class="prev" href="66e.html">上一篇</a><a class="next" href="cf92.html">下一篇</a></div><!-- Webmention 显示区域--><div class="webmention-section webmention-empty" data-page-url="posts/ba6a.html" data-full-url="https://cytrogen.icu/posts/ba6a.html" data-mode="static">
              <h3 class="webmention-title">Webmentions (<span class="webmention-count">0</span>)</h3>
              <div class="webmention-list"></div>
              <span>暂无 Webmentions</span>
            </div><div class="copyright"><p class="footer-links"><a href="../friends/index.html">友链</a><span class="footer-separator"> ·</span><a href="../links/index.html">邻邦</a><span class="footer-separator"> ·</span><a href="../contact/index.html">联络</a><span class="footer-separator"> ·</span><a href="../colophon/index.html">营造记</a><span class="footer-separator"> ·</span><a href="../atom.xml">RSS订阅</a></p><p>© 2025 - 2026 <a href="https://cytrogen.icu">Cytrogen</a>, powered by <a href="https://hexo.io/" target="_blank">Hexo</a> and <a href="https://github.com/cytrogen/hexo-theme-ares" target="_blank">hexo-theme-ares</a>.</p><p><a href="https://blogscn.fun" target="_blank" rel="noopener">BLOGS·CN</a></p></div></footer></div></div><a class="back-to-top" href="#top" aria-label="返回顶部"><svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M3.293 9.707a1 1 0 010-1.414L9.586 2a2 2 0 012.828 0l6.293 6.293a1 1 0 01-1.414 1.414L11 3.414V17a1 1 0 11-2 0V3.414L2.707 9.707a1 1 0 01-1.414 0z"></path></svg></a><script>document.addEventListener('DOMContentLoaded', function() {
  const codeBlocks = document.querySelectorAll('figure.highlight');
  
  codeBlocks.forEach(block => {
    let caption = block.querySelector('figcaption');
    if (!caption) {
      caption = document.createElement('figcaption');
      block.insertBefore(caption, block.firstChild);
    }

    const info = document.createElement('div');
    info.className = 'info';
    
    const filename = caption.querySelector('span');
    if (filename) {
      filename.className = 'filename';
      info.appendChild(filename);
    }
    
    const lang = block.className.split(' ')[1];
    if (lang) {
      const langSpan = document.createElement('span');
      langSpan.className = 'lang-name';
      langSpan.textContent = lang;
      info.appendChild(langSpan);
    }

    const sourceLink = caption.querySelector('a');
    if (sourceLink) {
      sourceLink.className = 'source-link';
      info.appendChild(sourceLink);
    }

    const actions = document.createElement('div');
    actions.className = 'actions';

    const codeHeight = block.scrollHeight;
    const threshold = 300;

    if (codeHeight > threshold) {
      block.classList.add('folded');
      
      const toggleBtn = document.createElement('button');
      toggleBtn.textContent = '展开';
      toggleBtn.addEventListener('click', () => {
        block.classList.toggle('folded');
        toggleBtn.textContent = block.classList.contains('folded') ? '展开' : '折叠';
      });
      actions.appendChild(toggleBtn);
    }

    const copyBtn = document.createElement('button');
    copyBtn.textContent = '复制';
    copyBtn.addEventListener('click', async () => {
      const codeLines = block.querySelectorAll('.code .line');
      const code = Array.from(codeLines)
        .map(line => line.textContent)
        .join('\n')
        .replace(/\n\n/g, '\n');
      
      try {
        await navigator.clipboard.writeText(code);
        copyBtn.textContent = '已复制';
        copyBtn.classList.add('copied');
        
        setTimeout(() => {
          copyBtn.textContent = '复制';
          copyBtn.classList.remove('copied');
        }, 3000);
      } catch (err) {
        console.error('复制失败:', err);
        copyBtn.textContent = '复制失败';
        
        setTimeout(() => {
          copyBtn.textContent = '复制';
        }, 3000);
      }
    });
    actions.appendChild(copyBtn);

    caption.innerHTML = '';
    caption.appendChild(info);
    caption.appendChild(actions);

    const markedLines = block.getAttribute('data-marked-lines');
    if (markedLines) {
      const lines = markedLines.split(',');
      lines.forEach(range => {
        if (range.includes('-')) {
          const [start, end] = range.split('-').map(Number);
          for (let i = start; i <= end; i++) {
            const line = block.querySelector(`.line-${i}`);
            if (line) line.classList.add('marked');
          }
        } else {
          const line = block.querySelector(`.line-${range}`);
          if (line) line.classList.add('marked');
        }
      });
    }
  });
});</script><script async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" id="MathJax-script"></script><script>(function() {
  document.addEventListener('DOMContentLoaded', function() {
    const themeToggle = document.querySelector('.theme-toggle');
    
    if (!themeToggle) return;
    
    const getCurrentTheme = () => {
      return document.documentElement.getAttribute('data-theme') || 'light';
    };
    
    const updateUI = (theme) => {
      const isDark = theme === 'dark';
      themeToggle.setAttribute('aria-pressed', isDark.toString());
    };
    
    const setTheme = (theme) => {
      document.documentElement.setAttribute('data-theme', theme);
      document.documentElement.style.colorScheme = theme;
      
      const pageWrapper = document.getElementById('page-wrapper');
      if (pageWrapper) {
        pageWrapper.setAttribute('data-theme', theme);
      }
      
      // Find and remove the temporary anti-flicker style tag if it exists.
      // This ensures the main stylesheet takes full control after the initial load.
      const antiFlickerStyle = document.getElementById('anti-flicker-style');
      if (antiFlickerStyle) {
        antiFlickerStyle.remove();
      }
      
      localStorage.setItem('theme', theme);
      updateUI(theme);
    };
    
    const toggleTheme = () => {
      const current = getCurrentTheme();
      const newTheme = current === 'light' ? 'dark' : 'light';
      setTheme(newTheme);
    };
    
    updateUI(getCurrentTheme());
    
    themeToggle.addEventListener('click', toggleTheme);
    
    if (window.matchMedia) {
      const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
      mediaQuery.addEventListener('change', function(e) {
        if (!localStorage.getItem('theme')) {
          const theme = e.matches ? 'dark' : 'light';
          setTheme(theme);
        }
      });
    }
  });
})();
</script><script src="../js/details-toggle.js" defer></script><script>(function() {
  document.addEventListener('DOMContentLoaded', function() {
    const backToTopBtn = document.querySelector('.back-to-top');
    
    if (!backToTopBtn) return;
    
    const toggleButtonVisibility = () => {
      const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
      const shouldShow = scrollTop > 200;
      
      if (shouldShow) {
        backToTopBtn.classList.add('is-visible');
      } else {
        backToTopBtn.classList.remove('is-visible');
      }
    };
    
    let ticking = false;
    const handleScroll = () => {
      if (!ticking) {
        requestAnimationFrame(() => {
          toggleButtonVisibility();
          ticking = false;
        });
        ticking = true;
      }
    };
    
    const scrollToTop = (event) => {
      event.preventDefault();
      window.scrollTo({
        top: 0,
        behavior: 'smooth'
      });
    };
    
    window.addEventListener('scroll', handleScroll);
    backToTopBtn.addEventListener('click', scrollToTop);
    
    toggleButtonVisibility();
  });
})();</script></body></html>