【iPhoneアプリ】【Swift】SolPlayer開発記(4)iPhone内にあるファイルを読み込む方法
すべての音源をソルフェジオに変える音楽プレイヤー、
「SolPlayer」の開発記、第4弾。(ここまでコピペ)
前回の記事では、AVAudioEngineを使って曲を再生する方法を紹介しました。
前回の記事↓
foresthill.hatenablog.com
今回は、「iPhone内にあるファイルを読み込む」方法を紹介します。
実装方法
私がアホなせいかもしれませんが、ここは意外と苦労しました。
redmineのチケット記録を観ると、予定工数が1に対し、実工数は6。(時間単位)
まぁこれを読んでくれているあなたは工数1以内で行けると思います^^b
さて、それでは実際の実装方法を紹介します。
メディアピッカー(MediaPicker)を使う
iPhone内にあるファイルを読み込む方法は、
ズバリ「メディアピッカー(MediaPicker)」を使うこと。
他にもいくつか方法はあるみたいですが、
ひと通り試した結果、自分にはこの方法が一番やりやすかったです。
このメディアピッカーを使うことで、読み込み処理を
自分で実装する必要がなくなります。
あとこちらでやるべきことは、
このメディアピッカーを呼び出す処理と、
そこから情報を取得する処理です。
さて、それでは例のごとく、他力本願でやっていきます。
上記記事を参考に、SolPlayerに実装したコードが以下となります。
必要な実装としては、細かく言えば以下のようになります。
- クラスの定義に「MPMediaPickerControllerDelegate」を付け加える
- 以下の3つの処理を追加
- メディアピッカー(MediaPicker)を呼び出す
- メディアピッカー(MediaPicker)でファイルが選択された後
- メディアピッカー(MediaPicker)で「キャンセル」が押されたとき
1.クラス定義
import UIKit import MediaPlayer import AVFoundation class ViewController: UIViewController, MPMediaPickerControllerDelegate {
2-1.メディアピッカーを呼び出す
@IBAction func addSong(sender: UIButton) { //MPMediaPickerControllerのインスタンス作成 let picker = MPMediaPickerController() //pickerのデリゲートを設定 picker.delegate = self //複数選択を可にする(true/falseで設定) picker.allowsPickingMultipleItems = true //AssetURLが読み込めない音源は表示しない picker.showsItemsWithProtectedAssets = false //CloudItemsもAssetURLが読み込めないので表示しない picker.showsCloudItems = false //ピッカーを表示する presentViewController(picker, animated:true, completion: nil) }
2-2.メディアピッカーで選択された情報を取り出す
//メディアアイテムピッカーでアイテムを選択完了した時に呼び出される(必須) func mediaPicker(mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) { //playlistにmediaItemを追加 mediaItemCollection.items.forEach { (mediaItem) in playlist?.append(mediaItem) } //ピッカーを閉じ、破棄する self.dismissViewControllerAnimated(true, completion: nil) }
mediaItemCollectionに選択されたファイルが、[MediaItem](MediaItemの配列)という形で入っています。
それを自作したプレイリスト(playlist)という配列型のデータに追加しています。
2-3.メディアピッカーで「キャンセル」された時
//選択がキャンセルされた場合に呼ばれる func mediaPickerDidCancel(mediaPicker: MPMediaPickerController) { // ピッカーを閉じ、破棄する dismissViewControllerAnimated(true, completion: nil) }
補足
ただ、このメディアピッカーを使う際に、
いくつか補足や注意点があります。
ファイル読み込みに関する注意点
複数選択可にする
参考サイトでは複数選択を不可(false)にしていましたが、
使ってみた感じ、複数選択できたほうが何かと便利なので、
「true(可)」にしています。
//複数選択を可にする(true/falseで設定) picker.allowsPickingMultipleItems = true
AssetURLを読み込めない音源を非表示にする
AssetURLを読み込めない音源ファイルは、そもそもAVAudioPlayerNodeで再生できません。
なので、ファイル自体を選択できないように、メディアピッカー上でも非表示にしちゃいます。
(ちなみに参考元のサイトでは、1つだけ音源を読み込み、その音源のAssetURLがnilの場合
再生しないという挙動にしているため、エラーは起きないようになっています)
//AssetURLが読み込めない音源は表示しない picker.showsItemsWithProtectedAssets = false //CloudItemsもAssetURLが読み込めないので表示しない picker.showsCloudItems = false
MediaItemに入っている情報
メディアピッカーでファイルを選択すると
MediaItemというクラスで取得できます。
この、MediaItemに入っている情報と、
入っていない情報があるので、
取得できる情報
- assetURL(音源のURL)※一番重要
- persistentID(ファイルを一意に特定するID)
- title(タイトル)
- artist(アーティスト名)
- albumTitle(アルバム名)
- artwork(アートワーク:画像)
- その他もろもろ
取得できない情報
- 再生時間
「再生時間こそ欲しいんだよ!」ってところで
イライラしたつまづいたので、ここにその実装方法を記しておきます。
呼び出しメソッド
func getDuration() -> Double { if self.assetURL != nil { do { let audioFile = try AVAudioFile(forReading: assetURL!) //サンプルレートの取得 let sampleRate = audioFile.fileFormat.sampleRate //再生時間 return Double(audioFile.length) / sampleRate } catch { // } } return 0.0 }
これを、再生時間を入れたい変数(フィールド)に入れます。
(実装例)
self.duration = getDuration()
以上、「iPhone内にあるファイルを読み込む方法」でした。
おまけ
ちなみに、実際にSolPlayerに実装した内容は、
もう少しカスタマイズしています。
//メディアアイテムピッカーでアイテムを選択完了した時に呼び出される(必須) func mediaPicker(mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) { //AppDelegateのインスタンスを取得しplayListを格納 let appDelegate:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate //playlistにmediaItemを追加 mediaItemCollection.items.forEach { (mediaItem) in playlist?.append(Song(mediaItem: mediaItem)) } appDelegate.playlist = playlist //print("playlist=\(playlist)") //ピッカーを閉じ、破棄する self.dismissViewControllerAnimated(true, completion: nil) //tableviewの更新 tableView.reloadData() }
付け加えた処理としては、
- playlistをAppDelegate上で持つようにした → 画面をまたいでplaylistが使える
- mediaItemをSongという自作クラスで詰め替えた → 機能を追加する際にもろもろ便利
- tableViewを更新 → playlistの内容がtableViewに表示されるようにしているため
こちらに関しては、もし気が向いたら詳細を解説したいと思います。
興味がある方はコメントください。
以上です。