资讯动态

Scratch音乐编程实战:用消息与链表实现《天空之城》合奏

发布时间:2026/10/4 9:35:10 来源:尧图企业网站定制
1. 项目思路拆解从“堆积木”到“写乐谱程序”1.1 为什么选《天空之城》做Scratch音乐编程课第一次在课堂上带学生做音乐项目我其实犹豫了很久。流行歌版权是个问题儿歌又太简单纯音阶练习学生五分钟就腻。后来定成《天空之城》原因有三个。第一这首曲子的主题旋律辨识度极高慢速、抒情、音域适中非常适合初学者用Scratch的“演奏音符”积木还原。第二它的结构并不复杂但又不是从头到尾一条直线——有前奏、主旋律、间奏还有重复和变化这就逼着你必须想清楚“怎么组织代码”而不是一股脑把音符从上往下排。第三它天然适合讲两个编程概念消息广播和链表。说实话很多Scratch音乐课的问题是“太像录音机”。学生把简谱抄进去用几十个播放音符积木堆完播放一遍结束。作品能响但换一首曲子就得全部重写项目也谈不上任何复用性。这次我换了个思路把乐谱当作数据把程序当作“读数据的演奏机器”。音符和节拍放进列表里角色只负责按顺序取数、播放多个声部之间靠广播消息协调乐句与乐句之间用链表结构串起来方便插曲和反复。这才是“音乐编程”和“用Scratch播放音乐”的本质区别。1.2 音乐编程要解决的三个核心问题用Scratch做音乐绕不开三个问题音符怎么表示、节拍怎么控制、多个声部怎么同步。音符在Scratch里其实很简单。“演奏音符(60)(0.5)拍”这个积木前面的数字是MIDI音高编号60对应中央C后面的数字是持续拍数。但真正难的是把简谱转成音高编号还要保证时值换算不出错。节拍是个更隐蔽的坑。Scratch的“等待()秒”积木和“演奏()拍”积木是两套时间系统前者依赖程序运行的实际秒数后者依赖软件内部的节拍器速度。如果不统一就会出现“音符还没播完就开始播下一个”或者“每个音间隔忽长忽短”的问题。我见过太多学生的作品谱子是对的听起来却乱七八糟十有八九就是节拍参数不对。第三个问题是声部同步。《天空之城》如果只弹单音旋律效果其实很干。加上一个简单的分解和弦伴奏立刻就有层次感了。但在Scratch里两个角色同时开始容易同时结束难中途切段落更难。这时候就需要广播消息来当“指挥”让所有声部听着同一个“口令”行动。1.3 为什么选“消息”和“链表”作为核心知识点这个项目放在Scratch进阶课程里目的不只是做出一首曲子而是借音乐场景讲两个真正重要的编程概念。消息对应的是Scratch里的“广播”和“当接收到”。它的核心价值是解耦——发送消息的人不需要知道谁会接收接收的人也不需要知道消息从哪里来。在音乐项目里一个“指挥者”角色不需要知道现在有几个声部在演奏只需要发出“开始”“暂停”“进入B段”“结束”这几条广播所有声部听到后各自执行。这在代码组织上是一次思路升级从“顺序执行”变成“事件驱动”。链表则是对Scratch列表的进一步抽象。Scratch原生没有指针但我们可以用两个列表模拟一个存数据一个存“下一个节点的编号”。这样就能实现真正的链式结构而不是简单的数组遍历。在这个项目里我把整首曲子的段落拆成一个链表前奏节点指向主旋律节点主旋律节点指向间奏节点间奏节点又可以指回主旋律节点实现反复。想插入一段新的乐句只需要改一个指针值不需要动其他数据。这两个概念放在一起还有一个巧妙的配合消息负责“什么时候演奏”链表负责“演奏什么内容”。一个控制流程一个组织数据程序结构就清爽了。2. 核心机制详解音符、节拍、消息、链表到底怎么配合2.1 音符与节拍先算清楚再动手编程很多教程直接给一个Scratch音高对照表让用户照着填。但如果不理解背后的对应关系一旦遇到谱子上没有标注MIDI号的情况还是会卡住。Scratch的“演奏音符()()拍”使用的是MIDI音高编号中央C简谱1是60每升高半音加1。所以简谱的do、re、mi对应60、62、64高音do是72。如果要升一个八度编号加12。这个规则非常稳定只需要记住一个基准点剩下的都可以推算出来。节拍的计算则要仔细。Scratch底部有一个“每分钟节拍数”的设定默认是60也就是每拍1秒。如果曲子要以90的BPM演奏那一拍就是60除以90约0.667秒。四分音符记1拍八分音符记0.5拍二分音符记2拍。我做了一张速查表方便学生对照音符时值拍数90BPM下的时长秒全音符42.67二分音符21.33四分音符10.67八分音符0.50.33十六分音符0.250.17实际做的时候我会把BPM设成90然后用“播放音符”积木的“拍”参数直接控制时值不再额外加“等待()秒”。这样整个程序的节奏会以Scratch节拍器为准不会因为电脑卡顿而漂移。2.2 消息广播用“指挥者”角色统一调度在Scratch里广播消息可以理解成“喊一嗓子”。一个角色喊“全体注意开始演奏”所有能听到这个消息的角色都会立刻执行各自对应的脚本。这个机制不需要发送者和接收者之间有直接关联所以特别适合音乐合奏。我的项目里设了一个“指挥者”角色它的任务不是演奏而是发广播。整个流程是这样的舞台出现“开始”按钮点击后指挥者广播“前奏开始”前奏播完广播“主旋律开始”主旋律完成广播“间奏开始”间奏结束广播“主旋律反复”。每个乐器角色只需要写好“当接收到XX消息”对应的乐句剩下的交给指挥者。使用消息机制最大的好处是加一个声部非常容易。比如我在项目里加了一个“低音”角色它不需要修改主旋律角色的任何代码只需要自己写三段响应脚本——接收到“前奏开始”就弹低音接收到“主旋律开始”就弹和弦根音如此类推。这种可扩展性用“顺序执行”是做不到的。2.3 链表结构用两个列表模拟真正的链式存储Scratch的“列表”本质上是数组元素按顺序存储按下标访问。但链表不一样它每个节点除了存数据还存着“下一个节点在哪里”。这样数据不一定要在物理空间上连续排列插入和删除也更灵活。在Scratch里模拟链表我用两个列表。第一个列表叫“节点数据”存每个节点的内容比如段落名称、起始音符在乐谱中的位置、重复次数。第二个列表叫“下一节点”存的是下一个节点的编号。如果某个节点是最后一个它的“下一节点”填0表示结束。举个具体例子。我的《天空之城》项目总共有5个节点节点编号节点数据段落名下一节点1前奏22主旋律A33间奏44主旋律A反复55结尾0指挥者角色拿到的是一个“当前节点编号”变量初始为1。每次演奏完一段它就去查“下一节点”列表找到下一个编号更新当前节点然后继续。这个过程在数据结构课本里叫“链表遍历”在Scratch里就是“变量读取列表值再写回变量”但背后的逻辑是完全一致的。2.4 消息与链表的结合点事件驱动的乐句循环更有意思的是消息机制和链表并非各管各的它们可以配合起来形成事件驱动的演奏循环。我设计的指挥者脚本是“死循环”加“条件判断”的结构。角色先读链表当前节点判断节点类型如果节点数据是“前奏”就广播“前奏开始”等待3秒让声部播完然后通过指针跳到下一个节点。如果节点是“主旋律A”就广播“主旋律A开始”但这次等待的时间需要通过计算得出因为主旋律比前奏长。这个等待时间是从乐谱总长度的数据里算出来的保证广播不会过早发出。这个设计解决了一个常见问题如果只靠“等待()秒”时间都是写死的换一首歌全部要重新调。但把段落长度也变成数据存进链表之后指挥者的逻辑就不用改了它只需要读数据、广播、等待、跳转。这就是数据结构让程序变得“通用”的实际价值。3. 实操过程从简谱到完整Scratch项目3.1 乐谱准备从《天空之城》主题中提取音符数据正式开始写代码之前我先带学生把简化版《天空之城》主题的简谱整理出来。我们用的是C大调简化版主旋律开头大致是小节简谱音符小节内时值说明16 7 1 3八分、八分、八分、四分27 1 3 7八分、八分、四分、八分36 7 1 3八分、八分、八分、四分47 1 3 7八分、八分、四分、八分在C大调里简谱的1对应MIDI号60那么6对应69、7对应71。高音1是72高音3是76。把这些转成MIDI号数组就是69, 71, 72, 76, 71, 72, 76, 71, 69, 71, 72, 76, 71, 72, 76, 71时值数组对应的是0.5, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5这两个数组放列表里一个是音高表一个是节拍表。演奏时循环从第1项开始每轮读取一个音高和一个节拍用“播放音符”积木演奏直到读完整张表。3.2 建立乐谱数据表音高列表和时值列表在Scratch的“变量”分类里新建三个列表“音高表”“节拍表”“当前指针”。前两个是全局的给演奏角色用第三个是演奏角色私有的防止和其他角色冲突。音高表建立的时候不要一个一个手动输入太容易错。我习惯先在纸上把简谱列好然后批量输入。Scratch的列表编辑器支持一次粘贴多行数据每行一个数字比在积木里一个个加要快得多。节拍表也一样我按八分音符0.5拍、四分音符1拍的规则填好。这里有一个关键细节音高表数量和节拍表数量必须完全一致。学生最容易犯的错就是中间漏了一个音符结果音高和节拍错位演奏出来节奏完全对不上。我在项目里专门加了一段初始化逻辑让角色播放前检查两个列表的长度是否相等不相等就停下来报错。3.3 演奏主旋律角色按列表数据播放音符主旋律角色的代码结构非常简单核心就三步读取当前指针指向的音高读取对应位置的节拍播放后让指针加1。用Scratch积木描述大概是当按下空格键 将 [当前指针 v] 设为 [1] 重复 (音高表 的项目数) 次 播放音符 (音高表 的第 (当前指针) 项) (节拍表 的第 (当前指针) 项) 拍 将 [当前指针 v] 增加 (1)这个循环最大的特点是“数据驱动”——角色本身不关心乐谱内容是什么它只负责按编号取数、播放、移动指针。换成任何一首歌只要重新填充列表内容角色代码一行都不用改。但要提醒的是“播放音符”积木本身不会阻塞程序它只是发起一个发声任务程序会立刻继续执行下一条指令。如果循环里不加任何等待所有音符会在极短时间内触发结果就是“嗡嗡”一声混响完全听不出旋律。正确做法是利用“播放音符()拍”的拍数参数让它自然占用对应的时间如果使用“演奏音符()()秒”积木则需要手动加“等待()秒”而且时长必须和音符一致。3.4 指挥者角色用链表遍历控制整首乐曲的段落切换有了主旋律接下来就是整首歌的段落调度。我的做法是做一个单独的“指挥者”角色它不发声只负责发广播。先在项目里建立两个全局列表“段落名称”和“下一节点”并填入第一节里那组数据。再建立一个私有变量“当前段落”初始为1。指挥者角色的积木逻辑当点击绿旗 将 [当前段落 v] 设为 [1] 重复直到 (当前段落) [0] 如果 (段落名称 的第 (当前段落) 项) [前奏] 那么 广播 [前奏开始 v] end 如果 (段落名称 的第 (当前段落) 项) [主旋律A] 那么 广播 [主旋律A开始 v] end 如果 (段落名称 的第 (当前段落) 项) [间奏] 那么 广播 [间奏开始 v] end 如果 (段落名称 的第 (当前段落) 项) [结尾] 那么 广播 [结尾开始 v] end 等待 [段落时长 v] 秒 将 [当前段落 v] 设为 (下一节点 的第 (当前段落) 项) end这里的“段落时长”也是一个列表每一项存的是该段落预计需要多少秒。这个值怎么算我先把段落里所有音符的拍数加起来换算成秒数再多加0.3秒的余量。比如主旋律A一共12拍BPM90时一拍0.667秒12拍就是8秒那“段落时长”里就填8.3。这样设计之后如果我想让《天空之城》在间奏之后重复一遍主旋律再进结尾我只需要把“下一节点”列表里间奏那一项的“3”改成“4”让间奏指回主旋律A节点而不是直接把一整段代码复制一遍。这就是链表相对数组的直观优势。3.5 多声部合奏让每个角色监听不同的消息指挥者发广播只是第一步真正让音乐有立体感的是多个声部同时响应。我在项目中加了三个演奏角色主旋律、分解和弦、低音。分解和弦角色接收“主旋律A开始”后它不会去读主旋律的音高表而是读取自己的“和弦音高表”和“和弦节拍表”。我给它预设的是一组“1-3-5-3”的分解和弦循环每小节重复一次和主旋律形成对位。低音角色更简单它只弹每小节的根音一拍一个时值都用1拍。三个角色都通过广播消息触发所以它们之间的代码是彼此独立的。主旋律角色不需要知道低音角色存在低音角色也不需要关心主旋律在哪个小节。只要广播消息的时间点正确整个合奏就能对齐。这个结构的扩展性非常好。以后我想加一个打击乐声部只需要新增一个角色监听同样的广播消息然后用“击打”类积木演奏节奏。不需要修改任何现有角色的代码。4. 常见问题与排查技巧实录4.1 高频踩坑点音符、节拍、广播的典型故障做这个项目时学生和学员问得最多的问题集中在几个地方。我把高频故障整理成一张速查表方便遇到问题直接查现象可能原因排查思路与解法所有音符挤在一起听不清旋律循环里没有等待或用了“播放音符()秒”但没加“等待”改用“播放音符()拍”并确保BPM正确高低音不对MIDI号换算错误或简谱识别错误回到中央C60的基准重新推算逐个对照节拍忽快忽慢等待秒数和拍数混用电脑卡顿导致漂移统一用拍数控制不在循环里混用两套计时广播接收方不执行广播消息名称和接收积木里的消息名称不完全一致检查消息名称是否“精确相同”包括大小写和空格主旋律播完了但伴奏还没结束各声部段落总时长不同指挥者等待时间不够给“段落时长”增加余量或按最慢声部计算段落顺序错乱链表“下一节点”数据填写错误检查每个节点的下一节点编号尤其注意是否有指向自己的死循环4.2 调音与节奏校准的实用技巧音乐项目的调试比普通Scratch项目难一点因为你没法“单步运行”听效果。我自己摸索出一个办法把“演奏速度”临时调到很慢比如把BPM降到30让每个音符都拖得很长这样就能听清楚音高对不对、先后顺序对不对。确认无误后再把BPM调回90。另一个技巧是把演奏角色“按段落拆开测试”。指挥者暂时不给段落时长改成手动按“1”“2”“3”键分别广播“前奏开始”“主旋律A开始”“间奏开始”。这样可以在开发阶段只测试某一个声部的某一段等每段都正确了再接通指挥者做整体联调。这比每次从头播到尾、发现问题还得听半分钟强得多。4.3 表演模式让作品从“自己听”变成“给别人看”很多学生做完之后只是点绿旗播放一遍演示效果很平淡。我给项目加了一个“表演模式”舞台上放三个按钮分别控制“开始演奏”“暂停/继续”“停止”。暂停和继续的实现很有意思也是消息机制的典型应用。指挥者广播“暂停”后所有声部角色进入一个“当接收到暂停等待直到接收到继续”的状态。这里用到了Scratch的“等待直到”积木条件写“接收到继续”。注意暂停前要先把当前段落保存到变量里继续时从这个段落重新开始而不是从头播。演出时还可以配合“外观”积木做一些视觉效果。比如低音角色播放时切换成深色造型主旋律角色切换成亮色造型让观众眼睛看到的声音来源和耳朵听到的一致。这虽然不影响程序逻辑但对课堂展示来说效果提升巨大。4.4 进一步扩展把链表升级成可编辑乐谱项目做完之后我建议学有余力的学生做一个“歌词编辑器”功能在舞台上动态修改链表里的段落名称和下一节点指向甚至把某一整个节点里面的音符数据换掉。这样作品就变成一个简易的“音乐播放器”不只能放《天空之城》还能放其他任何收入列表的曲子。我在实际操作中的体会是学生一旦理解了“数据与程序分离”的思路会开始主动设计自己的音乐作品而不再满足于照着谱子堆积木。这也是这个项目最值得肯定的地方——它不只是在教Scratch而是在借Scratch传达“用数据结构组织程序”的思维。最后再分享一个小技巧如果想让《天空之城》的结尾更有余韵可以把“结尾”节点的下一节点设置为0之前先广播一次“渐弱”消息让主旋律角色播放一个时值4拍的长音同时把音量在循环里逐渐调小到0。这个效果用Scratch的“将音量设为”积木加循环就能实现却能让作品听起来非常完整值得一试。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