[Swift5]AVAudioEngineを使ってリアルタイム処理を行う最小実装

##環境
- macOS: Catalina
- Xcode 11.6
- Swift 5.2



## リアルタイムに音声に処理を行う

- 入力をそのまま出力
- 入力にエフェクトをかけて出力

##入力をそのまま出力するコード

```swift
class ViewController: UIViewController {

    var engine = AVAudioEngine()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupAudioSession()
        
        let input = engine.inputNode
        let output = engine.outputNode
        let format = engine.inputNode.inputFormat(forBus: 0)
        engine.connect(input, to: output, format: format)

        try! engine.start()
        
    }

func setupAudioSession() {
        do {
            let session = AVAudioSession.sharedInstance()
            try session.setCategory(.playAndRecord, options: [.defaultToSpeaker, .allowBluetooth])
            try session.setActive(true)
        } catch {
            fatalError("Failed to configure and activate session.")
        }
    }

```

### 補足1 AVAudioEngine
AVAudioEngineは暗黙的にinputとoutputを持っているためノードを`attach`する必要性がない。
つなげる時は`connect`を用いる。

### 補足2　AudioSession

```swift
func setupAudioSession() {
        do {
            let session = AVAudioSession.sharedInstance()
            try session.setCategory(.playAndRecord, options: [.defaultToSpeaker, .allowBluetooth])
            try session.setActive(true)
        } catch {
            fatalError("Failed to configure and activate session.")
        }
    }
```

これは`AVAudioSession`の設定で

ステレオオーディオを録音するには、recordまたはplayAndRecordカテゴリのいずれかを使用するアプリのオーディオセッションが必要。

また、`option`でiPhoneのデフォルトのスピーカーを使用することとBluetoothイヤホンで再生と録音が可能に設定。

詳しくは[appleサンプル](https://developer.apple.com/documentation/avfoundation/avaudiosession/capturing_stereo_audio_from_built-in_microphones)を参考にしてください！

## 入力にエフェクトをかけて出力するコード

エフェクトをかけたい時にはノードを追加してあげると簡単にエフェクトをかけることができる。
**アプリ起動時はイヤホン付けてデバックしないととハウリングが起きるので注意！**

```swift
    var engine = AVAudioEngine()
    var delay = AVAudioUnitDelay()
    var reverb = AVAudioUnitReverb()

override func viewDidLoad() {
        super.viewDidLoad()
        setupAudioSession()
        
        let input = engine.inputNode
        let output = engine.outputNode
        let format = engine.inputNode.inputFormat(forBus: 0)
        delay.delayTime = 2.0
        reverb.loadFactoryPreset(.largeHall)
        reverb.wetDryMix = 40
        
        engine.attach(delay)
        engine.attach(reverb)
        engine.connect(input, to: delay, format: format)
        engine.connect(delay, to: reverb, format: format)
        engine.connect(reverb, to: output, format: format)

        try! engine.start()
        
    }
```

###補足3 エフェクトをつなげる時は`attach`してから
`inputNode`と`outputNode`は`attach`する必要性がなかったが、エフェクトNodeを使用する際には`attach`しないといけない。

---

遅延を入れてリバーブをかけるとコンサートホールにいるみたいなエフェクトになった！Bluetoothでもわかるくらいリバーブがいい感じにかかってて感動！

## エフェクトクラス一覧

他にもエフェクトがあるので紹介(今回のも含めて)

- AVAudioUnitReverb
リバーブ処理
- AVAudioUnitTimeEffect
非リアルタイムエフェクト処理
- AVAudioUnitTimePitch
高品質の再生速度と音程シフトを互いに独立して提供
- AVAudioUnitVarispeed
再生速度の制御
- AVAudioUnitDelay
遅延処理
- AVAudioUnitEQ
マルチバンドイコライザの実行 EQ→イコライザの略
- AVAudioUnitDistortion
歪みエフェクト

まだ使っていないエフェクトを使って音遊びしていきたい。

## まとめ

AVAudioEngineは暗黙的にinputとoutputを持っているためノードをつなげる必要性がない。

WWDC2019に新しくAVAudioEngineが新しくなったらしいので、

このセッションを見て復習する。

[What's New in AVAudioEngine](https://developer.apple.com/videos/play/wwdc2019/510/)