I'm trying to make a simple music player. I want the label to display the current position of the AVMIDIPlayer. With my code the label is only updated once at the very beginning:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var player:AVMIDIPlayer = AVMIDIPlayer()
var playerTime:Double = 999 {
didSet {
label.text = String(playerTime)
}
}
#IBOutlet var label: UILabel!
#IBAction func Play(_ sender: Any) {
player.play()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
do {
let audioPath = Bundle.main.path(forResource: “song”, ofType: "mid")
try player = AVMIDIPlayer(contentsOf: NSURL(fileURLWithPath: audioPath!) as URL, soundBankURL: nil)
playerTime = player.currentPosition
}
catch {
}
}
}
What have I missed, please? Thank you. Scarlett
The reason the label isn’t updating is you’re setting the text in viewDidLoad which is called only once. Use a Timer to update the label.
import UIKit
import AVFoundation
class ViewController: UIViewController {
var player:AVMIDIPlayer = AVMIDIPlayer()
var playerTime:Double = 999 {
didSet {
label.text = String(playerTime)
}
}
var timer = Timer()
#IBOutlet var label: UILabel!
#IBAction func Play(_ sender: Any) {
player.play()
// this will execute every 0.1 seconds, allowing you to update the label.
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { _ in
self.playerTime += 0.1
let min = self.playerTime.truncatingRemainder(dividingBy: 3600)) / 60
let sec = self.playerTime.truncatingRemainder(dividingBy: 60)
self.label.text = String(format: "%02d:%02d", min, sec)
}
}
func stop() {
// when you stop playback
timer.invalidate()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
do {
let audioPath = Bundle.main.path(forResource: “song”, ofType: "mid")
try player = AVMIDIPlayer(contentsOf: NSURL(fileURLWithPath: audioPath!) as URL, soundBankURL: nil)
playerTime = player.currentPosition
}
catch {
}
}
}
Related
I have the player below that makes a short beep. However, "Player.shared.play()" only plays once for the first time.
I can't trigger it again on demand.
Any help would be appreciated.
import Foundation
import AudioKit
class Player {
static let shared = Player()
let osc = AKOscillator()
let env:AKAmplitudeEnvelope
var panner = AKPanner()
init() {
osc.amplitude = 0.3
env = AKAmplitudeEnvelope(osc)
env.attackDuration = 0.01
env.decayDuration = 0.01
env.sustainLevel = 0.0
env.releaseDuration = 0.01
panner = AKPanner(env)
AudioKit.output = panner
try! AudioKit.start()
osc.start()
env.start()
panner.start()
}
func play() {
osc.stop()
osc.start()
env.stop()
env.start()
}
}
#jl303,
For some reason, you have to add a delay between the starting and stopping of the oscillator and the envelope. I added it with a DispatchQueue delay like this:
func playOsc() {
osc.start()
env.start()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [unowned self] in
self.osc.stop()
self.env.stop()
}
}
Here's the revised Player class in context:
import Foundation
import AudioKit
class Player {
static let sharedInstance = Player()
let osc = AKOscillator()
let env: AKAmplitudeEnvelope
var panner = AKPanner()
init() {
AKSettings.bufferLength = .medium
AKSettings.playbackWhileMuted = true
do {
try AKSettings.setSession(category: .playAndRecord, with: [.defaultToSpeaker, .allowBluetooth, .mixWithOthers])
} catch {
AKLog("Could not set session category.")
}
osc.amplitude = 0.3
env = AKAmplitudeEnvelope(osc)
env.attackDuration = 0.01
env.decayDuration = 0.01
env.sustainLevel = 0.0
env.releaseDuration = 0.01
panner = AKPanner(env)
AudioKit.output = panner
try! AudioKit.start()
}
func playOsc() {
osc.start()
env.start()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) { [unowned self] in
self.osc.stop()
self.env.stop()
}
}
}
Here's the ViewController to trigger the Oscillator sound on command:
import UIKit
class ViewController: UIViewController {
var player = Player.sharedInstance
#IBOutlet weak var oscPlayStopButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
setUpButtonStyle()
}
fileprivate func setUpButtonStyle() {
oscPlayStopButton.layer.cornerRadius = 12.0
oscPlayStopButton.layer.borderColor = UIColor.systemBlue.cgColor
oscPlayStopButton.layer.borderWidth = 1.0
}
#IBAction func playOscAction(_ sender: UIButton) {
player.playOsc()
}
}
You can download the Xcode project here:
https://github.com/markjeschke/osc-player
The idea is simple and I do not think that the question has been asked in the past.
I want to build a simple mp3 player.
some songs displayed in a collection view the user selects a song
segue to another view with options to play, pause or stop only issue
is when you go back to the home screen to select a new song with the
current still playing. It is impossible to deactivate the current
player. When you need to play the 2 songs, the 2 are playing together
I have tried a lot of things
- create a new instance of player (player = AVAudioPlayer())
- player.pause() and player.play()
I do not see what I am doing wrong really.
this is my code :
import UIKit
import AVFoundation
class LecteurViewController: UIViewController {
var chansonSelected: Chanson? = nil
var lecteur:AVAudioPlayer = AVAudioPlayer()
var timer1 = Timer()
var timer2 = Timer()
#IBOutlet weak var dureeChansonSlider: UISlider!
#IBOutlet weak var chansonImageView: UIImageView!
#IBOutlet weak var chansonVolumeSlider: UISlider!
#IBOutlet weak var debutLabel: UILabel!
#IBOutlet weak var finLabel: UILabel!
#IBAction func stopMusicAction(_ sender: UIBarButtonItem) {
var player = AVAudioPlayer()
lecteur.stop()
LecteurManager.isActive = false
}
#IBAction func pauseMusicAction(_ sender: UIBarButtonItem) {
var player = AVAudioPlayer()
lecteur.pause()
LecteurManager.isActive = false
}
#IBAction func jouerMusicAction(_ sender: UIButton) {
if LecteurManager.isActive {
changeSong()
print("lecteur déjà en cours")
} else {
var player = AVAudioPlayer()
lecteur.play()
}
print(LecteurManager.isActive )
LecteurManager.isActive = true
}
func changeSong() {
lecteur.stop()
//lecteur = AVAudioPlayer()
jouerLecteurMp3()
print(chansonSelected!)
lecteur.play()
}
override func viewDidLoad() {
super.viewDidLoad()
configureView()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
jouerLecteurMp3()
}
func configureView() {
self.title = (chansonSelected!.titre!).capitalized
chansonImageView.image = UIImage(named: "\(chansonSelected!.image).jpgs")
//formatter 'back' button
let backBtn = UIBarButtonItem(title: "< Playlist", style: .plain, target: self, action: #selector(LecteurViewController.reset(_sender:)))
self.navigationItem.leftBarButtonItem = backBtn
self.navigationController?.navigationBar.tintColor = UIColor.white
//contrôler volume chanson
chansonVolumeSlider.addTarget(self, action: #selector(LecteurViewController.ajusterVolume(_ :)), for: UIControlEvents.valueChanged)
//contrôler durée chanson
dureeChansonSlider.addTarget(self, action: #selector(LecteurViewController.ajusterDurée(_ :)), for: UIControlEvents.valueChanged)
updateUI()
}
func updateUI() {
//indiquer position chanson
timer1 = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(LecteurViewController.mettreAJourDurée), userInfo: nil, repeats: true)
//afficher durée chanson
timer2 = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(LecteurViewController.afficherDurée), userInfo: nil, repeats: true)
}
func reset(_sender:UIBarButtonItem) {
self.navigationController?.popViewController(animated: true)
}
func ajusterVolume(_ sender:UISlider) {
//print("volume ajusté \(chansonVolumeSlider.value)")
lecteur.volume = chansonVolumeSlider.value
}
func ajusterDurée(_ sender:UISlider) {
lecteur.currentTime = TimeInterval(dureeChansonSlider.value)
}
func mettreAJourDurée() {
dureeChansonSlider.value = Float(lecteur.currentTime)
}
func afficherDurée() {
print("durée actuelle: \(lecteur.duration - lecteur.currentTime)")
debutLabel.text = retournerPositionActuelle()
finLabel.text = retournerDureeTotal()
}
func retournerPositionActuelle() -> String {
let seconds = Int(lecteur.currentTime) % 60
let minutes = (Int(lecteur.currentTime) / 60) % 60
return String(format: "%0.2i:%0.2i", minutes, seconds)
}
func retournerDureeTotal() -> String {
let seconds = Int(lecteur.currentTime) % 60
let minutes = (Int(lecteur.currentTime) / 60) % 60
return String(format: "%0.2i:%0.2i", minutes, seconds)
}
func jouerLecteurMp3() {
let chanson = "bensound-\(chansonSelected!.titre!)"
let fichierMp3 = Bundle.main.path(forResource: chanson, ofType: "mp3")
do {
try lecteur = AVAudioPlayer(contentsOf: URL(string: fichierMp3!)!)
dureeChansonSlider.maximumValue = Float(lecteur.duration)
} catch {
print("erreur lecture mp3")
}
}
}
Try this:
func reset(_sender:UIBarButtonItem)
{
self.navigationController?.popViewController(animated: true)
lecteur.stop()
}
I am trying to stream a music from remote url. I am trying to run this in iOS 11 but it not play the music.
ViewController
var session = AVAudioSession.sharedInstance()
var LQPlayer: AVPlayer?
let LOW_URL = URL(string: "http://someLInk.pls")! // not an original url provided at this time.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.avPlayerSetup()
}
func avPlayerSetup() {
do {
try session.setCategory(AVAudioSessionCategoryPlayback)
try session.overrideOutputAudioPort(.none)
try session.setActive(true)
} catch {
print("AVPlayer setup error \(error.localizedDescription)")
}
}
func initPlayer() {
LQPlayer = AVPlayer(url: LOW_URL)
print("player allocated")
}
func deAllocPlayer() {
LQPlayer = nil
print("player deallocated")
}
#IBAction func playBtn(_ sender: Any) {
initPlayer()
LQPlayer?.play()
}
#IBAction func pauseBtn(_ sender: Any) {
LQPlayer?.pause()
deAllocPlayer()
}
}
I set Allow Arbitrary Loads YES in info.plist.
Above code the URL I given is dummy. Actual url is working fine.
Working Code with Live Video Stream
#IBOutlet weak var player_View: UIView!
var LQPlayer: AVPlayer?
let LOW_URL = URL(string:"http://www.streambox.fr/playlists/test_001/stream.m3u8")!
override func viewDidLoad() {
super.viewDidLoad()
self.avPlayerSetup()
LQPlayer = AVPlayer.init(url: LOW_URL)
let avPlayerView = AVPlayerViewController()
avPlayerView.view.frame = self.player_View.bounds
avPlayerView.player = LQPlayer
self.player_View.addSubview(avPlayerView.view)
}
func avPlayerSetup() {
do {
try audioSession.setCategory(AVAudioSessionCategoryPlayback)
try audioSession.overrideOutputAudioPort(AVAudioSessionPortOverride.speaker)
try audioSession.setActive(true)
} catch {
print("AVPlayer setup error \(error.localizedDescription)")
}
}
func initPlayer() {
LQPlayer = AVPlayer(url:LOW_URL)
print("player allocated")
}
func deAllocPlayer() {
LQPlayer = nil
print("player deallocated")
}
#IBAction func playBtn(_ sender: Any) {
// initPlayer()
LQPlayer?.play()
}
#IBAction func pauseBtn(_ sender: Any) {
LQPlayer?.pause()
deAllocPlayer()
}
I'm having some trouble playing a sound which is attached to a button/IBAction.
When I do the exact same thing for iOS in Xcode, it works perfectly. However, when I do this for OS X, it doesn't work. Any ideas?
import Cocoa
import AVFoundation
class ViewController: NSViewController, NSSpeechRecognizerDelegate {
var pingAudioPlayer : AVAudioPlayer?
var sr = NSSpeechRecognizer()
#IBOutlet var output: NSTextView?
func playPing(){
let pingSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("ping", ofType: "mp3")!)
pingAudioPlayer = AVAudioPlayer(contentsOfURL: pingSound, error: nil)
pingAudioPlayer!.prepareToPlay()
pingAudioPlayer!.currentTime = 0
pingAudioPlayer!.play()
}
#IBAction func soundTest(sender: AnyObject) {
playPing()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
sr.delegate = self
sr.commands = ["Ping", "Ping Mac"]
sr.startListening()
}
func speechRecognizer(sender: NSSpeechRecognizer, didRecognizeCommand command: AnyObject?) {
output!.string! += "\(command)\n"
playPing()
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
}
The main problem was the speechRecognizer method, it wasn't the right signature.
import AVFoundation
class ViewController: NSViewController, NSSpeechRecognizerDelegate {
var pingAudioPlayer : AVAudioPlayer?
var sr = NSSpeechRecognizer()
#IBOutlet var output: NSTextView?
func playPing(){
let pingSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("ping", ofType: "mp3")!)
pingAudioPlayer = try? AVAudioPlayer(contentsOfURL: pingSound)
pingAudioPlayer?.prepareToPlay()
pingAudioPlayer?.currentTime = 0
pingAudioPlayer?.play()
}
#IBAction func soundTest(sender: AnyObject) {
playPing()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
sr?.delegate = self
sr?.commands = ["Ping", "Ping Mac"]
sr?.startListening()
}
func speechRecognizer(sender: NSSpeechRecognizer, didRecognizeCommand command: String) {
output?.string! += "\(command)\n"
playPing()
}
}
I'm trying to trigger a sound after I say a word. The speech recognizer recognizes the word when I say it and I've set it up so it puts out a string each time I say the command. What I'd like to do is trigger a sound after I say that specific word. This is what I have so far.
import Cocoa
import AVFoundation
class ViewController: NSViewController, NSSpeechRecognizerDelegate {
var ping = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("ping", ofType: "mp3")!)
var pingAudioPlayer = AVAudioPlayer()
var sr = NSSpeechRecognizer()
#IBOutlet var output: NSTextView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
pingAudioPlayer = AVAudioPlayer(contentsOfURL: ping, error: nil)
sr.delegate = self
sr.commands = ["Ping", "Ping Mac"]
sr.startListening()
}
func speechRecognizer(sender: NSSpeechRecognizer, didRecognizeCommand command: AnyObject?) {
output!.string! += "\(command)\n"
pingAudioPlayer.play()
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
UPDATE:
import Cocoa
import AVFoundation
class ViewController: NSViewController, NSSpeechRecognizerDelegate {
var ping = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("ping", ofType: "mp3")!)
let pingAudioPlayer = AVAudioPlayer()
var sr = NSSpeechRecognizer()
#IBOutlet var output: NSTextView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
sr.delegate = self
sr.commands = ["Ping", "Ping Mac"]
sr.startListening()
}
func speechRecognizer(sender: NSSpeechRecognizer, didRecognizeCommand command: AnyObject?) {
output!.string! += "\(command)\n"
var pingAudioPlayer = AVAudioPlayer(contentsOfURL: ping, error: nil)
pingAudioPlayer.prepareToPlay()
pingAudioPlayer.play()
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
}
Not sure why the audio player is not playing the sound once the word is recognized. Any ideas?
You aren't telling the audio player which sound to play. Try this:
func speechRecognizer(sender: NSSpeechRecognizer, didRecognizeCommand command: AnyObject?) {
do{
let pingAudioPlayer = try AVAudioPlayer(contentsOfURL:ping)
pingAudioPlayer.prepareToPlay()
pingAudioPlayer.play()
}catch {
print("Error getting the audio file")
}
}