
AudioKit是由音频工程师,程序员和音乐家针对iOS和OSX开发的音频框架。 它提供了用于
处理和
合成声音的工具。 引擎盖下面是Swift,Objective-C,C ++和C以及Apple的Audio Unit API的组合。 令人敬畏的(而且相当复杂的)技术封装在非常友好的Swift API中,可以直接从Xcode Playgrounds访问!
在本教程中,我们将继续学习AudioKit,以及声音合成的
历史 。 您将学习声音物理学的基础知识,以及像Hammond Organ这样的首批合成器是如何工作的。 同样,将考虑现代技术,例如采样。
做自己喜欢的饮料,坐下来走!
第一步
从AudioKit 3.6开始,设置游乐场以使用框架变得非常简单。
在此处下载并解压缩入门播放列表。
旅程从几个步骤开始,以配置游乐场以使用AudioKit。
在Xcode中打开
AudioKitPlaygrounds.xcodeproj文件。 单击屏幕左下角的
+按钮,选择“
文件...” ,然后在“
操场”部分中选择“
空白 ”,将新文件与演示操场一起保存在“操场”文件夹中。
新添加的游乐场将启动,并且将如下所示:

将生成的代码替换为以下内容:
import AudioKitPlaygrounds import AudioKit let oscillator = AKOscillator() AudioKit.output = oscillator try AudioKit.start() oscillator.start() sleep(10)
直到您至少组装了一次项目,游乐场才会启动,为此,您可以使用菜单项
Product / Build或组合键
⌘-B 。 之后,再次运行游乐场,并听到嗡嗡声10秒钟。 (译者注:有时错误不会消失,您需要切换到另一个游乐场,然后再使它工作)。 您可以使用播放窗口左下方的“播放/停止”按钮停止播放或重新开始播放。
注意:如果仍然看到错误,请尝试重新启动Xcode。 不幸的是,框架和游乐场不是彼此很好的朋友,它们的行为可能无法预测。
振荡器和声音物理
人类已经通过各种物理对象播放音乐了数千年。 我们许多常用的乐器(例如吉他或鼓)已有数百年历史。 Elias Gray在1874年进行了使用电子电路产生声音的第一笔经记录的经验。 Elisha在电信领域工作,他发明了振荡器-最简单的音乐合成器。 和他一起,我们将开始潜水。
右键单击您的游乐场,选择“
新建游乐场页面”,然后将生成的代码替换为以下代码:
import AudioKitPlaygrounds import AudioKit import PlaygroundSupport
操场将开始产生连续的嗡嗡声-如预期的那样。 您可以单击停止停止它。
这几乎与我们在上一个游乐场中所做的相同,但是这次我们将深入研究细节。
按顺序考虑所有步骤:
- 在这里,我们创建一个振荡器。 振荡器是
AKNode
的后继者。 节点是构成生成和修改声音的音频链的元素。
- 在这里,我们将最后一个节点的输出与AudioKit引擎连接。 在我们的例子中,只有一个节点。 此外,框架会将节点的输出定向到音频回放设备。
- 好吧,我们启动振荡器,在输出端它开始发送声波。
振荡器会产生一个不停止的重复信号。 在此剧本中,
AKOscillator
生成一个正弦波。 使用AudioKit,数字正弦波信号被发送到扬声器或耳机。 结果,我们听到的声音以与我们产生的正弦波相同的频率振荡。 这个正弦波听起来不很音乐。

振荡器的声音由两个参数决定:振幅-正弦波的高度,确定音量和频率-声音的高度取决于它。
在操场上,在创建振荡器之后立即添加以下代码行:
oscillator.frequency = 300 oscillator.amplitude = 0.5
声音发生了变化,现在听起来是安静的两倍,并且声音要低得多。 信号的频率以赫兹(每秒重复数)测量,并确定音符的音高。 振幅(振幅)设置为0到1,并负责音量。
Elijah Gray的发明记录在有史以来的第一项电子乐器专利中。

