У меня есть клавиатура пианино. Когда я нажимаю клавишу, я хочу, чтобы предыдущая клавиша не прерывалась перед вызовом 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()
Подготовьте каждого игрока к игре и добавьте audioPlayers
массив с init KeyAudio
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)
}
И у меня есть функции от пользовательский вид пианино
Первый - 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)
}
})