I searched around stackoverflow but I couldn't find anything that helped. I am currently building a simple music app. My problem is that the slider that I am using to control the volume levels plays the song at full volume, or 100% of the volume when the app first runs. What I want to do is to adjust this to be at only 50% of the volume so when I drag the slider to the right, I can increase the volume. Currently, when I drag the slider to the right, the volume stays the same because like I mentioned before when I run the app, the volume is already at maximum level. However when I drag it to the left, the volume does decrease as expected which has me even more confused. I should also add the slider's value is set to be 0.5 at the time of creation as it should. I will post the code below, please help. I create the slider inside the configurePlayer() method, and I am trying to adjust the volume inside the last method
'''
import UIKit
import AVFoundation
class playerViewController: UIViewController {
var position: Int = 0
var Gabay = [Gabays]()
var player: AVAudioPlayer?
var timer: Timer?
@IBOutlet var holder: UIView!
let forWardButton = UIButton()
let backwardsButton = UIButton()
let playPauseButton = UIButton()
//userinterfact elements
private let coverImageView: UIImageView = {
let imageView=UIImageView()
imageView.contentMode = .scaleAspectFit
return imageView
}()
private let trackNameLabel: UILabel = {
let gabayNameLabel = UILabel()
gabayNameLabel.font = UIFont(name: "Helvetica-bold", size: 20)
return gabayNameLabel
}()
private let artist: UILabel = {
let artistName = UILabel()
artistName.font = UIFont(name: "Helvetica-bold", size: 20)
artistName.textAlignment = .left
return artistName
}()
//MARK: - life cycle
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemGreen
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if holder.subviews.count == 0{
configurePlayer()
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let player = player{
player.stop()
}
}
// MARK: - Table view data source
//configure
func configurePlayer() {
//set up player
let gabay = Gabay[position]
//loading the gabays from disc or array
let urlString = Bundle.main.path(forResource: gabay.trackName, ofType: "mp3")
do{
try AVAudioSession.sharedInstance().setMode(.default)
try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
guard let urlString = urlString else{return}
player = try AVAudioPlayer(contentsOf: URL(string: urlString)!)
guard let player = player else{return}
//play the audio
player.play()
}
catch{
print("Error is: \(error.localizedDescription)")
}
//set up imageView cover
coverImageView.frame = CGRect(x: 15, y: 10, width: holder.frame.size.width - 20, height: holder.frame.size.height - 350)
coverImageView.image = UIImage(named: gabay.imageName)
holder.addSubview(coverImageView)
//set up labels
trackNameLabel.frame = CGRect(x: 150, y: 15, width: holder.frame.size.width - 40, height: holder.frame.size.width + 470)
trackNameLabel.text = gabay.trackName
holder.addSubview(trackNameLabel)
artist.frame = CGRect(x: 150, y: 15, width: holder.frame.size.width - 40, height: holder.frame.size.width + 540)
artist.text = gabay.artist
holder.addSubview(artist)
//setting up buttons
playPauseButton.setTitle("", for: .normal)
playPauseButton.addTarget(self, action: #selector(playButtonTapped), for: .touchUpInside)
playPauseButton.frame = CGRect(x: 155, y: 600, width: (holder.frame.size.width)/6, height: holder.frame.size.height - 690)
playPauseButton.setImage(UIImage(systemName: "play.fill"), for: .normal)
holder.addSubview(playPauseButton)
backwardsButton.setTitle("", for: .normal)
backwardsButton.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside)
backwardsButton.frame = CGRect(x: 15, y: 600, width: (holder.frame.size.width)/6, height: holder.frame.size.height - 690)
backwardsButton.setImage(UIImage(systemName: "backward.fill"), for: .normal)
holder.addSubview(backwardsButton)
forWardButton.setTitle("", for: .normal)
forWardButton.addTarget(self, action: #selector(forwardButtonTapped), for: .touchUpInside)
forWardButton.frame = CGRect(x: 285, y: 600, width: (holder.frame.size.width)/6, height: holder.frame.size.height - 690)
forWardButton.setImage(UIImage(systemName: "forward.fill"), for: .normal)
holder.addSubview(forWardButton)
//set volume slider
let volumeSlider = UISlider()
volumeSlider.minimumValue = 0.0
volumeSlider.maximumValue = 1.0
volumeSlider.alpha = 0.4
volumeSlider.addTarget(self, action: #selector(volumeSliderChanged), for: .valueChanged)
volumeSlider.value = 0.1
volumeSlider.frame = CGRect(x: 15, y: 560, width: holder.frame.size.width - 40, height: (holder.frame.size.width)/8)
volumeSlider.setThumbImage(UIImage(systemName: "volume.3")?.withTintColor(.systemGray, renderingMode: .alwaysOriginal).resizableImage(withCapInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right:0)), for: .normal)
holder.addSubview(volumeSlider)
//set fast forward slider
let seekSlider = UISlider()
seekSlider.addTarget(self, action: #selector(seekThrough), for: .valueChanged)
seekSlider.minimumValue = 0.0
seekSlider.maximumValue = 1.0
seekSlider.frame = CGRect(x: 15, y: 700, width: holder.frame.size.width - 40, height: (holder.frame.size.width)/8)
seekSlider.setThumbImage(UIImage(systemName: "circle.fill")?.withTintColor(.clear, renderingMode: .alwaysOriginal).resizableImage(withCapInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right:0)), for: .normal)
holder.addSubview(seekSlider)
}
@objc func playButtonTapped(){
guard let player = player else{return}
if player.isPlaying{
playPauseButton.setImage(UIImage(systemName: "pause.fill"), for: .normal)
player.stop()
}else{
playPauseButton.setImage(UIImage(systemName: "play.fill"), for: .normal)
player.play()
}
}
@objc func backButtonTapped(){
if position > 0 {
position = position - 1
player?.stop()
for subview in holder.subviews {
subview.removeFromSuperview()
}
configurePlayer()
}
}
@objc func forwardButtonTapped(){
if position < Gabay.count - 1 {
guard let player = player else{return}
position = position + 1
player.stop()
for subview in holder.subviews {
subview.removeFromSuperview()
}
configurePlayer()
}
}
@objc func seekThrough(_ slider: UISlider){
//get the duration of the current playing gabay
var duration = player!.duration
duration += 1
//calculate
let newPosition = Double(slider.value)*duration
player!.currentTime = newPosition
//make slider move along the song
}
@objc func volumeSliderChanged(_ slider: UISlider){
let volumeValue = slider.value
player!.volume = volumeValue
//make the initial position of volume slider to be 50% of the volume
}
}
The function
volumeSliderChanged()is called every time the slider is used, which means any initialization added there will be repeatedly called every time someone uses the slider to the volume.Try adding
player!.volume = 0.5right underneathplayer = try AVAudioPlayer(contentsOf: URL(string: urlString)!)instead.Also try modifying the initial slider value from 0.1 to 0.5 in order for the slider position to match the starting volume.
As for the volume not decreasing, it might be because of linear vs. logarithmic volume control. Here's the extension from the article (AVPlayer changed to AVAudioPlayer):
Replacing every instance of
player!.volumewithplayer!.logarithmicVolumemight help with the issue.