许多年后,利奥·特雷敏(Leo Theremin)发明了一种至今使用的奇怪乐器-特雷敏(Theremin)。 在那儿,您可以通过手在乐器上方移动来改变声音的频率。 要了解Theremin的声音,您可以听海滩男孩的振动,Theremin的声音没什么可混淆的。
您可以模拟Thereminvox的声音,为此,将以下代码添加到振荡器设置中:
oscillator.rampDuration = 0.2
并用以下内容替换以AudioKit开头的行(
try AudioKit.start()
):
let performance = AKPeriodicFunction(every: 0.5) { oscillator.frequency = oscillator.frequency == 500 ? 100 : 500 } try AudioKit.start(withPeriodicFunctions: performance) performance.start()
rampDuration
属性使振荡器能够平滑地更改其参数的值(例如,频率或幅度)。
AKPeriodicFunction
是
AKPeriodicFunction
的有用工具,用于定期执行代码。 在我们的示例中,它每0.5秒将正弦波的频率从500Hz更改为100Hz。
恭喜你! 您刚刚完成了第一批。 一个简单的振荡器可以产生音符,但是听起来并不好。 有许多因素会影响物理仪器(例如钢琴)的声音。 进一步,我们将考虑其中的一些。
声音包络
乐器弹奏音符时,其声音的音量会随着时间而变化,并且变化的性质因乐器而异。 可以模拟这种效果的模型称为Attack-Decay-Sustain-Release(ADSR)包络(注意:可购买的合成器从未本地化,因此曲线的名称与该合成器面板上的名称相同)。

ADSR信封包含:
- 起音:声音达到最大音量的起音或时间。
- 衰减 :狂野或音量从最大下降到主要的时间
- 延音 :与前两个参数不同,主要音量不是时间,在经过攻击和野蛮之后以及释放合成器琴键之前,此音量将产生声音
- 释放 :释放或音量变为零的时间
在钢琴中,声音是通过敲击弦槌的锤子来提取的,因此在钢琴中很快,或者说是短促的打击和狂野。 小提琴的攻击力很强,狂野而持久,音乐家可以通过使用弓的方式来影响这些参数。
Hammond Novachord是最早的电子乐器之一。 该仪器于1939年制造,由163个真空管和1000多个电容器组成,重230千克。 不幸的是,只制作了几百本,他从未获得商业上的成功。

右键单击“
旅程 游乐场” ,选择“
新建游乐场页面”,然后创建一个名为
ADSR的新页面。 将生成的代码替换为以下内容:
import AudioKitPlaygrounds import AudioKit import PlaygroundSupport let oscillator = AKOscillator()
它只是创建了一个我们已经熟悉的振荡器。 接下来,在游乐场的末尾添加以下代码:
let envelope = AKAmplitudeEnvelope(oscillator) envelope.attackDuration = 0.01 envelope.decayDuration = 0.1 envelope.sustainLevel = 0.1 envelope.releaseDuration = 0.3
这将创建一个定义ADSR包络的
AKAmplitudeEnvelope
。 持续时间参数(attackDuration,destroyDuration,releaseDuration)以秒为单位指定,音量(sustainLevel)的设置范围为0到1。
AKAmplitudeEnvelope
是
AKAmplitudeEnvelope
的后继者,与
AKNode
相同,在上面的代码中,我们将振荡器包络节点传递给初始化程序,从而连接这些节点。
接下来,添加以下代码:
AudioKit.output = envelope let performance = AKPeriodicFunction(every: 0.5) { if (envelope.isStarted) { envelope.stop() } else { envelope.start() } } try AudioKit.start(withPeriodicFunctions: performance) performance.start() oscillator.start() PlaygroundPage.current.needsIndefiniteExecution = true
它将启动AudioKit,但是这次我们将ADSR节点的输出馈送到其输入。 为了听到ADSR效果,我们使用
AKPeriodicFunction
不断打开和关闭节点。

