大多数浏览器和
Developer App 均支持流媒体播放。
-
天鹅的探索 第三章:著名的卷轴
Swift Playgrounds 隆重推出《天鹅之旅》——一款老少咸宜的四章节互动冒险。诸位音乐家注意了!在这一章中,我们的英雄找到了一张神秘的音乐卷轴,只有你能将它解读出来。(就算你不认识乐谱也不用担心,我们聪明的蜥蜴会在一旁辅助的。总之,这肯定会是一次乐声美妙的体验。) 只要进行短暂的理论学习,掌握如何制作音符和不同的长度,也许你就能帮我们的英雄解开音乐之谜……走向旅程的下个阶段。 《天鹅之旅》专为 iPad 与 Mac 量身定制,其中结合了我们许多 Playground 教育体验中使用的框架与资源(如 Sonic Workshop、Sensor Arcade 与 Augmented Reality等)。要了解更多如何制作自己 Playground 的信息,请查看“为 iPad 与 Mac 创造 Swift Playground 内容”一节。 还有,别忘了去开发者论坛,分享你对我们这个支线任务的解决方法哦。
资源
相关视频
WWDC20
-
下载
(你好 WWDC 2020) 你好 欢迎参加 WWDC (天鹅的探索 第三章:著名的卷轴) 你好 WWDC 这里是“天鹅的探索” 我是 Rob 主持人 我们将深入了解 我们的顶尖团队为你打造的 Swift Playgrounds 挑战 准备好了吗? 在本集中 我们将基于对计时器 和 ToneOutput 的知识进行展开 在第三集中 你再次回到蜥蜴的小屋 揭开天鹅另一幅卷轴的神秘面纱 我不想剧透更多 但是我可以告诉你 要克服这一挑战 你需要了解拍子 以及如何演奏不同长度的音符 我们将从音乐理论速成班开始 你将学习四分音符和半音符之间的区别 第二个挑战仅使用单个音符长度 因此我们将重新使用计时器 并讨论如何创建可变的持续时间 最后 我们将完成另一个 很有趣的附加任务 首先来说说节奏吧 在之前的节目中 我们已经讨论了如何弹奏不同音高的音符 但是 正如你在天鹅的卷轴中看到的那样 我们需要学习如何演奏不同长度的音符 由于不是每个人都懂音乐 让我们以三个不同长度的音符为例 来进行讨论 在这里 我们有四分音符、二分音符 和附点二分音符 大多数拍子由四分音符定义 因此我们将其用作基准音符 二分音符的长度是四分音符的两倍 附点二分音符是四分音符的三倍 天鹅想要听到的歌曲速度 是每分钟 120 拍 这意味着一分钟内有 120 个四分音符 从那里 我们计算计时器的间隔 以便我们可以播放卷轴中每个音符的长度 在 Music.swift 中 我们包含了供你实现的协议 第一个是 Pitches 用于捕捉 ToneOutput 的频率 例子如图所示 你需要为天鹅卷轴中的每个音高 添加其他案例
接下来 我们需要将音符 表示为一定长度的音调 长度应为四分之一音符的倍数 例如 二分音符将返回 2.0 而八分音符将返回 0.5 例子如图所示 同样 你需要为卷轴中每个音符长度的 枚举添加案例 接下来 我们需要更新计时器代码 让我们与 Stephen 一起检查一下
如 Rob 所述 我们需要更新计时器代码 以允许使用变长音符 在开始使用该方法之前 我们先更新代码 使用 Rob 刚刚向你展示的类型 首先 我们更新示例 以使用刚才定义的音高和音符类型 不幸的是 这不会立即生效 因为计时器的 TimeInterval 不符合我们的音符长度 请记住 ToneOutput 会发出连续的声音 直到你告知它停止 我们更新计时器的方法可以利用这一点 首先 我们需要将计时器的间隔 设置为最短音符长度的持续时间 为此 我们将更新 NoteProtocol 以添加属性 shortestSupportedNoteLength 然后 我们更新音符的实现 在天鹅的卷轴中 由于四分音符是最短的音符 因此我们将选择四分音符来简化操作 最后 我们将计时器的间隔 更新为最短的音符长度乘以节拍 本示例假定每分钟 120 拍 也就是说四分音符的长度为 500 毫秒 接下来 我们需要将较长的音符 细分为较为平坦的音高阵列 (细分音符) 我们要为每个计时器间隔 向 ToneOutput 发送 一组音高指令 由于我们支持的最小音符是四分音符 因此我们仅发送一条指令 同理 二分音符会发送两条指令 附点二分音符会发送三条指令 依此类推
要细分音符 你需要 在 NoteProtocol 实现中 实现另一种方法 “细分”返回一组音高阵列 这组音高可以经过收集 并发送到 ToneOutput
现在 在计时器循环中 我们首先创建细分的音高阵列 然后 我们更新计时器循环 以迭代音高而不是音符阵列 这个完整的示例展示了完成挑战 所需的所有 API Rob 我们的观众 还有其他附加任务吗? 当然有 Stephen 但在此之前 我需要提示一下 这个附加任务将包含本章挑战的剧透信息 如果你想先完成挑战 请在此视频上点击暂停 完成挑战后再回来 祝你好运!
好吧 准备好了吗? 天鹅的挑战是演奏《欢乐颂》 而卷轴则为你提供了所有音符 让我们看看你是否可以升级该代码 在其下方弹奏低音和弦 我有一个温馨提示 (多个计时器) 你可以使用多个计时器将音调彼此叠加 在本集中 我们给出了一些提示 用来完成“天鹅的探索”中的第三个挑战 我们讨论了节奏以及拍子的定义 然后 我们讨论了 如何使用具有细分音高的 单个固定持续时间计时器 来演奏不同长度的音符 祝你好运 玩得开心 请加入我们的论坛 提供附加任务的解决方案 我们很想听听你的解决方案
-
-
2:03 - Example Pitch Implementation
// Example Pitch implementation public enum Pitch: Double, PitchProtocol { case a4 = 440.0 var frequency: Double { return self.rawValue } }
-
2:09 - NoteProtocol
// Music.swift public protocol NoteProtocol { /// Play this Note through a ToneOutput var tone: Tone { get } /// The duration of this Note as a multiple of quarter notes, /// e.g., a half note is 2.0, an eighth note is 0.5 var length: Float { get } }
-
2:24 - Example Note implementation
// Example Note implementation public enum Note: NoteProtocol { case quarter(pitch: Pitch) var tone: Tone { switch self { case .quarter(let pitch): return Tone(pitch: pitch.frequency, volume: 0.3) } } var length: Float { switch self { case .quarter(_): return 1.0 } } }
-
2:51 - Play more than one tone redux
// Play more than one tone redux let toneOutput = ToneOutput() let notes = [Note.quarter(pitch: .a4), .half(pitch: .c4), .quarter(pitch: .a4)] var index = 0 Timer.scheduledTimer(withTimeInterval: 0.4, repeats: true) { timer in guard index < tones.count else { timer.invalidate() owner.endPerformance() return } toneOutput.play(tone: tones[toneIndex].tone) index += 1 }
-
3:18 - Updating NoteProtocol
// Music.swift public protocol NoteProtocol { /// Play this Note through a ToneOutput var tone: Tone { get } /// The duration of this Note as a multiple of quarter notes, /// e.g., a half note is 2.0, an eighth note is 0.5 var length: Float { get } /// Length of the smallest Note supported static var shortestSupportedNoteLength: Float { get } }
-
3:36 - Updating the Timer interval
// Play more than one tone redux let toneOutput = ToneOutput() let notes = [Note.quarter(pitch: .a4), .half(pitch: .c4), .quarter(pitch: .a4)] var index = 0 let interval = TimeInterval(Note.shortestSupportedNoteLength * 0.5) // 120 BPM Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { timer in guard index < tones.count else { timer.invalidate() owner.endPerformance() return } toneOutput.play(tone: tones[toneIndex].tone) index += 1 }
-
4:15 - Adding subdivide to NoteProtocol
// Music.swift public protocol NoteProtocol { associatedtype PitchType: PitchProtocol /// Play this Note through a ToneOutput var tone: Tone { get } /// The duration of this Note as a multiple of quarter notes, /// e.g., a half note is 2.0, an eighth note is 0.5 var length: Float { get } /// Length of the smallest Note supported static var shortestSupportedNoteLength: Float { get } /// Subdivide into a series pitches, according to the shortest /// supported note func subdivide() -> [PitchType] }
-
4:30 - Putting it all together
// Play more than one tone redux let toneOutput = ToneOutput() let notes = [Note.quarter(pitch: .a4), .half(pitch: .a4), .quarter(pitch: .a4)] var pitches = [Pitch]() for note in notes { pitches.append(contentsOf: note.subdivide()) } var index = 0 let interval = TimeInterval(Note.shortestSupportedNoteLength * 0.5) Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { timer in guard index < pitches.count else { timer.invalidate() owner.endPerformance() return } toneOutput.play(tone: Tone(pitch: pitches[index].frequency, volume: 0.3)) index += 1 }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。