ios - Swift中的AVAudioPlayer多次停止问题
问题描述
我有钢琴键盘。当我按下琴键时,我希望在调用func PianoKeyUp之前不要中断前一个琴键。所以我在PianoKeyDown中创建了另一个播放器。
问题是:当同时按下创建的 AudioPlayers 键时未删除或同时删除发生并给出有关 AudioPlayers 数组中缺少元素和应用程序崩溃的错误。播放钢琴声音多个的更好方法是什么?
var audioPlayers = [KeyAudio]()
每个钢琴键都有一个结构,在ViewDidLoad()
循环中初始化
struct KeyAudio {
let audioPlayer : AVAudioPlayer
var playersArray : [AVAudioPlayer]
init(audioPlayer: AVAudioPlayer) {
self.audioPlayer = audioPlayer
var array = [AVAudioPlayer]()
array.append(audioPlayer)
self.playersArray = array
}
}
ViewDidLoad()
准备每个播放器播放并使用KeyAudioaudioPlayers
的 init 附加到数组
for key in 1...61 {
do {
let pianoSoundURL = URL(fileURLWithPath: Bundle.main.path(forResource: "\(key).wav", ofType: nil)!)
let audioPlayer = try AVAudioPlayer(contentsOf: pianoSoundURL, fileTypeHint: nil)
audioPlayer.volume = 0.1
audioPlayer.prepareToPlay()
let player = KeyAudio(audioPlayer: audioPlayer) // init
self.audioPlayers.append(player)
} catch(let error) {
print(error)
}
我有自定义钢琴视图的功能
First - keyDown - 按下钢琴键时触发
如果player.isPlaying
我创建另一个AudioPlayer
并将其附加到每个音符的公共数组中
func pianoKeyDown(_ keyNumber: UInt8) {
let number = Int(keyNumber)
audioPlayers[number].audioPlayer.setVolume(0, fadeDuration: 0.05)
if audioPlayers[number].audioPlayer.isPlaying {
let pianoSoundURL = URL(fileURLWithPath: Bundle.main.path(forResource: "\(number+1).wav", ofType: nil)!)
guard let duplicatePlayer = try? AVAudioPlayer(contentsOf: pianoSoundURL) else { return }
audioPlayers[number].playersArray.append(duplicatePlayer)
duplicatePlayer.prepareToPlay()
duplicatePlayer.currentTime = 0
DispatchQueue.global().async {
duplicatePlayer.play()
duplicatePlayer.setVolume(0.8, fadeDuration: 0.05)
}
} else {
guard let firstTimePlayer = audioPlayers[number].playersArray.first else { return }
firstTimePlayer.currentTime = 0
DispatchQueue.global().async {
firstTimePlayer.play()
firstTimePlayer.setVolume(0.8, fadeDuration: 0.05)
}
}
}
第二个- keyUp - 当手指被释放时,我停止第AudioPlayer
一次点击创建,然后检查AudioPlayer
下一次点击是否创建了另一个并且有问题
func pianoKeyUp(_ keyNumber: UInt8) {
let number = Int(keyNumber)
if let firstPlayer = audioPlayers[number].playersArray.first, firstPlayer.isPlaying {
audioPlayers[number].audioPlayer.setVolume(0, fadeDuration: 0.75)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.75, execute: {
DispatchQueue.global().async {
if self.audioPlayers[number].audioPlayer.isPlaying {
self.audioPlayers[number].audioPlayer.stop()
}
}
})
}
let isIndexValid = audioPlayers[number].playersArray.indices.contains(1)
if isIndexValid, audioPlayers[number].playersArray[1].isPlaying {
audioPlayers[number].playersArray[1].setVolume(0, fadeDuration: 0.75)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.75, execute: {
if self.audioPlayers[number].playersArray.indices.contains(1) {
self.audioPlayers[number].playersArray[1].stop()
self.audioPlayers[number].playersArray.remove(at: 1)
}
})
解决方案
推荐阅读
- java - 根据自定义时间单位计算天数
- python - Scrapy链接队列
- excel - 如何仅使用 ROW() 函数和增量值来增加行数?
- typescript - 如何获取 VS Code 调试数据,如断点、步骤、行代码
- visual-studio - FFTW Visual Studio fortran(intel)链接时未解析的符号
- python - Python 使用本地文件而不是 url 参数
- ios - iOS Packet Tunnel 源与目标模式和表单
- powershell - 用于插入 SQL 数据库的 CSV 数据的字符串操作和输出格式
- r - 使用 sjPlot 中的 plot_model() 重新排序 x 轴
- flutter - 嵌套的 StreamBuilder 是好的模式吗?