¿Cómo reproducir un sonido usando Swift?

149

Me gustaría reproducir un sonido con Swift.

Mi código funcionó en Swift 1.0 pero ahora ya no funciona en Swift 2 o posterior.

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
fuente
1
Echa un vistazo a SwiftySound . Más detalles en esta respuesta .
Adam
Si solo desea un sonido del sistema, consulte: Uso de sonidos del sistema existentes en la aplicación iOS
Honey

Respuestas:

292

Lo más preferible es que desee utilizar AVFoundation . Proporciona todos los elementos esenciales para trabajar con medios audiovisuales.

Actualización: Compatible con Swift 2 , Swift 3 y Swift 4 como lo sugieren algunos de ustedes en los comentarios.


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

Asegúrese de cambiar el nombre de su melodía, así como la extensión . El archivo debe importarse correctamente ( Project Build Phases> Copy Bundle Resources). Es posible que desee colocarlo assets.xcassetspara mayor comodidad.

Para archivos de sonido cortos, es posible que desee optar por formatos de audio no comprimidos, .wavya que tienen la mejor calidad y un bajo impacto en la CPU. El mayor consumo de espacio en disco no debería ser un gran problema para los archivos de sonido cortos. Cuanto más largos sean los archivos, es posible que desee utilizar un formato comprimido, como .mp3etc. pp. Compruebe los formatos de audio compatibles de CoreAudio.


Dato curioso: hay pequeñas bibliotecas ordenadas que hacen que la reproducción de sonidos sea aún más fácil. :)
Por ejemplo: SwiftySound

Devapploper
fuente
Lo sentimos, pero este código ya no funciona en swift 2.0, muestra un error "La llamada se puede lanzar, pero no está marcada con 'probar' y el error no se maneja"
Michel Kansou
2
Reemplazar bgMusic = AVAudioPlayer(contentsOfURL: bgMusicURL, fileTypeHint: nil)condo { bgMusic = try AVAudioPlayer(contentsOfURL: bgMusicURL, fileTypeHint: nil) } catch _ { return \\ if it doesn't exist, don't play it}
saagarjha
11
Tuve que hacer que el objeto AVAudioPlayer sea una variable de instancia para que esto funcione. Como variable local no jugaría nada, no hay error. Los delegados tampoco serían llamados.
Kaleb
2
¿Por qué usas un guardia aquí? player = try AVAudioPlayer(contentsOf: url) guard let player = player else { return }me parece un trabajo extra, ¿por qué no solo let player = try AVAudioPlayer(contentsOf: url)?
xandermonkey
2
El uso de una declaración de protección lo hace bastante seguro de fallar debido al valor nulo.
Aashish
43

Para 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)")
    }
}

La mejor práctica para los activos locales es ponerlo dentro assets.xcassetsy cargar el archivo de esta manera:

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
fuente
Este código funcionó para mí en iOS 10.2.1, xCode 8.2.1. Para mí, las dos líneas "pruebe AVAudioSession" marcaron la diferencia entre los sonidos que realmente se escuchan en un dispositivo real o no. Sin ellos, no hay sonido.
pvanallen
Esto me ayudó mucho, doaunque tengo problemas para entender lo que sucede en el bloque. Obviamente player!.play()se explica por sí mismo. Pero ¿cuál es el propósito de la setCategoryy setActivemétodos?
Shan Robertson
2
Si usted proporciona AVAudioSessionCategoryPlaybacka setCategory, se asegurará de que el audio se reproduce siempre a pesar de que el teléfono está en la pantalla de bloqueo o en modo silencioso. setActivees como decirle al sistema que su aplicación está lista para reproducir audio
Adi Nugroho
@AdiNugroho, ¿crees que podrías ayudar con mi pregunta: stackoverflow.com/questions/44201592/… ?
JamesG
Tengo muchos problemas con esto en iOS 11. Solía ​​funcionar pero ahora de repente no. ¿Algunas ideas?
nickdnk
15

iOS 12 - Xcode 10 beta 6 - Swift 4.2

Use solo 1 IBAction y apunte todos los botones a esa 1 acción.

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
fuente
55
Es curioso que asumas que todos están viendo "iOS 11 y Swift 4: el campo de entrenamiento completo de desarrollo de aplicaciones iOS" 😂😂
karlingen
12

Si el código no genera ningún error, pero no escucha el sonido, cree el reproductor como una instancia:

   static var player: AVAudioPlayer!

Para mí, la primera solución funcionó cuando hice este cambio :)

EranKT
fuente
Funciona para mi. ¿Alguien sabe por qué tienes que configurar esto como estático?
kuzdu
3
No creo que tenga que ser estático (¿ya?), Pero parece que si lo dejas fuera de alcance una vez creado, incluso si has llamado a play (), ¿no funcionará? Acabo de convertirlo en una variable de instancia de mi clase y funciona.
biomiker
3
@kuzdu Esto se debe a que no coloca el playeren el ámbito externo. De lo contrario, playerse deslocaliza y, por lo tanto, no puede reproducir ningún sonido, ya que ya no existe.
George_E
Trabajó para mí - sinstatic
Todd
5

Swift 4, 4.2 y 5

Reproduzca audio desde URL y desde su proyecto (archivo 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
fuente
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
}
Sr. Shin
fuente
1

Primero importe estas bibliotecas

import AVFoundation

import AudioToolbox    

establecer delegado como este

   AVAudioPlayerDelegate

escribe este bonito código en la acción del botón o algo de acción:

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% trabajando en mi proyecto y probado

Sr. Javed Multani
fuente
2
No hay necesidad de importar AudioToolboxen este lugar.
ixany
1

Probado con Swift 4 y 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
fuente
1

Swift 4 (compatible con 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
fuente
Me sale el siguiente error: The operation couldn’t be completed. (OSStatus error 1954115647.). He buscado en todas partes y no puedo encontrar una solución. Podría publicar una pregunta al respecto.
George_E
1

Estilo de juego:

archivo 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
}

En cualquier lugar del código

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

Este es un código básico para buscar y reproducir un archivo de audio en Swift.

Agregue su archivo de audio a su Xcode y agregue el código a continuación.

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
fuente
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
fuente
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 en swift 4 última versión. ButtonTag sería una etiqueta en un botón en su interfaz. Las notas están en una carpeta en una carpeta paralela a Main.storyboard. Cada nota se nombra como nota1, nota2, etc. ButtonTag proporciona el número 1, 2, etc. del botón que se hace clic y se pasa como parámetro

Egi Messito
fuente
0

importar AVFoundation

importar AudioToolbox

Clase 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 llamar a esta función

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

Nirbhay Singh
fuente
-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
fuente