【iPhoneアプリ】【Swift】SolPlayer開発記(5)再生機能を作り込む(シークバーと連動させる)
すべての音源をソルフェジオに変える音楽プレイヤー、
「SolPlayer」の開発記、第5弾。(ここまでコピペ)
前回の記事では、「iPhone内にあるファイルを読み込む方法」を解説しました。
今回は、「再生機能を作り込み、シークバーと連動させる」方法を紹介します。
実装方法
思いのほか、この機能も苦労しました。
redmineの記録を観ると、予定3時間に対し、実際にかかった時間は14時間。
再生機能の実装も含めての時間ですが、「予定よりかなりかかったなぁ」という印象汗
まぁこれを読んでくれているあなたは30ふん以内でry
シークバーと連動させる
さて、それでは実装方法を紹介します。
例のごとく他力本願です。
※一応、さくっとURLを紹介していますが、
このページにたどり着くまで結構時間かかってます汗
上記ページすべてをコピペ参考にできますが、
特に「任意の再生位置からの音声再生(シーク機能)」の情報が重要です。
一応、コードを提示。
画面側(ViewController)
毎秒ごとの処理
//シークバー @IBOutlet weak var timeSlider: UISlider! //現在時刻 @IBOutlet weak var nowTimeLabel: UILabel! //残り時刻 @IBOutlet weak var endTimeLabel: UILabel! //タイマー var timer: NSTimer! (中略) /** 初期処理 */ override func viewDidLoad() { //タイマーをセット timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(ViewController.didEverySecondPassed), userInfo: nil, repeats: true) } (中略) /** 毎秒ごとに行われる処理(timerで管理) */ func didEverySecondPassed(){ let current = solPlayer.currentPlayTime() //現在時刻と残り時刻を更新 nowTimeLabel.text = formatTimeString(current) endTimeLabel.text = "-" + formatTimeString(Float(solPlayer.duration) - current) //スライダー値を更新 timeSlider.value = current } (中略) /** 再生時間のスライダーが変更された時(Action→ValueChanged) - parameter sender: UISlider */ @IBAction func timeSliderAction(sender: UISlider) { solPlayer.timeShift(timeSlider.value) }
処理(ロジック)側(独自クラス)
/** SolffegioPlayer本体(音源再生を管理する) */ class SolPlayer { //プレイヤー var audioPlayerNode: AVAudioPlayerNode! = AVAudioPlayerNode() //音源ファイル var audioFile: AVAudioFile! //サンプルレート var sampleRate: Double! //時間をずらした時の辻褄あわせ var offset = 0.0 (中略) /** 現在の再生時刻を返すメソッド */ func currentPlayTime() -> Float { //サンプルレートが0の時は再生時間を取得しない(というかできない) if(sampleRate == 0){ return 0 } //便宜上分かりやすく書いてみる let nodeTime = audioPlayerNode.lastRenderTime let playerTime = audioPlayerNode.playerTimeForNodeTime(nodeTime!) let nowPlayTime = (Double(playerTime!.sampleTime) / sampleRate) return (Float)(currentTime + offset) } /** シークバーを動かした時の処理 */ func timeShift(current: Float){ //退避 offset = Double(current) //シーク位置(AVAudioFramePosition)取得 let restartPosition = AVAudioFramePosition(Float(sampleRate) * current) //残り時間取得(sec) let remainSeconds = Float(self.duration) - current //残りフレーム数(AVAudioFrameCount)取得 let remainFrames = AVAudioFrameCount(Float(sampleRate) * remainSeconds) audioPlayerNode.stop() if remainFrames > 100 { //指定の位置から再生するようスケジューリング audioPlayerNode.scheduleSegment(audioFile, startingFrame: restartPosition, frameCount: remainFrames, atTime: nil, completionHandler: nil) } audioPlayerNode.play() }
とりあえず、こんな感じです。
今回のテーマに関係ない個所は端折ってますので、
このまま書いても動かない可能性大です汗
なんとなく、書き方の雰囲気だけでも伝われば幸いです。
(全ソースコードは、今後GitHubで公開しようと思っています)
なお処理(ロジック)に関しては、便宜上わけてはいますが
好みによってはすべてViewControllerに記載しても構いません。
後で見返して、説明不足な点については今後追記したいと思います。
以上です。
次回は、「画面が表示されていない(または画面ロック)時にも、音楽を再生する方法」を紹介します。(要はバックグラウンド再生ですね)
お楽しみに。