【Swift】AVAudioPlayerの使い方。音楽や効果音を鳴らす。(Swift 2.1、XCode 7.2)
AVAudioPlayerとは
AVAudioPlayerとは、音を鳴らすための機能である。複数の音をループ回数や音量、速度などを設定して再生できる。
AVAudioPlayerを使うにはAVFoundationフレームワークをインポートする。ちなみに、音を鳴らす機能を持ったフレームワークは他にもあるが本記事ではAVAudioPlayerのみを紹介する。
AVAudioPlayerを試す
実際にAVAudioPlayerを試してみよう。
以降の手順を行う前のXcodeプロジェクトをGitHubに置いたので、試してみる人はご利用下さい。
⇒「テスト用プロジェクト」
事前準備ではテスト用の音楽ファイル(mp3)を2個取り込んでおいたのと、デバイス画面にボタンを2個配置しておいた。現段階ではボタンを押しても何も起きない。
ViewController.swiftを以下のコードに変更する。
音の再生はとてもシンプルに実装することができ、音声ファイルのURLを引数にAVAudioインスタンスを作成し、作成したインスタンスに対してplayメソッドを呼ぶだけである。
prepareToPlayメソッドは、再生開始までの遅延を無くすために音楽データをあらかじめバッファに読み込んでおくためにある。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
// // ViewController.swift // import UIKit import AVFoundation class ViewController: UIViewController { var player:AVAudioPlayer! let url = NSBundle.mainBundle().bundleURL.URLByAppendingPathComponent("sample_sound.mp3") //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() do { try player = AVAudioPlayer(contentsOfURL:url) //音楽をバッファに読み込んでおく player.prepareToPlay() } catch { print(error) } } //再生ボタン1押下時の呼び出しメソッド @IBAction func pushButton1(sender: UIButton) { //音楽を再生する。 player.play() } //再生ボタン2押下時の呼び出しメソッド @IBAction func pushButton2(sender: UIButton) { } } |
以下は実際のプレイ動画
2つの音を並列で鳴らす
複数の音を並列で鳴らす場合は、AVAudioPlayerインスタンスを音ファイルぶん作成し、各インスタンスのplayメソッドを呼び出す。
実際にやってみよう。VIViewController.swiftを以下のコードに変更する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
// // ViewController.swift // import UIKit import AVFoundation class ViewController: UIViewController { var player:AVAudioPlayer! var player2:AVAudioPlayer! let url = NSBundle.mainBundle().bundleURL.URLByAppendingPathComponent("sample_sound.mp3") let url2 = NSBundle.mainBundle().bundleURL.URLByAppendingPathComponent("sample_sound2.mp3") //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() do { try player = AVAudioPlayer(contentsOfURL:url) try player2 = AVAudioPlayer(contentsOfURL:url2) //音楽をバッファに読み込んでおく player.prepareToPlay() player2.prepareToPlay() } catch { print(error) } } //再生ボタン1押下時の呼び出しメソッド @IBAction func pushButton1(sender: UIButton) { //音楽を再生する。 player.play() } //再生ボタン2押下時の呼び出しメソッド @IBAction func pushButton2(sender: UIButton) { //音楽を再生する。 player2.play() } } |
以下は実際のプレイ動画
音を停止する
音を停止するにはstopメソッド、または、pauseメソッドを用いる。メソッド名から想像するのは、stopメソッドは再生位置が最初まで巻き戻り、pauseメソッドは再生位置は保存されてまた同じ位置から再生できる。といった仕様を想像する。
しかし、そのような動きにはならず、stopメソッドとpauseメソッドの両方とも、再生位置が保存されてまた同じ位置から再生される。
実際にやってみよう。ViewController.swiftを以下のコードに変更する。青ボタンでplayメソッド、赤ボタンでstopメソッドを呼び出している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
// // ViewController.swift // import UIKit import AVFoundation class ViewController: UIViewController { var player:AVAudioPlayer! let url = NSBundle.mainBundle().bundleURL.URLByAppendingPathComponent("sample_sound.mp3") //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() do { try player = AVAudioPlayer(contentsOfURL:url) //音楽をバッファに読み込んでおく player.prepareToPlay() } catch { print(error) } } //再生ボタン1押下時の呼び出しメソッド @IBAction func pushButton1(sender: UIButton) { //音楽を再生する。 player.play() } //再生ボタン2押下時の呼び出しメソッド @IBAction func pushButton2(sender: UIButton) { //音楽を停止する。 player.stop() } } |
以下は実際のプレイ動画。stopメソッドで音を停止したあと、再びplayメソッドを呼び出すと前回停止位置から再生が始まった。pauseメソッドも同じ動きになる。
最初まで巻き戻したいときは、以下のコードのようにstopメソッドのあとにAVAudioPlayerインスタンスのcurrentTimeプロパティの値を0に変更する。
1 2 3 4 5 6 7 8 9 |
//再生ボタン2押下時の呼び出しメソッド @IBAction func pushButton2(sender: UIButton) { //音楽を停止する。 player.stop() //最初の位置まで巻き戻す。 player.currentTime = 0 } |
以下は実際のプレイ動画。音が最初から再生されるようになった。
pauseメソッドを読んだあとも同様にcurrentTimeプロパティの値を0にすることで再生位置が最初に戻る。
となると、stopメソッドもpauseメソッドもどちらを使っても変わらないことになるが、stopメソッドの場合はバッファに読みこんだ音データがクリアされ、pauseメソッドの場合はバッファに残り続けるという違いがある。
なのでstopメソッドを使う場合は、次の再生で遅延が発生させたくないならstopメソッドの直後でprepareToPlayメソッドを呼んでバッファにデータをロードしておく必要がある。
処理負荷のことを考えると、何度も再生される音の場合はpauseメソッドを使い、一度再生して終わりの場合はstopメソッドを使うのでどうだろう。
といいつつも、今回のようなサイズの小さい音データでは双方の性能的な違いは認識できなかった。
音が再生中かを確認する
音が再生中かを確認するにはplayingプロパティを確認する。再生中の場合はtrue、再生中ではない場合はfalseになる。
例えば、ボタンを押したときにplayingプロパティがtrue(再生中)だったら音を停止し、falseだったら音を再生する場合は以下のコードのようになる。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//再生ボタン1押下時の呼び出しメソッド @IBAction func pushButton1(sender: UIButton) { if(player.playing) { //音が再生中の場合は停止する。 player.stop() player.currentTime = 0 } else { //音が停止中の場合は再生する。 player.play() } } |
以下は実際のプレイ動画
再生速度を指定する
再生速度を変更するにはrateプロパティの値を変更する。設定できる範囲は0.5〜2.0(半分のスピード〜2倍速)
rateプロパティの場合だけ、なぜかenableRateプロパティの値をtrueにして調整を許可しなければならない。
1 2 3 4 5 6 |
//rateの変更を許可する。 player.enableRate = true //2倍速にする。 player.rate = 2.0 |
以下は実際のプレイ動画。再生スピードが速くなった。
再生回数を指定する
再生回数を指定したい場合はnumberOfLoopsプロパティを変更する。
注意点は「2回再生する場合は1」、「3回再生する場合は2」のように実際の再生回数より1少ない数を設定することである。デフォルトは0(1回再生)。無限ループする場合は-1に設定する。
1 2 3 |
//3回再生する。 player.numberOfLoops = 2 |
以下は実際のプレイ動画
音量を指定する
音量を指定するにはvolumeプロパティの値を変更する。0.0は無音、1.0(デフォルト)はAudioPlayerインスタンスの最大音量とリファレンスに記載されているが、試しに1.0よりも数字を大きくしてみたところ、1.0のときよりも大きな音になった。
1 2 3 |
//音量を半分にする。 player.volume = 0.5 |
左右のバランスを指定する
音の左右のバランスを指定するにはpanプロパティの値を変更する。-1.0は左のスピーカーのみから音が流れ、0.0(デフォルト)は左右のスピーカーの音が同じ、1.0は右のスピーカーのみから音が流れるようになる。
1 2 3 |
//右のスピーカーからのみ音を出す。 player.pan = 1.0 |
遅延再生する
playメソッドを呼び出してから指定時間経過後に音を再生する場合はplayAtTimeメソッドを利用する。しかし、検証ではこのメソッドを使っても再生が遅延する様子は認識できなかった。何かわかったら追記する(Swift 2.1、XCode 7.2)。
引数にはAVAudioPlayerインスタンスの時間(currentTime)+遅延時間を設定する。
1 2 3 |
//遅延実行する。 player.playAtTime(player.currentTime + 10000.0) |
再生終了を検知する
音の再生が終了したのを検知させる場合はAVAudioPlayerDelegateを利用する。
以下のコードは、音1の再生が終わったら音2を再生する例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
// // ViewController.swift // import UIKit import AVFoundation class ViewController: UIViewController, AVAudioPlayerDelegate { var player1:AVAudioPlayer! var player2:AVAudioPlayer! let url1 = NSBundle.mainBundle().bundleURL.URLByAppendingPathComponent("sample_sound.mp3") let url2 = NSBundle.mainBundle().bundleURL.URLByAppendingPathComponent("sample_sound2.mp3") //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() do { try player1 = AVAudioPlayer(contentsOfURL:url1) try player2 = AVAudioPlayer(contentsOfURL:url2) //音楽をバッファに読み込んでおく player1.prepareToPlay() //デリゲート先に自分を設定する。 player1.delegate = self } catch { print(error) } } //再生ボタン1押下時の呼び出しメソッド @IBAction func pushButton1(sender: UIButton) { //音楽を再生する。 player1.play() } //再生ボタン2押下時の呼び出しメソッド @IBAction func pushButton2(sender: UIButton) { } //再生終了時の呼び出しメソッド func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) { player2.play() } } |
以下は実際のプレイ動画