AVAudioengine 播放/循环音频,多个按钮
AVAudioengine play / loop audio , multiple buttons
我有这个按钮可以播放和循环播放 wav。但是,如果我有第二个带有另一个循环的按钮怎么办?我希望第二个循环在按下后开始播放,但是,第一个循环必须完成他的 'round'。反之亦然(播放并循环第二个循环,按下按钮第一个循环并接管)
@IBAction func playButtonTapped(_ sender: Any) {
guard let filePath: String = Bundle.main.path(forResource: "25loop110", ofType: "wav") else{ return }
print("\(filePath)")
let fileURL: URL = URL(fileURLWithPath: filePath)
guard
let audioFile = try? AVAudioFile(forReading: fileURL) else{ return }
let audioFormat = audioFile.processingFormat
let audioFrameCount = UInt32(audioFile.length)
guard let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: audioFrameCount) else{ return }
do{
try audioFile.read(into: audioFileBuffer)
timeShift.rate = adjustedBpm/bpm
playerNode.scheduleFile(audioFile, at: nil, completionHandler: nil)
} catch{
print("over")
}
try? audioEngine.start()
playerNode.play()
playerNode.scheduleBuffer(audioFileBuffer, at: nil, options:.loops,completionHandler: nil)
}
您可以使用 .scheduleBuffer
的 completionHandler
参数来处理此行为。
例如,您可以这样做:
var nextAudioFilePath: String
var isPlaying: Bool = false
@IBAction func playLoopA() {
guard let path = Bundle.main.path(forResource: "audioFileA", ofType: "wav") else { return }
nextAudioFilePath = path
guard !isPlaying else { return }
play()
}
@IBAction func playLoopB() {
guard let path = Bundle.main.path(forResource: "audioFileB", ofType: "wav") else { return }
nextAudioFilePath = path
guard !isPlaying else { return }
play()
}
private func play() {
let fileURL = URL(fileURLWithPath: nextAudioFilePath)
...
playerNode.scheduleBuffer(audioFileBuffer, at: nil, options: [], completionHandler: { [weak self] in
self?.play()
})
}
我也找到了这个解决方案:
playerNode.scheduleBuffer(audioFileBuffer, at: nil, options:[.interruptsAtLoop, .loops],completionHandler: nil)
我有这个按钮可以播放和循环播放 wav。但是,如果我有第二个带有另一个循环的按钮怎么办?我希望第二个循环在按下后开始播放,但是,第一个循环必须完成他的 'round'。反之亦然(播放并循环第二个循环,按下按钮第一个循环并接管)
@IBAction func playButtonTapped(_ sender: Any) {
guard let filePath: String = Bundle.main.path(forResource: "25loop110", ofType: "wav") else{ return }
print("\(filePath)")
let fileURL: URL = URL(fileURLWithPath: filePath)
guard
let audioFile = try? AVAudioFile(forReading: fileURL) else{ return }
let audioFormat = audioFile.processingFormat
let audioFrameCount = UInt32(audioFile.length)
guard let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: audioFrameCount) else{ return }
do{
try audioFile.read(into: audioFileBuffer)
timeShift.rate = adjustedBpm/bpm
playerNode.scheduleFile(audioFile, at: nil, completionHandler: nil)
} catch{
print("over")
}
try? audioEngine.start()
playerNode.play()
playerNode.scheduleBuffer(audioFileBuffer, at: nil, options:.loops,completionHandler: nil)
}
您可以使用 .scheduleBuffer
的 completionHandler
参数来处理此行为。
例如,您可以这样做:
var nextAudioFilePath: String
var isPlaying: Bool = false
@IBAction func playLoopA() {
guard let path = Bundle.main.path(forResource: "audioFileA", ofType: "wav") else { return }
nextAudioFilePath = path
guard !isPlaying else { return }
play()
}
@IBAction func playLoopB() {
guard let path = Bundle.main.path(forResource: "audioFileB", ofType: "wav") else { return }
nextAudioFilePath = path
guard !isPlaying else { return }
play()
}
private func play() {
let fileURL = URL(fileURLWithPath: nextAudioFilePath)
...
playerNode.scheduleBuffer(audioFileBuffer, at: nil, options: [], completionHandler: { [weak self] in
self?.play()
})
}
我也找到了这个解决方案:
playerNode.scheduleBuffer(audioFileBuffer, at: nil, options:[.interruptsAtLoop, .loops],completionHandler: nil)