AVAudioEngineを使って音声にリアルタイムにエフェクトをかけて保存する方法(サンプルあり)

##はじめに
録音している音声にリアルタイムでエフェクトをかけて、その音声データをサーバにアップロードしたかったので、AVAudioEngineを使ってできないものかな〜と思ってサンプルを作ってみた時のメモです。
最後に簡単なサンプルのURLを貼っておりますので興味のある方は触ってみてください〜
##AVAudioEngineとは？
AppleのAVAudioEngine Class Referenceには以下のように記述されています。
>
The AVAudioEngine class defines a group of connected AVAudioNode objects, known as audio nodes. You use audio nodes to generate audio signals, process them, and perform audio input and output.


すなわち、複数のnodeで構成されておりそれらを組み合わせて使うことでオーディオ信号の生成や処理、音声の入出力が行えるクラスと言えそうです。
※AVAudioEngine はiOS8から追加された(iOS8以降で使える)クラスです。


##AVAudioEngineの基本的な使い方
これはとっても簡単です。
AVAudioEngineのインスタンスをつくってあげてNodeをつなげるだけで音声の入力と出力が行われます。

```swift:audioEngineManager.swift
let audioEngine = AVAudioEngine()
let input = audioEngine.inputNode
let mixer = audioEngine.mainMixerNode
audioEngine.connect(input!, to: mixer, format: input!.inputFormatForBus(0))
try! audioEngine.start()
```


## AVAudioEngineを使って録音する
音声の録音には ```- installTapOnBus:bufferSize:format:block:``` という関数を使います。
```audioEngine.start()```を呼び出す前に以下のように```installTapOnBus```を読んであげると音声を録音している間、逐一コールバックが呼ばれるのでその中で保存したい場所に書き込んであげればOKです！

```swift:audioEngineManager.swift
outputFile = try! AVAudioFile(forWriting: recFileURL, settings: recSettings)
        
let input = audioEngine.inputNode
input!.volume = 0
input!.installTapOnBus(0, bufferSize: 4096, format: input?.inputFormatForBus(0)) { (buffer, when) in
	 try! self.outputFile.writeFromBuffer(buffer)
   }
```


##エフェクトの種類
エフェクトは大きく分けると以下の２種類があります。
・**AVAudioUnitEffect**
・**AVAudioUnitTimeEffect**

**この２つの大きな違いはリアルタイムで処理をできるかどうかです。**

AVAudioUnitEffectクラス内のエフェクトはリアルタイムで処理ができるので入力した音声にエフェクトをかけてそのまますぐにスピーカーで出力するなどといったことが可能です。

一方で、AVAudioUnitTimeEffectクラス内のエフェクトは、
>"processes audio in non-realtime"

なので入力した音声にリアルタイムでエフェクトをかけることが不可能です。
(AVAudioUnit Class Referenceにはこのことがはっきり書いてあるのですが、私はちゃんと読まなかったのでここの違いに気付かずにハマってしまいました、、、)


##AVAudioUnitEffect
AVAudioUnitEffectには以下の4つのクラスが用意されています。
・**AVAudioUnitDelay**
・**AVAudioUnitDistortion**
・**AVAudioUnitEQ**
・**AVAudioUnitReverb**

**この4つのエフェクトはリアルタイムで処理を行うことができます。**

特に、AVAudioUnitDistortionというのが面白くて、これはDistortion(歪み)のエフェクトクラスなのですが```loadFactoryPreset```というメソッドの引数にたくさんのパラメーターが用意されており、簡単にロボット風の音声などに変換できたりします。
使い方はNodeを作ってつなげるだけです。

```swift:audioEngineManager.swift
let input = audioEngine.inputNode
let mixer = audioEngine.mainMixerNode

// Distortion
let distortion = AVAudioUnitDistortion()
distortion.loadFactoryPreset(.SpeechGoldenPi)
audioEngine.attachNode(distortion)
        
audioEngine.connect(input!, to: distortion, format: input!.inputFormatForBus(0))
audioEngine.connect(distortion, to: mixer, format: input!.inputFormatForBus(0))
try! audioEngine.start()
```


##AVAudioUnitTimeEffect
AVAudioUnitTimeEffectには以下の2つのクラスが用意されています。
・**AVAudioUnitTimePitch**
・**AVAudioUnitVarispeed**

**この２つに関してはリアルタイムで音声の変換を行うことができません。**

使い方(使いどころ)としては、一度録音した音声をplayerNodeを使って再生する際にエフェクトをかけるというのが一番現実的な使い方だと思っています。


##まとめ
AVAudioEngineは手軽に実装できて便利ではありますが、手の込んだことやリッチな機能を実装しようとするとAUGraphなどを使う必要があるなーと思いました。

iOS10で追加される音声認識APIの[Appleが公開しているサンプル](https://developer.apple.com/library/prerelease/content/samplecode/SpeakToMe/Introduction/Intro.html#//apple_ref/doc/uid/TP40017110)でもAVAudioEngineが使われていましたし、AVAudioEngineは今後に期待です:grinning: 

**音声にエフェクトをかけて録音・保存を行い再生するまでの簡単なサンプルプログラムは[git](https://github.com/ahirusun/AVAudioEngineSample)にありますので興味のある方は覗いてみてください。**