LoginSignup
36
35

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-06-22

はじめに

録音している音声にリアルタイムでエフェクトをかけて、その音声データをサーバにアップロードしたかったので、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をつなげるだけで音声の入力と出力が行われます。

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です!

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)
   }

エフェクトの種類

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

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

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

一方で、AVAudioUnitTimeEffectクラス内のエフェクトは、

"processes audio in non-realtime"

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

AVAudioUnitEffect

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

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

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

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

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

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

まとめ

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

iOS10で追加される音声認識APIのAppleが公開しているサンプルでもAVAudioEngineが使われていましたし、AVAudioEngineは今後に期待です:grinning:

音声にエフェクトをかけて録音・保存を行い再生するまでの簡単なサンプルプログラムはgitにありますので興味のある方は覗いてみてください。

36
35
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
35