首页 > 解决方案 > 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)

                }
            })

标签: iosobjective-cswiftavaudioplayerviewdidload

解决方案


推荐阅读