Como tocar um som usando o Swift?

149

Eu gostaria de tocar um som usando o Swift.

Meu código funcionou no Swift 1.0, mas agora não funciona mais no Swift 2 ou mais recente.

override func viewDidLoad() {
  super.viewDidLoad()

  let url:NSURL = NSBundle.mainBundle().URLForResource("soundName", withExtension: "mp3")!

  do { 
    player = try AVAudioPlayer(contentsOfURL: url, fileTypeHint: nil) 
  } catch _{
    return
  }

  bgMusic.numberOfLoops = 1
  bgMusic.prepareToPlay()

  if (Data.backgroundMenuPlayed == 0){
    player.play()
    Data.backgroundMenuPlayed = 1
  }
}
Michel Kansou
fonte
1
Dê uma olhada no SwiftySound . Mais detalhes nesta resposta .
22417 Adam
Se você deseja apenas um som do sistema, consulte: Usando sons existentes do sistema no iOS App
Honey

Respostas:

292

De preferência, você pode querer usar o AVFoundation . Ele fornece todos os elementos essenciais para trabalhar com mídia audiovisual.

Atualização: Compatível com Swift 2 , Swift 3 e Swift 4, conforme sugerido por alguns de vocês nos comentários.


Swift 2.3

import AVFoundation

var player: AVAudioPlayer?

func playSound() {
    let url = NSBundle.mainBundle().URLForResource("soundName", withExtension: "mp3")!

    do {
        player = try AVAudioPlayer(contentsOfURL: url)
        guard let player = player else { return }

        player.prepareToPlay()
        player.play()

    } catch let error as NSError {
        print(error.description)
    }
}

Swift 3

import AVFoundation

var player: AVAudioPlayer?

func playSound() {
    guard let url = Bundle.main.url(forResource: "soundName", withExtension: "mp3") else { return }

    do {
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        try AVAudioSession.sharedInstance().setActive(true)

        let player = try AVAudioPlayer(contentsOf: url)

        player.play()

    } catch let error {
        print(error.localizedDescription)
    }
}

Swift 4 (compatível com iOS 13)

import AVFoundation

var player: AVAudioPlayer?

func playSound() {
    guard let url = Bundle.main.url(forResource: "soundName", withExtension: "mp3") else { return }

    do {
        try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)            
        try AVAudioSession.sharedInstance().setActive(true)

        /* The following line is required for the player to work on iOS 11. Change the file type accordingly*/
        player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)

        /* iOS 10 and earlier require the following line:
        player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3) */

        guard let player = player else { return }

        player.play()

    } catch let error {
        print(error.localizedDescription)
    }
}

Certifique-se de alterar o nome da sua música e a extensão . O arquivo precisa ser importado corretamente ( Project Build Phases> Copy Bundle Resources). Você pode colocá-lo assets.xcassetspara maior comodidade.

Para arquivos de som curtos, você pode optar por formatos de áudio não compactados, como os .wavque têm a melhor qualidade e o menor impacto na CPU. O maior consumo de espaço em disco não deve ser um grande problema para arquivos de som curtos. Quanto mais longos os arquivos, você pode optar por um formato compactado, como .mp3etc. pp. Verifique os formatos de áudio compatíveis de CoreAudio.


Curiosidade: Existem pequenas bibliotecas organizadas que tornam a reprodução de sons ainda mais fácil. :)
Por exemplo: SwiftySound

Devapploper
fonte
Desculpe, mas este código não funciona mais em Swift 2.0 que solicitará um erro "Call pode jogar, mas não está marcado com 'try' eo erro não é tratado"
Michel Kansou
2
Substitua bgMusic = AVAudioPlayer(contentsOfURL: bgMusicURL, fileTypeHint: nil)pordo { bgMusic = try AVAudioPlayer(contentsOfURL: bgMusicURL, fileTypeHint: nil) } catch _ { return \\ if it doesn't exist, don't play it}
saagarjha
11
Eu tive que tornar o objeto AVAudioPlayer uma variável de instância para fazer com que isso funcionasse. Como uma variável local, não tocaria nada, sem erros. Os delegados também não seriam chamados.
Kaleb
2
Por que você usa um guarda aqui? player = try AVAudioPlayer(contentsOf: url) guard let player = player else { return }parece trabalho extra para mim, por que não apenas let player = try AVAudioPlayer(contentsOf: url)?
xandermonkey
2
Usar uma declaração de guarda faz com que você fique bem protegido contra falhas devido ao valor nulo.
Aashish
43

