#swift #xcode #avaudioplayer #avaudioengine #avkit
Вопрос:
Я пытаюсь зациклить 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.мм:175:-[AVAudioPCMBuffer initWithPCMFormat:Емкость кадра:]: (isPCMFormat)] 2021-04-06 20:31:51.832637 0200 avas[67546:8825321] *** Завершение работы приложения из-за неучтенного исключения «com.apple.coreaudio.avfaudio», причина: «требуемое условие ложно: isPCMFormat»
Я понятия не имею, как я могу сделать это другим (рабочим) способом. Кто-нибудь может мне помочь? 🙂
Большое вам спасибо!
Ответ №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)
}
}