一尘不染

获取AVAudioPlayer一次播放多种声音

swift

我试图让多个声音文件在AVAudioPlayer实例上播放,但是当一种声音播放时,另一种声音停止。我一次只能播放一种以上的声音。这是我的代码:

import AVFoundation

class GSAudio{

    static var instance: GSAudio!

    var soundFileNameURL: NSURL = NSURL()
    var soundFileName = ""
    var soundPlay = AVAudioPlayer()

    func playSound (soundFile: String){

        GSAudio.instance = self

        soundFileName = soundFile
        soundFileNameURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(soundFileName, ofType: "aif", inDirectory:"Sounds")!)
        do{
            try soundPlay = AVAudioPlayer(contentsOfURL: soundFileNameURL)
        } catch {
            print("Could not play sound file!")
        }

        soundPlay.prepareToPlay()
        soundPlay.play ()
    }
}

有人可以告诉我如何一次播放多个声音文件,以帮助我吗?任何帮助深表感谢。

非常感谢,凯


阅读 223

收藏
2020-07-07

共1个答案

一尘不染

音频停止的原因是因为您仅设置了一个AVAudioPlayer,所以当您要求类播放另一种声音时,当前您正在用新的AVAudioPlayer实例替换旧实例。您基本上是在覆盖它。

您可以创建GSAudio类的两个实例,然后在每个实例上调用playSound,或者使该类成为使用audioPlayers词典的通用音频管理器。

我更喜欢后一种选择,因为它可以使代码更简洁并且效率更高。您可以检查以前是否已经为声音创建了播放器,而不是例如创建新的播放器。

无论如何,我为您重新制作了您的课程,以便它可以一次播放多种声音。它也可以在自身上播放相同的声音(它不会替代声音的先前实例)希望对您有所帮助!

该类是单例,因此要访问该类,请使用:

GSAudio.sharedInstance

例如,要播放声音,您可以致电:

GSAudio.sharedInstance.playSound("AudioFileName")

并同时播放多种声音:

GSAudio.sharedInstance.playSounds("AudioFileName1", "AudioFileName2")

或者您可以将声音加载到数组中的某个位置,然后调用接受数组的playSounds函数:

let sounds = ["AudioFileName1", "AudioFileName2"]
GSAudio.sharedInstance.playSounds(sounds)

我还添加了playSounds函数,该函数可让您延迟以级联形式播放的每种声音。所以:

 let soundFileNames = ["SoundFileName1", "SoundFileName2", "SoundFileName3"]
 GSAudio.sharedInstance.playSounds(soundFileNames, withDelay: 1.0)

将在sound1之后播放sound2,然后sound3将在sound2之后播放秒,依此类推。

这是课程:

class GSAudio: NSObject, AVAudioPlayerDelegate {

    static let sharedInstance = GSAudio()

    private override init() {}

    var players = [NSURL:AVAudioPlayer]()
    var duplicatePlayers = [AVAudioPlayer]()

    func playSound (soundFileName: String){

        let soundFileNameURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(soundFileName, ofType: "aif", inDirectory:"Sounds")!)

        if let player = players[soundFileNameURL] { //player for sound has been found

            if player.playing == false { //player is not in use, so use that one
                player.prepareToPlay()
                player.play()

            } else { // player is in use, create a new, duplicate, player and use that instead

                let duplicatePlayer = try! AVAudioPlayer(contentsOfURL: soundFileNameURL)
                //use 'try!' because we know the URL worked before.

                duplicatePlayer.delegate = self
                //assign delegate for duplicatePlayer so delegate can remove the duplicate once it's stopped playing

                duplicatePlayers.append(duplicatePlayer)
                //add duplicate to array so it doesn't get removed from memory before finishing

                duplicatePlayer.prepareToPlay()
                duplicatePlayer.play()

            }
        } else { //player has not been found, create a new player with the URL if possible
            do{
                let player = try AVAudioPlayer(contentsOfURL: soundFileNameURL)
                players[soundFileNameURL] = player
                player.prepareToPlay()
                player.play()
            } catch {
                print("Could not play sound file!")
            }
        }
    }


    func playSounds(soundFileNames: [String]){

        for soundFileName in soundFileNames {
            playSound(soundFileName)
        }
    }

    func playSounds(soundFileNames: String...){
        for soundFileName in soundFileNames {
            playSound(soundFileName)
        }
    }

    func playSounds(soundFileNames: [String], withDelay: Double) { //withDelay is in seconds
        for (index, soundFileName) in soundFileNames.enumerate() {
            let delay = withDelay*Double(index)
            let _ = NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: #selector(playSoundNotification(_:)), userInfo: ["fileName":soundFileName], repeats: false)
        }
    }

     func playSoundNotification(notification: NSNotification) {
        if let soundFileName = notification.userInfo?["fileName"] as? String {
             playSound(soundFileName)
         }
     }

     func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) {
        duplicatePlayers.removeAtIndex(duplicatePlayers.indexOf(player)!)
        //Remove the duplicate player once it is done
    }

}
2020-07-07