I try to loop an mp3 file, where I can change its pitch while playing. I can change the pitch but I cannot loop the file. This is my code:
import AVKit
class ViewController: UIViewController {
@IBOutlet weak var speedSlider: UISlider!
@IBOutlet weak var speedLabel: UILabel!
let pitchControl = AVAudioUnitTimePitch()
let engine = AVAudioEngine()
override func viewDidLoad(){
super.viewDidLoad()
do{ try playSound(soundName: "audiSound1")} catch{}
}
@IBAction func speedSlided(_ sender: Any) {
pitchControl.pitch = speedSlider.value
speedLabel.text = String(speedSlider.value)
}
func playSound(soundName: String) throws{
guard let url = Bundle.main.url(forResource: soundName, withExtension: "mp3") else { return }
let file = try AVAudioFile(forReading: url)
let audioPlayer = AVAudioPlayerNode()
engine.attach(audioPlayer)
engine.attach(pitchControl)
engine.connect(audioPlayer, to: pitchControl, format: nil)
engine.connect(pitchControl, to: engine.mainMixerNode, format: nil)
audioPlayer.scheduleFile(try! AVAudioFile(forReading: url), at: nil)
try engine.start()
audioPlayer.play()
}
}
To make it loop, I tried using an AVAudioPCMBuffer(), see:
import AVKit
class ViewController: UIViewController {
@IBOutlet weak var speedSlider: UISlider!
@IBOutlet weak var speedLabel: UILabel!
let pitchControl = AVAudioUnitTimePitch()
let engine = AVAudioEngine()
override func viewDidLoad(){
super.viewDidLoad()
do{ try playSound(soundName: "audiSound1")} catch{}
}
@IBAction func speedSlided(_ sender: Any) {
pitchControl.pitch = speedSlider.value
speedLabel.text = String(speedSlider.value)
}
func playSound(soundName: String) throws{
guard let url = Bundle.main.url(forResource: soundName, withExtension: "mp3") else { return }
let file = try AVAudioFile(forReading: url)
let audioPlayer = AVAudioPlayerNode()
//New:
let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: file.fileFormat, frameCapacity: AVAudioFrameCount(file.length))
try? file.read(into: audioFileBuffer!)
engine.attach(audioPlayer)
engine.attach(pitchControl)
engine.connect(audioPlayer, to: pitchControl, format: nil)
engine.connect(pitchControl, to: engine.mainMixerNode, format: nil)
audioPlayer.scheduleBuffer(audioFileBuffer!,at: nil, options: .loops, completionHandler: nil) //Changed
try engine.start()
audioPlayer.play()
}
}
But when I run the project, it gives me a Thread 1: "required condition is false: isPCMFormat" Error :/ The exact error message is:
2021-04-06 20:31:51.824454+0200 avas[67546:8825321] [avae] AVAEInternal.h:76 required condition is false: [AVAudioBuffer.mm:175:-[AVAudioPCMBuffer initWithPCMFormat:frameCapacity:]: (isPCMFormat)] 2021-04-06 20:31:51.832637+0200 avas[67546:8825321] *** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'required condition is false: isPCMFormat'
I have no idea how I can make it loop in another (working) way. Can someone help me? :)
Thank you so much!