现在您可以听到音符如何循环播放,但是这次有点像钢琴。
该循环在每次迭代中每秒运行两次,以启动或停止ADSR。 当ADSR快速开始攻击时,音量在0.01秒内达到最大值,此后音量在0.1秒内下降到主音量并保持在0.5秒,最后在0.3秒后衰减。
您可以自己演奏这些参数,然后尝试演奏小提琴的声音。
我们遇到的声音基于
AKOscillator
生成的正弦波。 尽管ASDR有助于消除刺耳的声音,但您仍然不能将这些声音称为音乐声。
此外,我们将考虑如何获得更深的声音。
加成合成
每种乐器都有自己的特殊声音或音色。
音色是区分钢琴声音和小提琴声音的一种方法,即使它们可以演奏相同的音符。 音色的重要参数是声谱。 声谱描述了重现频率的范围,这些频率加在一起时会引起注意。 我们当前的游乐场使用的振荡器仅能以一种频率发出声音,而且听起来很人为。
使用一组振荡器演奏单个音符,您可以获得更生动的声音。 这种方法称为加成合成,这是我们下一个游乐场的主题。
右键单击操场,选择
New Playground Page并创建一个名为
Additive Synthesis的新页面。 将生成的代码替换为以下内容:
import AudioKitPlaygrounds import AudioKit import AudioKitUI import PlaygroundSupport func createAndStartOscillator(frequency: Double) -> AKOscillator { let oscillator = AKOscillator() oscillator.frequency = frequency return oscillator }
对于加法合成,您需要几个振荡器,为此我们将使用它。
createAndStartOscillator
接下来,添加代码:
let frequencies = (1...5).map { $0 * 261.63 }
在这里,我们采用从1到5的数字间隔,并将每个数字乘以261.53,即音符的频率。 由此产生的多个频率称为谐波。
现在添加代码:
let oscillators = frequencies.map { createAndStartOscillator(frequency: $0) }
在这里,我们为我们使用的每个频率创建了一个振荡器。
要组合振荡器,请添加以下代码:
let mixer = AKMixer() oscillators.forEach { $0.connect(to: mixer) }
AKMixer
是AudioKit节点的另一种类型。 它从一个或多个节点接收输入,并将它们组合为一个。
添加以下代码:
let envelope = AKAmplitudeEnvelope(mixer) envelope.attackDuration = 0.01 envelope.decayDuration = 0.1 envelope.sustainLevel = 0.1 envelope.releaseDuration = 0.3 AudioKit.output = envelope let performance = AKPeriodicFunction(every: 0.5) { if (envelope.isStarted) { envelope.stop() } else { envelope.start() } } try AudioKit.start(withPeriodicFunctions: performance) performance.start() oscillators.forEach { $0.start() }
使用此代码应该一切都清楚:将ADSR添加到混音器输出,通过AudioKit输出并定期打开/关闭它。
为了很好地处理加法合成,将这些频率的各种组合进行测试将很有用。 因此,像Live View这样的游乐场对我们来说是理想的机会。
为此,请添加代码:
class LiveView: AKLiveViewController { override func viewDidLoad() { addTitle("Harmonics") oscillators.forEach { oscillator in let harmonicSlider = AKSlider( property: "\(oscillator.frequency) Hz", value: oscillator.amplitude ) { amplitude in oscillator.amplitude = amplitude } addView(harmonicSlider) } } } PlaygroundPage.current.needsIndefiniteExecution = true PlaygroundPage.current.liveView = LiveView()
在AudioKit中,有专门用于在操场上方便工作的类。 在我们的示例中,
AKLiveViewController
使用
AKLiveViewController
,使用它我们垂直放置元素。 并为每个振荡器创建一个
AKSlider
。 滑块由振荡器的频率和幅度值初始化,并在与它们相互作用时引起阻塞。 在每个滑块的块中,我们更改相应振荡器的幅度。 因此,您只需向操场添加互动即可。
为了查看运动场的结果,您需要在屏幕上显示实时视图。 为此,请在窗口右上方选择带有相交圆圈的按钮,并确保为实时显示选择了正确的播放列表。

