2019年4月30日火曜日

Music Libraryの音楽を鳴らす

MediaPlayer、AVPlayer、AVAudioPlayerと3種類方法があるようだ。
ミュージック.appのようなMPMediaPickerContorollerを使うことで曲を簡単に選択できる。

MediaPlayerを使う

簡単さから言えば一番簡単。
currentPlaybackRateプロパティがあるが、再生速度の変更がなぜかできない。原因不明。


import UIKit
import MediaPlayer //Frameworkをインストールしておくこと

class ViewController: UIViewController, MPMediaPickerControllerDelegate {
//再生を継続するためにインスタンス変数としてPlayerを用意
var player:MPMusicPlayerController!
override func viewDidLoad() {
super.viewDidLoad()
player = MPMusicPlayerController.applicationMusicPlayer
}

@IBAction func pickMusic(_ sender: Any) {
let picker = MPMediaPickerController()
picker.delegate = self
//曲の複数選択の有無
picker.allowsPickingMultipleItems = false
present(picker, animated: true, completion: nil)
}
//音楽が選択された時呼ばれるdelegate
func mediaPicker(_ mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
player.setQueue(with: mediaItemCollection)
player.play() //曲の再生
//pickerを消す
dismiss(animated: true, completion: nil)
}
}

AVPlayerを使う

AVFoundationのimportが必要。
動画再生にも対応したclassのようだ。
ミュージックライブラリの曲のassetURLを取得する点がちょい面倒だが、簡単。
assetURLからPlayerを作るときはtry文が不要。
rateに負の数を入れれば逆再生もできる
再生位置の指定はseekメソッドで、引数はCMTimeなので面倒のようだ。

AVAudioPlayerを使う

AVFoundationのimportが必要。
AVPlayerのAudio(音声)特化class?
ミュージックライブラリの曲のassetURLを取得する点がちょい面倒だが、簡単。
assetURLからPlayerを作るときはtry文が必要。
rateに負の数を入れても逆再生はできない
再生位置の指定はcurrentTimeプロパティで簡単。単位は秒。公式の解説だと再生中は現在位置からのオフセット位置、停止中はplay()メソッド開始位置からのオフセット位置とあるが、どちらも変わらず、曲の先頭からのオフセット秒数みたい?

import UIKit
import MediaPlayer
import AVFoundation


class ViewController: UIViewController, MPMediaPickerControllerDelegate {
var player:AVAudioPlayer!

//音楽が選択された時呼ばれるdelegate
func mediaPicker(_ mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
//選択された曲を取得
let items = mediaItemCollection.items
if items.isEmpty {
print("曲が選択されていない")
return
}
//先頭の一曲のassetURLを取得
let item = items[0]
if let url = item.assetURL {
do {
player = try AVAudioPlayer(contentsOf: url)
} catch {
print("曲が取得できなかった。DRMの関係?")
player = nil
return
}
//曲の再生
player.play()
} else {
print("assetURL取得できなかった")
}
//pickerを消す
dismiss(animated: true, completion: nil)
}
}

曲などの情報を得る

先のmediaPickerのdelegateの、mediaItemCollectionの要素に曲名、アーチスト名などの情報にプロパティとしてアクセスできるので、取り出すのは簡単。

//音楽が選択された時呼ばれるdelegate
func mediaPicker(_ mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
let items = mediaItemCollection.items
if items.isEmpty {
print("曲が選択されていない")
return
}
let musicTitle = items[0].title //曲タイトル
let musicArtist = items[0].artist //アーチスト名
let albumTitle = items[0].albumTitle //アルバムタイトル
let albunArtist = items[0].albumArtist //アルバムアーチスト名

let artWork = items[0].artwork //アートワーク
imageView.image = artWork?.image(at: imageView.bounds.size)

//以下略
}

注意点

どのやり方をやっても、info.plistの Privacy - Media Library Usage Description を設定しないと
present(picker, animated: true, completion: nil)
でpickerが表示されない。
最近の傾向としてそうなのはわかるんだけど、エラーメッセージとか一切出てくれなかった。
似たようなので Privacy - Music Usage Description というのがあるので、間違えないこと。