2016-04-26 79 views
7

我試圖讓多個聲音文件在AVAudioPlayer實例上播放,但是當一個聲音播放時,另一個聲音會停止。我一次只能播放一個以上的聲音。這裏是我的代碼:獲取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() 
    } 
} 

任何人都可以請告訴我如何獲取多個聲音文件一次玩嗎?任何幫助深表感謝。

非常感謝, 凱

+0

你有沒有給我班上課? –

+0

@OlivierWilkinson我曾經嘗試過你的課,如果你想同時開始兩種聲音,但是我希望它能夠在第二個聲音開始播放的時候,我不希望它突然停止聲音已經在玩。感謝您的幫助 –

+0

我不確定我是否理解問題。 –

回答

10

聲音停止的原因是因爲你只需要一個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) 

將發揮SOUND2 Sound1例子後一秒鐘,然後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 
    } 

} 
+0

感謝您的編輯,但是當我嘗試使用這個類時,我得到:命令失敗,由於信號:分割故障:11.你知道如何解決這個問題嗎?非常感謝 –

+0

是的,我剛看到我自己,我無意中複製了一個與另一個衝突的函數。兩秒 –

+0

我編輯了代碼以避免分段錯誤,參見上文。或者只是刪除playSounds(soundFileNames:String ...,withDelay:Double)函數,使用數組的那個函數就可以了:) –

1

我創建了一個助手庫簡化了在Swift中播放聲音的過程。它會創建多個AVAudioPlayer實例,以允許多次同時播放相同的聲音。你可以從Github上下載它或者用Cocoapods導入。

這裏是鏈接:SwiftySound

的用法很簡單,因爲它可以:

Sound.play(file: "sound.mp3") 
+0

你是英雄我的朋友 –

1

所有的答案張貼的代碼頁;它不需要那麼複雜。

// Create a new player for the sound; it doesn't matter which sound file this is 
       let soundPlayer = try AVAudioPlayer(contentsOf: url) 
       soundPlayer.numberOfLoops = 0 
       soundPlayer.volume = 1 
       soundPlayer.play() 
       soundPlayers.append(soundPlayer) 

// In an timer based loop or other callback such as display link, prune out players that are done, thus deallocating them 
     checkSfx: for player in soundPlayers { 
      if player.isPlaying { continue } else { 
       if let index = soundPlayers.index(of: player) { 
        soundPlayers.remove(at: index) 
        break checkSfx 
       } 
      } 
     }