Para o Swift 3 :

import AVFoundation

/// **must** define instance variable outside, because .play() will deallocate AVAudioPlayer 
/// immediately and you won't hear a thing
var player: AVAudioPlayer?

func playSound() {
    guard let url = Bundle.main.url(forResource: "soundName", withExtension: "mp3") else {
        print("url not found")
        return
    }

    do {
        /// this codes for making this app ready to takeover the device audio
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        try AVAudioSession.sharedInstance().setActive(true)

        /// change fileTypeHint according to the type of your audio file (you can omit this)

        player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3)

        // no need for prepareToPlay because prepareToPlay is happen automatically when calling play()
        player!.play()
    } catch let error as NSError {
        print("error: \(error.localizedDescription)")
    }
}

A melhor prática para recursos locais é colocá-lo dentro assets.xcassetse você carrega o arquivo assim:

func playSound() {
    guard let url = Bundle.main.url(forResource: "soundName", withExtension: "mp3") else {
        print("url not found")
        return
    }

    do {
        /// this codes for making this app ready to takeover the device audio
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        try AVAudioSession.sharedInstance().setActive(true)

        /// change fileTypeHint according to the type of your audio file (you can omit this)

        /// for iOS 11 onward, use :
        player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)

        /// else :
        /// player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3)

        // no need for prepareToPlay because prepareToPlay is happen automatically when calling play()
        player!.play()
    } catch let error as NSError {
        print("error: \(error.localizedDescription)")
    }
}
Adi Nugroho
fonte
Este código funcionou para mim no iOS 10.2.1, xCode 8.2.1. Para mim, as duas linhas "try AVAudioSession" fizeram a diferença entre os sons realmente sendo ouvidos em um dispositivo real ou não. Sem eles, nenhum som.
precisa saber é o seguinte
Isso me ajudou muito, mas estou tendo alguns problemas para entender o que acontece no dobloco. obviamente player!.play()é auto-explicativo. Mas qual é o propósito dos métodos setCategorye setActive?
Shan Robertson
2
Se você fornecer AVAudioSessionCategoryPlaybackpara setCategory, ele vai garantir o áudio é sempre desempenhou embora telefone está em tela de bloqueio ou no modo silencioso. setActiveé como dizer ao sistema que seu aplicativo está pronto para áudio jogo
Adi Nugroho
@AdiNugroho você acha que poderia ajudar com a minha pergunta: stackoverflow.com/questions/44201592/… ?
26617 JamesGay
Estou tendo muitos problemas com isso no iOS 11. Costumava funcionar, mas agora de repente não funciona. Alguma ideia?
nickdnk
15

iOS 12 - Xcode 10 beta 6 - Swift 4.2

Use apenas 1 IBAction e aponte todos os botões para essa 1 ação.

import AVFoundation

var player = AVAudioPlayer()

@IBAction func notePressed(_ sender: UIButton) {
    print(sender.tag) // testing button pressed tag
    let path = Bundle.main.path(forResource: "note\(sender.tag)", ofType : "wav")!
    let url = URL(fileURLWithPath : path)
    do {
        player = try AVAudioPlayer(contentsOf: url)
        player.play()
    } catch {
        print ("There is an issue with this code!")
    }
}
Tony Ward
fonte
5
É engraçado que você está assumindo que todo mundo está assistindo "iOS 11 & Swift 4 - The Complete iOS App Desenvolvimento Bootcamp" 😂😂
karlingen
12

Se o código não gerar nenhum erro, mas você não ouvir som - crie o player como uma instância:

   static var player: AVAudioPlayer!

Para mim, a primeira solução funcionou quando fiz essa alteração :)

