iOS8からAVAudioEngineの登場により、CoreAudioがもっと使いやすくなりました。
今回はSwiftとPlaygroundを用いて音で遊んでみたいと思います。
最初に使用するクラスについて軽く説明です。
- 
AVAudioEngine
AVAudioNodeを管理するクラス
AVAudioEngineに対してAVAudioNodeをattachすることで入力にエフェクトなどをかけることができます。 - 
AVAudioNode
音の生成、処理、入出力のための抽象クラス
エフェクトなどはAVAudioUnitEffectクラスを使用しますが、これらもAVAudioNodeのサブクラスです。 
基本的には上記の2つクラスが元となっているようです。
では、簡単にマイク入力にエフェクトをかけてみましょう。
まず適当なPlaygroundを作成します。
このときPlatformは
Mac OSにしてください。
iOSにしてしまうと入力nodeの生成ができません。
ではとりあえず下のコードを一気に貼り付けてしまってください。
これでマイク入力にdelayとreverbがかかります。
import AVFoundation
import XCPlayground
XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)
var engine = AVAudioEngine()
//effectNodeの用意
var delay = AVAudioUnitDelay()
var reverb = AVAudioUnitReverb()
var input = engine.inputNode
var output = engine.outputNode
var format = input.inputFormatForBus(0)
var error:NSError?
//delayの設定
delay.delayTime = 1.5
delay.feedback = 20
//reverbの設定
reverb.loadFactoryPreset(.LargeRoom2)
reverb.wetDryMix = 80
//engineにdelayとreverbを追加
engine.attachNode(delay)
engine.attachNode(reverb)
//effectをつなぐ順番を指定 入力 -> delay -> reverb -> 出力
engine.connect(input, to: delay, format: format)
engine.connect(delay, to: reverb, format: format)
engine.connect(reverb, to: output, format: format)
// engineを実行
engine.startAndReturnError(&error)
比較的簡単そうに見えますよね。
特にエフェクトを繋いでいく部分はギターのエフェクターを繋いでいくような感覚ですね。
マイクの入力はAVAudioEngine生成時に確保してくれるようです。
次は任意のオーディオファイルを再生してみます。
これもPlaygroundでやりたかったのですが、Playgroundでファイルの読み込みがうまくできなかったのでCocoaAppliationで実装します。
CocoaApplicationテンプレートからプロジェクトを作ります。
import Cocoa
import AVFoundation
class ViewController: NSViewController {
	var engine = AVAudioEngine()
	//playerNodeの準備
	var player = AVAudioPlayerNode()
	//revebNodeの準備
	var reverb = AVAudioUnitReverb()
	override func viewDidLoad() {
		super.viewDidLoad()
		self.playAudio()
	}
	func playAudio() {
		var fileUrl = NSURL(fileURLWithPath: "/Users/Muukii/Desktop/sample.m4a")
		// オーディオファイルの読み込み
		var audioFile = AVAudioFile(forReading: fileUrl!, error: nil)
		if let file = audioFile {
			// reverbの設定
			reverb.loadFactoryPreset(.LargeHall2)
			// AudioEngineにnodeを設定
			engine.attachNode(player)
			engine.attachNode(reverb)
			engine.connect(player, to: reverb, format: file.processingFormat)
			engine.connect(reverb, to: engine.outputNode, format: file.processingFormat)
			engine.startAndReturnError(nil)
			// playerにオーディオファイルを設定
			self.player.scheduleFile(file, atTime: nil, completionHandler: { () -> Void in
				// 再生が終了すると呼ばれる
				println("Completion")
				})
				// 再生開始
				self.player.play()
			}
		}
	}
これで実行すると指定したファイルが再生されます。
ファイルフォーマットはwav,mp3,aacあたりなら大体再生できそうです。
簡単なサンプルはこれで以上となります。
今回エフェクトはDelayとReverbを使用しましたが、他には
- AVAudioUnitDistortion
 - AVAudioUnitEQ
 
など用意されています。全部で4種類なのでまだちょっと少ないですね。
AVAudioUnitEffectのサブクラスを作ることで独自のエフェクトは作れそうですが、
結局のところ内部ではCoreAudioが使用されているようで、
エフェクト処理はC,C++で書く必要がありそうです。
ただ、今までは音にエフェクトをかけるにはCoreAudioを直接使う必要がありましたが、
AVAudioEngineの登場によりObjective-C,Swiftで簡単に記述できるようになったのは素晴らしいと思います。
今後のAPI追加にも期待したいと思います。