为了更改乐器的音调,您可以分别更改每个滑块的值。 为了获得逼真的声音,建议您尝试上面屏幕截图中所示的配置。
Teleharmonium是最早使用添加剂合成的合成器之一,重达200吨! 他难以置信的体重和体型,很可能成为他默默无闻的原因。 比较成功的哈蒙德风琴使用了类似的音调轮,但体积要小得多。 它是1935年发明的,在渐进摇滚时代仍然是一种广受欢迎的乐器。

音调轮是一个旋转盘,沿边缘有小孔,而拾音器位于边缘附近。 Hammond管风琴具有整套的音调轮,可以以不同的速度旋转。 产生声音的一种非常不寻常的方法是机电的而不是电子的。
为了产生更逼真的声谱,还有其他几种技术:频率调制(Frequency Modulation或FM)和脉冲宽度调制(Pulse Width Modulation或PWM),这两种技术分别在
AKFMOscillator
和
AKPWMOscillator
的
AKFMOscillator
中可用。 我建议您尝试将两者都替换,而不是我们之前使用的
AKOscillator
。
和弦
在1970年代,运动开始于由模块化合成器(由单独的包络振荡器和滤波器组成)到微处理器的合成器。 代替使用模拟电路,声音开始以数字格式产生。 这使得合成器更便宜,更紧凑,雅马哈等品牌的合成器非常受欢迎。

我们所有的游乐场都只能一次演奏一个音符。 许多乐器一次可以演奏多个音符,它们被称为
和弦 。 只能演奏一个音符的乐器称为
单音 。
为了获得和弦声音,可以创建多个振荡器并将其发送到混音器,但是在AudioKit中,有一种更合适的方法。
在操场上创建一个新页面并将其命名为Polyphony。 将生成的代码替换为以下内容:
import AudioKitPlaygrounds import AudioKit import AudioKitUI import PlaygroundSupport let bank = AKOscillatorBank() AudioKit.output = bank try AudioKit.start()
在这里,我们创建了振荡器组
AKOscillatorBank
。 如果转到类声明,则会发现它是
AKPolyphonicNode
的继承人,而后者又是我们已经知道的
AKNode
的继承人,并且还实现了
AKPolyphonic
协议。
结果,振荡器组与我们之前讨论的是相同的AudioKit节点。 它的输出可以发送到混音器,信封或任何其他滤镜和效果。
AKPolyphonic
协议描述了如何在和弦音符上弹奏音符;让我们更详细地考虑它。
为了测试振荡器,我们需要一种同时演奏多个音符的方法。 这一点都不困难!
将以下代码添加到播放列表中,并确保实时显示处于打开状态:
class LiveView: AKLiveViewController, AKKeyboardDelegate { override func viewDidLoad() { let keyboard = AKKeyboardView(width: 440, height: 100) addView(keyboard) } } PlaygroundPage.current.liveView = LiveView() PlaygroundPage.current.needsIndefiniteExecution = true
运动场编译时,您将看到以下内容:

