Цикл mp3 с AVAudio

Я пытаюсь зациклить 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, 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()
    }
}

Но когда я запускаю проект, он дает мне Поток 1: необходимое условие ложно: isPCMFormat Ошибка: / Точное сообщение об ошибке:

2021-04-06 20: 31: 51.824454 + 0200 avas [67546: 8825321] [avae] AVAEInternal.h: 76 обязательное условие неверно: [AVAudioBuffer.mm:175:-[AVAudioPCMBuffer initWithPCMFormat: frameCapacity:]: (isPCMFormat)] 2021-04-06 20: 31: 51.832637 + 0200 avas [67546: 8825321] *** Завершение работы приложения из-за неперехваченного исключения 'com.apple.coreaudio.avfaudio', причина: 'требуемое условие неверно: isPCMFormat '

Понятия не имею, как сделать цикл другим (рабочим) способом. Кто-нибудь может мне помочь? :)

Большое спасибо!


person MunichCoder    schedule 06.04.2021    source источник


Ответы (1)


Это работает:

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)
    }
}
person MunichCoder    schedule 06.04.2021