Проблема множественной остановки AVAudioPlayer в swift - PullRequest
1 голос
/ 02 мая 2019

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

                }
            })

...