EranKT
fonte
Funciona para mim. Alguém sabe por que você precisa definir isso como estático?
Kuzdu
3
Eu não acho que tenha que ser estático (mais?), Mas parece que, se você deixar o escopo depois de criado, mesmo que você tenha chamado play (), ele não será reproduzido? Acabei de torná-lo uma variável de instância da minha classe e funciona.
Biomiker # 23/18
3
@kuzdu Isso ocorre porque você não coloca o playerescopo externo. Caso contrário, playeré deslocalizado e, portanto, não pode reproduzir nenhum som, pois ele não existe mais.
George_E
Trabalhou para mim - semstatic
Todd
5

Swift 4, 4.2 e 5

Reproduzir áudio a partir do URL e do seu projeto (arquivo local)

import UIKit
import AVFoundation

class ViewController: UIViewController{

var audioPlayer : AVPlayer!

override func viewDidLoad() {
        super.viewDidLoad()
// call what ever function you want.
    }

    private func playAudioFromURL() {
        guard let url = URL(string: "https://geekanddummy.com/wp-content/uploads/2014/01/coin-spin-light.mp3") else {
            print("error to get the mp3 file")
            return
        }
        do {
            audioPlayer = try AVPlayer(url: url as URL)
        } catch {
            print("audio file error")
        }
        audioPlayer?.play()
    }

    private func playAudioFromProject() {
        guard let url = Bundle.main.url(forResource: "azanMakkah2016", withExtension: "mp3") else {
            print("error to get the mp3 file")
            return
        }

        do {
            audioPlayer = try AVPlayer(url: url)
        } catch {
            print("audio file error")
        }
        audioPlayer?.play()
    }

}
Akbar Khan
fonte
3

Swift 3

import AVFoundation


var myAudio: AVAudioPlayer!

    let path = Bundle.main.path(forResource: "example", ofType: "mp3")!
    let url = URL(fileURLWithPath: path)
do {
    let sound = try AVAudioPlayer(contentsOf: url)
    myAudio = sound
    sound.play()
} catch {
    // 
}

//If you want to stop the sound, you should use its stop()method.if you try to stop a sound that doesn't exist your app will crash, so it's best to check that it exists.

if myAudio != nil {
    myAudio.stop()
    myAudio = nil
}
Mr.Shin
fonte
1

Primeiro importe essas bibliotecas

import AVFoundation

import AudioToolbox    

definir delegado como este

   AVAudioPlayerDelegate

escreva este código bonito na ação do botão ou algo:

guard let url = Bundle.main.url(forResource: "ring", withExtension: "mp3") else { return }
    do {
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        try AVAudioSession.sharedInstance().setActive(true)
        player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
        guard let player = player else { return }

        player.play()
    }catch let error{
        print(error.localizedDescription)
    }

100% trabalhando no meu projeto e testado

Mr.Javed Multani
fonte
2
Não há necessidade de importar AudioToolboxneste local.
Ixany
1

Testado com Swift 4 e iOS 12:

import UIKit
import AVFoundation
class ViewController: UIViewController{
    var player: AVAudioPlayer!
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    func playTone(number: Int) {
        let path = Bundle.main.path(forResource: "note\(number)", ofType : "wav")!
        let url = URL(fileURLWithPath : path)
        do {
            player = try AVAudioPlayer(contentsOf: url)
            print ("note\(number)")
            player.play()
        }
        catch {
            print (error)
        }
    }

    @IBAction func notePressed(_ sender: UIButton) {
        playTone(number: sender.tag)
    }
}
Ershin Bot
fonte
1

Swift 4 (compatível com iOS 12)

var player: AVAudioPlayer?

let path = Bundle.main.path(forResource: "note\(sender.tag)", ofType: "wav")
let url = URL(fileURLWithPath: path ?? "")
    
do {
   player = try AVAudioPlayer(contentsOf: url)
   player?.play()
} catch let error {
   print(error.localizedDescription)
}
imdpk
fonte
Eu recebo o seguinte erro: The operation couldn’t be completed. (OSStatus error 1954115647.). Procurei em todos os lugares e não consigo encontrar uma solução. Pode postar uma pergunta sobre isso.
George_E
1

Estilo de jogo:

arquivo Sfx.swift

