2019-03-11 23:49:00 Swift

Swift

Copy Copied! Full
import UIKit import MediaPlayer import AVFoundation class Singleton: NSObject { static let sharedInstance: Singleton = Singleton() private override init() {} var audioPlayer:AVAudioPlayer = AVAudioPlayer() var musicSliderTimer: Timer? var durationTimer: Timer? var skyAudioPath: String? var synthAudioPath: String? var skyAudioFile: AVAudioFile? var synthAudioFile: AVAudioFile? var sampleRate: Double? var duration: Double? var maxMin: Double? var maxSec: Double? var currentMin: Double? var currentSec: Double? var volume: UISlider? var musicSlider: UISlider? var currentTimeLabel: UILabel? var totalTimeLabel: UILabel? var songLabel: UILabel? var artistLabel: UILabel? var volumeLastValue: Float? } class MusicViewController: UIViewController, MPMediaPickerControllerDelegate { let singleton: Singleton = Singleton.sharedInstance @IBOutlet weak var musicLibraryButton: UIButton! @IBOutlet weak var skyButton: UIButton! @IBOutlet weak var synthButton: UIButton! override func viewDidLoad() { super.viewDidLoad() // 再生スライダーの生成・位置設定 singleton.musicSlider = UISlider() singleton.musicSlider?.frame = CGRect(x:(((self.view.bounds.width)/2)-100), y:(self.view.bounds.height-100), width:200, height:30) singleton.musicSlider?.addTarget(self, action: #selector(musicSliderController), for: .allEvents) self.view.addSubview(singleton.musicSlider!) // 音量バーの生成・位置設定 singleton.volume = UISlider() singleton.volume?.frame = CGRect(x: (((self.view.bounds.width)/2)-100), y: 100, width: 200, height: 30) singleton.volume?.addTarget(self, action: #selector(volumeController), for: .allEvents) self.view.addSubview(singleton.volume!) // 曲の現在再生時間ラベルの生成・位置設定 singleton.currentTimeLabel = UILabel() singleton.currentTimeLabel?.frame = CGRect(x:30, y:(self.view.bounds.height-100), width: 50, height: 30) self.view.addSubview(singleton.currentTimeLabel!) // 曲のトータル再生時間ラベルの生成・位置設定 singleton.totalTimeLabel = UILabel() singleton.totalTimeLabel?.frame = CGRect(x:(self.view.bounds.width)-75 , y:(self.view.bounds.height-100), width: 50, height: 30) self.view.addSubview(singleton.totalTimeLabel!) // 曲名ラベルの生成・位置設定 singleton.songLabel = UILabel() singleton.songLabel?.frame = CGRect(x:(((self.view.bounds.width)/2)-100), y:(self.view.bounds.height-200), width:200, height:30) self.view.addSubview(singleton.songLabel!) // アーティスト名ラベルの生成・位置設定 singleton.artistLabel = UILabel() singleton.artistLabel?.frame = CGRect(x:(((self.view.bounds.width)/2)-100), y:(self.view.bounds.height-150), width:200, height:30) self.view.addSubview(singleton.artistLabel!) // 初回呼び出し時(タイマーが生成されていないとき)の設定 if singleton.musicSliderTimer == nil { // ★曲セットメソッドの呼び出し // (★複数曲の場合/ライブラリからの選択曲の記述方法・場所不明) audioPlayerDif(resourceName: "sky", songLabel: "Touch the sky", artistLabel: "2002") // 再生スライダー用のタイマー(1秒ごとにsliderCountを実行) singleton.musicSliderTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(sliderCount(_:)), userInfo: nil, repeats: true) // 再生時間更新用のタイマー(0.1秒ごとにtimeCountを実行) singleton.durationTimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(timeCount(_:)), userInfo: nil, repeats: true) // 初期値設定 singleton.currentTimeLabel!.text = "00:00" singleton.volume?.value = (singleton.volume?.maximumValue)! / 2 // 2回目以降の呼び出しのとき } else { // 再生スライダーの最大値=曲のトータル再生時間に設定 // (★複数曲の場合の記述方法・場所不明) singleton.musicSlider!.maximumValue = Float(singleton.audioPlayer.duration) setTotalTime() singleton.volume?.value = singleton.volumeLastValue! } // Buttonの角丸装飾 musicLibraryButton.layer.cornerRadius = 10.0 skyButton.layer.cornerRadius = 10.0 synthButton.layer.cornerRadius = 10.0 } // このページから移動するときの音量を、volumeLastValueにセット override func viewWillDisappear(_ animated: Bool) { singleton.volumeLastValue = singleton.volume?.value } // 「ミュージックライブラリから選択」ボタンを押した時の動作(1曲だけ選択可能) @IBAction func musicLibraryButton(_ sender: Any) { // MPMediaPickerControllerのインスタンスを作成 let picker = MPMediaPickerController() // ピッカーのデリゲートを設定 picker.delegate = self // 複数選択を不可 picker.allowsPickingMultipleItems = false // ピッカーを表示 present(picker, animated: true, completion: nil) } // メディアアイテムピッカーで曲を選択した時に呼ばれるメソッド func mediaPicker(_ mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) { // このメソッドを抜ける際にピッカーを閉じ、破棄 defer { dismiss(animated: true, completion: nil) } // mediaItemCollection.itemsから、MPMediaItemの配列を取得 let items = mediaItemCollection.items if items.isEmpty { // itemが一つもなかったので戻る return } // 先頭のMPMediaItemを取得し、そのassetURLからプレイヤーを作成 let item = items[0] if let url = item.assetURL { do { // itemのassetURLからプレイヤーを作成 singleton.audioPlayer = try AVAudioPlayer(contentsOf: url) // playbackDuration = メディアプレイヤーの曲(MPMediaItem)の再生時間 let playbackDuration = item.playbackDuration singleton.maxMin = floor(playbackDuration / 60) singleton.maxSec = playbackDuration - (singleton.maxMin! * 60) // 曲のトータル再生時間を取得して表示 setTotalTime() // 曲情報をラベルに表示 let title = item.title ?? "不明な楽曲" singleton.songLabel!.text = "”\(title)”" let artist = item.artist ?? "不明なアーティスト" singleton.artistLabel!.text = artist // 再生スライダーの最大値と、音楽ファイルの長さを同期 singleton.musicSlider!.maximumValue = Float(singleton.audioPlayer.duration) } catch { print("error") } } } //選択がキャンセルされた場合に呼ばれるメソッド func mediaPickerDidCancel(_ mediaPicker: MPMediaPickerController) { // ピッカーを閉じ、破棄 dismiss(animated: true, completion: nil) } // "Touch The Sky" ボタンの動作 @IBAction func skyButton(_ sender: Any) { audioPlayerDif(resourceName: "sky", songLabel: "Touch the sky", artistLabel: "2002") singleton.musicSlider?.value = 0 } // "Touch The Sky" ボタンを押したときに呼ばれるメソッド // (★AudioPlayerDif()を、曲ごとに設定??) func audioPlayerDif(resourceName: String, songLabel: String, artistLabel: String) { // sky.mp3ファイルを、audioPlayerにセットして初期化 singleton.skyAudioPath = Bundle.main.path(forResource: resourceName, ofType: "mp3")! // ファイルエラー防止のための実行テスト do { // 曲の再生時間を取得するため、AudioFileを定義 singleton.skyAudioFile = try AVAudioFile(forReading: URL(fileURLWithPath: singleton.skyAudioPath!)) // 再生時間計算用のサンプルレートを取得 singleton.sampleRate = singleton.skyAudioFile!.fileFormat.sampleRate // ファイルが問題なければ、audioPlayer変数にaudioPathを定義 try singleton.audioPlayer = AVAudioPlayer(contentsOf: URL(fileURLWithPath: singleton.skyAudioPath!)) singleton.duration = floor(Double((singleton.skyAudioFile?.length)!) / singleton.sampleRate!) // 曲のトータル再生時間を取得して表示 setTotalTime() // 曲情報をラベルに表示 singleton.songLabel!.text = songLabel singleton.artistLabel!.text = artistLabel // 再生スライダーの最大値と、音楽ファイルの長さを同期 singleton.musicSlider!.maximumValue = Float(singleton.audioPlayer.duration) } catch { print("error") } } // "ぐっすり〜" ボタンの動作 @IBAction func synthButton(_ sender: Any) { audioPlayerDif(resourceName: "synth", songLabel: "ぐっすり寝れそうな優しいシンセサイザー", artistLabel: "WHITE BGM") singleton.musicSlider?.value = 0 } // 再生スライダーを動かしたときの挙動(動かした後の位置で曲を再生) @IBAction func musicSliderController(_ sender: Any) { singleton.audioPlayer.currentTime = TimeInterval(singleton.musicSlider!.value) } // 音量スライダーを動かしたときの挙動 @objc func volumeController(_ sender: UISlider) { singleton.audioPlayer.volume = singleton.volume!.value } // スライドバーを音楽ファイルの現在時間の位置にするメソッド @objc func sliderCount(_ timer: Timer!){ singleton.musicSlider!.value = Float(singleton.audioPlayer.currentTime) } // 現在再生時間を計算して表示するメソッド @objc func timeCount(_ timer: Timer!) { // ★ビルド後、音楽再生ページに移行すると、ここでエラー★ // (Thread 1: EXC_BAD_ACCESS (code=1, address=0x48)) //  ⇒ アクセスしようとしたメモリ領域のデータが、解放済で見当たらない? singleton.currentMin = floor(singleton.audioPlayer.currentTime / 60) singleton.currentSec = singleton.audioPlayer.currentTime - (singleton.currentMin! * 60) // 10秒の位が「0」のとき、「00:07」のように表示(これがないと「0:7」のようになる) if singleton.currentSec! < 10 { singleton.currentTimeLabel!.text = "0\(Int(singleton.currentMin!)):0\(Int(singleton.currentSec!))" // 10秒の位が「1以上」で、再生時間が10分未満のとき「05:17」のように表示 } else if singleton.currentSec! >= 10 && singleton.currentMin! < 10 { singleton.currentTimeLabel!.text = "0\(Int(singleton.currentMin!)):\(Int(singleton.currentSec!))" } else { singleton.currentTimeLabel!.text = "\(Int(singleton.currentMin!)):\(Int(singleton.currentSec!))" } print(singleton.audioPlayer.currentTime) } // 音楽ファイルのトータル再生時間を取得して表示するメソッド func setTotalTime() { singleton.maxMin = floor(singleton.duration! / 60) singleton.maxSec = singleton.duration! - (singleton.maxMin! * 60) singleton.totalTimeLabel?.text = "\(Int(singleton.maxMin!)):\(Int(singleton.maxSec!))" } // ミュージックレーベルへのリンク @IBAction func realmusicButton(_ sender: Any) { let url = URL(string: "https://www.realmusic.com/") if UIApplication.shared.canOpenURL(url! as URL){ UIApplication.shared.open(url! as URL, options: [:], completionHandler: nil) } } // 再生・一時停止・停止ボタン(ツールバー内)の動作 // 再生ボタン @IBAction func playButton(_ sender: Any) { singleton.audioPlayer.play() // ループ再生 singleton.audioPlayer.numberOfLoops = -1 } // 一時停止ボタン @IBAction func pauseButton(_ sender: Any) { singleton.audioPlayer.pause() } // 停止ボタン @IBAction func stopButton(_ sender: Any) { singleton.audioPlayer.stop() // 暫定で前回のまま(各曲選択メソッドの呼び出し?) singleton.audioPlayer.currentTime = 0 } }
RECOMMEND