0
votes

I am trying to build autopan(move the audio between left, middle and right channel) with AVaudioPlayer to play my music files. I could get it through AVAudioPlayer.pan method. Implemented to get AUTO pan by using timer in my swift code. Now the issue is ,audio is not playing smoothly and it breaks in between.

Here is my present code ,

class AudioPlayer: UIViewController {
  var player = AVAudioPlayer()

override func viewDidLoad() {
        super.viewDidLoad()
      prepareAudioSession()
    }

  func prepareAudioSession() {

           let audioFileName = "LPNumb"
           let audioFileExtension = "mp3"

           guard let filePath = Bundle.main.path(forResource: audioFileName, ofType: audioFileExtension) else {
               print("Audio file not found at specified path")
               return
           }
        do {
           let alertSound = URL(fileURLWithPath: filePath)
           try? player = AVAudioPlayer(contentsOf: alertSound)

        } catch {
            print(error)
        }
       }

  @IBAction func play(_ sender: AnyObject){
        player.play()
        if  player.isPlaying{
        _ = Timer.scheduledTimer(timeInterval: 0.50, target: self, selector: #selector(self.update1), userInfo: nil, repeats: true)
        _ = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.update2), userInfo: nil, repeats: true)
            _ = Timer.scheduledTimer(timeInterval: 1.50, target: self, selector: #selector(self.update3), userInfo: nil, repeats: true)
        }



    }
   @objc func update1() {
        player.pan = 0
     }
    @objc func update2() {
        player.pan = 1

    }
    @objc func update3() {
        player.pan = -1
    }

}

I want to make the output audio as MONO and require audio to be played AUTOPANNED smoothly.

1

1 Answers

3
votes

I think, you need make just one Timer for this task.
Take a look through the code:

import UIKit
import AVFoundation

enum PanState {
    case up
    case down
}

class ViewController: UIViewController {

    var audioPlayer: AVAudioPlayer?
    var timerForPan: Timer?
    var pan: Double = 0.0
    var panState: PanState = .up

    override func viewDidLoad() {
        super.viewDidLoad()

        if let path = Bundle.main.path(forResource: "LPNumb", ofType: "mp3") {
            let record = URL(fileURLWithPath: path)
            setupRecordToPlayer(from: record)
        }
        setTimers()
    }

    func setTimers() {
        timerForPan = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.updatePan), userInfo: nil, repeats: true)
    }

    func setupRecordToPlayer(from url: URL) {
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: url)
        } catch let error {
            debugPrint(error.localizedDescription)
        }
    }

    @IBAction func playButtonPressed(_ sender: UIButton) {
        audioPlayerToPlay()
    }

    @objc func updatePan() {
        if audioPlayer?.isPlaying ?? false {
            switch panState {
            case .up:
                self.pan += 0.1
                if pan >= 1 {
                    self.panState = .down
                }
            case .down:
                self.pan -= 0.1
                if pan <= -1 {
                    self.panState = .up
                }
            }
            audioPlayer?.pan = Float(self.pan)
        }
    }

    /// Prepare Audio player to play
    func audioPlayerToPlay() {
        audioPlayer?.prepareToPlay()
        do {
            try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])
        } catch {
            print(error.localizedDescription)
        }
        audioPlayer?.play()
    }
}