酷吧? 音乐键盘就在操场上!
AKKeyboardView
是
AKKeyboardView
的另一个实用程序,可让您轻松探索框架的可能性。 按这些键,您将发现它们没有发出任何声音。
使用以下命令更新
PlaygroundView
的设置:
let keyboard = AKKeyboardView(width: 440, height: 100) keyboard.delegate = self addView(keyboard)
这将使我们的
PlaygroundView
成为键盘代表,并允许您响应按键。
更新类声明,如下所示:
class LiveView: AKLiveViewController, AKKeyboardDelegate
还可以在
setUp
之后添加一些方法:
func noteOn(note: MIDINoteNumber) { bank.play(noteNumber: note, velocity: 80) } func noteOff(note: MIDINoteNumber) { bank.stop(noteNumber: note) }
每次您按下一个键,
noteOn
方法都会被
noteOn
,它所做的只是告诉振荡器组开始播放该音符,在
noteOff
方法中,该
noteOff
将停止播放。
按住鼠标并滑动键,您会听到一个优美的渐强声(一个音乐术语,表示声功率逐渐增加)。 振荡器组已经包含一个内置的ADSR效果,因此,一个音符的衰减与下一个音符的攻击混合在一起,听起来非常不错。
您可能已经注意到,给我们提供按键的音符不是以频率的形式出现的。 它们被声明为
MIDINoteNumber
。 如果您转到此类广告,则会看到以下内容:
public typealias MIDINoteNumber = Int
MIDI代表乐器数字接口。 这是乐器相互之间相互作用的一种普遍形式。 音符编号对应于标准音乐键盘上的音符。 第二个参数-此力度(力度)对应于按键的击打强度。 值越低,按键的触感越柔和,最终声音就越安静。
最后,您需要在按键上启用复音模式。 将以下代码添加到
setUp
方法:
keyboard.polyphonicMode = true
现在,您可以同时演奏多个音符,如图所示:

顺便说一下,这是在C专业:)
AudioKit的故事早就开始了。 今天,它使用了
Soundpipe和
Csound的代码(1985年启动的MIT项目)。 令人惊讶的是,我们现在在操场上启动并添加到iPhone中的代码是大约30年前编写的。
取样方式
我们之前探讨的声音合成技术正在尝试使用简单的基本块(振荡器,滤波器和混音器)来再现逼真的声音。 1970年代初期,计算机功能的发展导致出现了一种新的方法-采样声音,其目的是创建声音的数字副本。
采样是一种非常简单的技术,类似于数码摄影。 在以固定间隔进行采样的过程中,将记录声波的振幅:

有两个参数会影响声音的录制精度:
- 位深度 :或位深度,采样器可以播放的各个音量级别的数量
- 采样率 :或采样率,表示多久进行一次幅度测量。 以赫兹为单位。
让我们在一个新的游乐场中探索这些属性。 创建一个新页面并将其命名为“ Samples”。 将生成的代码替换为以下内容:
import AudioKitPlaygrounds import AudioKit import PlaygroundSupport let file = try AKAudioFile(readFileName: "climax-disco-part2.wav", baseDir: .resources) let player = try AKAudioPlayer(file: file) player.looping = true
上面的代码加载了样本,创建了音频播放器,并将其无休止地播放。
可
在此处找到带有本教程的WAV文件的存档。 下载它并解压缩到游乐场的Resources文件夹。
然后在游乐场的末尾添加以下代码:
AudioKit.output = player try AudioKit.start() player.play() PlaygroundPage.current.needsIndefiniteExecution = true
这将使您的音频播放器与AudioKit相连,您只需要调高音量即可欣赏!
, .
MP3-, , , . :
let bitcrusher = AKBitCrusher(player) bitcrusher.bitDepth = 16 bitcrusher.sampleRate = 40000
AudioKit:
AudioKit.output = bitcrusher
. , .
AKBitCrusher
— AudioKit, . , , ZX Spectrum BBC Micro. , .
, (. delay). ,
AKBitCrusher
. :
let delay = AKDelay(player) delay.time = 0.1 delay.dryWetMix = 1
0.1 .
dryWetMix
. 1 , .
:
let leftPan = AKPanner(player, pan: -1) let rightPan = AKPanner(delay, pan: 1)
AKPanner
, - . .
AudioKit. ,
AKBitCrusher
AudioKit :
let mix = AKMixer(leftPan, rightPan) AudioKit.output = mix
, , .

接下来是什么?
AudioKit. , -, , , . , , .
.