使用 AVAudio 循环 mp3

问题描述

我尝试循环播放一个 mp3 文件,在那里我可以在播放时改变它的音高。 我可以更改音高,但无法循环播放文件。这是我的代码

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()
    }
}

为了让它循环,我尝试使用 AVAudioPCMBuffer(),请参阅:

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,format: nil)
        audioPlayer.scheduleBuffer(audiofilebuffer!,at: nil,options: .loops,completionHandler: nil) //Changed
        try engine.start()
        audioPlayer.play()
    }
}

但是当我运行该项目时,它给了我一个线程 1:“所需条件为 false:isPCMFormat” 错误:/ 确切的错误消息是:

2021-04-06 20:31:51.824454+0200 avas[67546:8825321] [avae] AVAEInternal.h:76 要求条件为假:[AVAudioBuffer.mm:175:-[AVAudioPCMBuffer initacWithPCMFormat:frame :]: (isPCMFormat)] 2021-04-06 20:31:51.832637+0200 avas[67546:8825321] *** 由于未捕获的异常“com.apple.coreaudio.avfaudio”而终止应用程序,原因:“所需条件为假:isPCMFormat”

我不知道如何让它以另一种(工作)方式循环。有人能帮我吗? :)

非常感谢!

解决方法

这有效:

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()
        let audioFormat = file.processingFormat
        let audioFrameCount = UInt32(file.length)
        let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat,frameCapacity: audioFrameCount)
        
        try! file.read(into: audioFileBuffer!)
        let mainMixer = engine.mainMixerNode
        
        engine.attach(audioPlayer)
        engine.attach(pitchControl)
        engine.connect(audioPlayer,to: mainMixer,format: audioFileBuffer?.format)
        engine.connect(audioPlayer,to: pitchControl,format:audioFileBuffer?.format)
        engine.connect(pitchControl,to: engine.mainMixerNode,format: nil)
        
        try engine.start()
        audioPlayer.play()
        audioPlayer.scheduleBuffer(audioFileBuffer!,at: nil,options: .loops,completionHandler: nil)
    }
}