大多数浏览器和
Developer App 均支持流媒体播放。
-
天鹅之旅 第4章:序列完成
Swift Playgrounds 隆重推出《天鹅之旅》——一款老少咸宜的四章节互动冒险。大结局终于要来了:你已经熟练掌握了音符的使用技巧,但在这一章中,我们的英雄需要对多声部和声进行排序。 探索如何根据相应的 MIDI 代码对给出的乐器进行演奏,你可能需要帮助我们的英雄找出其中的旋律……并完成他们的旅程。 天鹅之旅》专为 iPad 与 Mac 量身定制,其中结合了我们许多 Playground 教育体验中使用的框架与资源(如 Sonic Workshop、Sensor Arcade 与 Augmented Reality等)。要了解更多如何制作自己 Playground 的信息,请查看“为 iPad 与 Mac 创造 Swift Playground 内容”一节。 还有,别忘了去开发者论坛,分享你对我们这个支线任务的解决方法哦。
资源
相关视频
WWDC20
-
下载
(你好 WWDC 2020) 你好 欢迎来到 WWDC (第 4 章:序列完成) 你好 欢迎回到《Swan's Quest》 我是你们的主持人 Rob 我们就要了解探索之行的最后一章了 希望大家到目前为止乐享其中 对于这个最后章节 我们要抛开 ToneOutputs 聊一聊取样乐器 在最后一章 你会最后一次见到 Lizard Swan 的胸部是个迷 我不想剧透 这么说吧 音序器在解决这一挑战中 将会起到关键作用 我们先从介绍音序器 以及在 Swift 中 构建音序器的一些建议开始 Stephen 会回来讨论用于演奏采样乐器的 内容 SDK 的 API 并简要概述 SDK 内提供的乐器资料库 他也会向你介绍我们是如何 在 GarageBand 中取样的 最后 对于那些不希望乐趣结束的人 我们会用最后的支线任务来完结 我们来聊聊步进音序器 在第三个挑战的最后 Swan 给了我们带两部和声的卷轴 好样的 Swan 与我们之前的挑战不同 这次挑战会需要多个乐器同时演奏 要同时演奏多个部分 我们要向你介绍如何构建步进音序器 信不信由你 对于这个音序器 你只需要一个计时器 不是用 ToneOutput 我们将利用 包含在内容 SDK 中的采样乐器 音序器是多轨定时循环 它被分成相等的块或步骤 在预定的持续时间内依次演奏 每个音轨代表一个有音调乐器的实例 音序器也用于无音调的乐器 如打击乐器
音序器用途非常广泛 它们非常适合创建有独特氛围的背景循环 或者可以放在旋律下面的鼓点节拍 步进音序器允许你在另一个音轨上 叠加多个音轨 这个例子中 有号音轨、吉他音轨和打击乐器音轨 这个序列中的每一列都是四分音符的长度 你看到的是八拍或者两小节的 4/4 拍 或者我们在音乐领域所说的普通拍子
这是一个音序器的定时循环的例子 计时器的间隔取决于 划分总的持续时间 四秒 在序列中 取决于拍子的总数 八拍 我们需要添加音轨和代码 以演奏每个音轨内的乐器 接下来的时间交给 Stephen 谢谢你 Rob 我们的内容 SDK 包括丰富的 API 和乐器资料库 我们首先介绍了 Sensor Arcade 中的乐器 API 并包括了名为 Sensor Create 的模板 这样你就可以创作自己的音乐了 然后去年 我们发布了 Sonic Workshop 它的配套起点是 Sonic Create 这两个都包括了七个乐器 和三个八度音符的样本 基本 API 是 playInstrument 方法 这个 API 需要参考包含在 Playgrounds 内容 SDK 中的七个乐器中的一个 电吉他、电贝斯、钢琴 暖铃、七合成器、贝斯合成器 和水晶合成器 playInstrument 方法要求的第二项目是 一个 MIDINoteProtocol 值 这些 MIDI 音符包括一个八位整数 对应于合适的 MIDI 代码 这是一个编码的 MIDI 音符的 第二个八度音阶的示例应用 注意:我们包括一个值“rest” 这使得我们可以在序列中 为乐器表示无声间隙
在我们更新代码前 我们需要讨论音轨 我们已在 Sequencer.Swift “TrackProtocol” 包括了另一个协议 这个包括了一个乐器值、音轨的长度 和一个方法 这为序列中给定的步骤 提供了 MIDI 音符 一种示例应用也许是这样的 请记得检查音符属性是否存在 并确保索引步骤不超过序列的边界 所有部分都就绪后 我们可以重新看一下最基本的示例 首先我们创建两个音轨 贝斯和钢琴 并把它们合并到一个数组中 一旦创建好 我们需要为每个音轨指定音符模式 最后 我们对选定的音轨进行循环 并为指定的乐器演奏音符 第一次通过序列之后 别忘了调用 endPerformance 方法 这样你的解决方案就得到了认可 在我们完成了序列一次循环后 我们来更新回收索引的代码
在将索引重置为零后 我们就可以调用 endPerformance Swan 就会知道我们完成了挑战
接下来 我要谈谈 GarageBand 中的采样 创建自己的乐器的一种方法是 从 GarageBand 自己采样 首先 打开 GarageBand 并选择 Keyboard 或者另一个你感兴趣的采样乐器 Keyboard 内有很多乐器选项 我选择了十三弦古筝 它是一种日本传统乐器 你也会注意到 你可以更改该乐器的很多其他属性 比如音调和共鸣
你还可以选择 Keyboard 使用的音阶 这样使得演奏你想要的音符更加简单 在此 我选择大调音阶
等录好各个音符后 你演奏一下 以确保它们的声音完全符合你的期望
如果需要 在导出前 你可以在 GarageBand 编辑器内 进行修改 一旦一切就绪 你就可以导出歌曲了 最无损格式是未压缩的 WAV 但你也可以以压缩的格式导出 等你导出后 修整各个音符 并把它们导入你的项目以创建乐器 Rob 对于最后一部分 我们应该进行非常酷的支线任务 Stephen 我非常同意 大家准备好了吗?你准备好了吗?
这次没有剧透 对于最后的这个支线任务 我们希望你 把四个章节你所做的一切组合起来 将 ToneOutput 添加为你的步进音序器的一个乐器 在这一集中 我们给出了 在《Swan's Quest》中 完成最后挑战的一些建议 你们了解了步进音序器 以及它们如何被用来创建多声部和声 我们向大家介绍了 包含在 Swift Playgrounds 内的 预采样乐器 然后向大家介绍了 如何采样并创建自己的乐器 希望大家享受《Swan's Quest》之旅 并了解了 Swift Playgrounds 更多内容 以及借助我们嵌入的内容 SDK 你所能实现的一切 如果你需要复习 或者只想再次乐享其中 那一定要查看我们之前的视频 祝好运 玩得痛快 加入我们的论坛 并分享你的支线任务解决方案 我们很乐意了解你完成的情况
-
-
2:26 - Barebones example of a sequencer
// A barebones example of a sequencer let numberOfBeats = 8 // two bars of 4/4 let duration = 4.0 // seconds let interval = duration / Double(numberOfBeats) var index = 0 Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { timer in // Play each track's Instrument // ... index = (index + 1 < numberOfBeats) ? index + 1 : 0 }
-
3:16 - Introduction to playInstrument(_:note:volume:)
// Sequencer.swift func playInstrument(_ kind: Instrument.Kind, note: MIDINoteProtocol, volume: Double = 75) // Instrument.swift public class Instrument { /// The kind of included instruments public enum Kind: String { case electricGuitar, bassGuitar, piano, warmBells, sevenSynth, bassSynth, crystalSynth } // ... }
-
3:38 - MIDINoteProtocol
// Sequencer.swift protocol MIDINoteProtocol { /// note as an 8-bit MIDI code var midiCode: UInt8 { get } }
-
3:48 - Example implementation for Notes
// Example implementation for Notes enum MIDINotes: UInt8, MIDINoteProtocol { case rest = 0 case C2 = 36 case D2 = 38 case E2 = 40 case F2 = 41 case G2 = 43 case A2 = 45 case B2 = 47 var midiCode: UInt8 { return self.rawValue } }
-
4:03 - TrackProtocol
// Sequencer.swift protocol TrackProtocol { associatedtype NoteType : MidiNoteProtocol /// The kind of instrument that the track sequences var instrument: Instrument.Kind { get } /// Number of beats contained in the sequence var length: Int { get } /// MIDI code for the sequence frame func note(for frame: Int) -> NoteType }
-
4:21 - Example implementation for Tracks
// Example implementation for Tracks struct Track : TrackProtocol { var instrument: Instrument.Kind var length: Int var notes: [MIDINotes]? = nil func note(for frame: Int) -> MIDINotes { guard let n = notes, frame < n.count else { return .rest } return n[frame] } }
-
4:34 - Implementing a Sequencer
// A barebones example of a sequencer let numberOfBeats = 8 // two bars of 4/4 let duration = 4.0 // seconds var bass = Track(instrument: .bassGuitar, length: numberOfBeats) var piano = Track(instrument: .piano, length: numberOfBeats) let tracks = [bass, piano] bass.notes = [.rest, .C2, .A2, .rest, .C2, .A2, .D2, .C2 ] piano.notes = [.A2, .A2, .C2, .F2, .A2, .C2, .none, .F2] let interval = duration / Double(numberOfBeats) var index = 0 Timer.scheduledTimer(withTimeInterval: interval, repeats: true, block: { timer in for track in tracks { playInstrument(track.instrument, note: track.note(for: index)) } index = (index + 1 < numberOfBeats) ? index + 1 : 0 })
-
5:00 - // Getting credit for our work
// Getting credit for our work Timer.scheduledTimer(withTimeInterval: interval, repeats: true, block: { timer in for track in tracks { playInstrument(track.instrument, note: track.note(for: index)) } if index + 1 < numberOfBeats { index = index + 1 } else { index = 0 owner.endPerformance() } })
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。