1

I have piano keyboard.When I press the key I want the previous key not to be interrupted before calling func pianoKeyUp.So I created another player in pianoKeyDown.

The problem is: When simultaneously press the key created AudioPlayers is not deleted or simultaneous deletion occurs and gives an error about the missing element in AudioPlayers array and app crashes.What is the better way to play piano sound multiple?

var audioPlayers = [KeyAudio]() 

There is a struct for each piano key that init in ViewDidLoad() in for key in cycle

     struct KeyAudio {
            let audioPlayer : AVAudioPlayer
            var playersArray : [AVAudioPlayer]

    init(audioPlayer: AVAudioPlayer) {
        self.audioPlayer = audioPlayer

        var array =  [AVAudioPlayer]()
        array.append(audioPlayer)
        self.playersArray = array
      }
    }

ViewDidLoad()

Prepare each player to play and append to audioPlayers array with init of 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)
                }

And I have functions from custom piano view

First - keyDown - triggered when piano key pressed

If player.isPlaying I create another AudioPlayer and append it to common array of each note

    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)
            }
        }
    }

And second - keyUp - when finger is released I stop AudioPlayer created by first tap, then check if another AudioPlayer created by next tap and there is the problem

    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)

                }
            })

0 Answers0