2016-04-26 5 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 для каждого из них или сделать класс универсальным аудио-менеджером, который использует словарь аудиоплеер.

Я предпочитаю последний вариант, поскольку он позволяет использовать более чистый код и также более эффективен. Вы можете проверить, действительно ли вы уже сделали плеер для звука, вместо того, чтобы, например, создать нового игрока.

В любом случае, я переделал для вас свой класс, чтобы он воспроизводил сразу несколько звуков. Он также может воспроизводить один и тот же звук над собой (он не заменяет предыдущий экземпляр звука) Надеюсь, это поможет!

Класс одноэлементно, поэтому для доступа к использованию класса:

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 
       } 
      } 
     } 
Смежные вопросы