swiftでサウンドを再生する、のに使ったコードメモ


# まえがき
[swiftを勉強したのでアプリ開発したいメモ](http://qiita.com/stlwolf/items/813d0020a5049e834a79)

上記開発中アプリの機能として、SEとBGM再生が欲しかったので
色々調べて実装してみたものをまとめます。

Audio周りはこの辺りを読めば、基本的なことは理解できそう。

- [Core Audioの概要 (TP40003577 0.0.0) - Apple Developer](https://developer.apple.com/jp/documentation/CoreAudioOverview.pdf)

あ、あとで読もう。

それとiOSヒューマンインターフェイスガイドラインの項目にも、
オーディオ動作に関して記述があったから参照するとよいかも。
[iOS ヒューマンインターフェイスガイドライン 音声](https://developer.apple.com/jp/documentation/UserExperience/Conceptual/MobileHIG/Sound.html#//apple_ref/doc/uid/TP40006556-CH44-SW1)

【確認環境】

- Xcode 7.3.1
- Swift 2.2

# AudioToolbox を使う

最初は簡単そうなAudioToolboxフレームワークのSystem Sound Servicesを使ってみる。
アプリケーション内でシステムサウンドとかをSEとして使う場合にはこれで十分そう。
再生できるファイルとかにもそこそこ制約あるっぽい。

参考にさせてもらったのはこのあたりです。

- [Swiftでシステムサウンドを再生する](http://qiita.com/hideji2/items/e7ed482ccffef2c0f66c)
- [[iPhone] System Sound 再生 (Swift)](https://akira-watson.com/iphone/systemsound.html)



## 準備する

フレームワークをインポートしときます。
「左上のプロジェクト名」→「Build Phases」→「Link Binary With Libraries」に
AudioToolbox.frameworkを追加しておく。もちろん使う所でimportする。

```
import AudioToolbox
```


## バイブレーションさせる

いきなり音が出ないやつだけど、まずは一番お手軽なやつから実装してみた。

```
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
```

これだけ。
SystemSoundIDにkSystemSoundID_Vibrateを与えて
バイブレーションのシステムサウンドIDを作成。そのままAudioServicesPlaySystemSoundを実行。
したらブルった。


## システムサウンドを再生してみる

再生できるシステムサウンドの一覧とかは以下を参考にした。

- [AudioServices](http://iphonedevwiki.net/index.php/AudioServices)
- [iOSのシステムサウンドを確認する](http://dev.classmethod.jp/smartphone/ios-systemsound/)


```
var soundId:SystemSoundID = 0

// システムサウンドへのパスを指定
if let soundUrl:NSURL = NSURL(fileURLWithPath: "/System/Library/Audio/UISounds/alarm.caf") {

	// SystemsoundIDを作成して再生実行
	AudioServicesCreateSystemSoundID(soundUrl, &soundId)
	AudioServicesPlaySystemSound(soundId)
}

```
これで指定したIDのサウンドが1回再生できた。
ちなみに最初ID:1325のFanfare.cafを試したら再生されずコンソールにwarning出てた。
一部のファイルはパスが違うっぽい。1つ潜ったところ(/New)にあった。
あと以下でも再生されるけど、これでやると消音時にバイブレーションするようになった。

```
var soundID: SystemSoundID = 1005 # 1005はalarm.cafのSystemSoundID
AudioServicesPlaySystemSound(soundId)
```

## 気になること

再生中のサウンドは```AudioServicesDisposeSystemSoundID```でsoundIDの破棄をすれば止まるのかな？
よくある「リスト選択したら1回試しに再生」される感じのものを実装したいのだけれども。
それをやるなら、AudioToolboxじゃない方がいいかな...

# AVAudioPlayer を使う
自分で用意したmp3ファイルとかをBGM等で再生したい、ぐらいの要求だったら
このAVAudioPlayerを使えば大体のことはいけそう。以下参考にしました。

- [[iPhone] AVAudioplayer 音楽の再生 (Swift)](https://akira-watson.com/iphone/avaudioplayer.html)
- [Swift:サウンド（効果音）を再生するサンプルコード](http://www.sirochro.com/note/swift-sound-play-sample/)

## 準備する
プロジェクト設定で最初からAVFoundationフレームワークは内包されているのか、
特に追加作業等はいらない。使うファイルでimportすればよい。

```
import AVFoundation
```

そして使用したいサウンドファイルも左ペインのファイルツリーからプロジェクトに追加しておく。
今回は"kane01.mp3"とした。(金じゃなくて鐘ですね)

## AVAudioPlayerで再生してみる

今やってるアプリではUIViewController内に関数として実装していますが、
そこから最低限必要な部分だけ出すとこれだけ。

```
// この変数は実際のコードではUIViewControllerクラス内で宣言してる
var audioPlayer: AVAudioPlayer! 

// サウンドデータの読み込み。ファイル名は"kane01"。拡張子は"mp3"
let audioPath = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("kane01", ofType: "mp3")!)

// swift2系からtryでエラー処理するようなので、do〜try〜catchで対応
do {
	// AVAudioPlayerを作成。もし何かの事情で作成できなかったらエラーがthrowされる
	audioPlayer = try AVAudioPlayer(contentsOfURL: audioPath)
	
	// イベントを通知したいUIViewControllerをdelegateに登録
	// delegateの登録するならAVAudioPlayerDelegateプロトコルの継承が必要
	audioPlayer.delegate = self
	
	// これで再生
	audioPlayer.play()
}
// playerを作成した時にエラーがthrowされたらこっち来る
catch {
	print("AVAudioPlayer error")
}
```

### 再生中のサウンドを停止する場合

まあ当たり前かもですけど、普通ですね。

```
// playingプロパティで再生中のチェックができる
if (audioPlayer.playing) {
    // サウンドの停止
    audioPlayer.stop()
}
```

# (現状の)結論
まあ簡単にできちゃいますね。これ以上にテクニカルなことをやろうとすると
もう少し調べないとダメそうですが、現状は一括でまとめたぐらいしか記事としての価値は。。。

BGM再生周りのコーディングを進めていけば、もうちょっとノウハウも出るかもなので
そしたら追記していきます。
特に各種デリゲートメソッドとか。。。