import AVFoundation

public let sfx = Sfx.shared
public final class Sfx: NSObject {
    
    static let shared = Sfx()
    
    var apCheer: AVAudioPlayer? = nil
    
    private override init() {
        guard let s = Bundle.main.path(forResource: "cheer", ofType: "mp3") else {
            return  print("Sfx woe")
        }
        do {
            apComment = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: s))
        } catch {
            return  print("Sfx woe")
        }
    }
    
    func cheer() { apCheer?.play() }
    func plonk() { apPlonk?.play() }
    func crack() { apCrack?.play() } .. etc
}

Em qualquer lugar no código

sfx.explosion()
sfx.cheer()
Fattie
fonte
1

Este é o código básico para encontrar e reproduzir um arquivo de áudio no Swift.

Adicione seu arquivo de áudio ao seu Xcode e adicione o código abaixo.

import AVFoundation

class ViewController: UIViewController {

   var audioPlayer = AVAudioPlayer() // declare globally

   override func viewDidLoad() {
        super.viewDidLoad()

        guard let sound = Bundle.main.path(forResource: "audiofilename", ofType: "mp3") else {
            print("Error getting the mp3 file from the main bundle.")
            return
        }
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: sound))
        } catch {
            print("Audio file error.")
        }
        audioPlayer.play()
    }

    @IBAction func notePressed(_ sender: UIButton) { // Button action
        audioPlayer.stop()
    }
}
M VIJAY
fonte
0
import UIKit
import AVFoundation

class ViewController: UIViewController{

    var player: AVAudioPlayer?

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func notePressed(_ sender: UIButton) {

        guard let url = Bundle.main.url(forResource: "note1", withExtension: "wav") else { return }

        do {
            try AVAudioSession.sharedInstance().setCategory((AVAudioSession.Category.playback), mode: .default, options: [])
            try AVAudioSession.sharedInstance().setActive(true)


            /* The following line is required for the player to work on iOS 11. Change the file type accordingly*/
            player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.wav.rawValue)

            /* iOS 10 and earlier require the following line:
             player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3) *//

            guard let player = player else { return }

            player.play()

        } catch let error {
            print(error.localizedDescription)
        }

    }

}
Hunter Akers
fonte
0
var soundEffect = AVAudioPlayer()

func playSound(_ buttonTag : Int){

    let path = Bundle.main.path(forResource: "note\(buttonTag)", ofType : "wav")!
    let url = URL(fileURLWithPath : path)

    do{
        soundEffect = try AVAudioPlayer(contentsOf: url)
        soundEffect?.play()
        // to stop the spound .stop()
    }catch{
        print ("file could not be loaded or other error!")
    }
}

funciona na versão mais recente do swift 4. ButtonTag seria uma tag em um botão na sua interface. As anotações estão em uma pasta paralela ao Main.storyboard. Cada nota é nomeada como nota1, nota2, etc. ButtonTag está fornecendo o número 1, 2, etc. a partir do botão clicado que é passado como param

Egi Messito
fonte
0

importar AVFoundation

importar AudioToolbox

classe final pública MP3Player: NSObject {

// Singleton class
static let shared:MP3Player = MP3Player()

private var player: AVAudioPlayer? = nil

// Play only mp3 which are stored in the local
public func playLocalFile(name:String) {
    guard let url = Bundle.main.url(forResource: name, withExtension: "mp3") else { return }

    do {
        try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
        try AVAudioSession.sharedInstance().setActive(true)
        player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
        guard let player = player else { return }

        player.play()
    }catch let error{
        print(error.localizedDescription)
    }
}

}

// Para chamar esta função

MP3Player.shared.playLocalFile (nome: "JungleBook")

Nirbhay Singh
fonte
-1
import AVFoundation
var player:AVAudioPlayer!

func Play(){
    guard let path = Bundle.main.path(forResource: "KurdishSong", ofType: "mp3")else{return}
    let soundURl = URL(fileURLWithPath: path)
    player = try? AVAudioPlayer(contentsOf: soundURl)
    player.prepareToPlay()
    player.play()
    //player.pause()
    //player.stop()
}
Mobin Valadi
fonte