54
42

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SwiftAdvent Calendar 2014

Day 25

AVAudioEngineを使ってみる

Last updated at Posted at 2014-12-25

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追加にも期待したいと思います。

54
42
2

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
54
42

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?