让AVAudioPlayer一次播放多个声音 [英] Get AVAudioPlayer to play multiple sounds at a time

查看:126
本文介绍了让AVAudioPlayer一次播放多个声音的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to get multiple sounds files to play on an AVAudioPlayer instance, however when one sound plays, the other stops. I can't get more than one sound to play at a time. Here is my code:

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

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

Can anyone please help me by telling me how to get more than one sound file to play at a time? Any help is much appreciated.

非常感谢,

Many thanks, Kai

推荐答案

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

The reason the audio stops is because you only have one AVAudioPlayer set up, so when you ask the class to play another sound you are currently replacing the old instance with a new instance of AVAudioPlayer. You are overwriting it basically.

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

You can either create two instances of the GSAudio class, and then call playSound on each of them, or make the class a generic audio manager that uses a dictionary of audioPlayers.

我更喜欢后一种选择,因为它允许更清晰的代码,也更有效。你可以检查一下你之前是否已经为声音制作了一个播放器,而不是制作一个新的播放器。

I much prefer the latter option, as it allows for cleaner code and is also more efficient. You can check to see if you have already made a player for the sound before, rather than making a new player for example.

无论如何,我重新制作了你的课程你这样它会立刻播放多个声音。它也可以播放相同的声音(它不会取代之前的声音实例)希望它有所帮助!

Anyways, I re-made your class for you so that it will play multiple sounds at once. It can also play the same sound over itself (it doesn't replace the previous instance of the sound) Hope it helps!

该类是一个单例,所以访问课程用法:

The class is a singleton, so to access the class use:

GSAudio.sharedInstance

例如,播放您要调用的声音:

for example, to play a sound you would call:

GSAudio.sharedInstance.playSound("AudioFileName")

并一次播放多个声音:

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

或者您可以在某个地方加载数组中的声音并调用接受数组的playSounds函数:

or you could load up the sounds in an array somewhere and call the playSounds function that accepts an array:

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

我还添加了一个playSounds函数,允许你以级联的格式延迟播放的每个声音。所以:

I also added a playSounds function that allows you to delay each sound being played in a cascade kind of format. So:

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

在sound1之后播放sound2,然后sound3播放在sound2等之后的第二个。

would play sound2 a second after sound1, then sound3 would play a second after sound2 etc.

这是班级:

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
    }

}

这篇关于让AVAudioPlayer一次播放多个声音的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